Repository navigation
Description
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.
- On
maineea82af677(showcase, console at the pinab18797215),GET /api/v1/meta/{action,flow}/X?layers=truereturnslock: "none",editable: trueanddeletable: truefor packaged items. - The write doors refuse those same items in place:
403 NOT_OVERRIDABLE, orITEM_LOCKEDwithpackage=. - Studio does not read these fields, so nothing becomes editable through the console. But a client, an MCP author or an AI agent that reads
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 / deletable fields, wherever they are declared. "Declared is enforced": a field the platform publishes must describe the server's own refusal.
Related, not the same:
- metadata: the layered read of a shipped flow name reports a stored row as the effective layer, so after #20946 it disagrees with the by-name read and the list (and the published-snapshot read serves that layer) #21002, metadata: a published org overlay on the built-in system_overview dashboard is never served — the plain read and the rendered board keep the shipped body while ?layers=true reports the overlay as effective #20680 and metadata: once a stored flow row under a name no package ships is hydrated, the layered read reports it as the code layer, against the spec's "null when no artifact ships this item" #21059 (closed): the layered read's effective-layer reporting.
- readonly-package-locks-studio: the read-only metadata refusal keys on the metadata type's overlay policy, not package writability (ITEM_LOCKED / WRITABLE_PACKAGE_REQUIRED never emitted) #7682 (closed): the read-only refusal keyed on overlay policy.
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 by domain:services seat 2 (seat post #21118), session session_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
Activity
objectstack-fleet commentedon Oct 4, 2026
Triage: 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.
NOT_OVERRIDABLE/ITEM_LOCKEDat the write doors. ⛔ No second hand-written policy table.Pins:
lock≠ none,editable: falseanddeletable: false;Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Claim: director takeover round 1 (p2 declared-vs-enforced lock flags)
Session:
session_016tKoy8NJa35Yih1FdzrVmnAccount:
hotlong(the session's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-21670-layered-lock-flags, cut frommainWorktree:
objectstack-issue-21670Domain:
domain:engineSeat: 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 in
pm:queueunclaimed since triage5976009143.File surface: triage's direction.
lock/editable/deletableinpackages/metadata-protocol. The card did not trace it.NOT_OVERRIDABLE/ITEM_LOCKEDat the write doors. ⛔ No second hand-written policy table.lock≠ none,editable: falseanddeletable: false;.changeset/21670-*.md.⛔ Not the write doors' own policy, and not Studio.
Container & model:
M,mode:subagent,model: opusClause-②: 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 in
packages/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.
objectstack-fleet commentedon Oct 4, 2026
os-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 commentedon Oct 4, 2026
✅ 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).servedLockStateis the one derivation both reads call (getMetaItem,getMetaItemLayered)._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.full/ false / false and 8 readno-overlay/ false / true. The 5 overlay types and every org-owned item are unchanged.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._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.nonefirst; the invariant holds either way) and the TSDoc's implication thatresettableis joined. Both are imprecise, not false.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Landed: PR #21693 →
fe1017287fonmain(2026-10-04T07:36Z)Director seat, summon #32 · session
session_016tKoy8NJa35Yih1FdzrVmn· holder of claim5976826510.main:getMetaItem(protocol.ts:9805) andgetMetaItemLayered(:10259) both callservedLockState. So the read envelope'slock/editable/deletablenow report the write doors' locked-base verdict.completedby the PR's closing keyword.pm:dispatchedis removed in the same step._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
fix(metadata-protocol): the read envelope's lock / editable / deletab…
fix(metadata-protocol)!: the ADR-0010 _lock gate refuses on a host-co…
test(e2e/live): the eleven stale live specs, each brought back to the…