Skip to content

De-amplify contract definitions#142

Open
ymichael wants to merge 12 commits into
mainfrom
bb/contract-de-amplification-scope-thr_bxcf4x4ky3
Open

De-amplify contract definitions#142
ymichael wants to merge 12 commits into
mainfrom
bb/contract-de-amplification-scope-thr_bxcf4x4ky3

Conversation

@ymichael

@ymichael ymichael commented Jun 14, 2026

Copy link
Copy Markdown
Owner

Why this PR exists

The contract layer had become an amplifier: adding or changing one public field could require edits across the public schema, typed route registration, SDK return interfaces, handler request plumbing, daemon command maps, and desktop IPC types that were not actually served by the server. That made small API changes noisy, raised the chance of drift, and made later behavioral work pay the same churn tax repeatedly.

This PR is the structural cleanup before those behavioral phases. It reduces the number of authoritative contract definitions and moves boundary-specific contracts to the package that owns them.

Concrete before / after

Before, desktop-only IPC lived inside @bb/server-contract even though the server never served it. For example, the app and Electron shell imported BbDesktopApi, browser IPC schemas, version-feed types, and popout IPC contracts from packages/server-contract/src/api-types.ts. After this PR, those contracts live in @bb/desktop-contract under src/browser.ts, src/info.ts, src/popout.ts, and src/version-feed.ts; @bb/server-contract no longer owns desktop IPC symbols.

Before, a public route shape had multiple authorities: the response type lived in api-types.ts, the route path/method lived in public-api.ts, typed route registration repeated the route shape in the server, and the SDK could still hand-declare a different return interface. After this PR, route descriptors colocate path, method, request, and response, typedRoutes registers from that descriptor, and SDK result types derive from PublicApiSchema success outputs. A thread route response change now flows through the descriptor-derived contract instead of a parallel SDK type universe.

Before, adding a daemon command meant touching separate command unions, schema maps, result maps, command type lists, routing metadata, and flush behavior. After this PR, each command is registered once in the host-daemon command registry with its descriptor: type, schema, resultSchema, delivery mode, retryability, flush behavior, and lane metadata. The unions and lookup maps derive from that descriptor table.

Before, request defaults could leak past the API boundary. For example, automation/thread creation inputs could still carry omitted/defaulted fields into internal code, forcing service types to accept optional forms. After this PR, route handlers resolve those inputs once, then internal code receives explicit values.

What changed

  • Created @bb/desktop-contract and moved the desktop IPC surface out of @bb/server-contract, including browser, version feed, theme, and popout IPC contracts.
  • Split the large public API type file into resource modules under packages/server-contract/src/api/.
  • Added route descriptors in @bb/hono-typed-routes so each route can colocate path, method, request, and response once.
  • Converted the public API schema to derive from those descriptors instead of maintaining a parallel schema shape.
  • Added a host-daemon command registry that derives command unions, schemas, command lists, and dispatch metadata from one descriptor table.
  • Removed dead daemon commands that no longer need to be part of the host command floor.
  • Changed SDK result typing to derive success response types from contract schemas instead of hand-declared response interfaces.
  • Resolved creation defaults once at the route boundary so internal services receive explicit values instead of carrying optional/defaulting logic deeper into the system.

Why this should be accepted

  • It directly lowers contract churn: public route shape, handler registration, and SDK typing now share source definitions instead of drifting in parallel.
  • It fixes an ownership boundary: desktop-only IPC contracts no longer live in the server contract package.
  • It removes known drift risk: SDK return types now come from z.infer over the contract instead of handwritten interfaces.
  • It makes daemon command registration auditable: adding a command is now centered on one descriptor rather than spread across maps, unions, and switch helpers.
  • It reduces future review load: later API and daemon changes should show smaller, more meaningful diffs because the derivation is structural.
  • It keeps runtime behavior intentionally narrow: the large diff is mostly contract/package reshaping, import rewiring, and boundary defaulting; dead daemon command removals are isolated and covered by contract/dispatch tests.

Review notes

The highest-value review path is:

  1. Check the new descriptor APIs in packages/hono-typed-routes.
  2. Check packages/server-contract/src/public-api.ts and the split resource modules to confirm route descriptors preserve the old public API shape.
  3. Check packages/host-daemon-contract/src/commands.ts for command registry derivations.
  4. Check the desktop extraction import rewiring to confirm desktop IPC moved to @bb/desktop-contract without changing the IPC channel semantics.
  5. Check the server route default-resolution changes where request optionals now become explicit internal values.

Validation

  • pnpm exec turbo run build typecheck lint test --cache-dir=.turbo/cache --output-logs=new-only
  • pnpm exec turbo run typecheck --filter=@bb/server --filter=@bb/sdk --filter=@bb/cli
  • pnpm exec turbo run test --filter=@bb/sdk --filter=@bb/cli

@ymichael ymichael force-pushed the bb/contract-de-amplification-scope-thr_bxcf4x4ky3 branch from 5a28daf to 59a2cb2 Compare June 14, 2026 03:31
@ymichael ymichael force-pushed the bb/contract-de-amplification-scope-thr_bxcf4x4ky3 branch from 59a2cb2 to 196bc63 Compare June 14, 2026 03:42
@ymichael

Copy link
Copy Markdown
Owner Author

Agreed. This is accurate, and I should not frame this PR as completing those two exit criteria.

What this PR does finish is the structural contract de-amplification work: desktop IPC extraction, public API resource split, route descriptors, descriptor-derived public API schema, host-daemon command registry, SDK return-type derivation, and an initial boundary-defaulting pass.

What it does not finish:

  • The optional-field allowlist target. I verified the current INTENTIONAL_OPTIONAL_SERVER_FIELDS count is still 96. This branch only removes a few entries, so the <=30 target remains follow-up work.
  • The field-addition probe. I do not have a recorded dummy-field add/count/revert probe for this PR, so we should not claim that exit check is satisfied.

I’d treat both as next-slice acceptance criteria, not as completed scope for this PR. The PR should be reviewed as the enabling structure that makes those follow-up reductions cheaper, not as the final Phase 1 completion marker.

@ymichael ymichael force-pushed the bb/contract-de-amplification-scope-thr_bxcf4x4ky3 branch from 196bc63 to 94c30f4 Compare June 14, 2026 21:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant