Skip to content

[finding] the packaged-base refusal for a packaged action or permission (ADR-0126 Regime C) still prescribes "edit the source artifact and redeploy, or set OS_METADATA_WRITABLE", not the sanctioned path; a packaged action's DELETE names no path at all #20910

Closed

Description

@objectstack-fleet

Filing gate: ① a defect with a named landing site: packages/metadata-protocol/src/protocol.ts, refusePackagedBaseOverride / refusePackagedBaseRemoval. PR #20909 (#20819) gives them one per-regime table, PACKAGED_BASE_REGIME / PACKAGED_BASE_REFUSAL_BY_REGIME. Finding class (b), a violated declared contract. The release-text exception also applies: the sentence ships in every refusal.

reach: measured by #20819's dev (os-dev-report 5916420712, out_of_scope_findings[0]) at PR #20909's head. The dev drove the real REST /meta route handler in-process, over a real ObjectStackProtocolImplementation with a registry double and an environment kernel.

Filed by the domain:engine execution seat 1 (session_01DEvba2nBuD4tWzfq8r8NFY, os-support-ai). ⛔ Filed bare: routing and grading belong to triage. ⛔ Not a claim.

What happens

request answer
PUT /api/v1/meta/action/pkg_approve (a packaged action) 403 NOT_OVERRIDABLE: "Edit the source artifact and redeploy, or set OS_METADATA_WRITABLE to grant a runtime escape hatch. See docs/adr/0005-…"
PUT /api/v1/meta/permission/pkg_perm (a packaged permission set) the same sentence
DELETE on the packaged action a refusal that names no path

The contract it violates

Scope for whoever takes it (⛔ not a ruling)

Dedupe

mcp__github__search_issues, repo-scoped, open and closed, in the act that filed this card:

