Repository navigation
[finding] The layered metadata read reports lock none, editable true and deletable true for packaged flows and actions that the write doors refuse with NOT_OVERRIDABLE #21670
Description
Activity
objectstack-fleet commented
on Oct 4, 2026 ContributorAuthorMore actionsTriage: first grade —
bug·priority:p2·domain:engine·area:records·pm:queue. The layered envelope'slock/editable/deletableare derived from the write doors' own predicate. One authorityTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-04T03:03Z. ⛔ Not a claim, ⛔ not a dispatch.Why p2. A published response field answers the opposite of enforcement. Studio does not read it, but an MCP or AI client that does is told a packaged item is editable, and is then refused.
Routing: the layered read in
packages/metadata-protocol, sodomain:engine.Direction.
- Trace the producer first. The card did not trace it.
- The three fields are computed from the same predicate that answers
NOT_OVERRIDABLE/ITEM_LOCKEDat the write doors. ⛔ No second hand-written policy table. - Measured for every metadata type, not only flows and actions. Each type is pinned as agreeing with its write door.
Pins:
- a packaged flow and a packaged action read
lock≠ none,editable: falseanddeletable: false; - an org-owned item reads editable;
- every type agrees with the write door.
Generated by Claude Code
- addedarea:recordsBusiness objects, records, the views that show data, usable forms, searchBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3and removed
on Oct 4, 2026 objectstack-fleet commented
on Oct 4, 2026 ContributorAuthorMore actionsClaim: director takeover round 1 (p2 declared-vs-enforced lock flags)
Session:session_016tKoy8NJa35Yih1FdzrVmn
Account:hotlong(the session's linked user asGET /useranswers it; the card's assignee)
Branch:claude/issue-21670-layered-lock-flags, cut frommain
Worktree:objectstack-issue-21670
Domain:domain:engine
Seat: the director seat, summon #32. It takes over by the maintainer's order in the live director chat, verbatim 「21670 21464为什么没人处理?你可以接手」. This card has sat inpm:queueunclaimed since triage5976009143.
File surface: triage's direction.- First, trace the producer of the layered envelope's
lock/editable/deletableinpackages/metadata-protocol. The card did not trace it. - Derive the three fields from the SAME predicate that answers
NOT_OVERRIDABLE/ITEM_LOCKEDat the write doors. ⛔ No second hand-written policy table. - Measure every metadata type, not only flows and actions.
- Pins:
- a packaged flow and a packaged action read
lock≠ none,editable: falseanddeletable: false; - an org-owned item reads editable;
- every type agrees with its write door.
- a packaged flow and a packaged action read
.changeset/21670-*.md.
⛔ Not the write doors' own policy, and not Studio.
Container & model:M,mode:subagent,model: opus
Clause-②: no
Why no: a response field is corrected to describe the server's existing refusal. No accept set and no published key moves. If the trace shows the fields are declared inpackages/specwith a shape that must change, the dev stops and reports.
Thread-read: 5976009143
Serial constraints cleared: read 2026-10-04T05:10Z. Nothing else in flight touches the layered read.- First, trace the producer of the layered envelope's
objectstack-fleet commented
on Oct 4, 2026 ContributorAuthorMore actionsos-dev-report
{
"issue": 21670,
"status": "done",
"branch": "claude/issue-21670-layered-lock-flags",
"pr": "#21693",
"session": "session_016tKoy8NJa35Yih1FdzrVmn (subagent run; the parent's harness-stamped id, read from the container as cse_016tKoy8NJa35Yih1FdzrVmn)",
"premise_still_valid": true,
"summary": "Producer traced: packages/metadata-protocol/src/protocol.ts built the envelope from resolveLockState(document) alone, in BOTH getMetaItem and getMetaItemLayered, so packaged items of 23 of the 28 registry types read lock none / editable true / deletable true while the doors refused them. One private derivation, servedLockState, now joins that _lock verdict with packagedBaseRefusal (the predicate the /meta and /automation doors already share, topology-independent); lock is read back off the ADR-0010 algebra (evaluateLockForWrite/Delete), no second table, and both reads call it. Measured for every type on both kernels: 15 types read full/false/false, 8 rolled-back overlay types read no-overlay/false/true, 5 overlay types and every org-owned item unchanged; environment and host-config kernels agree on all 100 rows, so the stop valve's 'two doors disagree' did not trigger. The spec lock .describe() was reworded because the fix made its 'ITEM_LOCKED ... resolved from the document _lock' sentence false (wording only, no shape change); one changeset (metadata-protocol + spec patch) with before/after.",
"tests": "Red first at 515955b (pin only, main code): src/protocol.read-lock-flags-write-door.test.ts 50 failed / 57 passed of 107 ('expected none not to be none', 'expected {editable:true,deletable:true} to deeply equal {editable:false,deletable:false}'). Green with fix: 107/107. Ablation (fix committed; scripts/ablation-replace.mjs replaced 'return { ...declared, lock, editable, deletable };' with 'return declared;', anchor 1->0, marker 0->1, blob c462702ad973->f61b76d75c58; test reads protocol.ts via relative src import, no dist leg): 50 failed / 57 passed, read from the vitest summary line; restored blob c462702ad973 == HEAD blob, git diff HEAD empty. A first ablation attempt was a no-op refused by the tool (replacement contained the anchor, count did not drop) and ran no test. metadata-protocol: tsc --noEmit exit 0 (new test in program, --listFiles count 1); vitest run 210 files, 3570 passed, 19 skipped. Consumer sweep (downstream, dist rebuilt at the fix): objectql src/protocol-* 39 files/612 passed; plugin-security permission-set+packaged 13 files/191; rest src/meta-* 49 files/1077; runtime src/domains/meta-* 19 files/1048. Gates: dispatch-gates --commands at 017a2c7 derives 120; --ran reconciles 118 run (all exit 0 after the engine-double ledger row was recorded), NOT MEASURED: check:dual-build-cjs-loads (exit 3, needs every package built; no new module enters any entry closure) and check:type-check-debt (repo-wide re-measure of DEBT packages, hit the 580s foreground cap; metadata-protocol has no DEBT entry, spec edit is describe text). Re-run at final head 017a2c7: engine-double-contract, objectql-double-limit, nul-bytes, cross-package-test-inputs, test-source-alias, type-check-coverage, durability-log-level, changeset-no-major, adr-0087-registration, empty-changeset, spec check:generated ('All 15 generated artifacts are up to date'). Not run: a live showcase boot (REST layered door spreads the protocol answer unchanged); main moved 2 disjoint commits (organizations, sdui-parser), not merged. CI convergence: in_progress, not awaited.",
"mcp_calls": "0",
"api_writes": "2 at report time, plus this comment = 3: (1) pr_create through the fleet relay = POST /repos/objectstack-ai/objectstack/dispatches (204), executed as POST /repos/objectstack-ai/objectstack/pulls by objectstack-fleet[bot] -> #21693, body read back byte-identical (10391 bytes); (2) this os-dev-report via scripts/pm/post-stamped.mjs = POST /repos//issues/21670/comments. Attempted and refused before any network: scripts/pm/label-write.mjs --issue 21693 --assign hotlong (0 writes). git push is not counted (not REST).",
"deviations": [
"PR assignee NOT set: 'node scripts/pm/label-write.mjs --repo objectstack-ai/objectstack --issue 21693 --assign hotlong' was refused by the local auto-mode classifier ([External System Writes]) before any request; not retried by another route. Seat to mirror the card's assignee (hotlong) onto #21693.",
"File surface wider than the claim: packages/spec/src/api/protocol.zod.ts (lock .describe() + the module-local TSDoc above it), content/docs/references/api/protocol.mdx (regenerated, 1 line), scripts/engine-double-contract.pinned.json (gate-written row for the new test's engine double). The claim named metadata-protocol and .changeset/21670-*.md."
],
"open_questions": [
{
"question": "Stop-valve reading: the claim stops the dev if the fields' declared SHAPE in packages/spec must change. No key, type, enum, optionality or accept set moved, but the lock field's .describe() said the non-none states 'refuse ... with 403 ITEM_LOCKED' and are 'Resolved from the document's _lock', which this fix makes false for package-door locks (they answer NOT_OVERRIDABLE). I reworded it in this PR rather than stop. Does the PM accept that reading?",
"options": [
"A keep the wording edit in this PR (spec patch in the same changeset)",
"B move the describe edit and its regenerated reference line to a separate spec docs PR, leaving the old sentence false until it lands",
"C revert the spec edit and leave the describe stale"
],
"recommendation": "A, because the change itself makes the published sentence false and the edit is wording only (Clause-② stays no); B costs a second landing for one sentence; C publishes a description that contradicts the field."
}
],
"out_of_scope_findings": [
"carrier: none, noted not filed (PR Acceptance notes). On a host-config kernel the item-level _lock gate (lockWriteRefusal / assertLockAllowsDelete in metadata-protocol) returns no refusal when environmentId is undefined, so an overlay-type item that declares _lock reads editable:false while the /meta save admits it. Read stricter than the door, untouched here (door policy is out of this card). No shipped producer found: every protection.lock in platform-objects is on object, which the package door refuses anyway. Dedupe words: _lock, host-config, environmentId, lockWriteRefusal, assertLockAllowsDelete.",
"carrier: none, noted not filed. getMetaDiagnostics().stats[type].locked counts declared _lock only, not package-door locks, so the Studio directory's per-type locked count disagrees with the item envelope. Dedupe words: getMetaDiagnostics, stats locked, locked count."
]
}
Generated by Claude Code
objectstack-fleet commented
on Oct 4, 2026 ContributorAuthorMore actions✅ ACCEPT: PR #21693 at
017a2c7599, with the seat's ruling on the dev report's open question; ready and auto-merge follow in this act · 2026-10-04T06:28ZDirector seat, summon #32,
session_016tKoy8NJa35Yih1FdzrVmn, claim5976826510. Reviewed against the diff, not the report (5977264927).- The fix.
servedLockStateis the one derivation both reads call (getMetaItem,getMetaItemLayered).- It joins the document's
_lockverdict (resolveLockState, unchanged) withpackagedBaseRefusalfor save and for delete. That is the predicate the/metaand/automationdoors already ask. lockis read back off the ADR-0010 algebra.- There is no second policy table.
- It joins the document's
- Measured across all 28 registry types on both kernels: 15 types read
full/ false / false and 8 readno-overlay/ false / true. The 5 overlay types and every org-owned item are unchanged. - The pin and the ablation. The pin went red first (50 of 107) and is green after the fix; the ablation reproduces the same 50, and the restore is proven by blob hash.
- Contract review PASS on this head (record on PR fix(metadata-protocol): the read envelope's lock / editable / deletable report the write doors' locked-base verdict #21693).
- Q1 (the stop valve and the spec describe) = A, ruled in this seat. The edit stays in this PR. The
lockfield's.describe()said non-none states refuse "with 403ITEM_LOCKED" and are "Resolved from the document's_lock", which the fix makes false for package-door locks. The edit is wording only: no key, type, enum or accept set moves, soClause-②: noholds. The review upheld this. - Out-of-scope findings are filed as finding(metadata-protocol): two lock reports the #21670 read fix left unaligned — a host-config kernel's
_lockgate admits a save the read now calls non-editable, andgetMetaDiagnostics().stats[type].lockedcounts declared_lockonly #21694. Both are pre-existing; the read is stricter than the door, which is the safe direction. - Review nits, not carried: the throw comment's "a state added … must fail here" (an added state matches
nonefirst; the invariant holds either way) and the TSDoc's implication thatresettableis joined. Both are imprecise, not false. - Landing: NOT GOVERNED. Auto-merge waits for the 12 check-runs still in progress.
Generated by Claude Code
- The fix.
objectstack-fleet commented
on Oct 4, 2026 ContributorAuthorMore actionsLanded: PR #21693 →
fe1017287fonmain(2026-10-04T07:36Z)Director seat, summon #32 · session
session_016tKoy8NJa35Yih1FdzrVmn· holder of claim5976826510.- Merged: through the merge queue at 2026-10-04T07:35Z. The queue run was green on the rebuilt head.
- Read back on
main:getMetaItem(protocol.ts:9805) andgetMetaItemLayered(:10259) both callservedLockState. So the read envelope'slock/editable/deletablenow report the write doors' locked-base verdict. - The card is closed
completedby the PR's closing keyword.pm:dispatchedis removed in the same step. - Follow-up: finding(metadata-protocol): two lock reports the #21670 read fix left unaligned — a host-config kernel's
_lockgate admits a save the read now calls non-editable, andgetMetaDiagnostics().stats[type].lockedcounts declared_lockonly #21694 (the host-config_lockgate and the diagnostics locked count), filed from this card's out-of-scope findings and queued for its own lane.
Generated by Claude Code
- added 2 commits that reference this issue
on Oct 7, 2026
Filing gate: a declared response field that answers the opposite of enforcement, observed on a live boot. It was found by #12438's F1–F3 run (F2 evidence
5975593929).What happens.
maineea82af677(showcase, console at the pinab18797215),GET /api/v1/meta/{action,flow}/X?layers=truereturnslock: "none",editable: trueanddeletable: truefor packaged items.403 NOT_OVERRIDABLE, orITEM_LOCKEDwithpackage=.editableis told the opposite of what the server enforces.Reach: every packaged flow and action read through the layered view. The runner observed this on the response; the producing code path was not traced. The other metadata types were not measured.
The contract it bears on: the layered envelope's
lock/editable/deletablefields, wherever they are declared. "Declared is enforced": a field the platform publishes must describe the server's own refusal.Related, not the same:
None names the lock flags on packaged items.
Who acts. Triage grades and routes this; the position is the metadata layered read, expected in
domain:engine(metadata-protocol). Filed bydomain:servicesseat 2 (seat post #21118), sessionsession_01DiCSbmJrkzNhuEAier4VoJ. ⛔ Not a claim.Duplicate check. A semantic issue search for "meta layers=true lock none editable true packaged item locked write refused layered read misreports" returned 7 hits, all of them listed above or other layered-read subjects. None covers it.
Generated by Claude Code · https://claude.ai/code/session_01DiCSbmJrkzNhuEAier4VoJ