You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
metadata audit: sys_metadata_audit documents denied codes (not_overridable, not_creatable, invalid_metadata, destructive_change) that no audit write stamps — enforce or remove #28355
Filing gate: ① a declared≠enforced observation, routed to the enforce-or-remove channel. It comes from the wave-3 accuracy slice S2 report (#27377 comment 6539872216, PR #28351). ⛔ Not a claim; triage grades and routes. Suggested labels are suggestions only.
Observed
packages/metadata-core/src/objects/sys-metadata-audit.object.ts (~L130) documents that a denied audit row carries one of 'not_overridable' | 'not_creatable' | 'item_locked' | 'invalid_metadata' | 'destructive_change'.
The S2 dev read, at a0f865491d: nothing in packages/ writes those codes into an audit row. They do exist as HTTP refusal codes in packages/metadata-protocol/src/protocol.ts (e.g. L17440, L20388, L21161).
PR docs(qa): wave-3 accuracy slice S2 — studio-authoring.json #28351 corrects studio-authoring checklist items to what the protocol really audits: an allowed attempt, and denials such as the stale-If-Match metadata_conflict. There is no audit row for a 422 spec refusal.
Not re-verified by the seat: whether each documented denied code is ever stamped on an audit row.
Why it matters
Who: an operator or agent reading /audit for a metadata name, and anyone writing a check against the audit object's documented vocabulary.
What happens: the object promises denial rows that never appear. A reader concludes no refused attempt happened when one did, which is a silent gap in the audit trail.
Directions (owner decides)
Enforce: stamp an audit row for each documented denial at the door that refuses it.
Remove: trim the documented vocabulary to the codes actually written.
Read fresh. sys_metadata_audit documents denied codes that no audit write stamps. A reader of /audit concludes that a refused attempt never happened. A silent gap in an audit trail is p2.
Triage's lean is to enforce for the codes a metadata door actually refuses (not_overridable, not_creatable, destructive_change and invalid_metadata): stamp a denied row at the refusing door, beside the existing metadata_conflict row. A refused authoring attempt is what an audit trail is for. Remove only the codes that no door refuses, and the PR names which.
Pin one denied row per enforced code, plus an allowed-attempt control.
Claim: PM loop round 1
Session: session_01QUs3BtyH9zgxKzYrJiH18J
Account: os-zhuang
Branch: claude/project-thread-bdj57c (the card thread's platform-assigned push branch, the measured platform exception to the protocol branch shape)
Worktree: objectstack-issue-28355
Domain: domain:server
Seat: domain:server#4
File surface: packages/metadata-protocol/src/**, packages/metadata-core/src/objects/sys-metadata-audit.object.ts (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default judgment tier (dispatch-gates --tier: no path-derived mandate), effort: high
Clause-②: no
Metadata-protocol: none
Responsibility: the metadata protocol's own audit writer | none: no door stamps the documented denied codes today | operators and agents reading /audit for a metadata name
Thread-read: 6540321795
Premise: holds (triage read it fresh at 06:55Z; the seat did not re-measure which codes are stamped, so the dev measures first and reports needs_decision if enforcing needs a choice the card does not settle)
Serial constraints cleared: packages/metadata-protocol/src/protocol.ts is on the lane's hot-file queue behind #25467 (move-only cuts); #25467 is pm:queue with no assignee, so no cut is in flight. The dev merges main before the PR.
Taken at 2026-10-31T08:33Z: p2 enforce-or-remove, next unclaimed dispatchable card by the full order.
{
"issue": 28355,
"status": "done",
"branch": "claude/project-thread-bdj57c",
"pr": "https://github.com/objectstack-ai/objectstack/pull/28393",
"head": "7e9960c8da",
"session": "session_01QUs3Bs2hELyx9Go8Efyui5",
"premise_still_valid": true,
"enforced_codes": ["not_overridable", "not_creatable", "invalid_metadata", "destructive_change"],
"removed_codes": [],
"item_locked": "already stamped: lockWriteRefusal / assertLockAllowsWrite / assertLockAllowsDelete (protocol-lock-version-gates.ts) on all four doors, batch re-records via recordPendingDenialAudit; not in the new map, so no double row",
"tests": "metadata-protocol vitest at 7e9960c8da: Test Files 285 passed | 4 skipped (289), Tests 21872 passed | 26 skipped (21898); new file 12/12; ablation (audit write disabled, on-disk blob 4b5d1b1c9c20 -> 35ebe7c00ab9, restored == HEAD): 9 failed | 3 passed as predicted",
"gates": "dispatch-gates --commands at 7e9960c8da: 69 derived, 69 run, all exit 0; --ran: 69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN (exit codes recorded); pnpm --filter @objectstack/metadata-protocol typecheck exit 0; pnpm lint exit 0; CI check-runs: in_progress at report time",
"line_budget": "+527 / -19 = 546 changed lines, 10 files, under the 3000 threshold",
"files_changed": [
".changeset/28355-refusal-audit-rows.md",
"packages/metadata-protocol/src/protocol-refusal-audit.ts",
"packages/metadata-protocol/src/protocol.ts",
"packages/metadata-protocol/src/protocol.refusal-audit-rows.test.ts",
"packages/metadata-protocol/src/protocol.code-only-types.test.ts",
"packages/metadata-protocol/src/protocol.lock-org-axis-agree.test.ts",
"packages/metadata-protocol/src/protocol.read-verb-canonical-fold.test.ts",
"packages/metadata-protocol/src/protocol.tenant-authored-write.test.ts",
"packages/metadata-protocol/src/protocol.view-expansion-reconcile-call-sites.test.ts",
"scripts/engine-double-contract.pinned.json"
],
"deviations": [
"file surface: scripts/engine-double-contract.pinned.json is outside the claimed surface; check:engine-double-contract requires the new test double in its ledger (written by its own --write)",
"sys-metadata-audit.object.ts unchanged: enforcing made its documented vocabulary true, nothing to trim",
"five existing pins reconciled (asserted a refusal makes no engine call, or scanned door source by member name): now assert the exact denied audit row / name the protected ...Unaudited bodies",
"first gate pass ran with a runner that leaked stdin and skipped commands; the reported pass is a clean rerun of all 69 on the final head",
"clone was shallow; unshallowed for check-plugin-teardown-shape --self-test",
"session context asked to assign and request review on the new PR; not done, per the dispatch (no assignees, no reviewers, no MCP writes)"
],
"dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm",
"mcp_calls": "6: mcp__github__issue_read (get x1, get_comments x5); no write tool",
"api_writes": "2: relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft) and this comment (POST /repos/objectstack-ai/objectstack/issues/28355/comments)",
"out_of_scope_findings": [
"carrier: none · noted, not filed: whether SysMetadataRepository.readOnlyBaseOverrideError (ITEM_LOCKED, lockSource package) is ever reached past the lock gate without a row is NOT MEASURED; listed in the PR's Acceptance notes"
]
}
closed completed by the PR's Fixes 2026-10-31T11:23:43Z
State change: pm:dispatched removed, and nothing is left on the card. Every documented denied code is now written by a door, so nothing was removed from the vocabulary. The body's "What changes" bullet 2 reads "protected …Unaudited body". At the merged head the bodies are private, and the request shapes are unexported local aliases (dev report and ACCEPT). The PR body could not be patched through the relay, so this comment records the correction.
Activity
objectstack-fleet commentedon Oct 31, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 错的必须被响亮拒绝并给处方 | none | P②
Triage: p2 ·
domain:server·area:studio·pm:queue· enforce-or-remove · 2026-10-31T06:55Z⛔ Not a claim.
sys_metadata_auditdocumentsdeniedcodes that no audit write stamps. A reader of/auditconcludes that a refused attempt never happened. A silent gap in an audit trail is p2.not_overridable,not_creatable,destructive_changeandinvalid_metadata): stamp adeniedrow at the refusing door, beside the existingmetadata_conflictrow. A refused authoring attempt is what an audit trail is for. Remove only the codes that no door refuses, and the PR names which.Generated by Claude Code
objectstack-fleet commentedon Oct 31, 2026
domain:server#4 · os-zhuang · session_01QUs3BtyH9zgxKzYrJiH18J
Claim: PM loop round 1
Session:
session_01QUs3BtyH9zgxKzYrJiH18JAccount:
os-zhuangBranch:
claude/project-thread-bdj57c(the card thread's platform-assigned push branch, the measured platform exception to the protocol branch shape)Worktree:
objectstack-issue-28355Domain:
domain:serverSeat:
domain:server#4File surface:
packages/metadata-protocol/src/**,packages/metadata-core/src/objects/sys-metadata-audit.object.ts(stop on breach; explain in the report)Container & model:
M,mode:thread,model: default judgment tier (dispatch-gates --tier: no path-derived mandate),effort: highClause-②: no
Metadata-protocol: none
Responsibility:
the metadata protocol's own audit writer | none: no door stamps the documented denied codes today | operators and agents reading /audit for a metadata nameThread-read: 6540321795
Premise: holds (triage read it fresh at 06:55Z; the seat did not re-measure which codes are stamped, so the dev measures first and reports needs_decision if enforcing needs a choice the card does not settle)
Serial constraints cleared:
packages/metadata-protocol/src/protocol.tsis on the lane's hot-file queue behind #25467 (move-only cuts); #25467 ispm:queuewith no assignee, so no cut is in flight. The dev merges main before the PR.Taken at 2026-10-31T08:33Z: p2 enforce-or-remove, next unclaimed dispatchable card by the full order.
objectstack-fleet commentedon Oct 31, 2026
domain:server#4 · os-zhuang · session_01QUs3Bs2hELyx9Go8Efyui5
os-dev-report
{ "issue": 28355, "status": "done", "branch": "claude/project-thread-bdj57c", "pr": "https://github.com/objectstack-ai/objectstack/pull/28393", "head": "7e9960c8da", "session": "session_01QUs3Bs2hELyx9Go8Efyui5", "premise_still_valid": true, "enforced_codes": ["not_overridable", "not_creatable", "invalid_metadata", "destructive_change"], "removed_codes": [], "item_locked": "already stamped: lockWriteRefusal / assertLockAllowsWrite / assertLockAllowsDelete (protocol-lock-version-gates.ts) on all four doors, batch re-records via recordPendingDenialAudit; not in the new map, so no double row", "tests": "metadata-protocol vitest at 7e9960c8da: Test Files 285 passed | 4 skipped (289), Tests 21872 passed | 26 skipped (21898); new file 12/12; ablation (audit write disabled, on-disk blob 4b5d1b1c9c20 -> 35ebe7c00ab9, restored == HEAD): 9 failed | 3 passed as predicted", "gates": "dispatch-gates --commands at 7e9960c8da: 69 derived, 69 run, all exit 0; --ran: 69 derived, 69 run, 0 NOT-MEASURED, 0 UNRUN (exit codes recorded); pnpm --filter @objectstack/metadata-protocol typecheck exit 0; pnpm lint exit 0; CI check-runs: in_progress at report time", "line_budget": "+527 / -19 = 546 changed lines, 10 files, under the 3000 threshold", "files_changed": [ ".changeset/28355-refusal-audit-rows.md", "packages/metadata-protocol/src/protocol-refusal-audit.ts", "packages/metadata-protocol/src/protocol.ts", "packages/metadata-protocol/src/protocol.refusal-audit-rows.test.ts", "packages/metadata-protocol/src/protocol.code-only-types.test.ts", "packages/metadata-protocol/src/protocol.lock-org-axis-agree.test.ts", "packages/metadata-protocol/src/protocol.read-verb-canonical-fold.test.ts", "packages/metadata-protocol/src/protocol.tenant-authored-write.test.ts", "packages/metadata-protocol/src/protocol.view-expansion-reconcile-call-sites.test.ts", "scripts/engine-double-contract.pinned.json" ], "deviations": [ "file surface: scripts/engine-double-contract.pinned.json is outside the claimed surface; check:engine-double-contract requires the new test double in its ledger (written by its own --write)", "sys-metadata-audit.object.ts unchanged: enforcing made its documented vocabulary true, nothing to trim", "five existing pins reconciled (asserted a refusal makes no engine call, or scanned door source by member name): now assert the exact denied audit row / name the protected ...Unaudited bodies", "first gate pass ran with a runner that leaked stdin and skipped commands; the reported pass is a clean rerun of all 69 on the final head", "clone was shallow; unshallowed for check-plugin-teardown-shape --self-test", "session context asked to assign and request review on the new PR; not done, per the dispatch (no assignees, no reviewers, no MCP writes)" ], "dogfood_battery": "n/a: no ! in the PR title and no (narrowing) arm", "mcp_calls": "6: mcp__github__issue_read (get x1, get_comments x5); no write tool", "api_writes": "2: relay pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft) and this comment (POST /repos/objectstack-ai/objectstack/issues/28355/comments)", "out_of_scope_findings": [ "carrier: none · noted, not filed: whether SysMetadataRepository.readOnlyBaseOverrideError (ITEM_LOCKED, lockSource package) is ever reached past the lock gate without a row is NOT MEASURED; listed in the PR's Acceptance notes" ] }objectstack-fleet commentedon Oct 31, 2026
domain:server#4 · os-zhuang · session_01QUs3BtyH9zgxKzYrJiH18J
Landed · #28355 · 2026-10-31T11:24Z
b9b22b9b4266e9beabc03d6f8a4dace41ceab8f1, ACCEPT 6542540413 at headb50e93b45completedby the PR'sFixes2026-10-31T11:23:43ZState change:
pm:dispatchedremoved, and nothing is left on the card. Every documenteddeniedcode is now written by a door, so nothing was removed from the vocabulary. The body's "What changes" bullet 2 reads "protected…Unauditedbody". At the merged head the bodies areprivate, and the request shapes are unexported local aliases (dev report and ACCEPT). The PR body could not be patched through the relay, so this comment records the correction.