Files
boocode/openspec/changes/contracts-ssot/tasks.md
indifferentketchup 649ce71eff feat: single-source cross-app wire contracts in @boocode/contracts (v2.7.13)
Move all hand-synced cross-app wire contracts into one built workspace
package, @boocode/contracts, consumed by server/web/coder/coder-web via
workspace:* + a per-subpath exports map. The ws-frames and provider-config
Zod schemas are schema-first (z.infer); MessageMetadata, ErrorReason,
AgentSessionConfig, the provider snapshot types, and WorktreeRiskReport are
each single-sourced. Deletes the byte-identical copies and their parity
tests, fixes a live AgentSessionConfig drift (coder dead copy removed,
unified to the web required/nullable shape), removes the dead pending_change
WS arms in the fallback SPA, and inverts the build order (contracts builds
first) across root build, Dockerfile, and the coder deploy docs. Reverses
the shared-package decision declined in v2.5.12.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-02 21:24:08 +00:00

6.3 KiB
Raw Blame History

Tasks — @boocode/contracts SSOT

Nine phases, each independently verifiable. Phases 17 are the migration units (one contract group each after a proven tracer); Phase 8 is the audit gate; Phase 9 is the human smoke test. All shipped 2026-06-02.

Phase 1 — Tracer: scaffold package + build-order inversion + web proof SHIPPED

  • Create packages/contracts (@boocode/contracts): declaration:true, per-subpath exports map, zod ^3.23.8. Placeholder src/index.ts.
  • Add packages/* to pnpm-workspace.yaml.
  • Invert build order everywhere: root package.json build script, Dockerfile (COPY packages/* + contracts build before web/server), coder deploy command.
  • Regenerate pnpm-lock.yaml (Dockerfile uses --frozen-lockfile).
  • Prove the web consumption path end-to-end: tsc -b (composite+Bundler), vite dev HMR, and vite build all resolve the built .d.ts+.js via the exports map.
  • Verify all consumer builds + docker compose build boocode green.
  • Remove Phase 1 probe artifacts before Phase 2.

Phase 2a — Single-source the ws-frames runtime schema SHIPPED

  • Move ws-frames schema to packages/contracts/src/ws-frames.ts (./ws-frames subpath).
  • Repoint 8 server/coder importers + 2 web validators to @boocode/contracts/ws-frames.
  • Delete apps/server/src/types/ws-frames.ts; drop server ./ws-frames exports subpath.
  • Delete apps/web/src/api/ws-frames.ts.
  • Move KNOWN_FRAME_TYPES drift + accept/reject tests into the package (11/11); delete byte-parity test; keep broker fail-closed tests in server importing from the package.
  • Container smoke: docker compose up, /api/health 200, broker imports from package.

Phase 3 — Single-source provider snapshot types SHIPPED

  • Move ProviderSnapshotEntry, ProviderModel, ProviderMode, ThinkingOption, AgentCommand, ProviderSnapshotStatus to packages/contracts/src/provider-snapshot.ts (./provider-snapshot subpath).
  • apps/coder/src/services/provider-types.ts re-exports them (importers unchanged).
  • Delete web mirror block; delete provider-types-parity.test.ts (coder 6 tests).
  • All builds and typechecks green; server 543 / coder 293 unchanged.

Phase 4 — Single-source the Zod provider-config schemas SHIPPED

  • Move ProviderOverrideSchema, CoderProvidersFileSchema, ProviderConfigPatchSchema + z.infer types to packages/contracts/src/provider-config.ts (./provider-config subpath).
  • apps/coder/src/services/provider-config.ts imports + re-exports (importers unchanged).
  • Delete 17-line web hand-mirror.
  • Coder provider-config tests 13/13; all builds green.

Phase 5 — Single-source type-only contracts (MessageMetadata + AgentSessionConfig) SHIPPED

  • Move MessageMetadata, ErrorReason, AgentSessionConfig to packages/contracts/src/message-metadata.ts (./message-metadata subpath).
  • Unify AgentSessionConfig to the web required/nullable shape; delete the coder's dead all-optional copy (zero live importers confirmed).
  • Delete all duplicate MessageMetadata + ErrorReason copies (confirmed byte-identical).
  • Repoint server api.ts, web types, and MessageBubble.tsx to the package.
  • Server 543 / coder 293 unchanged; all builds green.

Phase 6 — Single-source WorktreeRiskReport SHIPPED

  • Move WorktreeRiskReport to packages/contracts/src/worktree-risk.ts (./worktree-risk subpath); unify name (coder RiskReportWorktreeRiskReport).
  • Delete all three copies (shapes identical, names differed).
  • Repoint sessions.ts, ProjectSidebar.tsx, orphan-worktree-reaper.ts, worktree-safety.ts via re-exports; checkWorktreeWorkAtRisk returns shared type.
  • Server 543 / coder 293 unchanged; all builds green.

Phase 7 — Migrate apps/coder/web (fallback SPA) SHIPPED

  • Add @boocode/contracts workspace:* dep to apps/coder/web/package.json.
  • Delete hand-copied 9-arm WsFrame union; import canonical WsFrame from the package.
  • Reconcile field conflicts: tool_result.error boolean→string; tokens_used number→number|null; snapshot.messages cast as Message[]; chat_id ?? ''.
  • Delete dead pending_change_added/pending_change_updated reducer arms + the entire dead onPendingChange WS plumbing (DiffPane prop, Session.tsx listener).
  • Confirm HTTP pending-change apply/reject path untouched.
  • apps/coder/web Vite build green; root build + server 543 / coder 293 green.

Phase 8 — Audit every requirement bullet PASSED (12/12)

  • Verify one definition per contract (file + line evidence for each).
  • Verify z.infer for both Zod contracts (ws-frames, provider-config).
  • Verify all four consumers wired via exports map (no project refs, no src imports).
  • Verify all hand-copies + parity tests deleted; drift/broker tests preserved.
  • Verify single zod version; build-order inverted in root + Dockerfile + deploy docs.
  • Verify packages/* in workspace; dead pending_change_* arms gone.
  • Verify web strict union preserved + coherent post-migration.
  • Close gap G: update coder deploy command in all 7 doc sites (CLAUDE.md, apps/coder/CLAUDE.md, BOOCODER.md, docs/ARCHITECTURE.md, docs/project-discovery.md, README.md, docs/coder-backends.md).
  • Correct now-false byte-parity/duplication claims in CLAUDE.md conventions, apps/server/CLAUDE.md broker note, docs/coder-backends.md, and docs/coding-standards/cross-app-contract-parity.md (rewritten to describe the SSOT).
  • Mark DEFERRED-WORK §3 + STALE-DEPRECATED item as shipped.
  • Clean docker compose build --no-cache boocode green; server 543 / coder 293 / contracts 11 at exact baselines; nothing staged (HEAD e5ce01a).

Phase 9 — Human smoke test PASSED (Sam, 2026-06-02)

  • Web dev HMR, web prod build at :9500, live WS stream rendering.
  • Coder restart + a turn; fallback SPA; pending-change apply.

Verify (all runs green)

  • pnpm -C packages/contracts build
  • pnpm -C apps/server test (543)
  • pnpm -C apps/coder test (293)
  • pnpm -C apps/server build && pnpm -C apps/coder build
  • npx tsc -p apps/web/tsconfig.app.json --noEmit
  • docker compose build --no-cache boocode