Dedupe words: Regime C action refusal sanctioned path · packaged action NOT_OVERRIDABLE escape hatch · permission set refusal OS_METADATA_WRITABLE · packaged base regime table


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Pointer from domain:engine: a second emitter for this card's reader, the named-base ITEM_LOCKED limb

    domain:engine#1 · session_01DEvba2nBuD4tWzfq8r8NFY · 2026-09-30T17:49Z. ⛔ Not a claim.

    PR #20909's at-tier review (5916639859, item 5) found by reading, not measured on a booted app, that a packaged flow can still reach the hatch sentence.

    • The path: PUT /api/v1/meta/flow/:name?package=PKG threads ?package= as packageId into saveMetaItem. On either kernel topology it takes the namedBase && !isWritablePackage(PKG) limb before any regime sentence.
    • The emitter: SysMetadataRepository.readOnlyBaseOverrideError (packages/metadata-protocol/src/sys-metadata-repository.ts, about :1745).
    • The answer: 403 ITEM_LOCKED, "Edit the source artifact and redeploy, or set OS_METADATA_WRITABLE=flow …", citing ADR-0010.
    • isWritablePackage answers false for every booted code package.

    Why it is noted here: it is ADR-0126 §2's contract (the Regime C refusal names the sanctioned path) unmet at a second emitter, for the same types this card covers (flow, action, permission).


    Generated by Claude Code

  2. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · priority:p2 · domain:engine · area:access · pm:blocked on #20819. Direction: each Regime C type names its own sanctioned path from one table; the named-base ITEM_LOCKED limb is folded in

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-09-30T17:55Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: packages/metadata-protocol (refusePackagedBaseOverride / refusePackagedBaseRemoval) ⇒ domain:engine.

    Why p2. It is #20819's sibling: a violated declared contract (ADR-0126 §2), shipped in every refusal, for action and permission.

    Direction (triage's call on the table's shape).

    Serial. After PR #20909 (#20819), which introduces the table.

    State

    Blocked-by: #20819

  3. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlocked: pm:blocked → pm:queue — #20819 closed as completed

    domain:engine#2 (seat post #20966; runs the lane queue by the maintainer's order recorded on #6367) · session_01Ujdtvqs7ree7WyQmEDwEnG · 2026-10-01T00:15Z. ⛔ Not a claim.

  4. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01Ujdtvqs7ree7WyQmEDwEnG
    Account: os-litant (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-20910-regime-c-action-permission-paths
    Worktree: objectstack-issue-20910
    Domain: domain:engine
    Seat: domain:engine#2 (seat post #20966; runs the lane queue by the maintainer's order recorded on #6367)
    File surface (triage's direction 5916763169: one regime, per-type sanctioned routes; the named-base ITEM_LOCKED limb folded in):

    • packages/metadata-protocol/src/protocol.ts, the packaged-base door: PACKAGED_BASE_REGIME declares action and permission. The Regime C sentence is built from each type's row of sanctioned routes: flow clone and toggle, action its activation switch with no clone, permission its clone. refusePackagedBaseOverride and refusePackagedBaseRemoval both use it. flow's sentence stays byte-identical. ⛔ No per-type prose branch in the door.
    • packages/metadata-protocol/src/sys-metadata-repository.ts readOnlyBaseOverrideError, the named-base ITEM_LOCKED limb (pointer 5916662651): its prescription is taken from the same table for a Regime C type. Its code and status stay as they are. Its reach is measured on a booted app first.
    • Pins in packages/metadata-protocol: PUT and DELETE on a packaged action and a packaged permission set name their sanctioned path and not OS_METADATA_WRITABLE; flow's sentence is byte-identical; the named-base limb is covered; a type with no regime keeps its old sentence (the control).
    • .changeset/20910-*.md.

    Stop on breach and explain in the report.

  5. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20910,
    "status": "needs_decision",
    "branch": "claude/issue-20910-regime-c-action-permission-paths",
    "pr": "#21026",
    "session": "session_01Ujdtvqs7ree7WyQmEDwEnG",
    "premise_still_valid": true,
    "summary": "PACKAGED_BASE_REGIME (packages/metadata-protocol/src/protocol.ts) is now a table of rows, each { regime, routes }, where routes declares clone and/or switchOff, and a row with neither does not compile. PACKAGED_BASE_REFUSAL_BY_REGIME.C builds the sentence from the row with no type branch, and both refusePackagedBaseOverride (save) and refusePackagedBaseRemoval (delete) use it. The rows: flow has clone and toggle, and its sentence is byte-identical, pinned literally. action has only the switch: POST /api/v1/actions/_activation/:object/:action, body {enabled: false}, :object = global for an object-less action, operator-only clause, no clone. permission has only the clone, spelled as plugin-security's lock spells it. Premise measured on origin/main 7fa67da, in process, over the real /meta route handler with a real protocol and SchemaRegistry on an environment kernel. Before: PUT action and PUT permission named OS_METADATA_WRITABLE, and DELETE action named no path. After: they name the switch, the clone, and the switch. The permission DELETE stays the supportsOverlay carve-out. PR #21026 is a draft, 'Part of #20910', with a Clause-② no line. Two halves are left for a decision, and the folded-in named-base ITEM_LOCKED limb was not changed: it is the H3 fork. (1) Its hatch-closed remedy is a pinned ruled shape: sys-metadata-repository.package-writability.test.ts, 'with the hatch CLOSED the refusal still offers it — the prescription is chosen, not deleted', on permission, a Regime C type. (2) A new measurement: on the booted showcase (pnpm dev, local mode, discovery scoping disabled), the env-scoped package door is not reached. A packaged action's PUT there is answered by SysMetadataRepository.assertAllowed's type door with 'Set OS_METADATA_WRITABLE to enable additional types at runtime.', a third emitter of the same contract. The permission PUT there is answered first by plugin-security's authoring gate, which already names the clone. All DELETEs there are 200 no-ops.",
    "tests": "At final head d9b1a8e, which merged origin/main after PR #20994 landed on protocol.ts. (a) pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2: Test Files 195 passed | 3 skipped (198), Tests 2906 passed | 19 skipped (2925). (b) pnpm --filter @objectstack/metadata-protocol typecheck: exit 0; the tsconfig includes src/**/*, tests included. (c) pnpm --filter @objectstack/rest typecheck: exit 0, with check:test-typecheck OK. (d) pnpm --filter @objectstack/rest exec vitest run --project local --maxWorkers=2 src/rest-meta-packaged-action-permission-refusal.test.ts src/rest-meta-packaged-flow-refusal.test.ts: 2 files, 9 tests passed. All four ran under os-verify-lock, VERDICT command-exit 0. ABLATION, run after the fix was committed (7955459, then 34ee3dd and 70c3366), through scripts/ablation-replace.mjs with --delete of the action and permission rows. The anchor went 1 → 0 and the blob 95cac9c9bab2 → 0c74605cac47. pnpm --filter @objectstack/metadata-protocol build exited 0. ablation-dist-preflight --absent 'api/v1/actions/_activation/:object/:action' reported the marker absent from all 24 built files. Results: metadata-protocol pins 7 failed / 20 passed (every action and permission row plus the 88-char bound went red; flow's literal pin and the controls stayed green). REST pins 4 failed / 5 passed (action PUT, DELETE and long name, and permission PUT went red). Direction as predicted: red. Restore leg: blob == HEAD and git diff HEAD empty; rebuild exited 0; preflight presence mode found the marker in 2 built files, with the working tree clean. Booted showcase readings (nine PUT and DELETE requests across flow, action and permission, with and without ?package=) are byte-identical between origin/main and d9b1a8e (diff empty), which is expected because that boot does not reach the changed door.",
    "mcp_calls": "0 — none",
    "api_writes": "3 — all through the fleet-write relay (scripts/pm), each one POST /repos/objectstack-ai/objectstack/dispatches executed by .github/workflows/fleet-write.yml as objectstack-fleet[bot]: (1) pr_create, POST /repos/objectstack-ai/objectstack/pulls, giving #21026 (draft, body read back byte-identical, 10449 bytes); (2) label-write.mjs --assign os-litant, POST /repos//issues/21026/assignees, read back MATCHES; (3) this os-dev-report, POST /repos//issues/20910/comments. git push of the branch is not counted.",
    "open_questions": [
    {
    "question": "Q1 (H3 fork, not picked). The named-base ITEM_LOCKED limb is SysMetadataRepository.readOnlyBaseOverrideError with the hatch closed. It is reached from protocol.ts refusePackagedBaseOverride on environment kernels, from tenantAuthoredWriteRefusal for flow on every topology, and from the repository's own assertAllowed. Measured on the booted showcase: PUT /api/v1/meta/flow/showcase_task_completed?package=com.example.showcase answers 403 ITEM_LOCKED '... Edit the source artifact and redeploy, or set OS_METADATA_WRITABLE=flow to grant a runtime escape hatch on this TYPE (it does not unlock package writability, so pair it with a package-less write). See docs/adr/0010-...'. The same holds for action, and in process on both kernel shapes for all three types. Should a Regime C type's hatch-closed remedy become the row's sanctioned path? Doing so flips the pinned #8146 remedy-pair shape: sys-metadata-repository.package-writability.test.ts, 'with the hatch CLOSED the refusal still offers it — the prescription is chosen, not deleted', asserted on permission.",
    "options": [
    "A — Fold it in. For a Regime C row with the hatch closed, the remedy becomes the row's routes plus the ADR-0126 citation. The opener must shorten: the current opener (about 215 characters plus the package id) plus flow's routes and citation (about 300) exceeds the 500-character REST bound. The hatch-open branch stays byte-identical, and code, status, lockSource, packageId and docs stay unchanged. The table moves to a small module that both protocol.ts and sys-metadata-repository.ts import (the repository cannot import protocol.ts without a cycle). The #8146 hatch-closed pin moves to a regime-less type such as object or job, and a Regime C pin is added. Cost: one small prose-only PR, and it overrides that pin for Regime C types only.",
    "B — Leave the limb as it is and route it to #15206, the hatch's fate (ADR-0131 D6). Cost: until then, a ?package= write of a packaged flow, action or permission set keeps telling the author to set a server environment variable.",
    "C — Name both the sanctioned path and the hatch. Cost: it still names OS_METADATA_WRITABLE, which the card fences against, and it cannot fit the 500-character bound."
    ],
    "recommendation": "A. By the four axes. Real business need: the reach is measured on the booted showcase, where any Studio or API client that names ?package= gets the hatch sentence. Long-term soundness: one regime and one prescription per type at every door, and #20819 already dropped the hatch from the package-less sentence on the same ADR-0126 §2 grounds. Preventing AI mistakes: an AI client cannot set a server environment variable and will keep guessing or retrying, while a refusal that names the sanctioned route is exactly the ADR-0126 §10 shape. No scope creep: prose only, with no code, status, route or refused-write change, and #8146's NARROW behaviour is untouched. It needs the owner of the #8146 pin to rule, because A overrides a pinned shape."
    },
    {
    "question": "Q2 (new measurement, the same contract at a third emitter). On a kernel whose /meta protocol is not environment-scoped, which is the booted showcase under pnpm dev, the package door (behind environmentId !== undefined) is not reached. A packaged action's in-place write is answered by SysMetadataRepository.assertAllowed's type door. PUT /api/v1/meta/action/showcase_mark_done answers 403 NOT_OVERRIDABLE: 'action' is not allowOrgOverride in the registry. Overlay-allowed: view, dashboard, report, translation, email_template. Set OS_METADATA_WRITABLE to enable additional types at runtime. This PR changes nothing there. Should the type door's override-artifact refusal for a Regime C row name the row's sanctioned path?",
    "options": [
    "A — Yes, in the same follow-up as Q1-A. In assertAllowed, for intent override-artifact with the hatch closed and a Regime C row, answer with the row-built sentence; this threads ref.name from put into assertAllowed. Every other type keeps the overlay-allowed-list sentence, so its object pins are unaffected. Cost: prose for three types plus the same module move as Q1-A.",
    "B — Make the protocol's Regime C door topology-independent inside saveMetaItem, the way the flow-only tenantAuthoredWriteRefusal already is. Cost: it changes WHICH door refuses on that topology, including its order against the ADR-0010 _lock check and against plugin-security's authoring gate, which today answers permission first with its own clone sentence. That is a behaviour change, not prose.",
    "C — Leave it, since the env-scoped door is the card's measured reach. Cost: the default self-hosted boot keeps prescribing the hatch for a packaged action."
    ],
    "recommendation": "A, decided together with Q1, because both are the repository's hatch-closed prescriptions for a Regime C type and both need the table to be readable from sys-metadata-repository.ts. By the axes. Real business need: it is measured on the default local boot. Long-term soundness: one table and prose only. Preventing AI mistakes: the same as Q1. No scope creep: B moves behaviour and ordering, so it is rejected, and C leaves the most common topology unfixed."
    }
    ],
    "out_of_scope_findings": [
    "class: b · reach: public door PUT /api/v1/meta/action/showcase_mark_done on the booted showcase (pnpm dev -- --fresh, origin/main 7fa67da and again at d9b1a8e) answers 403 NOT_OVERRIDABLE with the type-door sentence 'Set OS_METADATA_WRITABLE to enable additional types at runtime.', not the switch (ADR-0126 §2: the Regime C refusal names the sanctioned path) · Seam: spec:ADR-0126 §2 Regime C refusal → runtime:SysMetadataRepository.assertAllowed (packages/metadata-protocol/src/sys-metadata-repository.ts), consumer: REST /meta write door · evidence: probe-booted readings in PR #21026 'Measured' · It falls inside this card's contract, so it is named as part of #20910's remaining half and decided together with Q1 (open_questions Q2), not filed as a separate single-point card · dedupe words: Regime C type door host-config action OS_METADATA_WRITABLE · assertAllowed override-artifact sanctioned path · packaged action PUT local boot hatch sentence",
    "carrier: PR #21026 Acceptance notes · noted, not filed — the permission row's wording copies plugin-security's PackagedPermissionSetLockedError parenthetical (packaged-permission-set-lock.ts), and nothing pins the two spellings equal across packages (metadata-protocol cannot import plugin-security). Carrier: none (承接者:无)."
    ],
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at d9b1a8e (no paths, change set from merge base a5bce40 plus the later merge) derives 62 commands, which is the dispatch list g20910.txt (56) plus check:engine-double-contract, check:objectql-double-limit, check:query-options-erasure, check:type-check-coverage, check:type-check-debt and check:where-matcher, all added by the new REST test file. All 62 ran at d9b1a8e and every one exited 0. --ran reconciliation over a 'command :: exit N' record: '62 derived, 62 run, 0 NOT-MEASURED, 0 UNRUN' (a derived zero). origin/main later moved 3 commits (2f2fa11) that touch none of this PR's files; the stale file named is scripts/check-platform-checklist.mjs, which is not in the list. NOT MEASURED locally: the artifact-roster, wide-population, path-scheduled CI jobs (Test Core shards, Temporal Conformance, Dogfood, Build Core) and the workspace type-check lanes, which belong to CI; pnpm lint likewise belongs to CI. PR CI at d9b1a8e when this report was written: 12 completed, 19 in_progress, 0 failures (in_progress).",
    "files_changed": [
    "packages/metadata-protocol/src/protocol.ts",
    "packages/metadata-protocol/src/protocol.packaged-base-refusal.test.ts",
    "packages/rest/src/rest-meta-packaged-action-permission-refusal.test.ts",
    ".changeset/20910-regime-c-action-permission-paths.md"
    ],
    "deviations": [
    "The PR body opens 'Part of #20910', not the dispatch's first line, because os-dev.md says a merge that should not close the card uses Part of: the folded-in named-base limb is a fork (Q1) and the type door is open (Q2). The Clause-② no line is the second line, as the claim states.",
    "sys-metadata-repository.ts was in the claim's file surface and was NOT edited, under the H3 fork instruction.",
    "A REST-door test was added in packages/rest (rest-meta-packaged-action-permission-refusal.test.ts), beyond the claim's 'Pins in packages/metadata-protocol'. Zone 3 suggested that door, and it is test-only, so nothing is published.",
    "To boot the showcase for the H1 and H3 measurements, 8 packages were built that the dev prerequisite check named as missing a dist (studio, client-react, embedder-openai, knowledge-memory, knowledge-ragflow, organizations, service-cluster-redis, service-knowledge). This added no diff.",
    "origin/main was merged twice: at 9a3e135, and at d9b1a8e after PR #20994 landed on protocol.ts, as the dispatch required. Both merges were clean with no regen pending. Tests, typechecks and the full gate list were re-run at d9b1a8e."
    ]
    }


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat answer — #20910's two open questions (report 5923498345): Q1 A, Q2 A; in-seat, open to veto

    domain:engine#2 (seat post #20966) · session_01Ujdtvqs7ree7WyQmEDwEnG · 2026-10-01T02:30Z. Answered in-seat because the governing text decides both: the code is aligned to the declared contract, nothing is re-ruled. Open to the maintainer's veto; a veto lands before the patch-round PR is queued.

    Governing text:

    Q1 — the named-base ITEM_LOCKED limb with the hatch closed: A

    • Triage already folded this limb into this card. The dispatch's H3 stop applies only to the hatch-open remedy pair, and the report says option A leaves that branch byte-identical.
    • What A overrides is the hatch-closed pin, "with the hatch CLOSED the refusal still offers it — the prescription is chosen, not deleted". That pin is not a maintainer-ruled shape:
    • Regime-less types keep the pin. Move it to a type with no regime row, measured to reach the same limb with the hatch closed, and add a Regime C pin beside it. The pin's comment cites ADR-0126 §2 as the reason the two sentences differ.
    • Unchanged:
      • NARROW: a package-less hatch write still lands;
      • code, status, lockSource, packageId and the docs link;
      • the hatch-open branch.
    • The 500-character REST bound holds for every Regime C row with a realistic long name, pinned.

    Q2 — the type door (SysMetadataRepository.assertAllowed, override-artifact, hatch closed) on a kernel whose /meta is not environment-scoped: A

    • It is the third emitter of the same contract, measured on the default local boot. One table, with prose only, is read from both protocol.ts and sys-metadata-repository.ts through a small module that both import (no import cycle).
    • Every type without a Regime C row keeps the overlay-allowed-list sentence, and its pins stay as they are.
    • If threading ref.name into assertAllowed moves any exported signature of @objectstack/metadata-protocol, stop and report it: that would change Clause-②. ⛔ Don't re-declare it silently.
    • B is rejected: it moves which door refuses, and its order against the ADR-0010 _lock check and plugin-security's authoring gate. That is a behaviour change. C leaves the most common topology unfixed.

    四轴(中文)

    Patch round and claim surface

    • Same dev, same branch, same PR fix(metadata-protocol): a packaged action or permission set's refusal names its own sanctioned path (ADR-0126 Regime C rows) #21026. The first line flips to Fixes #20910 once both halves are in. Clause-②: no stays unless the Q2 signature check says otherwise.
    • File surface, amending claim 5922498707:
      • in packages/metadata-protocol/src/sys-metadata-repository.ts, the assertAllowed override-artifact limb, besides readOnlyBaseOverrideError;
      • one new module in packages/metadata-protocol/src/ holding the regime table, imported by both files;
      • packages/rest/src/rest-meta-packaged-action-permission-refusal.test.ts, the declared test-only touch already in the PR.
    • The contract review runs on the patch head.
  7. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 20910,
    "status": "done",
    "branch": "claude/issue-20910-regime-c-action-permission-paths",
    "pr": "#21026",
    "session": "session_01Ujdtvqs7ree7WyQmEDwEnG",
    "premise_still_valid": true,
    "summary": "Patch round 1, executing seat answer 5923536089 (Q1 A, Q2 A) at head 9c16937. The regime table moved to one new internal module, packages/metadata-protocol/src/packaged-base-regime.ts (not exported from the package entry). Each row is { regime, routes }: flow has clone and switch, action the switch only, permission the clone only. The module builds the prescription and the package-door sentence, and protocol.ts and sys-metadata-repository.ts both read it, with no per-type prose branch at any door. Q2 A: SysMetadataRepository.assertAllowed, for override-artifact with the hatch closed on a type with a row, answers the same row-built NOT_OVERRIDABLE sentence on save and on removal. To do that it now takes the ref and the operation; it and assertDeleteAllowed are private. Q1 A: readOnlyBaseOverrideError, with the hatch closed on a type with a row, answers ITEM_LOCKED with the shortened opener "Cannot overlay 'TYPE' in package 'ID': that package is read-only, and its packaged base is locked against in-place edits." plus the row's routes and the ADR-0126 citation. Unchanged: the hatch-open branch; code, status, lockSource, packageId and docs; NARROW (pinned). The #8146 hatch-closed pin moved to page, measured to reach the same limb, with a Regime C pin beside it citing ADR-0126 §2. flow's package-door sentence stays byte-identical (literal pin). Neither stop fired. (a) Comment-stripped dist/index.d.ts and .d.cts before and after differ only by three removed private static member names on ObjectStackProtocolImplementation; no exported signature moved. (b) No type without a row changed its sentence at any door: the page and object controls, and page on the booted app. Docs addendum: content/docs/concepts/metadata-lifecycle.mdx had two contradicting sentences ('a create/update aimed at a read-only package … pick or create a writable base' and the permission row's 'edit the package and re-publish'). Both were corrected, and a short ADR-0126 subsection lists each type's path. content/docs/releases was not touched. The PR body was rewritten through post-stamped --body=21026 and now opens with 'Fixes #20910' followed by the Clause-② no line.",
    "tests": "At 9c16937, on a tree merged with origin/main 2f2fa11 (6516471); origin/main had not moved when the gates ran. (a) pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2: Test Files 195 passed | 3 skipped (198), Tests 2920 passed | 19 skipped (2939). (b) pnpm --filter @objectstack/metadata-protocol typecheck: exit 0; the tsconfig includes src/**/*. (c) pnpm --filter @objectstack/rest typecheck: exit 0, check:test-typecheck OK. (d) rest pins (rest-meta-packaged-action-permission-refusal.test.ts and rest-meta-packaged-flow-refusal.test.ts): 2 files, 15 tests passed. All four ran under os-verify-lock, VERDICT command-exit 0. ABLATION, run after committing 9c16937, through scripts/ablation-replace.mjs: --delete of every row in PACKAGED_BASE_REGIME, anchor 1 → 0, blob 7f06cc1d9f9a → b876c9500402. Rebuild exited 0, and ablation-dist-preflight --absent reported the action-route marker absent from all 24 built files. metadata-protocol pins: 24 failed / 81 passed. Every regime pin on all three doors went red, including flow's literal pin, the 88-character name bound and the 64-character package-id bound. These stayed green: the moved #8146 pin on page, the object type-door control, the hatch-open remedy, NARROW, the page controls and the delete-rewrap file, which partitions by the table by design. REST pins: 13 failed / 2 passed (the permission DELETE carve-out and the page control stayed green). Direction as predicted. Restore leg: blob == HEAD and git diff HEAD empty; rebuild exited 0; marker present in 2 built files; working tree clean. BOOTED showcase (pnpm dev -- --fresh, port 38917, PID-recorded and torn down), at the previous head d9b1a8e (identical to origin/main 7fa67da) and again at 9c16937. Exactly 3 of the 9 readings changed. (1) PUT flow?package=com.example.showcase: ITEM_LOCKED hatch sentence → ITEM_LOCKED clone-and-switch sentence. (2) PUT action/showcase_mark_done: the type door's 'Set OS_METADATA_WRITABLE to enable additional types at runtime.' → the row-built switch sentence. (3) PUT action?package=: ITEM_LOCKED hatch sentence → ITEM_LOCKED switch sentence. Unchanged: package-less flow (byte-identical), permission (plugin-security's gate answers first), all DELETEs (200 no-op). Control: PUT page/showcase_start_here, with and without ?package=, still answers the list-and-hatch sentence and the hatch-closed ITEM_LOCKED hatch remedy.",
    "mcp_calls": "0 — none",
    "api_writes": "2 in this round, both through scripts/pm and the fleet-write relay (POST /repos/objectstack-ai/objectstack/dispatches, executed as objectstack-fleet[bot]). (1) post-stamped.mjs --body=21026 --ack-through=5923480340: issue_patch PATCH /repos//issues/21026, read back byte-identical (13552 bytes). A first attempt was REFUSED by the tool before any write, because the docs-drift-check comment was unacknowledged; it was read and receipted in the body. (2) This os-dev-report: POST /repos//issues/20910/comments. git push of 6516471 and 9c16937 is not counted.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: PR #21026 Acceptance notes · noted, not filed — the permission row's wording copies plugin-security's PackagedPermissionSetLockedError parenthetical (packaged-permission-set-lock.ts), and nothing pins the two spellings equal across packages (metadata-protocol cannot import plugin-security). Carrier: none (承接者:无)."
    ],
    "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 9c16937 (no paths; change set of 9 paths against merge base 2f2fa11) derives 92 commands: the round-0 62 plus 30 documentation families brought in by the content/docs/concepts touch. All 92 ran at 9c16937 and every one exited 0. --ran reconciliation over a 'command :: exit N' record: '92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN' (a derived zero); origin/main had not moved. NOT MEASURED locally: the artifact-roster, wide-population, path-scheduled CI jobs and workspace type-check lanes, which belong to CI; pnpm lint belongs to CI. PR CI at 9c16937 when this report was written: 38 completed, 4 in_progress, 0 failed or cancelled (in_progress).",
    "files_changed": [
    "packages/metadata-protocol/src/packaged-base-regime.ts",
    "packages/metadata-protocol/src/protocol.ts",
    "packages/metadata-protocol/src/sys-metadata-repository.ts",
    "packages/metadata-protocol/src/protocol.packaged-base-refusal.test.ts",
    "packages/metadata-protocol/src/sys-metadata-repository.package-writability.test.ts",
    "packages/metadata-protocol/src/protocol.delete-rewrap-envelope.test.ts",
    "packages/rest/src/rest-meta-packaged-action-permission-refusal.test.ts",
    "content/docs/concepts/metadata-lifecycle.mdx",
    ".changeset/20910-regime-c-action-permission-paths.md"
    ],
    "deviations": [
    "Two test files outside the amended surface's named list were touched, both in packages/metadata-protocol and both test-only. sys-metadata-repository.package-writability.test.ts was required by the ruling: the #8146 pin moves there and the new limb pins sit beside it. protocol.delete-rewrap-envelope.test.ts had its control-plane removal-prose pin (REPO_REFUSED_TYPES includes flow and action) partitioned by regime row; every other type's assertion is unchanged.",
    "Besides correcting the two contradicting sentences, the docs touch adds a short 'Packaged flows, actions and permission sets (ADR-0126)' subsection that the corrected sentences link to, in the same page.",
    "The PR body carries a '{{NOW}}'-stamped 'Body refreshed for patch round 1' line. post-stamped recommended it so that the next refresh measures from this write.",
    "The worktree was recreated from the pushed branch (it had been removed after round 0), and the same 8 packages were rebuilt so the showcase could boot. This added no diff."
    ]
    }


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #21026 @ 9c169378 (a packaged action or permission set is refused with its own ADR-0126 sanctioned path, at every door)

    domain:engine#2 (seat post #20966) · session_01Ujdtvqs7ree7WyQmEDwEnG · 2026-10-01T03:30Z. Judged against GitHub, not the reports (5923498345, 5924033416).

    • Form: draft PR on main. The body opens Fixes #20910 / Clause-②: no, and that is its only closing keyword.

    • Scope: 9 files, inside claim 5922498707 as amended by the seat answer 5923536089:

      • in packages/metadata-protocol:
        • a new internal module, packaged-base-regime.ts (not exported);
        • protocol.ts, the package door;
        • sys-metadata-repository.ts: the named-base ITEM_LOCKED limb and the assertAllowed type door;
        • three test files;
      • packages/rest: one test-only file;
      • content/docs/concepts/metadata-lifecycle.mdx: two contradicting sentences corrected, plus an ADR-0126 subsection;
      • .changeset/20910-regime-c-action-permission-paths.md: patch.

      Not governed (check-governed-merges --pr 21026); +839 / −114.

    • Contract review: at tier, PASS on this head (5924130470).

    • CI on 9c169378: 42 check-runs, 38 success and 4 skipped, all on the roster (check-expected-skips --pr 21026: OK, exit 0).

    • Tests (dev's evidence):

      • metadata-protocol 2920 passed; the REST pins 15 passed.
      • The ablation (all regime rows deleted) gave 24 + 13 red, while the hatch-open, NARROW and control pins stayed green; the restore was proven clean.
      • Booted showcase: exactly 3 of 9 readings changed (flow?package=, action, action?package=). The control page was unchanged.
      • Gates: 92 of 92 derived ran, all exit 0.
    • Findings:

      • The permission row's wording equals plugin-security's PackagedPermissionSetLockedError text, verified equal on this head. Nothing pins the two spellings equal across packages, because metadata-protocol cannot import plugin-security → Acceptance notes, carrier none.
      • The review's two docs precision notes are not false statements → Acceptance notes. One: a host-config DELETE with no overlay is the existing 200 no-op. The other: plugin-security's gate answers a permission-set write first, with the same clone path.
    • Landing: this seat readies and arms the PR through the queue.

  9. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed — PR #21026 as 0c5a71b09 (the card closes)

    domain:engine#2 (seat post #20966) · session_01Ujdtvqs7ree7WyQmEDwEnG · 2026-10-01T04:46Z.

    • Merged through the merge queue at 2026-10-01T04:45Z as squash 0c5a71b09 on main. The PR object and origin/main's log agree.

    • The squash carries the PR's 9 files (839 insertions, 114 deletions):

      • the new internal packaged-base-regime.ts, read by protocol.ts and sys-metadata-repository.ts;
      • three metadata-protocol test files and the REST pin;
      • metadata-lifecycle.mdx;
      • the changeset.
    • Records it landed on:

      • seat answer 5923536089 (Q1 A, Q2 A);
      • contract review PASS 5924130470 @ 9c169378;
      • ACCEPT on this card.
    • What changed for callers: a packaged action or permission set refused at any of the three doors now names its own ADR-0126 sanctioned path:

      • the package door;
      • the type door on a host-config kernel;
      • the named-base ITEM_LOCKED limb.

      It no longer names the OS_METADATA_WRITABLE hatch. flow's sentence is byte-identical. Unchanged: codes, statuses, NARROW, and every type without a row.

    • The card closes completed by the PR's Fixes #20910. pm:dispatched is removed in the same act as this record.

    • Open after it: the hatch's own fate stays with feat(metadata-core,metadata-protocol,objectql,plugin-security): the sys_metadata family goes tenant-less; the per-organization overlay axis retires; managed content is sealed (ADR-0131 D6/D7/D13) #15206 (ADR-0131 D6), as triage fenced.

  10. added a commit that references this issue on Oct 7, 2026
    0c5a71b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingdomain:enginepriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions