Maintainer ruling on the set-initial-password disposition question raised by #10534 / #10660: option C — bind the route into the SDK, then ledger it as sdk. This card is C's first half. The ledger row is the second half and is deliberately a separate card (ordering argued below).
⚠️Public-surface widening ⇒ Clause-② contract review. This card adds a method to ObjectStackClient, which is published surface. It must not be merged on a dispatching seat's own authority.
What is measured
All three readings taken on origin/main at 81845c65a.
1. The route has no SDK binding, and the zero is a real zero.
packages/client/src setInitialPassword = 0
packages/client/src set-initial-password = 0
positive controls, same corpus, same expression:
getConfig = 1
auth.me = 1
accounts = 10
changePassword = 1
Both spellings return nothing while four sibling auth members return non-zero, so the absence is an absence and not a broken pattern.
2. sdk is the ledger's rule, not one of several equals.
disposition distribution in AUTH_ROUTE_LEDGER:
sdk 54 · server-only 1 · disabled 1 · gap 0
54 of 56. server-only is a single reviewed exception, not a co-equal category to fall into by default.
3. The gap disposition is behind a shrink-only ratchet.
packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.ts
:189 it('gap and mismatch counts only shrink', () => {
:192 expect(AUTH_ROUTE_LEDGER.filter((e) => e.disposition === 'gap').length).toBeLessThanOrEqual(0);
The test is named for its own direction. Filing this route as gap would not be "recording a number" — it would be reversing a ratchet, which is the thing the ratchet exists to refuse.
Why C and not the alternatives
Scope
Add setInitialPassword to the auth namespace in packages/client/src/index.ts, shaped like its siblings already in that namespace (getConfig, changePassword, changeEmail — all this.getRoute('auth') + this.fetch(...)), hitting the route the plugin already mounts.
⛔ Out of scope, and a maintainer floor if attempted: any change to the route's own accept/reject behaviour, its admit set, or its server-side guards. This card binds a client to an already-mounted route. It does not touch what that route allows. A permission-boundary loosening is not this card's to make.
⛔ Not in this card: the AUTH_ROUTE_LEDGER row. That is the follow-up card, which will name this method.
Gates this touches — confirm both legs, do not assume
packages/client/src/client-url-conformance.test.ts sweeps the SDK surface automatically, so a new method lands inside two live assertions:
:363every client method is classified — driven or explicitly non-HTTP — the new method is enumerated by enumerateMethods; it must either drive cleanly or be declared in NON_HTTP (it should drive, like its siblings).:373every URL the SDK builds matches a route some surface mounts — the URL this method builds must match the compiled ledger union.
On leg :373, note what it will and will not prove here. The dispatcher ledger still carries a * /auth/** prefix row, and client-url-conformance.test.ts:123-129 says in its own words that exact rows are sorted ahead of wildcard families precisely because otherwise "every /api/v1/auth/* URL would still be absorbed by the dispatcher's * /auth/** row and keep counting as weak evidence". Until the follow-up card adds the exact row, this method's URL matches on that weak evidence. Report which pattern it matched, by name, rather than reporting only that the test was green. A green here is not yet proof the wire path is right.
Ordering — why this card is first
packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.ts:152 requires every sdk-disposition row to name a client method. The ** fallback above is what makes the reverse order safe: this method can land while its exact ledger row does not yet exist, but a sdk row naming a method that does not exist would be a claim of coverage the SDK does not have — the exact failure packages/client/src/route-ledger-coverage.test.ts was written for (its header cites #3528, where "the ledger equivalent of the day would have said resume → automation.resume while no such method existed").
So: this card, then the ledger card.
Acceptance
auth.setInitialPassword exists on ObjectStackClient and resolves to a function.- Both conformance legs above pass, with the matched pattern named in the report.
- Changeset present.
- PR stays draft until contract review PASSes; the reviewing seat must not be the dispatching seat.
Refs
Part of #10534 · #10660 (the ledger/docs PR that surfaced the question; its body must not close #10534 while this remains open) · #10050 · #3563 / #3642 (the conformance guards above) · #3656 (the auth ledger's own charter)
Maintainer ruling on the
set-initial-passworddisposition question raised by #10534 / #10660: option C — bind the route into the SDK, then ledger it assdk. This card is C's first half. The ledger row is the second half and is deliberately a separate card (ordering argued below).ObjectStackClient, which is published surface. It must not be merged on a dispatching seat's own authority.What is measured
All three readings taken on
origin/mainat81845c65a.1. The route has no SDK binding, and the zero is a real zero.
Both spellings return nothing while four sibling auth members return non-zero, so the absence is an absence and not a broken pattern.
2.
sdkis the ledger's rule, not one of several equals.54 of 56.
server-onlyis a single reviewed exception, not a co-equal category to fall into by default.3. The
gapdisposition is behind a shrink-only ratchet.packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.tsThe test is named for its own direction. Filing this route as
gapwould not be "recording a number" — it would be reversing a ratchet, which is the thing the ratchet exists to refuse.Why C and not the alternatives
server-only). The route is reachable by clients; recording it as server-only to make the table close would be a false statement about the surface, which is the failure mode Attachment tombstoning silently no-ops on a PREDICATE delete — the beforeDelete→afterDelete stash dies with the per-row context #10240's triage named as "the state machine lying".gap). See measurement 3 — it reverses a shrink-only ratchet.Scope
Add
setInitialPasswordto theauthnamespace inpackages/client/src/index.ts, shaped like its siblings already in that namespace (getConfig,changePassword,changeEmail— allthis.getRoute('auth')+this.fetch(...)), hitting the route the plugin already mounts.⛔ Out of scope, and a maintainer floor if attempted: any change to the route's own accept/reject behaviour, its admit set, or its server-side guards. This card binds a client to an already-mounted route. It does not touch what that route allows. A permission-boundary loosening is not this card's to make.
⛔ Not in this card: the
AUTH_ROUTE_LEDGERrow. That is the follow-up card, which will name this method.Gates this touches — confirm both legs, do not assume
packages/client/src/client-url-conformance.test.tssweeps the SDK surface automatically, so a new method lands inside two live assertions::363every client method is classified — driven or explicitly non-HTTP— the new method is enumerated byenumerateMethods; it must either drive cleanly or be declared inNON_HTTP(it should drive, like its siblings).:373every URL the SDK builds matches a route some surface mounts— the URL this method builds must match the compiled ledger union.On leg
:373, note what it will and will not prove here. The dispatcher ledger still carries a* /auth/**prefix row, andclient-url-conformance.test.ts:123-129says in its own words that exact rows are sorted ahead of wildcard families precisely because otherwise "every/api/v1/auth/*URL would still be absorbed by the dispatcher's* /auth/**row and keep counting as weak evidence". Until the follow-up card adds the exact row, this method's URL matches on that weak evidence. Report which pattern it matched, by name, rather than reporting only that the test was green. A green here is not yet proof the wire path is right.Ordering — why this card is first
packages/plugins/plugin-auth/src/auth-route-ledger.conformance.test.ts:152requires everysdk-disposition row to name a client method. The**fallback above is what makes the reverse order safe: this method can land while its exact ledger row does not yet exist, but asdkrow naming a method that does not exist would be a claim of coverage the SDK does not have — the exact failurepackages/client/src/route-ledger-coverage.test.tswas written for (its header cites #3528, where "the ledger equivalent of the day would have saidresume → automation.resumewhile no such method existed").So: this card, then the ledger card.
Acceptance
auth.setInitialPasswordexists onObjectStackClientand resolves to a function.Refs
Part of #10534 · #10660 (the ledger/docs PR that surfaced the question; its body must not close #10534 while this remains open) · #10050 · #3563 / #3642 (the conformance guards above) · #3656 (the auth ledger's own charter)