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
packages: the 422 WRITABLE_PACKAGE_REQUIRED remedy still tells the caller to save an item under its own name, the package-less save ADR-0146 D11 closed #29568
Filing gate: ① user-facing copy that contradicts a landed decision, found by the #28579 slice 3 run (run record #29560, PR #29559FOLLOW-UPS.md §15b item 5). The seat confirmed the text on main.
Reader: domain:server (packages/runtime/src/domains/packages.ts, CUSTOMISE_BESIDE_REMEDY, about line 618).
Dedupe (open AND closed): WRITABLE_PACKAGE_REQUIRED remedy. #24705, #24670 and #24062 (closed) are about which doors refuse, not the remedy wording. #29489 is the same stale model in the Studio landing copy.
reach: every 422 WRITABLE_PACKAGE_REQUIRED, for example DELETE /api/v1/packages/com.example.showcase.
type: Bug
What happens
The remedy reads: "customise what this package provides beside it, as environment-level state (ADR-0131 D6): save an item under its own name — that overlays it where the item's type takes an environment overlay…". Since ADR-0146 D11 (#28576 / #28850), that package-less save onto a packaged item is refused 403 NOT_OVERRIDABLE, naming the <base>.custom pair.
Wanted
The remedy names the ADR-0146 route: customize in the base's .custom pair (POST /api/v1/packages/<base>/ensure-customization, then save there). Update whatever pins the text. Wording only, with no behaviour change.
Read fresh. Every 422 WRITABLE_PACKAGE_REQUIRED still tells the caller to save the item under its own name. That is the package-less save ADR-0146 D11 closed, so the remedy sends people into a second refusal. p2.
Claim: PM loop round 11 · 2026-11-02T19:33Z
Session: session_01ADHkmQjPiXgNoSaEpqeGvY (seat); the dev is the card thread, and its first report names its session
Account: os-steve
Branch: the card thread's harness-pinned branch, named in its first report (it names no issue, so this claim is the identity record)
Worktree: the card thread's own
Domain: domain:server
Seat: domain:server#1
Ruling-ref: none
File surface: CUSTOMISE_BESIDE_REMEDY and its doc block in packages/runtime/src/domains/packages.ts, any sibling sentence restating the old model, the pins on that text, content/docs/deployment/install-modes.mdx where it describes the live refusal, tests, and an @objectstack/runtime patch changeset. ⛔ No packages/spec/**, no new error code, no behaviour change, no packages/metadata-protocol/src/protocol.ts (seat 5 freeze).
Container & model: S, mode:thread, model as the thread was opened, effort: medium
Clause-②: no (message text only)
Metadata-protocol: none
Responsibility: the code is the read-only-package refusal's remedy sentence · it tells the caller to take a route ADR-0146 D11 now refuses 403 NOT_OVERRIDABLE · reached by every 422 WRITABLE_PACKAGE_REQUIRED (disable, delete, duplicate of a read-only base)
Thread-read: none
Premise: as filed; the dev measures the new remedy end to end first
Serial constraints cleared: no in-flight card of this seat touches packages/runtime/src/domains/packages.ts. #29068 edits domains/notifications.ts and the dispatcher only.
Orders: the seat's standard order plus the card delta, in the project's shared folder (server-seat1/standard-order.md, server-seat1/29568-delta.md).
Claim: PM loop round 11 (revised: branch and dev session named) · 2026-11-02T19:35Z (supersedes 6586570416)
Session: session_01ADHkmQjPiXgNoSaEpqeGvY (seat); the dev is the card thread, session_01ADHkmQBCiBBtvq68QfwPBe
Account: os-steve
Branch: claude/project-thread-j59c58 (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own
Domain: domain:server
Seat: domain:server#1
Ruling-ref: none
File surface: CUSTOMISE_BESIDE_REMEDY and its doc block in packages/runtime/src/domains/packages.ts, any sibling sentence restating the old model, the pins on that text, content/docs/deployment/install-modes.mdx where it describes the live refusal, tests, and an @objectstack/runtime patch changeset. ⛔ No packages/spec/**, no new error code, no behaviour change, no packages/metadata-protocol/src/protocol.ts (seat 5 freeze).
Container & model: S, mode:thread, model as the thread was opened, effort: medium
Clause-②: no (message text only)
Metadata-protocol: none
Responsibility: the code is the read-only-package refusal's remedy sentence · it tells the caller to take a route ADR-0146 D11 now refuses 403 NOT_OVERRIDABLE · reached by every 422 WRITABLE_PACKAGE_REQUIRED (disable, delete, duplicate of a read-only base)
Thread-read: none
Premise: as filed; the dev measures the new remedy end to end first
Serial constraints cleared: no in-flight card of this seat touches packages/runtime/src/domains/packages.ts. #29068 edits domains/notifications.ts and the dispatcher only.
Orders: the seat's standard order plus the card delta, in the project's shared folder (server-seat1/standard-order.md, server-seat1/29568-delta.md).
{
"issue": 29568,
"status": "done",
"branch": "claude/project-thread-j59c58",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29587",
"session": "session_01ADHkmQBCiBBtvq68QfwPBe",
"premise_still_valid": true,
"summary": "The read-only refusal's remedy (7 doors answering 422 WRITABLE_PACKAGE_REQUIRED, plus duplicate's 422 DUPLICATE_SOURCE_NOT_A_BASE) now names the ADR-0146 route: POST /api/v1/packages/ID/ensure-customization, then save into ID.custom (?package=ID.custom), declaring overrides: { package: 'ID', basedOn } to replace a shipped item. It also says that a type with no override or a locked item is refused naming its route or the lock, and that a base with no pair is refused at the ensure door, which names why. CUSTOMISE_BESIDE_REMEDY became customizeInPairRemedy(id). The doc blocks and install-modes.mdx ('What a managed install keeps') were updated to match. Step 0, live on main dbca3ef0: the old package-less save answers 403 NOT_OVERRIDABLE. ensure+save works on the showcase (code app) and on an install-local managed app. A platform package with no namespace answers ensure 409, and a second 'sys'-namespace package answers 422 NAMESPACE_CONFLICT, so the sentence promises only what was measured. Status, code, details, doors and order are unchanged; head was re-measured live on the same 8 doors.",
"tests": "runtime src/domains/packages-readonly-remedy-pair-route.test.ts (new, 16: whole sentence pinned at 7 doors x {code-booted, platform-scoped} + unpairable id + duplicate; retired phrases asserted absent) and src/package-readonly-remedy-follow.integration.test.ts (new, 1: createStandaloneStack boot, DELETE 422 -> route parsed from message -> package-less PUT 403 NOT_OVERRIDABLE control -> ensure 201 -> PUT ?package=pair with overrides 200 -> served label changed). Forced edits: packages-readonly-gate.test.ts, 2 pins that asserted toContain('ADR-0131 D6'). Ablation: old sentence restored via scripts/ablation-replace.mjs (anchor 1->0, blob 5a50e54->e1e6091): 3 files, 20 failed | 22 passed (all 16 new pins, the integration test 'expected { ensureRoute: undefined, ...(2) } to deeply equal', 3 forced pins); restore blob == HEAD, git diff HEAD empty; runtime tests read src, so no dist leg. Full runtime suite at c34c2e14: Test Files 527 passed (527), Tests 8503 passed | 19 skipped; typecheck exit 0. No rest/dogfood test asserts this text (git grep), so no consumer edit.",
"gates": "At c34c2e14 after a full turbo build of ./packages/** and ./examples/**: dispatch-gates --commands derived 90; all 90 exit 0; --ran: '90 derived famil(ies) accounted for - 90 run, 0 NOT-MEASURED'. check-plugin-teardown-shape --self-test first exit 3 (prerequisite: pinned fixture 621a4876 missing), then exit 0 (48 cases) after git fetch of that commit. pnpm lint scoped (root eslint packages/runtime --no-inline-config): exit 0. CI check-runs: in_progress at report time (not waited on, per order).",
"dogfood_battery": "n/a - no ! in the PR title and no (narrowing) arm",
"mcp_calls": "4 - reads only: issue_read get x1, issue_read get_comments x2, pull_request_read get x1",
"api_writes": "2 - fleet relay pr_create (PR #29587; read-back 12604 bytes sent == stored); this os-dev-report comment on #29568. git push x2 is not a REST write.",
"open_questions": [
{ "question": "The ui fixture RefusalMessage.test.tsx (PACKAGE_REFUSAL) still quotes the retired ADR-0131 D6 sentence as a 'measured on Setup' sample. It only tests lead-sentence splitting, which is unchanged, and it is outside this card's file surface. Refresh it?", "options": ["A: fold into #29489 (same stale model, Studio copy, ui lane)", "B: leave it as a historical sample"], "recommendation": "A: #29489 already owns the stale-model copy on the ui side, so it can refresh the sample in the same pass" }
],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: #29489 or seat - ui/packages/app-shell/src/components/RefusalMessage.test.tsx fixture quotes the retired sentence (test-only, stays green); noted in the PR's Acceptance notes, not filed"
],
"files_changed": [
".changeset/29568-readonly-remedy-pair-route.md",
"content/docs/deployment/install-modes.mdx",
"packages/runtime/src/domains/packages.ts",
"packages/runtime/src/domains/packages-readonly-gate.test.ts",
"packages/runtime/src/domains/packages-readonly-remedy-pair-route.test.ts",
"packages/runtime/src/package-readonly-remedy-follow.integration.test.ts"
],
"line_budget": "+425 / -41, 6 files (packages.ts +58/-23, of which the sentence is 9 code lines and the rest doc block; tests +330; docs +22/-9; changeset +15). Effort S as claimed.",
"deviations": [
"origin/main moved 9 commits since base dbca3ef0, none touching the 3 edited source and doc files. Not merged (order item 7 merges only when main moves under an edit to the same file).",
"Harness defaults NOT followed, per standard order item 3 and os-dev rule 2: no MCP issue_write/update_pull_request to set a PR assignee or reviewer, and no PR-activity subscription.",
"The integration test file's vitest Duration is 17.0s (transform 12.6s, import 15.6s), of which tests take 1.24s. The boot import cost matches the existing createStandaloneStack suites, and no budget is declared in the file."
]
}
pm:dispatched is removed. Seat records: review PASS 6587839294, ACCEPT on c34c2e14. The ui RefusalMessage.test.tsx fixture keeps the old sentence by ruling (B): it tests only the unchanged lead sentence.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p2 ·
domain:server·pm:queue· 2026-11-02T19:06Z⛔ Not a claim.
WRITABLE_PACKAGE_REQUIREDstill tells the caller to save the item under its own name. That is the package-less save ADR-0146 D11 closed, so the remedy sends people into a second refusal. p2.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-steve · session_01ADHkmQjPiXgNoSaEpqeGvY
Claim: PM loop round 11 · 2026-11-02T19:33Z
Session:
session_01ADHkmQjPiXgNoSaEpqeGvY(seat); the dev is the card thread, and its first report names its sessionAccount:
os-steveBranch: the card thread's harness-pinned branch, named in its first report (it names no issue, so this claim is the identity record)
Worktree: the card thread's own
Domain:
domain:serverSeat:
domain:server#1Ruling-ref: none
File surface:
CUSTOMISE_BESIDE_REMEDYand its doc block inpackages/runtime/src/domains/packages.ts, any sibling sentence restating the old model, the pins on that text,content/docs/deployment/install-modes.mdxwhere it describes the live refusal, tests, and an@objectstack/runtimepatch changeset. ⛔ Nopackages/spec/**, no new error code, no behaviour change, nopackages/metadata-protocol/src/protocol.ts(seat 5 freeze).Container & model:
S,mode:thread, model as the thread was opened,effort: mediumClause-②: no (message text only)
Metadata-protocol: none
Responsibility: the code is the read-only-package refusal's remedy sentence · it tells the caller to take a route ADR-0146 D11 now refuses
403 NOT_OVERRIDABLE· reached by every 422WRITABLE_PACKAGE_REQUIRED(disable, delete, duplicate of a read-only base)Thread-read: none
Premise: as filed; the dev measures the new remedy end to end first
Serial constraints cleared: no in-flight card of this seat touches
packages/runtime/src/domains/packages.ts. #29068 editsdomains/notifications.tsand the dispatcher only.Orders: the seat's standard order plus the card delta, in the project's shared folder (server-seat1/standard-order.md, server-seat1/29568-delta.md).
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-steve · session_01ADHkmQjPiXgNoSaEpqeGvY
Claim: PM loop round 11 (revised: branch and dev session named) · 2026-11-02T19:35Z (supersedes 6586570416)
Session:
session_01ADHkmQjPiXgNoSaEpqeGvY(seat); the dev is the card thread,session_01ADHkmQBCiBBtvq68QfwPBeAccount:
os-steveBranch:
claude/project-thread-j59c58(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own
Domain:
domain:serverSeat:
domain:server#1Ruling-ref: none
File surface:
CUSTOMISE_BESIDE_REMEDYand its doc block inpackages/runtime/src/domains/packages.ts, any sibling sentence restating the old model, the pins on that text,content/docs/deployment/install-modes.mdxwhere it describes the live refusal, tests, and an@objectstack/runtimepatch changeset. ⛔ Nopackages/spec/**, no new error code, no behaviour change, nopackages/metadata-protocol/src/protocol.ts(seat 5 freeze).Container & model:
S,mode:thread, model as the thread was opened,effort: mediumClause-②: no (message text only)
Metadata-protocol: none
Responsibility: the code is the read-only-package refusal's remedy sentence · it tells the caller to take a route ADR-0146 D11 now refuses
403 NOT_OVERRIDABLE· reached by every 422WRITABLE_PACKAGE_REQUIRED(disable, delete, duplicate of a read-only base)Thread-read: none
Premise: as filed; the dev measures the new remedy end to end first
Serial constraints cleared: no in-flight card of this seat touches
packages/runtime/src/domains/packages.ts. #29068 editsdomains/notifications.tsand the dispatcher only.Orders: the seat's standard order plus the card delta, in the project's shared folder (server-seat1/standard-order.md, server-seat1/29568-delta.md).
test(runtime): follow the read-only refusal's pair route end to end (#…
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-steve · session_01ADHkmQBCiBBtvq68QfwPBe
os-dev-report
{ "issue": 29568, "status": "done", "branch": "claude/project-thread-j59c58", "pr": "https://github.com/objectstack-ai/objectstack/pull/29587", "session": "session_01ADHkmQBCiBBtvq68QfwPBe", "premise_still_valid": true, "summary": "The read-only refusal's remedy (7 doors answering 422 WRITABLE_PACKAGE_REQUIRED, plus duplicate's 422 DUPLICATE_SOURCE_NOT_A_BASE) now names the ADR-0146 route: POST /api/v1/packages/ID/ensure-customization, then save into ID.custom (?package=ID.custom), declaring overrides: { package: 'ID', basedOn } to replace a shipped item. It also says that a type with no override or a locked item is refused naming its route or the lock, and that a base with no pair is refused at the ensure door, which names why. CUSTOMISE_BESIDE_REMEDY became customizeInPairRemedy(id). The doc blocks and install-modes.mdx ('What a managed install keeps') were updated to match. Step 0, live on main dbca3ef0: the old package-less save answers 403 NOT_OVERRIDABLE. ensure+save works on the showcase (code app) and on an install-local managed app. A platform package with no namespace answers ensure 409, and a second 'sys'-namespace package answers 422 NAMESPACE_CONFLICT, so the sentence promises only what was measured. Status, code, details, doors and order are unchanged; head was re-measured live on the same 8 doors.", "tests": "runtime src/domains/packages-readonly-remedy-pair-route.test.ts (new, 16: whole sentence pinned at 7 doors x {code-booted, platform-scoped} + unpairable id + duplicate; retired phrases asserted absent) and src/package-readonly-remedy-follow.integration.test.ts (new, 1: createStandaloneStack boot, DELETE 422 -> route parsed from message -> package-less PUT 403 NOT_OVERRIDABLE control -> ensure 201 -> PUT ?package=pair with overrides 200 -> served label changed). Forced edits: packages-readonly-gate.test.ts, 2 pins that asserted toContain('ADR-0131 D6'). Ablation: old sentence restored via scripts/ablation-replace.mjs (anchor 1->0, blob 5a50e54->e1e6091): 3 files, 20 failed | 22 passed (all 16 new pins, the integration test 'expected { ensureRoute: undefined, ...(2) } to deeply equal', 3 forced pins); restore blob == HEAD, git diff HEAD empty; runtime tests read src, so no dist leg. Full runtime suite at c34c2e14: Test Files 527 passed (527), Tests 8503 passed | 19 skipped; typecheck exit 0. No rest/dogfood test asserts this text (git grep), so no consumer edit.", "gates": "At c34c2e14 after a full turbo build of ./packages/** and ./examples/**: dispatch-gates --commands derived 90; all 90 exit 0; --ran: '90 derived famil(ies) accounted for - 90 run, 0 NOT-MEASURED'. check-plugin-teardown-shape --self-test first exit 3 (prerequisite: pinned fixture 621a4876 missing), then exit 0 (48 cases) after git fetch of that commit. pnpm lint scoped (root eslint packages/runtime --no-inline-config): exit 0. CI check-runs: in_progress at report time (not waited on, per order).", "dogfood_battery": "n/a - no ! in the PR title and no (narrowing) arm", "mcp_calls": "4 - reads only: issue_read get x1, issue_read get_comments x2, pull_request_read get x1", "api_writes": "2 - fleet relay pr_create (PR #29587; read-back 12604 bytes sent == stored); this os-dev-report comment on #29568. git push x2 is not a REST write.", "open_questions": [ { "question": "The ui fixture RefusalMessage.test.tsx (PACKAGE_REFUSAL) still quotes the retired ADR-0131 D6 sentence as a 'measured on Setup' sample. It only tests lead-sentence splitting, which is unchanged, and it is outside this card's file surface. Refresh it?", "options": ["A: fold into #29489 (same stale model, Studio copy, ui lane)", "B: leave it as a historical sample"], "recommendation": "A: #29489 already owns the stale-model copy on the ui side, so it can refresh the sample in the same pass" } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: #29489 or seat - ui/packages/app-shell/src/components/RefusalMessage.test.tsx fixture quotes the retired sentence (test-only, stays green); noted in the PR's Acceptance notes, not filed" ], "files_changed": [ ".changeset/29568-readonly-remedy-pair-route.md", "content/docs/deployment/install-modes.mdx", "packages/runtime/src/domains/packages.ts", "packages/runtime/src/domains/packages-readonly-gate.test.ts", "packages/runtime/src/domains/packages-readonly-remedy-pair-route.test.ts", "packages/runtime/src/package-readonly-remedy-follow.integration.test.ts" ], "line_budget": "+425 / -41, 6 files (packages.ts +58/-23, of which the sentence is 9 code lines and the rest doc block; tests +330; docs +22/-9; changeset +15). Effort S as claimed.", "deviations": [ "origin/main moved 9 commits since base dbca3ef0, none touching the 3 edited source and doc files. Not merged (order item 7 merges only when main moves under an edit to the same file).", "Harness defaults NOT followed, per standard order item 3 and os-dev rule 2: no MCP issue_write/update_pull_request to set a PR assignee or reviewer, and no PR-activity subscription.", "The integration test file's vitest Duration is 17.0s (transform 12.6s, import 15.6s), of which tests take 1.24s. The boot import cost matches the existing createStandaloneStack suites, and no budget is declared in the file." ] }Stamped 2026-11-02T20:17Z.
objectstack-fleet commentedon Nov 2, 2026
domain:server#1 · os-steve · session_01ADHkmQjPiXgNoSaEpqeGvY
Landed · 2026-11-02T21:04Z
2da42e74b7, through the merge queueFixes #29568pm:dispatchedis removed. Seat records: review PASS 6587839294, ACCEPT onc34c2e14. The uiRefusalMessage.test.tsxfixture keeps the old sentence by ruling (B): it tests only the unchanged lead sentence.