feat: add repo-config Durable Object + push sync workflow#113
Merged
neekolas merged 21 commits intoxmtplabs:mainfrom Apr 20, 2026
Merged
feat: add repo-config Durable Object + push sync workflow#113neekolas merged 21 commits intoxmtplabs:mainfrom
neekolas merged 21 commits intoxmtplabs:mainfrom
Conversation
Add smol-toml dependency and declare the workflow, durable object, and SQLite migration bindings required by the upcoming repo config loader. Implementations of RepoConfigDO and RepoConfigWorkflow land in later tasks; typecheck currently passes because wrangler emits placeholder comments for unresolved class names.
Colocated test suite for the upcoming sqlite-backed RepoConfigDO: binding smoke checks plus five round-trip scenarios (fresh read, defaults applied, overwrite-no-merge, volume path-only default size, and distinct-fullName isolation). Each test uses its own idFromName to avoid cross-test state.
RepoConfigDO is a sqlite-backed Durable Object (see wrangler.toml migration v1 new_sqlite_classes) that stores one StoredRepoConfig envelope per repository, routed by idFromName(repositoryFullName). It exposes two RPC methods: - setRepoConfig(cfg): persists the sparse envelope via the synchronous ctx.storage.kv.put API (no await). - getRepoConfig(): reads the envelope and projects it into a fully resolved RepoConfig via resolveRepoConfigSettings, returning null when no value has been written. The class is re-exported from src/main.ts so Wrangler can resolve class_name = "RepoConfigDO" on the Worker entry. worker-configuration.d.ts is regenerated via wrangler types so the binding is typed as DurableObjectNamespace<RepoConfigDO> and the RPC methods are reachable from callers with full type safety. Per EARS-REQ-12 the DO performs no GitHub or Coder I/O — it is a passive store.
…ions Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…low payload The earlier regeneration (commit 2f5eb86) ran before the RepoConfigWorkflow class existed, so wrangler fell back to an unparameterized Workflow type. With the class now present, the generator resolves the payload generic.
neekolas
reviewed
Apr 20, 2026
…KV keys Per reviewer feedback on PR xmtplabs#113: store repositoryId, repositoryFullName, and installationId under their own KV keys, and keep only the sparse settings parsed from the TOML file under the `config` key. The four synchronous .put calls run back-to-back with no awaits between them, so they commit as a single implicit transaction. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Resolves #112
Summary
On every push to a repo's default branch, the Worker now fetches
.code-factory/config.tomlfrom the head SHA, sparse-validates it (TOML + Zod), and overwrites a per-repo SQLite-backed Durable Object. Defaults are applied only on read, so the stored record stays sparse and defaults can evolve without migrations.New surfaces
ConfigPushEvent— fifth variant of theEventunion (src/events/types.ts).RepoConfigWorkflow— dedicatedWorkflowEntrypointthat runsrunSyncRepoConfig(src/workflows/repo-config-workflow.ts).runSyncRepoConfig— three-step factory:fetch-config-file→parse-and-validate→store-repo-config(src/workflows/steps/sync-repo-config.ts).RepoConfigDO— SQLite-backed Durable Object using synchronousctx.storage.kv(src/durable-objects/repo-config-do.ts).GitHubClient.getRepoContentFile— 404/directory/symlink/non-base64 all resolve tonull(src/services/github/client.ts).[sandbox],[harness],[[scheduled_jobs]](src/config/repo-config-schema.ts).Wiring
wrangler.toml— new[[workflows]],[[durable_objects.bindings]], and[[migrations]](v1,new_sqlite_classes = ["RepoConfigDO"]).src/main.ts— branches workflow dispatch onresult.type === "config_push".TaskRunnerWorkflow—config_pushguard throwsNonRetryableError(misrouting is observable, not silent).buildInstanceId— deterministic compositeconfig_push-{repoName}-{headSha}-{deliveryId}preserves the dedupe anchor.Testing
introspectWorkflowover the realREPO_CONFIG_WORKFLOWbinding.Test plan
npm run typecheck— cleannpm run lint— cleannpm run format:check— cleannpm test— 350 passednpx wrangler typesis idempotent against the committedworker-configuration.d.tsSpec & plan
docs/plans/2026-04-20-issue-112-design.mddocs/plans/2026-04-20-issue-112-tasks.mdFollow-ups (not in this PR)
contents:readforgetRepoContentFileto see.code-factory/config.toml.scheduled_jobs[].schedulecron validation is a string today; future work could add a cron-pattern check.RepoConfigDO.getRepoConfig()in separate issues per §2 non-goals.🤖 Generated with Claude Code
Note
Add
RepoConfigDODurable Object andRepoConfigWorkflowto sync repo config on pushconfig_pushevent type and routes default-branch GitHub push webhooks to a newRepoConfigWorkflowinstead ofTaskRunnerWorkflow.RepoConfigWorkflowruns three steps: fetch.code-factory/config.tomlat the pushed SHA viaGitHubClient.getRepoContentFile, parse/validate it withparseRepoConfigToml(usingsmol-tomland Zod), then write sparse settings toRepoConfigDO.RepoConfigDOis a new SQLite-backed Durable Object keyed by repository full name; it stores identity fields and sparse config separately, applying Zod defaults only at read time viaresolveRepoConfigSettings.TaskRunnerWorkflownow throwsNonRetryableErrorif it receives aconfig_pushpayload.RepoConfigDOSQLite migration (v1) andREPO_CONFIG_WORKFLOWbinding are provisioned on next deploy.Macroscope summarized cc532f3.