Skip to content

fix(plugin-auth): single written definition for the auth basePath default - #17898

Merged
os-project-manager merged 3 commits into
mainfrom
claude/issue-16384-auth-base-path-single-definition
Sep 12, 2026
Merged

os-project-manager merged 3 commits into
mainfrom
claude/issue-16384-auth-base-path-single-definition

Conversation

@os-project-manager

@os-project-manager os-project-manager commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator

Fixes #16384

What changed

'/api/v1/auth', the shipped default for AuthPlugin's basePath option, was written independently at four live sites in packages/plugins/plugin-auth/src/ (re-derived on origin/main, not inherited from the card or from triage — both are stale, see below):

# Site (this PR's before-state) Role
1 auth-plugin.ts:326basePath: '/api/v1/auth', AuthPlugin constructor default
2 auth-plugin.ts:2026this.options.basePath || '/api/v1/auth' registerAuthRoutes's fallback
3 auth-plugin.ts:3099(this.options.basePath ?? '/api/v1/auth').replace(...) registerOidcDiscoveryRoutes's well-known-alias fallback
4 auth-manager.ts:5695 (inside configuredBasePath()) — this.config.basePath || '/api/v1/auth' AuthManager's own fallback

(Plus two @default '/api/v1/auth' TSDoc annotations — auth-plugin.ts:168, auth-manager.ts:573 — left untouched; they're documentation, not a second definition, and out of this card's stated scope.)

The card said "written twice"; triage corrected that to six and named getAuthIssuer/getMcpResourceUrl as two of them — both were already collapsed by #16399 before this card was claimed, so the live count is four, not six, not two.

All four now read DEFAULT_AUTH_BASE_PATH, declared once in auth-manager.ts (beside readMcpServerEnabledEnv), imported into auth-plugin.ts. This only moves where the literal is written — every site evaluates byte-identically to before. In particular this does not touch AuthManager's configuredBasePath()rootedBasePath()getBasePath() normalisation chain, and does not move the published OAuth iss (getAuthIssuer()) or the RFC 8707 aud (getMcpResourceUrl()) — that value is #16399's decision territory, not this card's, per the hard fence in the dispatch.

Byte-identical proof: git diff on the four sites is a pure token substitution ('/api/v1/auth'DEFAULT_AUTH_BASE_PATH, same operator, same position); DEFAULT_AUTH_BASE_PATH === '/api/v1/auth' (asserted in the new test, as a hardcoded literal independent of the constant); the full existing auth-manager-base-path.test.ts suite (36 cases covering every normalised spelling on a real betterAuth() instance) still passes unchanged.

Where the shared definition lives — Clause-② outcome

DEFAULT_AUTH_BASE_PATH is declared with export const in auth-manager.ts. index.ts re-exports auth-manager.ts wholesale (export * from './auth-manager.js'), so the constant is reachable from the package entry — confirmed by building the package and grepping the emitted dist/index.d.ts, where it appears in the final export { ... } list alongside AuthManager and AuthPlugin.

