The capstone #3636 anticipated ("a client method whose target route exists on no surface can be flagged mechanically — file that as the capstone if it doesn't fall out naturally"). It did not fall out naturally, and tranche 3 showed why it matters.
Where the audit now stands
All three server surfaces the SDK reaches are ledgered and CI-guarded:
| Surface | Ledger | Tranche |
|---|
| Dispatcher | packages/runtime/src/route-ledger.ts | #3563 |
| REST server | packages/rest/src/rest-route-ledger.ts | #3587 |
| Autonomous service mounts | service-storage/src/storage-route-ledger.ts, service-i18n/src/i18n-route-ledger.ts | #3636 |
Each guard runs server → client: enumerate what the surface mounts, demand a reviewed disposition, and for sdk rows demand the named client method exists.
The hole all three share
The method exists is not the method can be called. No guard compares the URL the client builds against the patterns any server mounts, so a client method can name a real function, carry a green ledger row, and still 404 on every surface.
That is not hypothetical — it is the recurring bug this audit keeps rediscovering:
Four instances, four tranches, one class. The i18n pair is the sharpest: route-ledger.ts has carried sdk rows for those two routes since tranche 1, and both methods were wire-level 404s the whole time. The dispatcher's own domain body happily accepts the query dialect — but nothing routes a bare /translations to that body, so the tolerance was unreachable.
What the guard should do
Union the three ledgers into one set of mounted patterns, then assert every URL the SDK constructs matches one of them.
Getting the client's URLs mechanically is the real design question. Options:
- Drive the client with a recording
fetch. A fixture calls every namespace method with dummy args and captures the URL; match each against the union, :param segments as wildcards. Pro: tests the real code path, catches dialect bugs exactly as they ship. Con: needs a call fixture per method, and the fixture list itself needs a completeness guard (every method on every namespace is invoked) or coverage rots silently — the same failure mode this whole audit is about. - Declare the target route per client method and assert both ends. Cheap and total, but it is an assertion about the code rather than of it: a method could still be edited away from its declared route.
- Static extraction of template literals in
index.ts. No fixtures, but brittle against the client's getRoute() indirection and dynamic segments.
Option 1 is the honest one; option 2 is a reasonable stepping stone if the fixture cost bites. Whichever lands, the completeness check ("no client method escaped the sweep") is the part that must not be skipped.
Note the union must stay a union — a route mounted by only one surface is still legitimately reachable, so the guard cannot demand a pattern appear in all three ledgers.
Acceptance
- Every URL an
ObjectStackClient method builds matches a pattern in some surface's ledger. - Every client method is provably included in the sweep.
- Wired into CI at zero, like the tranche-1/2/3 ratchets.
Refs: #3563 (tranche 1), #3587 (tranche 2), #3636 (tranche 3), #3584 / #3611 (prior instances of the class), docs/audits/2026-07-dispatcher-client-route-coverage.md.
The capstone #3636 anticipated ("a client method whose target route exists on no surface can be flagged mechanically — file that as the capstone if it doesn't fall out naturally"). It did not fall out naturally, and tranche 3 showed why it matters.
Where the audit now stands
All three server surfaces the SDK reaches are ledgered and CI-guarded:
packages/runtime/src/route-ledger.tspackages/rest/src/rest-route-ledger.tsservice-storage/src/storage-route-ledger.ts,service-i18n/src/i18n-route-ledger.tsEach guard runs server → client: enumerate what the surface mounts, demand a reviewed disposition, and for
sdkrows demand the named client method exists.The hole all three share
The method exists is not the method can be called. No guard compares the URL the client builds against the patterns any server mounts, so a client method can name a real function, carry a green ledger row, and still 404 on every surface.
That is not hypothetical — it is the recurring bug this audit keeps rediscovering:
analytics.explaincalled/explain; nothing served it (Reconcile the four dispatcher↔client shape mismatches (analytics ×2, storage ×2) — #3563 follow-up #3584)analytics.metacalled/meta/:cube; no server mounted that shape (Reconcile the four dispatcher↔client shape mismatches (analytics ×2, storage ×2) — #3563 follow-up #3584)meta.getViewsent?type=; REST mounts only/ui/view/:object/:type(UI view route speaks two dialects — REST's path-param form is unreachable by the SDK's query-param form (#3587 finding) #3611)i18n.getTranslationssent/translations?locale=xxandi18n.getFieldLabelssent/labels/:object?locale=xx; every surface mounts only the path form (Route audit tranche 3: autonomously-mounted service routes (service-storage / service-i18n) — #3587 follow-up #3636)Four instances, four tranches, one class. The i18n pair is the sharpest:
route-ledger.tshas carriedsdkrows for those two routes since tranche 1, and both methods were wire-level 404s the whole time. The dispatcher's own domain body happily accepts the query dialect — but nothing routes a bare/translationsto that body, so the tolerance was unreachable.What the guard should do
Union the three ledgers into one set of mounted patterns, then assert every URL the SDK constructs matches one of them.
Getting the client's URLs mechanically is the real design question. Options:
fetch. A fixture calls every namespace method with dummy args and captures the URL; match each against the union,:paramsegments as wildcards. Pro: tests the real code path, catches dialect bugs exactly as they ship. Con: needs a call fixture per method, and the fixture list itself needs a completeness guard (every method on every namespace is invoked) or coverage rots silently — the same failure mode this whole audit is about.index.ts. No fixtures, but brittle against the client'sgetRoute()indirection and dynamic segments.Option 1 is the honest one; option 2 is a reasonable stepping stone if the fixture cost bites. Whichever lands, the completeness check ("no client method escaped the sweep") is the part that must not be skipped.
Note the union must stay a union — a route mounted by only one surface is still legitimately reachable, so the guard cannot demand a pattern appear in all three ledgers.
Acceptance
ObjectStackClientmethod builds matches a pattern in some surface's ledger.Refs: #3563 (tranche 1), #3587 (tranche 2), #3636 (tranche 3), #3584 / #3611 (prior instances of the class),
docs/audits/2026-07-dispatcher-client-route-coverage.md.