Uh oh!
There was an error while loading. Please reload this page.
Repair the two plugin-auth admin-audit durability swallows — batch 6 of the #12981 worklist - #13592
Conversation
…` sites swallowed Two tier-1 DARK durability swallows on plugin-auth's admin surface (#12981 batch 6): an administrative action landed, its audit row was refused, and the endpoint answered 200 with nothing recorded anywhere. Control flow is unchanged at both sites — an admin operation must never fail over its own audit — but the refusal is no longer silent. Both catches were doing two jobs and were only right about one. plugin-audit UNINSTALLED means no sys_audit_log object, so nothing ever claimed the action would be audited and silence is correct. A REFUSED write is the other thing entirely, and it wore the same catch. Each site now asks getSchema('sys_audit_log') — the registry that owns the answer — rather than reading the driver's error text, which would decide the same question by guessing. getSchema is declared optional on AdminUserDataEngine and IdentityImportEngine, so it is additive; where it is absent the site cannot measure the difference and therefore reports. What was hiding in the silence: sys_account is in plugin-audit's SKIP_OBJECTS, so the row refused in writeAdminAudit was the only record that a password was administratively reset; and the run-level import row is a shape plugin-audit's actionFor structurally cannot emit, so the per-row create rows kept the trail looking complete while who ran the import and under which policy was gone. Both sinks are re-exported from index.ts and declare no error, so the LEVEL stays warn and remains #13398's question; only the SILENCE is repaired here. Each seam is pinned, plus absence-asserting cases so a seam that warns unconditionally cannot pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZC5rNQj3WEet5HAmmAkMs
…atch 6 pins Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZC5rNQj3WEet5HAmmAkMs
…inned) Coverage grew, which is the direction the shrink-only ledger wants; the gate's own verdict line asked for --write. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016ZC5rNQj3WEet5HAmmAkMs
📓 Docs Drift CheckThis PR changes 1 package(s): 7 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 3 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 11 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7ed3b984fd1cce8647c394467088a494e06e3c9a && git checkout 7ed3b984fd1cce8647c394467088a494e06e3c9a
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 9c120f0308d5aed3c26f53c406054a95a631d156 15b211752b3c19f88b2a2b82b7a7f0b336e2817a && git checkout -B drift-repro 9c120f0308d5aed3c26f53c406054a95a631d156 && git merge --no-ff 15b211752b3c19f88b2a2b82b7a7f0b336e2817a
node scripts/docs-audit/affected-docs.mjs --json 9c120f0308d5aed3c26f53c406054a95a631d156
|
os-steve
commented
Aug 31, 2026
📎 转录留档 — 本 PR 依据的 #13398 裁决,原卡已不可达
⛔ 这不是一条新裁决,也不是本席的判断。这是一份转录,出处三件如下:
本席于 2026-08-30 ~12:5xZ 亲自读过该评论全文,下列为当时所读原文,⛔ 未经改写、未经节选。 转录原文(#13398 |
Uh oh!
There was an error while loading. Please reload this page.
Part of #12981
Batch 6 of the #12981 repair programme. Two tier-1 DARK durability swallows on
plugin-auth's admin surface: an administrative action landed, its audit row was refused, and the endpoint answered200with nothing recorded anywhere. Control flow is unchanged at both sites — an admin operation must never fail over its own audit — but the refusal is no longer silent.The population, re-measured rather than recalled
The card's "15 files" was measured at
origin/main@196a6c73eand is stale by construction. Ran the repo's own instrument,scripts/measure-durability-swallow-family.mjs, self-test first so the numbers are a measurement and not a matcher that quietly stopped matching:b997272)15b2117)DARK 10 → 8 and QUIET 93 → 95: the two repaired sites left the member set entirely rather than moving to
channelled, because they now log. That is the declared repair — silence fixed, level deferred — and it is the accounting a reviewer can check without reading the diff.The two sites
Both
catchblocks were doing two jobs and were only right about one of them:sys_audit_logobject at all, so nothing ever claimed the action would be audited. Silence is correct, and reporting here would put a line on every admin action in every deployment that does not run plugin-audit — the "warn nobody reads" that [automation/approvals] 进程重启后审批决策静默失效:挂起 flow run 仍只存内存(#1518 标记 COMPLETED 但 17.0.0-rc.1 未生效),approve 落库却永不推进且零报错 #4420 is the historical accident for.Both spelled
catch { }. Each site now asksgetSchema('sys_audit_log')— the registry that owns the answer — instead of reading the driver's error text, which would decide the same question by guessing.admin-user-endpoints.tswriteAdminAudit()sys_accountis in plugin-audit'sSKIP_OBJECTS, so for/admin/set-user-passwordits generic writer emits zero rows — the row refused here was the only record that a password was ever administratively resetadmin-import-users.tsaction: 'import'with a nullrecord_idis a shape plugin-audit'sactionForstructurally cannot emit. The per-rowcreaterows still land, which is what made this dangerous: the trail looked complete while who ran the import, under which password policy, and what it did in aggregate was gonegetSchemais declared optional onAdminUserDataEngineandIdentityImportEngine, so it is additive and nothing that type-checks today stops doing so. Where it is absent the site cannot measure the difference and therefore reports — an unmeasurable write must not be a silent one, and that direction is pinned by its own case.Level:
warnat both sites, silence-only — and why that is not my callBoth sinks are
logger?: { warn(msg: string): void }, and both are published:index.tscarriesexport * from './admin-user-endpoints.js'andexport *for./admin-import-users.js. Neither declareserror. Raising the level means widening a published sink shape, which the maintainer's 2026-08-30 ruling on #13398 refused as actively harmful — it would enrol every module on that type into the shrink-onlycheck:optional-error-sink-contractpopulation. Same finding batch 5 recorded forAuthManager.⇒ Both sites are silence-repaired, neither is level-repaired, and the LEVEL remains #13398's question. No published sink shape is changed here.
Two census hits deliberately NOT repaired
auth-manager.ts:4784verifyMcpAccessToken()— a census over-collection, not a member. Itstryholds no write at all: it isjwtVerifyplus payload destructuring, andreturn nullis the correct answer for an expired or wrong-audience token. The reportedwrite=update@6456is same-file helper resolution reachingrecordSignInOutcome, which batch 5 already repaired at its own catch. Repairing it to fit the pattern would be the mirror-image defect AGENTS.md names for this rule.verify/src/harness.ts:695andplugin-sharing/src/share-link-service.ts:638— out of this slice; the first is a verification harness whose gate answers either way, the second is usage telemetry. Neither is obviously a claim-to-persist.Verification
Reverse-verified rather than asserted. The repair was committed first (
a2fbf54), so the restore leg had a real reference point; the mutation reverted both source files to the merge base and was confirmed on disk before anything was measured — not by an editor exit code:Ablated run: 5 failed | 17 passed — and the five are exactly the five that should redden:
The two "a healthy write reports nothing on this channel" cases stay green in both directions by design — they are absence-asserting controls against a seam that warns unconditionally, not pins. Restore proved by
git diff HEADempty and a cleangit status. Nodistleg applies: these tests import./admin-user-endpoints.js, a relative sibling vitest resolves tosrc/.All results below read from each gate's own verdict line, with exit codes captured before any pipe, on the pushed tree
15b2117:pnpm --filter @objectstack/plugin-auth exec vitest runoveradmin-user-endpoints.test.ts,admin-import-users.test.ts,durability-swallow-repair.test.ts— 3 files, 81 passedpnpm --filter @objectstack/plugin-auth typecheck— greenpnpm lint(eslint . --no-inline-config, whole repo) — green, run in full; no narrowing to declarecheck:type-check-debt—29 ledger entries re-measured, 1542 raw tsc errors, none above its recorded number. surplus: none, on the built closure the gate demands. This is the measurement that matters for the new test code:plugin-authhides its tests fromtsc, so the packagetypecheckreads none of them, and a green there would have been NOT MEASURED for the test file.check:engine-double-contract— was red, by its own verdict line:RETAINED [update]: … now pins 2 engine double(s), ledger records 1. Coverage grew, which is the direction this ledger wants. Ratcheted with--writeas instructed (one line,1 -> 2); re-run green.check:where-matcher,check:objectql-double-limit,check:logger-receiver-detach,check:cross-package-test-inputs,check:query-options-erasure,check:dispatcher-error-vocabulary,check:type-check-coverage,check:dual-build-cjs-loads,check:nul-bytes,check:published-files,check:slot-lookup,check:test-source-alias,check:type-source-resolution,check:page-declaration-shape,check:doc-authoring,check:changeset-gate-self-tests,check:objectui-changeset,check:pm-half-states,check:agent-test-spelling,check:bash32-floor,check:cli-command-ids,check:entry-guard,check:parse-guard,check:pnpm-filter-targets,check:watch-hint-literal, and thecheck-adr-0087-registration/check-changeset-no-major/check-ci-filter-parity/check-comment-mask-adoption/check-cross-package-test-inputs/check-empty-changeset/check-keyed-text-bounds/check-plugin-teardown-shape/check-undeclared-dep-imports/release-rehearsal-clone --self-testscripts.scripts/pm/check-half-states.mjs— NOT MEASURED, exit 3PREREQUISITE NOT MET: this container has no valid GitHub credential, so nothing was swept. Not a red; CI runs it with a real token.Gate families were re-derived from the actual diff, twice: the first derivation named 29 families, and re-deriving after the ledger commit added
scripts/**grew it to 41. The added families were run rather than assumed.Note on the gate this card is about
scripts/check-durability-degradation-log-level.mjsis green over both files, before and after. That green means NOT MEASURED for these sites, never "level approved" — the gate matches callee names from an 18-entry vocabulary andql.insert(...)is not in it. Its vocabulary is untouched here, and no entry was added toscripts/durability-degradation.baseline.json, which stays empty.Generated by Claude Code