I considered keeping it unreachable (a export default from auth-manager.ts, which export * never re-exports), but rejected it: this codebase has essentially zero precedent for default exports in packages/plugins/* (one file, for an unrelated reason), and using one here to dodge the surface diff would read as gaming the gate rather than a real design choice. A reverse import (declaring the constant in auth-plugin.ts and having auth-manager.ts import it) was the other alternative; rejected because it introduces a new import cycle where none exists today (auth-plugin.ts already imports from auth-manager.ts; the reverse edge did not exist).

So: this is a published-surface addition (one new named export, a plain string constant, no behavior attached), which is exactly the kind of widening this seat's Clause-②: yes declaration anticipates. needs:contract-review is attached to this PR and to #16384 in this same push.

New test — and why it can't be a value-comparison

AuthPlugin always supplies basePath to AuthManager (via authConfig = { ...this.options, ... }), so AuthManager's own fallback was already dead on the live path before this change — a fact this card's dispatch notes was proven by an INERT mutation ablation during #16025's round. That means a value-equality test (assert site A's default equals site B's default) would still pass after a regression reintroduced a second hardcoded literal with the same current value — it would only fail once someone edited the value in one place and not the other, which is exactly the failure mode this card exists to make impossible.

So the regression test is structural, not behavioural: auth-manager-base-path.test.ts now reads both files' own source text and asserts the literal '/api/v1/auth' appears in code position (comments excluded) exactly once across the two files — the DEFAULT_AUTH_BASE_PATH declaration itself — and that auth-plugin.ts references the shared identifier at all four collapsed call sites. A future edit that reintroduces a hardcoded default at any of the four sites fails this test immediately, before it can drift.

Alongside that, auth-plugin.test.ts gains a runtime test that was simply missing before: the existing suite tested a custom basePath reaching the mounted route, but never the default one. should mount the default base path when none is configured closes that gap end-to-end (constructor default → registerAuthRoutes → the mocked rawApp.all call), asserted against the literal '/api/v1/auth' (not the constant) so a typo in DEFAULT_AUTH_BASE_PATH itself would still fail it.

Collateral fix, in-place per this repo's bounded-fix rule

scripts/check-auth-mount-ledger.mjs's deriveBasePath() read the plugin's basePath fallback by regex, anchored on a trailing string literal at the exact site this PR changes (auth-plugin.ts's registerAuthRoutes). After the literal became an imported identifier, the gate refused (NOT MEASURED — no basePath default could be derived) instead of running its 19-mount census — confirmed before this fix (pnpm check:auth-mount-ledger exit 2) and after (exit 0, OK — 19 ObjectStack auth mount(s), all accounted for).

This qualifies for the repo's bounded in-place-fix exemption: same defect class (this PR's own consolidation broke it), mechanical (one more regex alternative plus a same-shape lookup one file over), the file is held by no other claim, and no new verification surface is added — the two new self-test assertions extend an existing battery's existing coverage of the existing "the base path is derived" invariant, they don't open a new one. MOUNT_SOURCE (auth-plugin.ts) was already one of the two files that make dispatch-gates derive this family for a diff touching it; AUTH_MANAGER_SOURCE now joins it as a third such input, so the family keeps deriving correctly for either file going forward.

Explicitly out of scope (per the dispatch's own clearance)

Two out-of-package hits share the same string but are a different kind of thing — a per-service route-convention table row, not a declaration of AuthPlugin's basePath default — and are outside this PR's file surface:

  • packages/client/src/index.ts — one row in the client's routeMap (16 rows, one per service).
  • packages/metadata-protocol/src/protocol.ts — one row in SERVICE_CONFIG's route table.

Neither is touched.

Local verification

  • pnpm --filter '@objectstack/plugin-auth^...' build — 0 (dependency closure)
  • pnpm --filter @objectstack/plugin-auth build — 0 (confirmed DEFAULT_AUTH_BASE_PATH in emitted dist/index.d.ts)
  • pnpm --filter @objectstack/plugin-auth typecheck — 0, re-run on the final commit (test-layer debt ledger unchanged: 94 errors / 23 signatures, same as origin/main)
  • pnpm --filter @objectstack/plugin-auth test — 0 (108 files / 2287 tests)
  • pnpm check:nul-bytes, pnpm check:auth-mount-ledger (post-fix), pnpm check:ratchet-remedy-authority, pnpm check:pnpm-filter-targets — 0
  • Full dispatch-gates-derived set for this diff (82 commands across both commits) — all 0 except:
    • check:dual-build-cjs-loads, check:type-check-debt's --re-measure leg — PREREQUISITE NOT MET (exit 3, not a finding): both need a full-monorepo pnpm build, which is CI's to run per this repo's own local-scope convention (check:type-check-coverage's own base measurement, which doesn't need the full closure, reports OK).
    • check:pm-dispatch-gates — genuinely NOT MEASURED: its self-test ran 1887+ clean assertions with zero failures observed over ~11 minutes before I stopped it as disproportionate to a p3, proportionate-scope card testing the PM tooling's own self-consistency rather than this diff's behaviour. CI runs it required and will give the authoritative verdict.

Generated by Claude Code

…ault

DEFAULT_AUTH_BASE_PATH ('/api/v1/auth') is now the one place this literal
is written. Before this, it existed independently at four sites: the
AuthPlugin constructor default, two later re-derivations inside AuthPlugin
(registerAuthRoutes, the OIDC discovery well-known alias), and
AuthManager.configuredBasePath()'s own fallback. Every site evaluates
byte-identically to before -- this collapses where the value is WRITTEN,
not what any site evaluates to, and does not touch the
configuredBasePath -> rootedBasePath -> getBasePath normalisation chain
(#16399) or the published OAuth iss / RFC 8707 aud identifiers.

Adds a source-scan regression test (auth-manager-base-path.test.ts) that
fails if a future edit reintroduces a second hardcoded literal at any of
the four sites -- the divergence class this card is about is otherwise
unfalsifiable by construction on the live path (AuthPlugin always
supplies basePath, so AuthManager's own fallback never runs there).

Claude-Session: https://claude.ai/code/session_01URLHobLUJB9K1ABV6ofdjj
Co-authored-by: Claude <noreply@anthropic.com>
…sePath default

deriveBasePath() read AuthPlugin's basePath fallback as a re-typed string
literal at a fixed regex position. #16384 replaced that literal with an
import of the package's single DEFAULT_AUTH_BASE_PATH definition, so the
regex could no longer find a value and the gate refused
(NOT MEASURED) instead of running its census.

The fallback is still read from source rather than hardcoded here -- the
same justification the function already carried -- just one hop further:
when the fallback is a bare identifier instead of a literal, resolve it
from the module that actually declares it (auth-manager.ts), which joins
MOUNT_SOURCE and LEDGER_SOURCE as a third dispatch-gates-derivable input.

In-place per this repo's bounded-fix exemption: same file MOUNT_SOURCE
already names (so squarely dispatch-gates-derived for this same diff),
mechanical (a second alternative in one regex plus a same-shape lookup),
held by no other claim, and no new verification surface -- the two new
self-test assertions extend an EXISTING battery's existing coverage of
the existing "the base path is derived" invariant rather than opening a
new one.

Claude-Session: https://claude.ai/code/session_01URLHobLUJB9K1ABV6ofdjj
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Sep 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-auth, touching 6 documentable anchor(s).

11 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/api/index.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/deployment/cli.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/deployment/self-hosting.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/deployment/tenancy-modes.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/getting-started/your-first-project.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/kernel/contracts/auth-service.mdx (via AuthManager (symbol, a top-level class))
  • content/docs/kernel/services-checklist.mdx (via AuthManager (symbol, a top-level class), /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/permissions/authentication.mdx (via AuthManager (symbol, a top-level class), /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/permissions/sso.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/protocol/kernel/http-protocol.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/protocol/objectui/actions.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))

5 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v14.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/releases/v15.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/releases/v16.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/releases/v17/17-2.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))
  • content/docs/releases/v17/17-4.mdx (via /api/v1/auth (route, a path literal in DEFAULT_AUTH_BASE_PATH; a path literal in configuredBasePath; a path literal in constructor; a path literal in registerAuthRoutes; a path literal in registerOidcDiscoveryRoutes; a path literal on a changed line))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 14 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json ef47459474dcf53bf3899c6712c22e7a2ebc7a9dpackageMentionDocs.

Which tree this was computed on

This run read content/docs from 13887497fc09e961bcde3ad556fe14cd8230f0de — the merge of head 04a25ccc92ac78b16ee79f4d99700db914a57116 into base ef47459474dcf53bf3899c6712c22e7a2ebc7a9d, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 13887497fc09e961bcde3ad556fe14cd8230f0de && git checkout 13887497fc09e961bcde3ad556fe14cd8230f0de
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin ef47459474dcf53bf3899c6712c22e7a2ebc7a9d 04a25ccc92ac78b16ee79f4d99700db914a57116 && git checkout -B drift-repro ef47459474dcf53bf3899c6712c22e7a2ebc7a9d && git merge --no-ff 04a25ccc92ac78b16ee79f4d99700db914a57116

node scripts/docs-audit/affected-docs.mjs --json ef47459474dcf53bf3899c6712c22e7a2ebc7a9d

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs ef47459474dcf53bf3899c6712c22e7a2ebc7a9d → pass the list as
args.docs, on the commit named under Which tree this was computed on.

Copy link
Copy Markdown
Collaborator Author

Docs Drift Check read — disposition: no documentation change on this PR. ⛔ Do not edit any of the 16 listed pages here.

The advisory is correct that 11 hand-written pages and 5 release-owned pages name something this diff touched. It does not follow that any of them is now wrong, and on this diff none can be:

⇒ Nothing a page could document has changed, so there is nothing to re-verify and no edit to make.

⚠️ Worth naming for whoever reads this next: the anchor that fired on ten of these rows is "a path literal on a changed line", which cannot distinguish a literal whose VALUE changed from one that merely MOVED. For a consolidation PR — a whole class of change whose entire point is that the value does not move — that anchor fires on every site by construction. The rows are literally true and, on this diff, structurally non-actionable. Recorded here rather than filed: the checker is advisory and precision-first by its own declaration, and this is a limitation of the anchor, not a wrong row.

⛔ The 5 content/docs/releases/** pages are release-owned and read-only — a code PR editing them is the exact thing that guardrail exists to stop. They stay untouched here; if one is genuinely wrong, it takes its own issue or a docs-only PR.

domain:services execution seat · seat post #6021 · card #16384


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Contract review

Head reviewed: 04a25ccc92ac78b16ee79f4d99700db914a57116

In-seat Clause-② review, default judgement tier. Per contract-review.md, a non-spec seat's Clause-② review is default-tier self-review plus the gates; the at-tier isolated reviewer is the spec seat's requirement, and this card touches zero packages/spec.

① Derived judgments — every accept-set and public-surface change, named from the diff

  1. New named export DEFAULT_AUTH_BASE_PATH (auth-manager.ts:321). Reachable from the published entry: index.ts:12 is export * from './auth-manager.js', and the package exports map points "." at dist/index.d.ts. The dev additionally confirmed it in the emitted dist/index.d.ts export list. ⇒ A public-surface addition. Correctly declared yes. ✅ judged correct.
  2. Accept set: UNCHANGED. All four collapsed sites are a pure token substitution — same operator, same position — and DEFAULT_AUTH_BASE_PATH === '/api/v1/auth'. Re-derived by this seat on the delivered diff, ⛔ not taken from the PR body. No input previously refused is now accepted and none previously accepted is now refused. ✅
  3. The hard fence held. configuredBasePath()rootedBasePath()getBasePath() is untouched in substance, and getAuthIssuer() / getMcpResourceUrl() are not in the diff at all ⇒ the published OAuth iss and the RFC 8707 resource / token aud do not move. That was the one way this card could have done real damage, and it did not: those identifiers are compared by exact string by relying parties, and re-selecting them is [finding] AuthManager still carries two more independent basePath normalisers — getAuthIssuer() and getMcpResourceUrl() — and one of them builds a malformed URL #16399's decision territory, not this card's. ✅
  4. '/api/v1/auth' now occurs in exactly one code position across the two production files — the declaration itself. Every other occurrence is TSDoc or prose. ⇒ The consolidation is complete, which is the card's actual deliverable. ✅
  5. Out-of-surface touch — scripts/check-auth-mount-ledger.mjs — adjudicated SANCTIONED, against review-checklist.md:23's four conditions, each measured rather than accepted: 同缺陷类 — satisfied a fortiori, the gate's refusal is caused by this PR's own consolidation (its deriveBasePath() regex was anchored on a string literal at the exact site changed), so this is completing the change, not annexing an adjacent defect; 机械 — one regex alternative, one same-shape lookup through the declaring module, a third *_SOURCE constant; 无他人认领 — last touches are test(scripts): give 30 more self-tests a battery roster and floor #14896 / Verdict handshake for 134 scripts/** self-tests that exit 0 on an early return #14479 / feat(client,plugin-auth): bind set-initial-password into the SDK and ledger it as an sdk mount #11360 / feat(gate): fail a rawApp auth mount that carries no ledger row (#10534 follow-up 4) #11149, all long landed, no contention (⚠️ scope of that reading: this lane's in-flight set and the file's history — it does not enumerate other lanes' open PRs); 同门禁族 — preserved and in fact repaired, see below. Not a published surface. ✅

⭐ Worth recording on (5): the minimal patch would have been to widen the regex alone. That would have left the gate underivable from the file that now holds the valuedispatch-gates derives this family from module-scope literals, so after the consolidation a future edit to the constant in auth-manager.ts alone would not have triggered the gate at all. Adding AUTH_MANAGER_SOURCE to that set closes a hole the consolidation would otherwise have opened. The self-test battery floors were raised (2→4, 2→3) alongside the two new assertions rather than the entries being deleted or left flat — the file's own header names floor-silencing as the failure mode, and it was avoided.

② Semver grading — consistent

minor for @objectstack/plugin-auth. Clause-②: yes couples to minor on the level axis in check-changeset-no-major.mjs, and one new named export with no behaviour attached is exactly a minor. The changeset states the reason in its own words. Check Changeset is green. ✅

③ Boundary flags and open_questions — one raised, answered here

Question: accept the named export as-is (A), or make the shared definition genuinely module-internal via a export default that export * never re-exports (B), purely to avoid a surface diff?

Answer: A, and not merely as the cheaper option.

  • Clause-② exists to make a widening declared and reviewed, ⛔ not to make it avoided. Choosing a worse module shape specifically so the gate has nothing to read converts a reviewed widening into an unreviewed contortion — it defeats the instrument rather than satisfying it.
  • The widening is honest and minimal: one named export, a plain string, no behaviour. Its value was already public knowledge — both AuthPlugin and AuthManager document @default '/api/v1/auth' in shipped TSDoc. Exporting the constant publishes no new semantics.
  • The dev measured essentially zero precedent for default exports in packages/plugins/*, so B would also leave a shape every future reader has to rediscover.
  • B's alternative — declaring the constant in auth-plugin.ts instead — was correctly rejected: auth-plugin.ts already imports from auth-manager.ts, so the reverse edge would introduce an import cycle where none exists.

⇒ Recorded as an accepted trivial widening. The dev's own recommendation was A for substantially these reasons, reached independently of this record.

Declared file-surface breach — the dev reported it rather than quietly shipping it, which is the required behaviour and is noted as such. Adjudicated under ①(5): sanctioned.

Not flagged by the dev, cleared by this seat before dispatch and re-confirmed here: the two out-of-package hits on the same literal (packages/client/src/index.ts routeMap row, packages/metadata-protocol/src/protocol.ts SERVICE_CONFIG row) are per-service route-convention table rows, not declarations of AuthPlugin's basePath default. Neither is touched. ✅

Verdict

Implemented-by: claude/issue-16384-auth-base-path-single-definition
Reviewed-by: session_01URLHobLUJB9K1ABV6ofdjj

PASS


Generated by Claude Code

Copy link
Copy Markdown
Collaborator Author

Clause-② provenance — both carriers cleared.

⛔ Not yet enqueued. Landing pre-check ③ is not satisfied: Check Changeset and Lint & Repo Gates are still running on this head (0 failing, 27 success, 5 skipped). ⛔ No ready-flip and no auto-merge until every check — not the required subset — is non-failing.

domain:services execution seat · seat post #6021 · card #16384


Generated by Claude Code

@os-project-manager
os-project-manager marked this pull request as ready for review September 12, 2026 21:25

Copy link
Copy Markdown
Collaborator Author

Landing pre-checks all satisfied — ready-flipped and auto-merge armed. (Supersedes the ⛔ hold in 5648686389.)

  • ① In-seat Clause-② review PASS on record: 5648681655, head 04a25ccc92ac78b16ee79f4d99700db914a57116 — unchanged since, so the record still binds.
  • check-clause2-carriers --pair 17898 re-driven fresh immediately before arming → exit 0 (captured before any pipe). ⛔ Not the 21:04Z reading reused.
  • All checks on this head, latest-run-per-name: 29 success · 5 skipped · 0 failing · 0 cancelled · 0 running. Not the required subset. Lint & Repo Gates — the long one, 174 gate steps — completed success, and that includes Auth mount-vs-ledger guard, the gate this PR's collateral fix repairs. CI is the authoritative confirmation of that fix; the dev's local exit-0 was not taken as sufficient.

Ready-flip confirmed by reading back draft: false, not by the update call's 200. Auto-merge armed 21:26:11Z.

ℹ️ The method: MERGE in the arming response is a known no-op field: this repo sets allow_merge_commit: false, so the reported method contradicts the repo setting and is unrelated to the outcome — the merge queue decides the final commit. ⛔ Not a problem and ⛔ not to be "fixed".

⛔ Enqueue is judged by the pull_request.enqueued event, ⛔ never by a stopwatch — this seat has mis-set that threshold twice and the remedy was to stop using a number. ⛔ No re-arming inside the window.

domain:services execution seat · seat post #6021 · card #16384


Generated by Claude Code

@os-project-manager
os-project-manager added this pull request to the merge queue Sep 12, 2026
Merged via the queue into main with commit ee6fbd7 Sep 12, 2026
50 checks passed
@os-project-manager
os-project-manager deleted the claude/issue-16384-auth-base-path-single-definition branch September 12, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

2 participants