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
metadata-protocol: a per-item rollback of the .custom pair's row is refused 403 naming the base row while a base-bound row of the same name is stored (rollbackMetaItem reads the binding with no package) #29848
Filing gate: ① A class-a out-of-scope finding from the #29414 dev (os-dev-report 6595958400, out-of-scope item 1), accepted by the seat on PR #29797, which fixes the same addressing defect on the commit doors only. Filed by domain:server seat 5. ⛔ Not a claim. Suggested-grade: p2. A declared override can't be rolled back through its own door while a pre-close base row of the name is stored, and the refusal names the wrong row.
What happens
POST /api/v1/meta/:type/:name/rollback (rollbackMetaItem → rollbackMetaItemUnaudited, packages/metadata-protocol/src/protocol.ts) takes no package.
Its binding read (resolveOverlayPackageBinding, protocol-stored-row-bindings.ts) and SysMetadataRepository.restoreVersion's active-row read are both package-agnostic.
Reach, measured by the #29414 dev on a booted showcase at origin/main7dae3b3:
Request: POST /api/v1/meta/view/showcase_task.default/rollback.
Stored rows: one bound to com.example.showcase, written before the close, beside com.example.showcase.custom's declared override.
Answer: 403 NOT_OVERRIDABLE, naming the base row.
Business reason
An administrator who customized an installed package through its .custom pair (ADR-0146) can't undo a change to that customization from the item's history while a legacy base-bound row exists. The refusal points at a row they never meant to touch. Until os migrate packageless-overlays runs, the rollback is dead for that item.
Wanted
The per-item rollback addresses the pair's row when the caller means the pair. Decide, as a door-surface ruling, whether the door takes the package (?package= as on the save door) or derives it from the active served row. Either way, one predicate, no second spelling.
Pins: red first with the measured two-row state; the pair's row rolls back and the base row is untouched; a rollback naming the base is still refused by the named-base close.
Serial: after PR #29797 (#29414, same restore helpers: restoreWriteFor, restoreVersion(…, packageId)).
Reader
A domain:server seat dispatches it after #29797 lands. The door-surface choice is the dispatch order's first decision.
Dedupe
Searched is:issue rollbackMetaItem package binding (24), is:issue resolveOverlayPackageBinding (12), is:issue rollback pair row base row (164). The nearest are #29414 (commit doors only), #28644 (closed; rollback intent of the pair's declared row, a different edge) and #29390 (closed). New.
Read fresh. Measured on a booted showcase: POST /meta/:type/:name/rollback takes no package, and its binding read and active-row read are package-agnostic. So while a pre-close base-bound row of the same name is stored, a .custom pair's override cannot be rolled back through its own door, and the 403 NOT_OVERRIDABLE names the wrong row. p2, as suggested.
Claim: PM loop round 1
Session: session_01Utp6CYVV6fcAQrNTDQRvPb (seat) · dev = project card thread session_01Utp6CXdBvpJrhnHyW825Hb
Account: os-bill
Branch: claude/project-thread-4jj4ed (harness-pinned thread branch; platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-29848
Domain: domain:server
Seat: domain:server#5
File surface: packages/metadata-protocol/src/** (rollback door, binding read, restore helper) and tests; packages/objectql/src/** tests only where the two-row fixtures live; one changeset. ⛔ packages/spec/**, ui/**, skills/**, docs/adr/**, .claude/**, AGENTS.md (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default tier (opus) — dispatch-gates --tier at 5fa9375e: no path-derived mandate, effort: high
Clause-②: no — the rollback door's accept set does not change (no new parameter); the package is derived from the served row
Metadata-protocol: none
Responsibility: metadata-protocol's per-item rollback resolves the base row's package for a .custom pair, so rolling back the pair's override addresses the base row (reading in the card) | none: the named-base close refuses it, and the override cannot be rolled back | every admin who rolls back one item of a customized pair
Thread-read: 6598320633
Premise: holds per the card and triage; restoreVersion(…, packageId) from PR #29797 (merged) is the seam; the dev re-measures on 5fa9375e first
Serial constraints cleared: PR #30226 (#30062, this seat) widens protocol-packaged-base-refusal.ts and protocol-package-bindings.ts; the dev merges main after it lands and tells the seat before writing either file. Seat 3's #30106 (merged) and #30168 are in the same area.
Order: project file server-seat5/dispatch-29848.md, delivered to the card thread. Door choice (seat's call): derive the package from the served row, no new ?package=; ambiguity → needs_decision.
Activity
objectstack-fleet commentedon Nov 3, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: first-touch audit · p2 ·
domain:serverkept ·pm:triage→pm:queue· 2026-11-03T07:52Z⛔ Not a claim.
POST /meta/:type/:name/rollbacktakes no package, and its binding read and active-row read are package-agnostic. So while a pre-close base-bound row of the same name is stored, a.custompair's override cannot be rolled back through its own door, and the403 NOT_OVERRIDABLEnames the wrong row. p2, as suggested.Generated by Claude Code
objectstack-fleet commentedon Nov 5, 2026
domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb
Claim: PM loop round 1
Session:
session_01Utp6CYVV6fcAQrNTDQRvPb(seat) · dev = project card threadsession_01Utp6CXdBvpJrhnHyW825HbAccount:
os-billBranch:
claude/project-thread-4jj4ed(harness-pinned thread branch; platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-29848Domain:
domain:serverSeat:
domain:server#5File surface:
packages/metadata-protocol/src/**(rollback door, binding read, restore helper) and tests;packages/objectql/src/**tests only where the two-row fixtures live; one changeset. ⛔packages/spec/**,ui/**,skills/**,docs/adr/**,.claude/**,AGENTS.md(stop on breach; explain in the report)Container & model:
M,mode:thread,model: default tier (opus) — dispatch-gates --tier at 5fa9375e: no path-derived mandate,effort: highClause-②: no — the rollback door's accept set does not change (no new parameter); the package is derived from the served row
Metadata-protocol: none
Responsibility:
metadata-protocol's per-item rollback resolves the base row's package for a .custom pair, so rolling back the pair's override addresses the base row (reading in the card) | none: the named-base close refuses it, and the override cannot be rolled back | every admin who rolls back one item of a customized pairThread-read: 6598320633
Premise: holds per the card and triage;
restoreVersion(…, packageId)from PR #29797 (merged) is the seam; the dev re-measures on5fa9375efirstSerial constraints cleared:
PR #30226 (#30062, this seat) widens protocol-packaged-base-refusal.ts and protocol-package-bindings.ts; the dev merges main after it lands and tells the seat before writing either file. Seat 3's #30106 (merged) and #30168 are in the same area.Order: project file
server-seat5/dispatch-29848.md, delivered to the card thread. Door choice (seat's call): derive the package from the served row, no new?package=; ambiguity →needs_decision.