fix(spec): list plugin-security's class-field error codes under its own ledger key - #19782
Conversation
…wn ledger key Adds INVALID_STATE, NOT_FOUND and NOT_OVERRIDABLE provenance rows under @objectstack/plugin-security, and replaces the packaged-set lock comment that claimed NOT_OVERRIDABLE was a StandardErrorCode needing no row. Claude-Session: https://claude.ai/code/session_01VWsFyWDp8Rjb2Ma6a3Cyo8 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 8 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 — 139 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 992be0195a29f10b7f393448e9235343ee80f4b8 && git checkout 992be0195a29f10b7f393448e9235343ee80f4b8
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 4b23e4fab548c43c17754925fe0e1c66dbacd99c 5a1a2efda0e5b6a01b0779f8e7ce4c96606084e3 && git checkout -B drift-repro 4b23e4fab548c43c17754925fe0e1c66dbacd99c && git merge --no-ff 5a1a2efda0e5b6a01b0779f8e7ce4c96606084e3
node scripts/docs-audit/affected-docs.mjs --json 4b23e4fab548c43c17754925fe0e1c66dbacd99c
|
Contract reviewServed-tier: ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Rendered by an isolated at-tier review subagent (fed the card, the PR and the head's check-runs only — not the dispatch order), adopted by Generated by Claude Code |
Fixes #19441
Clause-②: yes
What changed
Two halves, in two packages, landed together (the triage rider: the registration and the comment are not interchangeable).
packages/specledger —ERROR_CODE_LEDGER['@objectstack/plugin-security']gains three provenance rows,INVALID_STATE,NOT_FOUND,NOT_OVERRIDABLE, each with a comment naming the throwing class, its status and its door. They cover all four emission points the card listed (NOT_OVERRIDABLEis stamped by two classes, one row). Every code was already registered under another package (@objectstack/rest,@objectstack/metadata-protocol), so theErrorCodeunion and the wire are unchanged: provenance, not identity. TheNOT_FOUNDentry inSTANDARD_SYNONYM_WAIVERSkeeps itscode/shadows; itsreasontext now names plugin-security among the emitters (the same edit theFORBIDDENwaiver got when cloud-connection joined).plugin-security— thePackagedPermissionSetLockedErrordocblock no longer says "the code is a StandardErrorCode, so no ledger entry is minted". It now says what is true:NOT_OVERRIDABLEis a registered extension code, NOT aStandardErrorCodemember, and this package's own owner key lists it. The two overlay-discard error classes get a one-line pointer to their rows. The plugin-security edits are comments only.Premise check (on
origin/main041c8cf6)packaged-permission-set-lock.ts:266,:287andpermission-set-overlay-discard.ts:91,:101, all spelledreadonly code = '...'.assertPermissionSetNotPackageDeclaredis called frompermission-set-projection.ts(three sites) andpackaged-permission-set-lock-gate.ts.discardPermissionSetOverlayis registered bysecurity-plugin.tsand served by rest'sPOST .../security/permission-sets/:id/discard-overlay. The classes are exported fromindex.ts.packages/plugins/plugin-security/dist/*.js(controlUNIQUE_VIOLATION: 1).check:error-code-provenancedeclares class fields out of its scan (see its header, "BLIND ... and a class field"), so it was green before this PR and is still green now (exit 0).Tests
error-code-ledger.test.ts:lists the plugin-security class-field stamps under their stamping package. It checks each code is listed under plugin-security AND is still listed under its first owner, and that it parses as anErrorCode. It also checksNOT_OVERRIDABLEis absent fromStandardErrorCode.options, with a lit control:PERMISSION_DENIEDis present.pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/api/error-code-ledger.test.ts: 21 passed.src/api(44 files): 1518 passed.packaged-permission-set-lock*.test.tsandpermission-set-overlay-discard.test.ts(3 files): 33 passed.typecheckfor@objectstack/spec(including scripts-typecheck and test-typecheck) and for@objectstack/plugin-security: exit 0.NOT_OVERRIDABLErow withscripts/ablation-replace.mjs(anchor x1 -> x0, marker x0 -> x1) and ran the pin:1 failed | 20 passed, failing withNOT_OVERRIDABLE listed under plugin-security: expected [ 'INVALID_METADATA', ...(5) ] to include 'NOT_OVERRIDABLE'. After the restore the blob equals HEAD (d8ad7285) andgit diff HEADis empty. The suite imports the ledger fromsrc, so no dist rebuild was involved. My first attempt was a no-op: the replacement text was already inside the anchor, so the tool refused and restored. It is not counted.Gates (head
5a1a2efd)dispatch-gates.mjs --commandslisted 89 commands;--ranreconciled all of them (86 run, 3 NOT MEASURED, 0 unrun). All 86 that ran exited 0, includingcheck:error-code-provenance,check:dispatcher-error-vocabulary,check:error-code-casing,check:api-surface,check:docs,check:authorable-surface,check:adr-0087-registration,check-changeset-no-majorandcheck:nul-bytes.NOT MEASURED, each exit 3 PREREQUISITE (they need a whole-workspace build that was not done locally; left to CI):
check:dual-build-cjs-loads,check:i18n,check:type-check-debt.pnpm lint(a repo-wide scan) was not run locally; that is CI's run.Changeset level
The dispatch suggested
patch. The changeset grades@objectstack/specminor instead: AGENTS.md's Post-Task Checklist saysClause-②: yestakes at leastminor,check-changeset-no-major.mjs's level axis enforces that, and the ledger header says registering a code widens the published face. The precedent is #19437 (the prior plugin-security ledger row: spec minor). plugin-security has no changeset entry because its diff is comments only.Acceptance notes
check:error-code-provenancesee class-field spellings, is not done here. That is a gate-population change and a separate decision. Measurement for it: these four stamps were invisible to the gate because class fields are out of its scan. The new vitest pin holds only these rows; a future class-field stamp in any package would still be invisible to the gate.Generated by Claude Code