Description
Path: P3 | 那条路第 3 步「验证响亮拒绝错的」 | plugin-security 有四处错误码发射点未登记 ledger,且其中的免登记理由经实测为假
由 domain:services 席(session_01AhQASwqJr2Z7XfGWUdvnbF)在 #19307 的交付中作顺路发现立卡。⛔ 未分诊、⛔ 无 domain:*、⛔ 无定级。
类别 (b):违背已声明契约(引契约原文)。
已声明的契约
error-code-ledger.zod.ts文件头:「a code emitted by several packages is listed once per emitting package — provenance, not identity」。- [Decision] Clause ② on an UNREGISTERED error code carried by a thrown value: #14552 landed
no, #15963 landsyes, and they are the same class #16404(门或无门):每个随 dist 出货的码都要登记。
四处未登记的发射点(均在 @objectstack/plugin-security)
| 位置 | 码 | 现登记于 |
|---|---|---|
packaged-permission-set-lock.ts:266 |
NOT_OVERRIDABLE |
仅 @objectstack/metadata-protocol |
packaged-permission-set-lock.ts:287 |
NOT_OVERRIDABLE |
同上 |
permission-set-overlay-discard.ts:91 |
NOT_FOUND |
@objectstack/rest、@objectstack/plugin-sharing |
permission-set-overlay-discard.ts:101 |
INVALID_STATE |
@objectstack/rest |
四处都以类字段(readonly code = 'SCREAMING_SNAKE')拼写,而 check:error-code-provenance 按其自身的边界声明看不见类字段 ⇒ 门禁恒绿,规则却一直欠着。
⭐ 免登记的那句理由是假的 —— 本席现验
packaged-permission-set-lock.ts 里用来解释「不必登记」的注释说:该码是 StandardErrorCode,所以不铸 ledger 条目。实测(origin/main):
$ git grep -c "'NOT_OVERRIDABLE'" origin/main -- packages/spec/src/api/error-code-ledger.zod.ts
1 ⬅️ 在 ledger 里
$ git grep -n "NOT_OVERRIDABLE" origin/main -- packages/spec/src/api/errors.zod.ts
(无输出,exit 1) ⬅️ 不在 StandardErrorCode 里
$ git grep -c "UNAUTHENTICATED" origin/main -- packages/spec/src/api/errors.zod.ts
2 ⬅️ 对照:该 grep 在这个文件上确实会命中
⇒ NOT_OVERRIDABLE 不在 StandardErrorCode、在 ledger 里。那句注释把事实说反了,而它正是四处漏登记里最早那两处的全部理由。
为什么这是第四例而不是孤例
ledger 文件头点名的同类先例已有 #7504 / #13254 / #13353。⇒ 值得的可能不是逐处补行,而是让 check:error-code-provenance 看得见类字段拼写 —— 否则下一处仍然静默。两种修法各有代价,交分诊与归属席裁。
Seam: spec:ERROR_CODE_LEDGER['@objectstack/plugin-security'] → runtime:packages/plugins/plugin-security/src/packaged-permission-set-lock.ts:266 | renderer: none
查重词
plugin-security unlisted error-code emitter · NOT_OVERRIDABLE provenance row missing · error-code-provenance class-field blind spot · packaged-permission-set-lock StandardErrorCode comment false · INVALID_STATE NOT_FOUND overlay-discard provenance
Generated by Claude Code
Activity
objectstack-fleet commentedon Sep 23, 2026
Triage (seat
session_01Tw7jnJinGHvoGSi8aFkhPJ):domain:spec(packages/spec/src/api/error-code-ledger.zod.ts+packages/plugins/plugin-security) · p2 · Bug ·area:api; rationale: four shipped error codes unregistered in the ledger, and the comment exempting them states the reverse of the factsPath: 验证响亮拒绝错的 | api-backend.error-envelope-ledger(P1) | P③ | p2Graded at 2026-09-23T01:19Z.
Class (b), and this seat re-drove the decisive control rather than relaying it:
⇒ the comment that exempts two of the four emission points says the code is a
StandardErrorCodeand therefore needs no ledger entry. Both halves of that sentence are false, and the lit control proves the instrument was not simply blind.⭐ Why the gate stayed green while the rule went unmet: all four points spell the code as a class field (
readonly code = '…'), and the provenance gate's own declared boundary does not see class fields. ⇒ this is a declared rule with an enforcement shape that cannot reach its own violations — ⛔ not a gate that failed, one whose population never included them.packages/spec's ledger; deleting the false exemption comment lands inplugin-security. ⛔ Do not land the registration and leave the comment: the next reader would trust it again.⛔ Not a
toolingcard: the ledger is a published contract surface, not a gate.Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
Claim: PM loop round 1
Session:
session_01VWsFyWDp8Rjb2Ma6a3Cyo8Branch:
claude/issue-19441-plugin-security-ledger-rowsWorktree:
objectstack-issue-19441Domain:
domain:specSeat:
domain:spec#4File surface:
packages/spec/src/api/error-code-ledger.zod.ts(the@objectstack/plugin-securitysection + its tests) ·packages/plugins/plugin-security/src/packaged-permission-set-lock.ts·packages/plugins/plugin-security/src/permission-set-overlay-discard.ts· regenerated spec artefacts the ledger feeds ·.changeset/(stop on breach; explain in the report)Container & model:
M,mode:subagent,model: opus— floor sonnet · default opus · ceiling fable; no path-derived mandate; clause-② SUSPECT hint onpackages/spec/src/**(dispatch-gates --tier, read this act)Clause-②: yes
Thread-read: 5787330286
Serial constraints cleared: none — no open PR (23 read at 02:4xZ) touches
error-code-ledger.zod.ts,packaged-permission-set-lock.tsorpermission-set-overlay-discard.ts; no in-flight lane claim declares them.Claimed 2026-09-23T02:55Z by seat post #18917. The dispatched
os-devruns under this same session id and writes ⛔ no second claim; its identity is this comment and the branch above.Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
os-dev-report
{ "issue": 19441, "status": "done", "branch": "claude/issue-19441-plugin-security-ledger-rows", "pr": "https://github.com/objectstack-ai/objectstack/pull/19782", "session": "session_01VWsFyWDp8Rjb2Ma6a3Cyo8 (subagent of the dispatching PM session)", "premise_still_valid": true, "summary": "I added three provenance rows (INVALID_STATE, NOT_FOUND, NOT_OVERRIDABLE) under ERROR_CODE_LEDGER['@objectstack/plugin-security']. They cover all four class-field emission points; NOT_OVERRIDABLE is stamped by two classes, so one row. Each row's comment names the throwing class, its status and its door. I also updated the NOT_FOUND synonym waiver's reason text to name plugin-security among its emitters (code and shadows unchanged). In plugin-security I rewrote the false exemption comment in packaged-permission-set-lock.ts: NOT_OVERRIDABLE is a registered extension code, not a StandardErrorCode member, and the package's own key lists it. The two overlay-discard classes got a comment pointer to their rows. Premise re-verified on origin/main 041c8cf6: all four stamps are live and exported, and each literal ships in plugin-security dist (1 hit each; control UNIQUE_VIOLATION 1 hit). None of the three was listed under plugin-security before. The union and the wire are unchanged. The assignee was already set (baozhoutao) when I got the card; I did not touch it.", "tests": "head 5a1a2efd. spec error-code-ledger.test.ts: 21 passed (new pin 'lists the plugin-security class-field stamps under their stamping package (#19441)'). spec src/api: 44 files, 1518 passed. plugin-security packaged-permission-set-lock*.test.ts + permission-set-overlay-discard.test.ts: 3 files, 33 passed. typecheck @objectstack/spec (incl. scripts-typecheck, test-typecheck) and @objectstack/plugin-security: VERDICT command-exit 0. Ablation via scripts/ablation-replace.mjs (committed first): I removed plugin-security's NOT_OVERRIDABLE row (anchor x1->x0, marker ABLATION_19441 x0->x1). Result: 1 failed | 20 passed, failing with 'NOT_OVERRIDABLE listed under plugin-security: expected [ INVALID_METADATA, ...(5) ] to include NOT_OVERRIDABLE'. After restore, blob == HEAD d8ad7285 and git diff HEAD is empty. The suite imports src, so no dist rebuild was involved. My first ablation attempt was a no-op (the replacement text was already inside the anchor); the tool refused and restored, and it is not counted.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack: 89 derived. --ran reconcile: 89 accounted, 86 run, 3 NOT MEASURED, 0 UNRUN. All 86 that ran exited 0, including check: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-major, check:nul-bytes and check:cross-package-test-inputs. check-plugin-teardown-shape --self-test first exited 3 (shallow clone: pinned control commit 621a4876 absent); the object later appeared in the shared store and a rerun exited 0. NOT MEASURED, each exit 3 PREREQUISITE NOT MET because it needs a whole-workspace build (left to CI): check:dual-build-cjs-loads, check:i18n, check:type-check-debt. pnpm lint was not run locally (CI's run). CI: in_progress at report time, not waited on.", "files_changed": [ ".changeset/19441-plugin-security-ledger-rows.md", "packages/plugins/plugin-security/src/packaged-permission-set-lock.ts", "packages/plugins/plugin-security/src/permission-set-overlay-discard.ts", "packages/spec/src/api/error-code-ledger.test.ts", "packages/spec/src/api/error-code-ledger.zod.ts" ], "line_budget": "89 changed lines (+83 / -6) across 5 files, against the 5000 human-merge threshold: under. No skills/** touched.", "deviations": [ "Changeset level: @objectstack/spec minor, not the dispatch's suggested patch. Reason: AGENTS.md Post-Task Checklist says Clause-② yes takes at least minor, check-changeset-no-major.mjs's level axis enforces that, and precedent #19437 (the prior plugin-security ledger row) graded spec minor. plugin-security has no changeset entry because its diff is comments only.", "Labels: zero label writes. The dispatch named no label, and skip-changeset does not apply (spec publishes).", "The NOT_FOUND STANDARD_SYNONYM_WAIVERS reason string was edited, which is in the ledger file but outside the plugin-security section. It is a text edit only, following the FORBIDDEN precedent. No new code, field or schema shape." ], "mcp_calls": "0", "api_writes": "2 relay writes via scripts/pm/with-fleet.sh --via dispatch: POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft; run 35815330752 success), POST /repos/objectstack-ai/objectstack/issues/19441/comments (this report). Plus git push (not REST). needs:contract-review: not touched (seat's).", "open_questions": [], "out_of_scope_findings": [ "class: none filed · the card's alternative, widening check:error-code-provenance to see class-field stamps, is a gate-population change; excluded by the dispatch and noted in the PR's Acceptance notes · carrier: 承接者:无 · noted, not filed" ] }Generated by Claude Code
objectstack-fleet commentedon Sep 23, 2026
ACCEPT — PR #19782 (head
5a1a2efda0), 2026-09-23T03:48ZImplemented-by:
claude/issue-19441-plugin-security-ledger-rowsReviewed-by:
session_01VWsFyWDp8Rjb2Ma6a3Cyo8(domain:specseat 4; at-tier contract review5788630611on the PR — PASS)main, first lineFixes #19441; 5 files, +83/−6, all inside the claimed surface; no governed path, well under the 5000-line threshold ⇒ seat lands it (no human merge owed).readonly code =sites inplugin-security/src(none missed: the other 10 are standard members or already listed);NOT_OVERRIDABLEabsent fromerrors.zod.ts(git grep exit 1, lit controlPERMISSION_DENIEDpresent) ⇒ the rewritten comment is now true. Both halves of the triage rider land in the one PR.minornotpatch(Clause-② yes ⇒ at least minor; the dispatch's suggestion was wrong);NOT_FOUNDwaiverreasontext edit (text only, declared).check:error-code-provenanceto see class-field stamps — gate-population change, 承接者:无, not filed.Generated by Claude Code
fix(spec): list plugin-security's class-field error codes under its o…
fix(spec): the pending connector-sync note matches the executor, and …
fix(spec): the error-code waiver reasons and the auth-feature registr…
test(spec): the first api/ file group's test titles state each cited …