Found while implementing #10974 (binding auth.setInitialPassword). Not a live wire defect today — every sdk row in AUTH_ROUTE_LEDGER happens to name a method that does exist. What is missing is the check that keeps it that way.
The claim that does not hold
packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.ts:152 is the auth ledger's "every sdk entry names its client method" test. Read literally, it checks only that the field is non-empty:
constsdkWithout=AUTH_ROUTE_LEDGER.filter((e)=>e.disposition==='sdk'&&!e.client).map((e)=>e.route);
!e.client is falsy-on-absent. A row spelled client: 'auth.setInitialPasword' (typo), or naming a method that was later renamed or deleted, passes this test unchanged.
The resolution check exists for every other ledger, and not this one
The sibling ledgers each have a client-side half that instantiates an ObjectStackClient and asserts typeof resolve(e.client) === 'function':
| ledger | resolution guard |
|---|
ROUTE_LEDGER (dispatcher) | packages/client/src/route-ledger-coverage.test.ts |
REST_ROUTE_LEDGER | packages/client/src/rest-route-ledger-coverage.test.ts |
STORAGE_ROUTE_LEDGER | packages/client/src/service-route-ledger-coverage.test.ts |
I18N_ROUTE_LEDGER | same file |
DATASOURCE_ROUTE_LEDGER | same file |
AUTH_ROUTE_LEDGER | none |
Measured — every consumer of the symbol repo-wide:
packages/qa/dogfood/test/route-ledger-live-mount-parity.dogfood.test.ts
packages/client/src/client-url-conformance.test.ts → uses r.route only (compiled into PATTERNS)
packages/client/src/route-ledger-response-schema.test.ts → uses rows for response-shape, not client resolution
packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.ts
scripts/check-ratchet-remedy-authority.mjs · scripts/check-auth-mount-ledger.mjs
Nothing in that list resolves an auth row's client string against a client instance. client-url-conformance.test.ts imports AUTH_ROUTE_LEDGER but reads r.route exclusively — it matches URLs the SDK builds against routes, which is the opposite direction and does not read the client field at all.
Why it matters
AUTH_ROUTE_LEDGER is the largest of the ledgers (56 rows, 54 of them sdk) and it is the one whose rows are written by hand alongside a vendor surface that moves under it. The failure this guard family was built for is stated in route-ledger-coverage.test.ts's own header:
This is the direction #3528 shipped through: the ledger equivalent of the day would have said "resume → automation.resume" while no such method existed.
That exact shape is currently unguarded for auth.
Note for whoever picks this up
#10974's body asserts that a sdk row naming a nonexistent method is "the exact failure packages/client/src/route-ledger-coverage.test.ts was written for". That test reads ROUTE_LEDGER (the dispatcher's), not AUTH_ROUTE_LEDGER, so it would not have caught an auth row. The sequencing argument in #10974 partly rests on that — worth reading together with it.
Likely shape of the fix
Add an AUTH_ROUTE_LEDGER leg to packages/client/src/service-route-ledger-coverage.test.ts (or a sibling file), reusing the brokenIn helper already there. The ledger is pure data with no imports, so the existing relative-source-import convention applies unchanged — no new package edge.
Refs
Found during #10974 · #3528 (the originating failure) · #3563 / #3636 (the guard family) · #3656 (the auth ledger's charter)
Found while implementing #10974 (binding
auth.setInitialPassword). Not a live wire defect today — everysdkrow inAUTH_ROUTE_LEDGERhappens to name a method that does exist. What is missing is the check that keeps it that way.The claim that does not hold
packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.ts:152is the auth ledger's "everysdkentry names its client method" test. Read literally, it checks only that the field is non-empty:!e.clientis falsy-on-absent. A row spelledclient: 'auth.setInitialPasword'(typo), or naming a method that was later renamed or deleted, passes this test unchanged.The resolution check exists for every other ledger, and not this one
The sibling ledgers each have a client-side half that instantiates an
ObjectStackClientand assertstypeof resolve(e.client) === 'function':ROUTE_LEDGER(dispatcher)packages/client/src/route-ledger-coverage.test.tsREST_ROUTE_LEDGERpackages/client/src/rest-route-ledger-coverage.test.tsSTORAGE_ROUTE_LEDGERpackages/client/src/service-route-ledger-coverage.test.tsI18N_ROUTE_LEDGERDATASOURCE_ROUTE_LEDGERAUTH_ROUTE_LEDGERMeasured — every consumer of the symbol repo-wide:
Nothing in that list resolves an auth row's
clientstring against a client instance.client-url-conformance.test.tsimportsAUTH_ROUTE_LEDGERbut readsr.routeexclusively — it matches URLs the SDK builds against routes, which is the opposite direction and does not read theclientfield at all.Why it matters
AUTH_ROUTE_LEDGERis the largest of the ledgers (56 rows, 54 of themsdk) and it is the one whose rows are written by hand alongside a vendor surface that moves under it. The failure this guard family was built for is stated inroute-ledger-coverage.test.ts's own header:That exact shape is currently unguarded for auth.
Note for whoever picks this up
#10974's body asserts that a
sdkrow naming a nonexistent method is "the exact failurepackages/client/src/route-ledger-coverage.test.tswas written for". That test readsROUTE_LEDGER(the dispatcher's), notAUTH_ROUTE_LEDGER, so it would not have caught an auth row. The sequencing argument in #10974 partly rests on that — worth reading together with it.Likely shape of the fix
Add an
AUTH_ROUTE_LEDGERleg topackages/client/src/service-route-ledger-coverage.test.ts(or a sibling file), reusing thebrokenInhelper already there. The ledger is pure data with no imports, so the existing relative-source-import convention applies unchanged — no new package edge.Refs
Found during #10974 · #3528 (the originating failure) · #3563 / #3636 (the guard family) · #3656 (the auth ledger's charter)