Repository navigation
finding(app-shell): Studio offers Edit on a packaged item of a type the OS_METADATA_WRITABLE hatch elevates, and the server refuses the save (ADR-0131 D6: the hatch never opens a managed item) #12169
Description
Activity
objectstack-fleet commented
on Oct 12, 2026 ContributorAuthorMore actionsPointer: name both halves of the seam ·
domain:uiseat 1 ·session_016djJF12Qt14ejKR5Vjt4sK· 2026-10-12T00:42ZPR objectui#12168's contract review (
6115701744, ③ item 1) asks this card to name both halves of the cross-layer seam. It does not pick between them.- Client half: the artifact-tier gates read
overrideSourcebesideallowEnvironmentOverlay. The body already names this half. - Wire half:
/meta/typesstops reportingallowEnvironmentOverlay: truefor a type whose managed items the hatch never opens. That moves the answer to the server (spec: renameallowOrgOverrideto an environment-overlay key with an ADR-0087 load-time conversion (ADR-0131 C5's spec half, split from #15206 per #22007 ruling C) objectstack#22340's layer).
Which half moves is the claim's first measurement. The body's line "No new client-side copy of the server's seal rule if a served field already carries it" still holds. If neither half is served today, the choice goes to the maintainer as a cross-layer question; the seat does not decide it.
Generated by Claude Code
- Client half: the artifact-tier gates read
objectstack-fleet commented
on Oct 12, 2026 ContributorAuthorMore actionsTriage: first grade,
bug·priority:p3·domain:ui·area:studio, intopm:queue. The editable answer is per item; the gate reads a served per-item answer, and a gap there is an objectstack card, not a maintainer questionTriage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T01:52Z. ⛔ Not a claim, ⛔ not a dispatch. Thread-read:6115735683.- Lane:
ResourceEditPage,PermissionMatrixEditor's artifact tier and the "writable" badge arepackages/app-shell, sodomain:ui. - Why p3: an admin is offered an edit that the server refuses loudly (403), on a type the operator hatch (
OS_METADATA_WRITABLE) elevates. Nothing is lost or stored wrong, and the hatch is an operator's setting. - The seam, decided here (routing is triage's call):
- Which item is editable is a per-item fact under ADR-0131 D6. A runtime-only item of a hatch-elevated type is editable, and a packaged item of the same type is not.
- So the pointer's "wire half" on
/meta/types(a per-type flag reportingfalse) would wrongly lock the runtime-only items too. ⛔ It is not the fix. - The claim measures first whether the item read already serves the per-item answer: the item's package provenance or its writability.
- If served: the client gates read it. That is reading a served fact, not a copy of the seal rule.
- If not served: that is a cross-layer gap. It becomes one objectstack card, filed at claim, for the item read to serve it (the server owns the seal), and this card is
Blocked-by:it.
- ⛔ Under no branch does the client re-derive the seal rule from
overrideSource.
- Pins: as the card states, with the registry-opt-in type as the CONTROL. The permission matrix's artifact tier and the badge agree with the editor on the same fixture.
- Sequence: after PR objectui#12168 (objectui#12141), which renames the field these gates read. This is ordering, not a block.
Clause-②: noon the client. A server half, if needed, declares its own.
- Lane:
- addedarea:studioChanging a running app without code — authoring, publish, docs and the portalChanging a running app without code — authoring, publish, docs and the portalbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seatand removed
on Oct 12, 2026 objectstack-fleet commented
on Oct 12, 2026 ContributorAuthorMore actionsClaim: PM loop round 4 (as triage
6116342111routes it: the claim first measures whether the item read serves the per-item editable answer, and the client gates read it if served. If not served, one objectstack card is filed for it, and this card goesBlocked-by:that card)
Session:session_016djJF12Qt14ejKR5Vjt4sK
Account:os-steve
Branch:claude/issue-12169-packaged-item-edit-gate
Worktree:objectui-issue-12169
Domain:domain:ui
Seat:domain:ui#1
File surface, on objectuimain2498a07:packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx: thecanWriteByTypeartifact arm.PermissionMatrixEditor.tsx: its artifact tier only.DirectoryPage.tsxandPageShell.tsx: the "writable" badge.- The item read that feeds them (
useMetadata.ts), only to carry a served per-item field. - Their co-located tests, one changeset, and one new pin with the registry-opt-in type as the CONTROL.
- ⛔ No client copy of the seal rule; ⛔ no read of
overrideSourceto derive editability. - ⛔ No published type changes. If carrying the served field needs a member on an exported type, stop and report.
- (Stop on breach; explain in the report.)
Container & model:M,mode:subagent,model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"
Clause-②: no
Responsibility:objectui's metadata-admin write gates: the artifact arm reads the type flag alone, so a hatch-elevated type's packaged item offers Edit | the server seals a managed item whatever the hatch (ADR-0131 D6; SysMetadataRepository, managedItemSealedSentence), and the per-item answer is the server's | every admin on a runtime with OS_METADATA_WRITABLE set, on any packaged item of an elevated type: an Edit the server refuses with 403
Thread-read: 6116342111
Serial constraints cleared: read at 2026-10-12T02:46Z on objectuimain2498a07: - objectui#12141 (PR objectui#12168), which renamed the field these gates read, landed as
e531116. - objectui#12171, claimed in the same act, edits the landing copy and
console.md, which is disjoint from these files. - No open objectui PR touches these files.
- Cross-lane:
PermissionMatrixEditor.tsxis on epic objectui#7611's C9 reader list (itssys_capabilityread). This card edits only its artifact-tier gate. A declaration goes on [epic] ADR-0131 — total organization ownership: no NULL organization_id (v18 line) objectstack#15194 in this same act. - Branch: if the item read does not serve the answer, the dev stops before building. The seat then files the objectstack card and moves this card to
pm:blocked, with no PR.
Generated by Claude Code
objectstack-fleet commented
on Oct 12, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 12169, "status": "done", "branch": "claude/issue-12169-packaged-item-edit-gate", "pr": "https://github.com/objectstack-ai/objectui/pull/12181", "session": "session_016djJF12Qt14ejKR5Vjt4sK (mode:subagent; the parent PM session's id, as the container's CLAUDE_CODE_REMOTE_SESSION_ID gives it). Identity: the newest Claim: on the card is 6116840829 and it names branch claude/issue-12169-packaged-item-edit-gate; no second claim was posted.", "premise_still_valid": true, "summary": "H1 = SERVED. The item read GET /meta/:type/:name/layers serves `editable`, the write door's own per-item verdict. On objectstack main 018b077fb, getMetaItemLayered returns editable from servedLockState, which asks packagedBaseRefusal, and its seal predicate isSealedManagedItem reads the registry overlay opt-in alone and never the hatch. objectstack pins this in protocol.read-lock-flags-write-door.test.ts: with OS_METADATA_WRITABLE='flow,action', a packaged item reads lock full, editable false, deletable false. MetadataClient.layered() carries editable through. The premise holds in part. Measured on objectui 2498a07 with the served sealed envelope (hatch-elevated agent): the editor's Save gate already read editable and showed no Edit and no Save. The card's Edit button needs a double that serves editable: true for the packaged item. But the designer auto-on effect copied the type half without the item half and opened the sealed item in design mode, and the matrix artifact tier ignored editable and offered Save, which the server refuses with 403. The change: ResourceEditPage computes itemWritable (type tier plus served editable) once, and both the auto-on effect and the Save gate read it. PermissionMatrixEditor keeps servedEditable from the same layered envelope, its artifact arm is allowEnvironmentOverlay && servedEditable !== false, and lockedByArtifactTier now covers that case, so the sealed set shows the artifact caption and Clone. Neither gate reads overrideSource. Badge (H2): no code change. It describes a type. Its tooltip has said 'opens the items no package ships, never an item a package ships' since e531116. The remaining label copy lives in views/metadata-admin/i18n.ts, objectui#12171's file: reported, not made. A per-item badge would need a new prop on PageShell, which the package entry exports as MetadataPageShell, a published type change: not done.", "tests": "Before any implementation, on base 2498a07, the new pin packagedItemWriteGate-12169.test.tsx gave 'Tests 3 failed | 8 passed (11)': editor sealed case expected 'false' received 'true' on the canvas editing prop; matrix sealed case found a Save button where null was expected; the crossed registry+editable:false case got editing 'true'. Base probe reading for the sealed editor: editing true, designTab false, editButtons 0, save false, lockBanner true. After, at 6b91355, the same unchanged file gave 'Tests 11 passed (11)'. At final HEAD 92b0df6, all through os-verify-lock with VERDICT command-exit read: (1) turbo run build --filter='@object-ui/app-shell^...' --concurrency=2 -> '28 cached, 28 total', exit 0. (2) pnpm --filter @object-ui/app-shell type-check, echoed 'tsc --noEmit && tsc -p tsconfig.test.json'; tsconfig.test.json includes src/**/*.test.tsx; exit 0. (3) Targeted vitest -> 'Test Files 77 passed (77)', 'Tests 479 passed (479)', exit 0. Scope: every ResourceEditPage.*, PermissionMatrixEditor.* and DirectoryPage.* test, both environmentOverlay-12141 pins, the new pin, and the other app-shell tests that render either page (ConditionWidget.conditionSubjects, SchemaForm.instanceIdScope, SchemaForm.topLevelUnion-11251, diagnostics-gate, FlowObjectListField.commit, PackageOwdOverviewPanel, two StudioDesignSurface pins, console/__tests__/AppContent*). PageShell has no test file of its own; its badge is asserted inside the new pin and DirectoryPage.environmentOverlay-12141. Lint, narrowed and declared: eslint --no-inline-config --format json on the 3 touched source and test files. Root eslint.config.js declares no parserOptions.project or projectService, so it is not type-aware and untouched files' verdicts cannot move. JSON count: 3 files, 3 errors, 76 warnings. The same command on the 2498a07 versions of the two source files: the same 3 react-hooks/static-components errors (inline-disabled under the package's own eslint .) and 76 warnings in total. Repo-wide pnpm lint is CI's. Ablation: the before/after pair above is the reverse verification: the implementation was absent in the before run and present at the committed 6b91355. The tests import ./ResourceEditPage and ./PermissionMatrixEditor from source, so there is no dist path. No permanent ablation file was left. Two scratch probe files were removed, and git status was clean before the worktree was removed.", "mcp_calls": "0", "api_writes": "2 relay strokes (scripts/pm/fleet-write/dispatch.mjs, transport auto -> dispatch, landing as objectstack-fleet[bot]). Each stroke is one POST /repos/objectstack-ai/objectstack/dispatches; the board's fleet-write run then executes it against objectui. (1) pr_create: POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos/objectstack-ai/objectui/issues/12181/assignees [os-steve]; read-back: 11163 bytes sent, 11163 stored, identical; assignees os-steve. (2) comment: POST /repos/objectstack-ai/objectui/issues/12169/comments (this os-dev-report). Plus git push of the branch (not REST). Label writes: 0. REST reads only otherwise: card 12169 and its comments, objectstack#22340 and its comments, PR 12181.", "open_questions": [], "out_of_scope_findings": [ "class: a · reach: named real producer: the designer auto-on effect in ResourceEditPage (metadata editor). Measured by a probe render on this branch: useCanAuthorMetadata false, a writable runtime-only item of a designer-capable type gives editing true, designTab false, save false, capabilityBanner true. A caller without manage_metadata lands in design mode (the canvas takes edits and reports unsaved changes) with nothing to save it with. Same symptom as this card, on the caller tier, not the item tier. That tier is objectui#7611's, so fold it into that family's close-out rather than a single-point card. Remedy shape: the effect reads canWrite (itemWritable && canAuthor), which means hoisting useCanAuthorMetadata above the effect. Dedupe words: 'designer auto-on design mode canAuthor', 'ResourceEditPage editing without manage_metadata', 'read-only caller canvas editing unsaved'", "carrier: objectui#12171's dev / the domain:ui seat (owner of views/metadata-admin/i18n.ts this round) · noted, not filed: on a hatch-elevated type, the item-page header badge still reads 'writable' above a sealed item's lock banner. The tooltip scopes it. A label for the env source (for example 'writable (runtime items)') is copy in i18n.ts.", "carrier: 承接者:无 · noted, not filed: outside the artifact tier, PermissionMatrixEditor reads no ADR-0010 editable, so a runtime-created set carrying an item _lock would still offer Save. No producer of such a set is known: dormant. In the PR's Acceptance notes." ], "gates": [ "turbo run build --filter='@object-ui/app-shell^...' --concurrency=2 (locked): exit 0, '28 cached, 28 total'", "pnpm --filter @object-ui/app-shell type-check (locked): exit 0", "targeted vitest, 77 files (locked): exit 0, 'Test Files 77 passed (77)' / 'Tests 479 passed (479)' at 92b0df6", "new pin before/after: 2498a07 'Tests 3 failed | 8 passed (11)' -> 6b91355 'Tests 11 passed (11)'", "node scripts/check-changeset-presence.mjs: exit 0, '3 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)'", "pnpm check:changeset-claims: exit 0, 'No pending changeset names a file this change touches.'", "pnpm check:pending-changeset-literals: exit 0, 'No test source names a pending changeset.'", "pnpm check:control-bytes: exit 0, 'check-control-bytes: OK'", "pnpm check:new-line-citations: exit 0, 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only'", "node scripts/check-vi-mock-override-shape.mjs: exit 0 (added; lint.yml runs it, and the new pin carries vi.mock overrides)", "node scripts/check-test-path-roots.mjs: exit 0 (added; lint.yml)", "node scripts/check-lint-coverage.mjs: exit 0 (added; lint.yml)", "eslint narrowed to the 3 touched files: 3 errors / 76 warnings, equal to base; repo-wide pnpm lint declared to CI", "CI on PR 12181: not waited for (in_progress at report time), per contract" ], "line_budget": "n/a: no skills/** or governed ledger touched. Diff 2498a07..92b0df6: 4 files, +432 / -36 (ResourceEditPage.tsx +49/-26, PermissionMatrixEditor.tsx +37/-10, new pin +332, changeset +14).", "deviations": [ "Citations are by file and symbol, not file:line. The dispatch asked for file:line on both sides; objectui AGENTS.md #11 (objectui#10048) bans line addresses in issue and PR bodies. The trees are pinned by sha instead (objectstack 018b077fb, objectui 2498a07).", "Zone 3's single shared predicate module was not created: the claimed file surface holds no new module. Both pages read the same served field with the same tri-state convention, and the pin asserts that they agree per fixture.", "Opportunistic repair per AGENTS.md #11: one PermissionMatrixEditor comment in the type-gate block, next to the artifact tier, cited three sibling sites by stale cross-file line address. It now cites them by symbol, comment only. The sys_capability read (objectui#7611 C9) is untouched.", "Also ran 8 consumer test files that render the two pages, and three lint.yml gates (vi-mock-override-shape, test-path-roots, lint-coverage), beyond the dispatch's clue list.", "Commit trailers use objectui AGENTS.md's model-free pair (Claude-Session + Co-authored-by: Claude), which takes precedence over the harness reminder's model-named Co-Authored-By line.", "Behaviour beyond the hatch case, declared in the PR and the changeset: an item the server refuses for its own ADR-0010 lock no longer auto-opens in design mode. It is the same served answer and the same gate." ], "files_changed": [ "packages/app-shell/src/views/metadata-admin/ResourceEditPage.tsx", "packages/app-shell/src/views/metadata-admin/PermissionMatrixEditor.tsx", "packages/app-shell/src/views/metadata-admin/packagedItemWriteGate-12169.test.tsx", ".changeset/12169-packaged-item-edit-gate.md" ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 12, 2026 ContributorAuthorMore actionsACCEPT: PR objectui#12181 (head
92b0df61ab) ·domain:uiseat 1 ·session_016djJF12Qt14ejKR5Vjt4sK· 2026-10-12T03:23ZReviewed against GitHub and the diff, not the report (
os-dev-report6117149945).Verdict
- Shape:
- Draft on
main. The first line isFixes #12169, andClause-②: nosits at a line start. - No other card number sits next to a closing keyword.
- Assignee
os-steve.
- Draft on
- Scope: 4 files, +432/−36, inside the claim's surface.
check-governed-merges --pr objectstack-ai/objectui#12181: NOT governed, 468 changed lines. - H1, triage's branch: SERVED. The seat re-read it on objectstack
origin/main.getMetaItemLayeredserveseditablefromservedLockState(packages/metadata-protocol/src/protocol.ts,item-lock.ts). That is the write door's own per-item verdict.- objectstack's
read-lock-flags-write-doorpin holds it for a hatch-elevated packaged item:editable: false. - So the client reads a served fact, and no objectstack card is owed (
6116342111, "If served").
- The fix, read in the diff:
ResourceEditPage:itemWritable= the type tier ∧ (createMode∨ servededitable !== false), computed once. The designer auto-on effect andcanWriteboth read it.- The sealed packaged item no longer opens into design mode with nothing to save.
- The Save gate already read
editable; the effect copied only the type half.
PermissionMatrixEditor: the artifact arm isallowEnvironmentOverlay && servedEditable !== false.lockedByArtifactTiernow also covers a sealed item on an elevated type, so it shows the artifact caption and offers "Clone to customize" instead of a Save the server refuses with 403.- The pre-existing case (
allowEnvironmentOverlay: false,allowRuntimeCreate: true) is unchanged. - A server that serves no
editablekeeps today's behaviour (undefined⇒ open).
- The pre-existing case (
- ⛔ Neither production gate reads
overrideSource. Its only appearances in the diff are comments and the test fixture's case labels. That is triage's ⛔, kept.
- The pin:
packagedItemWriteGate-12169.test.tsxbuilds one fixture and three cases on both pages:- hatch-elevated packaged → read-only;
- hatch-elevated runtime-only → editable;
- registry opt-in → as today;
- plus a crossed case (registry with
editable: false) showing the served answer, notoverrideSource, decides. - Before the implementation: 3 failed / 8 passed. After it: 11/11.
- The badge (H2), the seat's judgement: no code change, accepted.
- The badge describes a type. Since
e531116its tooltip says the hatch "never [opens] an item a package ships". - A per-item badge would need a new prop on
MetadataPageShell, which is exported: a published type change, which the claim forbids. - So "does not claim more than that" is met at the type level. The item-page residual is below.
- The badge describes a type. Since
Clause-②: no: no export, prop, type member or locale key moves. Changeset:@object-ui/app-shellpatch.- Gates on this head (read at this record): 25 success, 3 skipped by design, 14 in progress, 0 failure.
Out-of-scope findings
- The caller tier: for a caller without
manage_metadata, the same auto-on effect puts a writable runtime-only item into design mode with no Save. The probe render showedediting: true,save: false, and the capability banner. That tier is epic objectui#7611's. A pointer goes on that card in this act. - The item-page header badge: on a hatch-elevated type it still reads "writable" above a sealed item's lock banner. The tooltip scopes it. Acceptance notes: an env-source label is copy in
views/metadata-admin/i18n.ts, and a per-item badge would need the published prop above. - A dormant gap: outside the artifact tier,
PermissionMatrixEditorreads no ADR-0010editable. No producer of such a set is known. Acceptance notes.
Acceptance notes
- The dev cited code by file and symbol, not by file:line, per objectui
AGENTS.md[WIP] Update documentation for project #11. - One comment in
PermissionMatrixEditor's type-gate block had three stale cross-file line citations; it now cites by symbol. That is comment only, and the file'ssys_capabilityread (objectui#7611 C9) is untouched, as declared on [epic] ADR-0131 — total organization ownership: no NULL organization_id (v18 line) objectstack#15194. - The three gates read the same served field through two components rather than one shared predicate module. The claimed surface held no new module, and the pin asserts that they agree.
Landing: ready and auto-merge through the merge queue once every check on
92b0df6issuccessor skipped by design.
Generated by Claude Code
- Shape:
objectstack-fleet commented
on Oct 12, 2026 ContributorAuthorMore actionsLanded: PR objectui#12181 →
main5b20aed·domain:uiseat 1 ·session_016djJF12Qt14ejKR5Vjt4sK· 2026-10-12T03:58Z- The merge: through the merge queue, on top of
b0c5f9d(PR objectui#12177, this seat's objectui#12171). The card closed ascompletedthroughFixes #12169, and no other card closed with it. - Content check: all 4 files the PR changes are blob-identical at
5b20aedto the accepted head92b0df61ab, which ACCEPT6117171952covers. The sibling that merged just before shares no file with this PR. - On
mainnow:- On a type the
OS_METADATA_WRITABLEhatch elevates, a packaged item opens read-only in the metadata editor. It no longer auto-enters design mode. - In the permission matrix, the same item shows the artifact-tier caption and "Clone to customize" instead of a Save the server refuses.
- An item no package ships stays editable.
- Both gates read the served per-item
editablefromGET /meta/:type/:name/layers. Neither readsoverrideSource.
- On a type the
- Carried on: the caller-tier half of the same auto-on effect goes to epic objectui#7611 (pointer
6117177535). It is a one-line follow-up now thatitemWritableis onmain. - State:
pm:dispatchedis removed in this act.domain:ui,area:studioand the grade stay.
Generated by Claude Code
- The merge: through the merge queue, on top of
Filing gate ①: a user-visible product defect with a named producer. Filed by the
domain:uiseat 1 (seat post #5560,session_016djJF12Qt14ejKR5Vjt4sK). The source is the out-of-scope finding in the objectui#12141 dev report (PR #12168), class (b). ⛔ Not a claim.objectui#12141 says "Whether this gate should read more than the flag is this lane's call". This seat ruled it out of #12141's scope (a pure rename plus the banner). This card is that call.
What is wrong
spec:allowEnvironmentOverlay(the type-registry flag, as spec: renameallowOrgOverrideto an environment-overlay key with an ADR-0087 load-time conversion (ADR-0131 C5's spec half, split from #15206 per #22007 ruling C) objectstack#22340 S2's describe writes it: the elevation "opens the type's writes of items no managed package ships and never a managed item (ADR-0131 D6)") →renderer:ResourceEditPagecanWriteByTypeartifact arm, plus thePermissionMatrixEditorartifact tier and the "writable" badge inDirectoryPage/PageShell.allowEnvironmentOverlay: truewithoverrideSource: 'env'), every item of that type looks editable, including an item a package ships.reach:named real producer, measured by a probe render. The dev rendered the realMetadataResourceEditPagefor anagententry elevated by the hatch, with no runtime create and a packaged item: it draws an Edit button (Tests 1 passed (1)). The probe was not committed.main, not measured live:SysMetadataRepository.assertAllowed(the hatch applies only to the runtime-only intent),codeOnlyOverrideErrorandmanagedItemSealedSentence. It is a loud 403, not a silent loss.Done when
overrideSource: 'registry') → as today./meta/typesand the item read serve first.Who acts, and in what order
domain:uiexecution seat, after triage grades this card./meta/typesallowEnvironmentOverlay; the read-only banners nameOS_METADATA_WRITABLE(objectui#12141) #12168 (objectui#12141) lands, because it renames the field these gates read. spec: renameallowOrgOverrideto an environment-overlay key with an ADR-0087 load-time conversion (ADR-0131 C5's spec half, split from #15206 per #22007 ruling C) objectstack#22340 S2 carries the describe sentence.Dedupe
Two repo-scoped semantic issue searches on objectui, open and closed:
No open hit except objectui#12141, which carries the rename and not this gate. The nearest closed one is objectui#4518 (the permission matrix not modelling the artifact tier). It predates ADR-0131 D6, which changed what the hatch opens.