Skip to content

docs(adr-0069): record ruling C′'s enforcement and the API-key admission seam - #23875

Merged
os-zhuang merged 2 commits into
mainfrom
claude/issue-23483-adr-0069-enforcement-note
Oct 16, 2026
Merged

os-zhuang merged 2 commits into
mainfrom
claude/issue-23483-adr-0069-enforcement-note

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #23483
Clause-②: no

What this changes

One governed record edit, docs/adr/0069-enterprise-authentication-hardening.md alone (+8 / -0). No code, no test, no other ADR.

  1. A sixth "Enforcement seam summary" entry: API-key admission. It names resolveApiKeyAdmission in packages/core/src/security/api-key.ts, fed by userAuthGates, as the key half of D3's amended note. With it, "Each row in D1-D6 names exactly one of these seams" stays true for D3.
  2. A dated status note under "Implementation status (2026-07-04)": "Status (2026-10-14): ruling C′ is enforced." It follows the ADR's dated-row and "Correction (bug(plugin-auth): [auth] no cache service registered 在 CacheServicePlugin 注册前 21ms 就喊了 —— 误报,且把人引向「你需要 Redis」 #4772)" convention and leaves the 2026-07-04 table unchanged. It names PR feat(spec,core,plugin-auth)!: an API key answers as its owner's session does when the ADR-0069 policy holds the account (#23287) #23440 (0f059078ec) and PR fix(core,cloud-connection,mcp)!: every API-key admission names its owner-posture source, so a held owner's key is refused at install-local and on every MCP stdio call (#23455, #23456) #23508 (daafae6d6d) and covers four facts:
    • the closed AuthGateCodeSchema and the scopes AUTH_GATE_SCOPES declares;
    • the held outcome of resolveApiKeyAdmission;
    • every key-admitting seam asking the owner's posture;
    • the forced-reset revocation, on by default.

Every sentence measured on main (34b740f2d1)

  • packages/spec/src/kernel/execution-context.zod.ts:40: AuthGateCodeSchema = z.enum(['PASSWORD_EXPIRED', 'PASSWORD_RESET_REQUIRED', 'MFA_REQUIRED']). :65: AUTH_GATE_SCOPES is Record<AuthGateCode, AuthGateScope> (typed total), with MFA_REQUIRED: 'account' and both password codes 'credential'.

  • packages/core/src/security/api-key.ts: ApiKeyAdmission has a held arm. Near :822, userAuthGates is asked for the owner, and accountScopeAuthGate picks the account-scope posture. The function returns { outcome: 'held', principal, gate }. Before returning, stampAdmittedKey (:832-:839) stamps the held key's use — last_used_at, at most hourly, and, where the lifecycle policy anchors one, a no-expiry key's grace end as expires_at — so its inactivity window does not run out during the hold (pinned by api-key-lifecycle.test.ts:220-:226). Nothing is revoked, and the hold keeps no state of its own. resolveApiKeyPrincipal collapses held to undefined.

  • Seam sweep. Every non-test caller of resolveAuthzContext / resolveApiKeyAdmission passes userAuthGateSourceOf(authService):

    • runtime resolve-execution-context.ts:254;
    • rest-server.ts:3338;
    • settings-service-plugin.ts:333;
    • storage-service-plugin.ts:1251 and :1428;
    • service-datasource/admin-routes.ts:509;
    • sharing-plugin.ts:973;
    • marketplace-install-local-plugin.ts:3371;
    • MCP stdio (plugin.ts:520, :691, through resolveStdioUserAuthGates).

    The parameter is typed required (UserAuthGateSource | undefined). The only sys_api_key lookup by hash on main is api-key.ts:678, inside resolveApiKeyAdmission. No seam is open.

  • packages/plugins/plugin-auth/src/admin-user-endpoints.ts:697: revokeSessionsAndKeys = body.revokeSessionsAndKeys !== false (on unless a literal false is passed). The sys_user action field has defaultValue: true (sys-user.object.ts:306). forced-reset-revocation.ts ends sessions through the D4 mechanism and sets revoked: true on every unrevoked key.

  • Both PRs are ancestors of origin/main: merge-base --is-ancestor exits 0 for each, and the control leg origin/main~5 also exits 0.

Gates

The gates were derived with node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 683acf2c: 19 families. All 19 exit 0. check:doc-formula-expressions first exited 3 (a prerequisite was not built); it was green after turbo run build --filter=@objectstack/formula --filter=@objectstack/lint under the verify lock. --ran reconciliation: "19 derived famil(ies) accounted for — 19 run, 0 NOT-MEASURED (a DERIVED zero)". pnpm check:pm-governed-prose was also run outside the derivation and exits 0.

Acceptance notes

  • D3's amended note names the key behaviour ("an API key answers as the session does") but not the symbol resolveApiKeyAdmission. The card's file surface is the summary entry and the status note, so the D3 note is left as ruled. The sixth entry points back to it ("the key half of D3's amended note").
  • Changeset: none. docs/adr/** publishes nothing (the os-dev fast-path no-publish rule), so this PR takes skip-changeset.
  • Tier H (docs/adr/**): the maintainer lands this PR after the seat's CONTRACT_REVIEW_TIER review of the governed text.

维护者速读(草稿)

改了什么:只改 ADR-0069 一个文件(+8 行)。「Enforcement seam summary」新增第 6 个强制点「API-key admission」(resolveApiKeyAdmission)。「Implementation status」表下新增一条 2026-10-14 的状态注记,写明裁决 C′ 已由 PR #23440 与 #23508 落地:posture 代码集是封闭的,并区分 account/credential 两种作用域;MFA 未达标用户的 API key 被「挂起」(held)而不是吊销——挂起不另存状态,姿态解除即恢复;挂起期间照常记录使用时间(last_used_at),以免闲置期限在挂起中耗尽;所有接收 API key 的入口都会查询属主的 posture;管理员强制重置密码时默认吊销该用户的会话与 API key。

为什么改:ADR 原文说「D1-D6 每一行恰好对应一个强制点」,但强制点清单里缺少 API key 入口,而 D3 修订注记已经依赖这个入口,记录与代码不一致。现在两个阻塞项(#23455、#23456)都已合并,代码已经兑现,记录可以如实补上,不会写出代码没有兑现的强制。

风险与代价(含回滚):纯文档,不发布任何包,不影响运行时。风险只在于文字是否与代码一致;每一句都已对照 main 实测并附了行号。回滚只需 revert 这一个提交。

席位意见:建议批准合并。新增的第 6 个强制点和 2026-10-14 状态注记,席位与契约复核都逐句对照 main 的代码核过。第一轮契约复核(6214537670)指出「挂起期间什么都不写」不实:挂起的 key 仍会记录使用时间。补丁轮只改了这一句,第二轮复核在新 head 18b3f3215b 上 PASS(6214838689)。只改 ADR 一个文件,不发布任何包,回滚只需 revert 这一个提交。

你要做的:看过席位的合约复核记录后,批准并合并本 PR(Tier H,需要维护者本人操作)。


Generated by Claude Code

…ion seam

A dated status note names what PR #23440 and PR #23508 enforce on main:
the closed posture vocabulary and its scopes, the held outcome of the
shared key-admission seam, every key-admitting seam asking the owner's
posture, and the forced reset's revocation, on by default. The seam
summary gains the API-key admission seam as its sixth entry, so "each
row names exactly one of these seams" stays true for D3.

Claude-Session: https://claude.ai/code/session_01XgS6gBdsbPNicv9ELY6ne5
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/xs documentation Improvements or additions to documentation labels Oct 16, 2026
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 16, 2026
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 683acf2c274af29f29faf02b44ff986ab88e8466
Local-runs: none
Scope: docs/adr/0069-enterprise-authentication-hardening.md + packages/spec/src/kernel/execution-context.zod.ts, packages/spec/src/kernel/index.ts, packages/core/src/security/api-key.ts, packages/core/src/security/auth-gate.ts, packages/core/src/security/resolve-authz-context.ts, packages/core/src/security/api-key-lifecycle.test.ts, packages/runtime/src/security/resolve-execution-context.ts, packages/rest/src/rest-server.ts, packages/services/service-settings/src/settings-service-plugin.ts, packages/services/service-storage/src/storage-service-plugin.ts, packages/services/service-datasource/src/admin-routes.ts, packages/plugins/plugin-sharing/src/sharing-plugin.ts, packages/cloud-connection/src/marketplace-install-local-plugin.ts, packages/mcp/src/plugin.ts, packages/plugins/plugin-auth/src/admin-user-endpoints.ts, packages/plugins/plugin-auth/src/forced-reset-revocation.ts, packages/platform-objects/src/identity/sys-user.object.ts, PR #23440 (0f059078ec), PR #23508 (daafae6d6d)

① Derived judgments

Read against main at the PR's base 34b740f2d1 (the merge-base; origin/main at 944f03850e moves none of the cited files). The diff is +8 / −0 in one governed file. No code, no accept set and no published export changes; the public surface it changes is the ADR's record text, so each added sentence was checked as a claim about the code on main.

Right:

  • Sixth seam entry. resolveApiKeyAdmission is at packages/core/src/security/api-key.ts:631, takes userAuthGates: UserAuthGateSource | undefined (:653), asks it for the key's owner (:822-825), picks the account-scope posture through accountScopeAuthGate (:829; auth-gate.ts:122-125) and returns { outcome: 'held', principal, gate } (:839). "Each row in D1-D6 names exactly one of these seams" stays true: every D1-D6 table row is byte-unchanged and still names one of seams 1-5; seam 6 is what D3's amended note (a note, not a row) relies on, which is exactly the gap the card's filing gate named.
  • Closed vocabulary. packages/spec/src/kernel/execution-context.zod.ts:40 declares AuthGateCodeSchema = z.enum(['PASSWORD_EXPIRED', 'PASSWORD_RESET_REQUIRED', 'MFA_REQUIRED']), exported on the ./kernel subpath through src/kernel/index.ts:144; :65 declares AUTH_GATE_SCOPES as a frozen record typed total over AuthGateCode, with MFA_REQUIRED: 'account' and both password codes 'credential'.
  • The door refuses with the posture's code. resolve-authz-context.ts:525-529 carries a held key's principal together with its authGate; rest-server.ts:2473 and :3403-3406, storage-service-plugin.ts:1257 and the MCP per-call refusal (plugin.ts, AUTH_GATE_REFUSAL_STATUS = 403) answer it. resolveApiKeyPrincipal (api-key.ts:603-613) returns undefined for every outcome but admitted, so a held owner's key yields no principal. A credential-scope posture leaves accountScopeAuthGate at null and the key admitted.
  • Seam sweep, re-run. git grep for resolveAuthzContext(, resolveApiKeyAdmission( and resolveApiKeyPrincipal( over the whole tree minus tests finds ten non-test call sites, each passing the owner's posture source: runtime resolve-execution-context.ts:254, rest-server.ts:3338, settings-service-plugin.ts:333, storage-service-plugin.ts:1251 (the family door, resolveApiKeyAdmission direct) and :1428 (the download authorizer), service-datasource/admin-routes.ts:509, sharing-plugin.ts:973, marketplace-install-local-plugin.ts:3371, and the MCP stdio face at plugin.ts:525 and :696 through resolveStdioUserAuthGates (:149-157, a wrapper over userAuthGateSourceOf). No caller exists outside packages/; the only sys_api_key lookup by hash is api-key.ts:678, inside the seam. exec-context-seam.testkit.ts:130 passes undefined on purpose and is a test kit, not a seam. No caller is open.
  • "PR fix(core,cloud-connection,mcp)!: every API-key admission names its owner-posture source, so a held owner's key is refused at install-local and on every MCP stdio call (#23455, #23456) #23508 made userAuthGates a required input." Its diff flips userAuthGates?: UserAuthGateSource to userAuthGates: UserAuthGateSource | undefined on resolveApiKeyAdmission and on ResolveAuthzInput, and adds the parameter to resolveApiKeyPrincipal; its file list carries marketplace-install-local-plugin.ts and mcp/src/plugin.ts. "The two seams that still admitted a held owner's key" is the right count: the storage download authorizer gained the source in the same PR, but storage-service-plugin.ts:1413-1422 records that the family door had already refused a held key ahead of it, and cards security(cloud-connection): the marketplace install-local resolver admits an API key without asking its owner's account posture, where ruling C′ refuses it at every seam #23455 and security(mcp): the stdio face resolves OS_MCP_STDIO_API_KEY with no owner posture, so a held owner's key starts and serves stdio MCP where ruling C′ refuses it at every seam #23456 name exactly those two.
  • Forced reset. admin-user-endpoints.ts:697 reads revokeSessionsAndKeys = body.revokeSessionsAndKeys !== false; sys-user.object.ts:306-310 gives the action field defaultValue: true; forced-reset-revocation.ts:125-131 stamps expires_at into the past plus revoked_at / revoke_reason (the D4 mechanism) and :157 sets revoked: true on every unrevoked key. "On unless the administrator passes a literal false" and "a revoked key stays revoked after the password change" both hold, and the default is the maintainer's letter A (6165848580).
  • Convention and provenance. The note is a bold dated paragraph placed after the "Implementation status (2026-07-04)" table, the form of "Implementation status (2026-07-04):" (line 161), "Correction (bug(plugin-auth): [auth] no cache service registered 在 CacheServicePlugin 注册前 21ms 就喊了 —— 误报,且把人引向「你需要 Redis」 #4772):" and "Settled 2026-08-04 (decision(plugin-auth): 会话的「记录之处」到底在哪 —— better-auth secondaryStorage 一旦接上 cache,ADR-0069 D4 的会话管控就静默失效 #4785)"; the 2026-07-04 table, the D3 amended note and every ruled sentence are byte-unchanged. Both cited merge commits are ancestors of origin/main (merge-base --is-ancestor exits 0 for each), both merged 2026-10-14.

Wrong (one sentence):

  • "Nothing is written: the same key is admitted again once the posture clears." The second half holds; the first does not. On the held path resolveApiKeyAdmission calls stampAdmittedKey BEFORE it returns (api-key.ts:832-839), which writes sys_api_key.last_used_at (at most once an hour) and, for a key signed with no expiry, expires_at (:410-429). That is deliberate and pinned: api-key-lifecycle.test.ts:220-226, "a held key is stamped too (ruling C′ item 4: it resumes when the owner remediates)", asserts exactly one update on a held outcome. Ruling C′ item 4 (6159450584) and the D3 note say "a refusal, not a revocation", which is narrower and true; the PR body says "nothing is written for the hold", also true. The ADR text dropped the qualifier and now claims a write-free path that the code and its own test contradict. An accepted ADR stating "nothing is written" is precisely the kind of sentence this card was filed to remove (filing gate ①: a named location whose sentence the landed work makes untrue). Fix, one clause inside the card's file surface, for example: "No revocation is written — the hold keeps no state of its own, though the key's use is still stamped (last_used_at, and the no-expiry grace) so its inactivity window does not run out during the hold — and the same key is admitted again once the posture clears."

② Semver level

Clause-②: no is right: the diff is docs/adr/** alone, no released package ships it, and no export, schema or accept set moves. No changeset is owed; skip-changeset is the correct declaration. Check-runs on the head: the required contexts read Lint & Repo Gates success, TypeScript Type Check success, Test Core success, Governed Surface Queue Guard success, Build Core skipped (paths filter). Check Changeset has two runs on this head: the opened run (116939046692) failed inside the label race the workflow's own header measures, and the labeled run (116947093942), fired after the seat applied skip-changeset at 2026-10-16T11:20:15Z, is skipped, the pass state the workflow defines for the label. Every other run is success or skipped. The gates are green; the verdict below is on the record text, not on a gate.

③ Boundary flags

  • Dev deviation 1 (skip-changeset not applied by the dev): closed. The seat applied the label at 2026-10-16T11:20:15Z and the labeled run skipped the gate.
  • Dev deviation 2 (the primary checkout detached to free the branch for the worktree): procedural, no effect on the diff; nothing owed.
  • Open question 1 (name resolveApiKeyAdmission inside D3's note?): A, as the dev recommends. The D3 note is ruled text (C′ item 5, the maintainer's hand), the card's file surface names only the summary entry and the status note, and the sixth entry already points back to the note. Not escalated.
  • Open question 2 (note dated 2026-10-14 or 2026-10-16?): A, 2026-10-14. Both merge commits landed that day (0f059078ec at 2026-10-14T12:32:52Z, daafae6d6d at 2026-10-14T16:12:41Z), and the ADR's dated entries date the fact, not the edit. Not escalated.
  • Nothing is escalated to the maintainer. The one finding in ① is the dev's to fix on this branch; a fresh record on the new head is owed before the maintainer's hand lands it (Tier H).

Implemented-by: claude/issue-23483-adr-0069-enforcement-note
Reviewed-by: session_01HjR8RUwTPQ3TgbfKihmxp9

VERDICT: FAIL

…g is written"

On the held path resolveApiKeyAdmission stamps the key (last_used_at, and
a no-expiry key's grace end) before it returns, so the status note's
"nothing is written" was untrue. The note now says what holds: a refusal,
not a revocation, no state of its own, the use stamped so the inactivity
window does not run out during the hold.

Claude-Session: https://claude.ai/code/session_01XgS6gBdsbPNicv9ELY6ne5
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 18b3f3215b5bc3d0a7572a2dc6fe808cb6357481
Local-runs: none
Scope: docs/adr/0069-enterprise-authentication-hardening.md + packages/spec/src/kernel/execution-context.zod.ts, packages/spec/src/kernel/index.ts, packages/core/src/security/api-key.ts, packages/core/src/security/auth-gate.ts, packages/core/src/security/resolve-authz-context.ts, packages/core/src/security/api-key-lifecycle.test.ts, packages/runtime/src/security/resolve-execution-context.ts, packages/rest/src/rest-server.ts, packages/services/service-settings/src/settings-service-plugin.ts, packages/services/service-storage/src/storage-service-plugin.ts, packages/services/service-datasource/src/admin-routes.ts, packages/plugins/plugin-sharing/src/sharing-plugin.ts, packages/cloud-connection/src/marketplace-install-local-plugin.ts, packages/mcp/src/plugin.ts, packages/plugins/plugin-auth/src/admin-user-endpoints.ts, packages/plugins/plugin-auth/src/forced-reset-revocation.ts, packages/platform-objects/src/identity/sys-user.object.ts, PR #23440 (0f059078ec), PR #23508 (daafae6d6d)

① Derived judgments

Patch round on the FAIL record 6214537670 (head 683acf2c27, posted 2026-10-16T11:30:44Z). The net diff against main is still +8 / −0 in the one governed file; git diff 683acf2c27..18b3f3215b is one line, the held-key bullet of the status note, and nothing else: the sixth seam entry, the other three bullets, the 2026-07-04 table and D3's amended note are byte-identical to the head already judged. The base is unchanged (merge-base 34b740f2d1), and git diff 34b740f2d1..origin/main (497518c3f6) over every cited file is empty, so each sentence is still a claim about the code on main today. No code, no accept set and no published export changes.

The patched sentence, checked against stampAdmittedKey exactly (packages/core/src/security/api-key.ts:410-441, called on the held path at :837, before the held return at :839):

  • "The hold is a refusal, not a revocation: it keeps no state of its own, and the same key is admitted again once the posture clears." Right. Nothing on the held path writes a hold: the gate is read (:822-829) and returned (:839); the only write is the use stamp below, which is [Decision] API key 的生命周期与存放:到期上限与不活动失效取多长,key 继续放自有 sys_api_key 还是迁到 @better-auth/api-key(#23287 裁决 C′ 的留项) #23367's record of use and not hold state. Ruling C′ item 4 (6159450584) words it the same way.
  • "The key's use is still stamped while it is held (last_used_at, at most hourly, …)". Right. :419-422 writes last_used_at when the row carries none or the recorded use is at least API_KEY_LAST_USED_STAMP_INTERVAL_MS (:179, one hour) old — at most one write per key per hour, and the stamp runs for a held key exactly as for an admitted one (:832-837; pinned at api-key-lifecycle.test.ts:220-226, one update asserted on a held outcome).
  • "… and, where the lifecycle policy anchors one, a no-expiry key's grace end as expires_at". Right, and tighter than the previous record's offer. :423-426 writes expires_at only when the row has no expiry AND legacyGraceEndMs(policy) resolves, which :361-364 does only from a policy whose startedAt parses (the grace is the policy's landing plus API_KEY_LEGACY_GRACE_DAYS); policy is the auth service's lifecycle policy or undefined on a kernel without one (:707-714). "Where the lifecycle policy anchors one" is that condition.
  • "so its inactivity window does not run out during the hold". Right. idleWindowStartMs (:377-390) anchors the idle window on last_used_at first, which is what the stamp keeps moving; the code's own comment at :832-836 states the same purpose.
  • A stamp failure never fails the request and is reported once per engine (:405-408, :430-439); the sentence claims the stamp, not its durability, so nothing more is owed of it.

Everything else in the record, unchanged and still right (re-read on this head rather than carried over): the sixth seam entry names resolveApiKeyAdmission (:631), fed by userAuthGates (:653), holding on account scope (:822-829, :839); "Each row in D1-D6 names exactly one of these seams" stays true with every D1-D6 row byte-unchanged; AuthGateCodeSchema (execution-context.zod.ts:40, exported on ./kernel through src/kernel/index.ts:144) and the total AUTH_GATE_SCOPES (:65) carry the three codes and the two scopes as stated; the seam sweep by git grep over the whole tree minus tests still finds ten non-test call sites, each passing the owner's posture source (runtime resolve-execution-context.ts:254, rest-server.ts:3338, settings-service-plugin.ts:333, storage-service-plugin.ts:1251 and :1428, service-datasource/admin-routes.ts:509, sharing-plugin.ts:973, marketplace-install-local-plugin.ts:3371, MCP stdio plugin.ts:525 and :696 through resolveStdioUserAuthGates), no caller outside packages/, and the only sys_api_key hash lookup at api-key.ts:678 inside the seam; PR #23508 flipped userAuthGates? to userAuthGates: UserAuthGateSource | undefined on both resolvers and added it to resolveApiKeyPrincipal, closing exactly the two seams the note names (storage-service-plugin.ts:1413-1422 records the download authorizer was already behind its family door); the forced reset reads revokeSessionsAndKeys !== false (admin-user-endpoints.ts:697) with defaultValue: true (sys-user.object.ts:310) and revokes through the D4 stamp plus revoked: true (forced-reset-revocation.ts:125-131, :157); the dated note keeps the ADR's own convention and edits no ruled text; both cited merge commits remain ancestors of origin/main.

② Semver level

Clause-②: no and skip-changeset are right: the diff is docs/adr/** alone, no released package ships it, no export, schema or accept set moves. Check-runs on 18b3f3215b (39 runs): Lint & Repo Gates, TypeScript Type Check, Test Core and Governed Surface Queue Guard success; Build Core skipped on the paths filter; Check Changeset skipped (116952646987), the pass state the workflow defines for the label, which was already on the PR when this head's synchronize run fired; every other run is success or skipped, none red. The gates are green.

③ Boundary flags

  • Dev deviation 1 (the PR body was not patched; the dev writes a body once and names the replacement in pr_body_patch): open, and it is the seat's write, not the dev's. The body's measured-on-main bullet still reads "The function returns { outcome: 'held', principal, gate }, and nothing is written for the hold." (line 18 of the body on this head), and the maintainer digest's held-key line still says only that the key is held rather than revoked, without the stamp. Neither is governed record text and neither is in the diff, so the verdict below does not turn on them; but the maintainer reads the body before landing a Tier H PR, so the seat applies the dev's two pr_body_patch replacements (from report 6214701931) before requesting the maintainer's hand. Nothing further is owed by the dev.
  • Dev deviation 2 (the worktree was re-created from the branch at 683acf2c27; no merge with main): right call — no conflict, no main-caused red, and no cited file moved on main.
  • Open questions: none this round. The two from round 1 are settled as A and A (D3's note stays as ruled; the note is dated 2026-10-14, the enforcement date) by the seat's patch-round post 6214592668, and this head carries them that way.
  • Nothing is escalated to the maintainer. The landing is Tier H (docs/adr/**): this record is the seat's contract-tier review of the governed text; the maintainer's hand lands it.

Implemented-by: claude/issue-23483-adr-0069-enforcement-note
Reviewed-by: session_01HjR8RUwTPQ3TgbfKihmxp9

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT (Tier H, the maintainer's hand) · PR #23875 @ 18b3f3215b (#23483) · domain:spec seat 1 · os-elon-musk · session session_01HjR8RUwTPQ3TgbfKihmxp9 · 2026-10-16T11:49Z

Reviewer of record. Every item below was checked against GitHub and the code, not against the reports (6214013357 and 6214701931 on #23483).

  • Shape: Draft, base main. The first line is Fixes #23483, the body's only closing keyword, then Clause-②: no, matching claim 6213793261. 1 file (docs/adr/0069-enterprise-authentication-hardening.md), +8/−0. Assignee os-elon-musk. skip-changeset applied by the seat (an ADR edit publishes nothing).
  • Tier H: check-governed-merges reads the one path on the register (docs/adr/**). ⛔ The seat does not ready, queue or arm it. It lands by the maintainer's hand, or by an authorized approval followed by this seat.
  • Contract review: FAIL 6214537670 on 683acf2c27, on one sentence ("Nothing is written" for a held key, while stampAdmittedKey stamps its use). Patch round on the same claim and session. PASS 6214838689 on 18b3f3215b, this head; the patch changed that one line and nothing else.
  • The seat's own read:
    • AuthGateCodeSchema (execution-context.zod.ts:40) and AUTH_GATE_SCOPES (:65) are as stated.
    • resolveApiKeyAdmission returns held (api-key.ts:839).
    • The forced reset is revokeSessionsAndKeys !== false (admin-user-endpoints.ts:697).
    • The review re-ran the seam sweep (ten non-test call sites, each passing the owner's posture source) and found no open seam.
  • The dev's two open questions, the seat's calls: both A. D3's amended note stays as ruled, and the sixth entry points back to it. The note is dated 2026-10-14, the enforcement date, the ADR's own convention for dated rows.
  • PR body: the seat applied the dev's two pr_body_patch replacements (the measured-on-main api-key.ts bullet and the 速读 line now name the use stamp) and filled in 席位意见.
  • CI on this head: 31 success, 8 skipped by their filters, 0 failed.

Generated by Claude Code

@os-zhuang
os-zhuang marked this pull request as ready for review October 16, 2026 11:51
@os-zhuang
os-zhuang enabled auto-merge October 16, 2026 11:52
@os-zhuang
os-zhuang added this pull request to the merge queue Oct 16, 2026
Merged via the queue into main with commit 570f01d Oct 16, 2026
54 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-23483-adr-0069-enforcement-note branch October 16, 2026 12:05
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/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

3 participants