Skip to content

fix(spec): register document-print-and-mail in loadBuiltinCsds (board N64) - #435

Merged
LamaSu merged 2 commits into
masterfrom
fix/builtin-print-and-mail-csd
Sep 30, 2026
Merged

LamaSu merged 2 commits into
masterfrom
fix/builtin-print-and-mail-csd

Conversation

@LamaSu

@LamaSu LamaSu commented Sep 29, 2026 •

Copy link
Copy Markdown
Owner

Summary

Board row N64 (Gate E; blocks R46). Steward ruling #3523.

document-print-and-mail.csd.json is the reference vertical's workflow CSD (print, then hand-off, then mail). It was added on 8/27, after the loadBuiltinCsds() list was written, and was never registered. The gateway's shared registry (getCsdRegistry(), packages/gateway/src/routes/csd.ts) is built from that list, so:

  • on master today, getCsdRegistry().findUrlByType("document-print-and-mail") returns undefined;
  • R10 (/api/agent-plans/validate, on the stack at feat(gateway): live provider re-read for externally authored plans (R10) #355, not yet on master) reads that same registry through csdForType. Once the stack lands, it would return null for the print leg, and the reference vertical could not validate.

The real-state trace (#433) proved the gap against real DB rows and the real registry. It then had to close the gap with a test-local register() call.

This PR adds one entry to the builtins array (packages/spec/src/csd/registry.ts) and updates the tests that count builtins.

What changes, and what does not

The CSD is unchanged: status: "draft", kind: "workflow", no composition block, no type field.

  • The D2 registry snapshot (/api/compose/registry-snapshot) is unchanged. The adapter projects only active CSDs that carry a composition block (registry-contract-adapter.ts:126-129), and this CSD fails both tests.
    • To be plain: no builtin carries a composition block today, so the snapshot holds no builtin contracts either way.
    • The new digest test is therefore a tripwire for the day this CSD becomes active with a composition block. It does not prove the filter.
    • The filter is proven by registry-contract-adapter.test.ts and by the gateway test "excludes draft and retired CSDs from the served snapshot".
  • No existing type can be captured. findUrlByType takes exact matches only: the URL slug first, then an explicit type field, then the name. This CSD has no type field, so 2d-print, courier-route and the other types resolve as before.
  • What becomes visible: the reference vertical now appears wherever the shared registry is listed.
    • GET /api/csd.
    • The capability-type union in routes/capabilities.ts (csdRegisteredTypes).
    • A2A pcc-suggest-templates (kind: workflow).
    • A2A author-integration usage attribution, for an operator publishing type document-print-and-mail.
    • That visibility is the point of N64, but it surfaces a draft CSD. See the review ask below.
  • Status is not a gate on this path. findUrlByType, list() and suggest() do not filter on status, and neither does R10's csdForType or the compile path. Only the D2 snapshot identity does (capability-contract-identity.ts:124). So with this PR, the type of a draft CSD resolves for R10. That is N64's intent, and it is the membership question below.
  • Consumers checked, via a sweep for loadBuiltinCsds and getCsdRegistry across the repo:
    • gateway csd, capabilities, registry-snapshot, discover and a2a-tasks;
    • contract-builder compileAll, which is used only in tests.

Tests

Head bef59df9: 2d808180 (the fix) plus a comment-only commit that states the tripwire.

Suite Result
pnpm -C packages/spec exec vitest run 38 files, 799 passed
gateway: every test file that touches the CSD registry, snapshot, capability list or a2a 24 files, 361 passed
contract-builder babel-pcc + liquid-handling-plr 77 passed (see note)

Count assertions:

  • 8 → 9: spec csd.test.ts, spec evidence-primitives.test.ts, contract-builder babel-pcc.test.ts.
  • 9 → 10: gateway csd.test.ts, whose count includes the compiled-in dashboard manifest.

The "all built-in CSDs have kind = 'base'" test becomes "the 8 capability built-ins are base; the reference vertical is the one workflow".

New tests in spec csd.test.ts:

  • resolves the reference vertical's capability type (board N64);
  • leaves the D2 registry snapshot digest unchanged (draft, no composition block).

Mutation checks on registry.ts, run against spec csd.test.ts (57 tests):

  • dropping the builtin: killed, 6 failed;
  • disabling the slug-match pass: killed, 1 failed (the N64 test).

Note: on master, babel-pcc.test.ts fails at file level in a worktree without a built @pcc/spec dist. That failure predates this PR and is unrelated to it. I ran it with a source alias. CI builds first.

Follow-up (not in this PR)

#433 (the real-state trace, stacked on #415) asserts the gap before seeding: external-plan-real-state-trace.test.ts:139, toBeUndefined(). Once this lands and the stack picks up master, that line flips. I will replace the prove-then-seed step with a resolve-via-builtin assertion then. #433 has no queued review pack.

Review asks

  • kits (builtin membership): should a draft workflow CSD be a builtin, visible in /api/csd and in template suggestions, and resolvable by R10 (nothing on that path gates on status)?
    • The alternative is to promote it to active first.
    • Promoting would still not touch the D2 snapshot while the CSD has no composition block.
    • Adding a composition block later would move the digest. That is a separate change.
  • Cross-family: a small first-review pack follows (steward #3523).

🤖 Generated with Claude Code

LamaSu and others added 2 commits September 28, 2026 19:55
… N64)

The reference vertical's workflow CSD (print + hand-off + mail) was added on
8/27, after the builtin list was written, and never registered. So the
gateway's shared registry could not resolve its capability type:
csdForType("document-print-and-mail") was null in production, and R10
could not resolve the print leg. The real-state trace (#433) proved this.

Scope: one entry in the builtins array. The CSD stays status "draft",
kind "workflow", with no composition block.

- The D2 registry snapshot takes only active CSDs with a composition
  block, so its digest is unchanged. A new test pins it byte-identical
  with and without this CSD.
- findUrlByType matches exactly (URL slug, then an explicit type, then
  the name). The CSD has no type field, so it cannot capture an existing
  type such as 2d-print.

Tests:
- Count assertions move 8 -> 9 (spec csd and evidence-primitives,
  contract-builder babel-pcc) and 9 -> 10 (gateway csd, which adds the
  dashboard manifest).
- New tests pin the N64 resolution and the unchanged snapshot digest.
- Mutations: dropping the builtin fails 6 tests; disabling the slug pass
  fails the N64 test.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
… proof

No builtin carries a composition block today, so both snapshots in the test
hold no builtin contracts. The adapter filter itself is proven elsewhere
(registry-contract-adapter.test.ts, the gateway draft/retired test).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@LamaSu
LamaSu marked this pull request as ready for review September 30, 2026 19:16
@LamaSu
LamaSu merged commit 5393655 into master Sep 30, 2026
5 checks passed
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