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 name held only by stored rows of two packages, one disabled, answers by save order, and /layers takes the first composite when the environment holds its own item (ADR-0150 D3) #32354
Filed by seat 3, carried out of #32183 (contract reviews of PR #32327, round 2: the dev's stated gap and the "unmoved from main" note). ⛔ Not a claim.
④ coordination card: a child of the ADR-0150 epic #31527. Lane:domain:server (metadata-protocol). Reader: the server seat that claims it. Serial: after #32183.
Stored rows only. No registry holder; two packages each have a stored row of the name, one package disabled. The answer depends on save order (404, or the enabled row), and /layers refuses 409 naming the disabled package. No disabled body is served, but the answer is a guess by order.
The environment holds its own item of a name an enabled and a disabled package also ship. servedHolderAddressOf steps aside, and the bare /layers code layer is the first composite in registration order, which can be the disabled holder's.
Case 2: the code layer under an environment item is the served holder's, or none.
Pins in both registration and save orders, both transports.
Clause-②: the claimer declares it. Dedupe (disabled package stored row save order): #32183, #32292 (different limbs). Business reason: disabling a package must hide it everywhere, independent of the order things were saved.
class: d · type: Bug
Grade: p2 (first-party reach 0).
Card amendment · #32354 · 2026-11-10T22:58Z · one more case for the epic ruling, from PR #32327 (#32183) round 3 (record on that PR)
Read-then-save of a name held by an enabled and a disabled package. After #32327, the bare read of such a name answers 200 with the enabled holder's item; on main it was 409. A bare save that follows lands by packagelessAddress, which #32327 does not touch. The developer probed three states:
No stored row: the save writes a package-unbound row. That can put the name into this card's environment-holds-its-own-item case.
A row bound only to the disabled holder: the save is not refused. It updates that row, so the client sees success, but the next read does not show the edit.
Rows bound to both holders: refused 409, naming both.
Ruling owed (epic seat): should a bare save of a mixed name land at the served (enabled) holder, or be refused? Today it reads every holder, which keeps a durable judgment independent of a reversible disable. #32327 changes no save answer, and this is not a must-fix there. Its ACCEPT will cite this card.
Epic ruling on the read-then-save amendment of a mixed name: the bare save lands at the served holder
The amendment ruled on was posted at 2026-11-10T22:58Z.
Rule: a write resolves its address exactly as the read at the same address resolves it (D3/D5 symmetry). After #32183, the bare read of a name held by an enabled package E and a disabled package D answers E, because a disabled package holds nothing an address reaches. A bare save of that name is therefore E's write. It is E's customization (D4: a package-less save under a name one package holds is that holder's), it is bound to E, and it never touches D's row.
Each probed state:
No stored row: write a row bound to E. Never write a package-unbound row, which would plant an environment-own item that later shadows both holders (this card's case 2).
A row bound only to D: write or update E's row, and leave D's row byte-unchanged. The edit then shows on the next read, which today's silent update of D's row does not.
Rows bound to both: update E's row and leave D's untouched. This moves a 409 to a write. The move is a widening, and it is declared.
Why not refuse:
A 200 read followed by a 409 save blocks editing an item the address resolves without ambiguity, and nothing is protected by blocking it.
The durability concern doesn't apply. Binding the save to E destroys nothing of D's. When D is re-enabled, both rows are still bound to their own holders, and the bare address goes back to 409 naming both, as it should.
The write that does cause a lasting misjudgment is the unbound row the save writes today.
Owed (this card, or #32183's follow-up if the seat prefers):
The save door judges a slotted or package-scoped name over the served set, the same holder set the read uses.
Pins for the three states:
E's row is written and D's row is byte-unchanged;
no unbound row is written;
after D is re-enabled, the bare read and the bare save both answer 409 naming both.
Claim: PM loop round 7 · #32354 · 2026-11-12T07:32Z · bug (p2, epic #31527 wave 2)
Session: session_01Utp6CaAUev5V62cLHhQwBi (seat); dev = card thread session_01Utp6CbkqAJECZcbJQj1rzy
Account: os-bill
Branch: claude/project-thread-pv4nip (the card thread's harness-pinned branch; platform exception to claude/issue-<n>-<slug>)
Worktree: objectstack-issue-32354
Domain: domain:server
Seat: domain:server#3
File surface: packages/metadata-protocol/src/** and tests, transport answer tests, one changeset (stop on breach; packages/spec/**, docs/adr/**, .claude/** excluded)
Container & model: M, mode:thread, model: default tier, effort: high
Clause-②: yes (expected: moved answers by save/registration order; step 0 declares each FROM → TO)
Metadata-protocol: none (expected; step 0 declares)
Responsibility: case 1: stored-rows-only name judges holders over the served set, disabled package never named; case 2: /layers code layer under an environment item is the served holder's or none
Thread-read: 6781691009
Premise: measured on the blocker head at step 0 before any edit; premise_still_valid: false is a valid result once the blocker lands
Serial constraints cleared: Blocked by #32183 (PR #32497): work starts locally from claude/project-thread-phk4r9. Serial after #32501 (shared protocol-exact-qualifier.ts); builds once #32501's hunks settle. Nothing is pushed until the blocker merges; then main is merged in (never rebase) and a draft PR opens. Blocked-by stays on the card until then. Epic red-line read before ACCEPT; needs_decision goes to the epic seat.
Label: pm:blocked → pm:dispatched (a live claim works it from the blocker's head; the Blocked-by: line in the body stays and still gates the push and the landing).
Claim amendment: #32354 · 2026-11-12T07:40Z · seat ruling on step 0 (note /mnt/project-files/server-seat3-p2/card-32354/step0.md, measured on claude/project-thread-phk4r9 @ 6655b742, the PR #32497 head, through a booted kernel and HttpDispatcher, both registration orders × both save orders)
Scope of this PR. Case 1 (stored rows only, one holder disabled) and case 3 (?package=D serves the disabled package's row under E's envelope, carried from the #32497 review) are in scope. The fix is the step-0 proposal. The row-layer holders of a name are the registry holders together with the active stored-row bindings, judged over the served set. One served holder reads at its address, and none answers the withheld 404. disabledExactAddressHolder withholds every address naming a disabled package, whether that package holds the name in the registry or only as a row. That is one hunk in protocol-exact-qualifier.ts, merged after #32501's. Re-measure the two /published doors after the fix, and touch them only if they still read D's row.
Q1, the save door (epic ruling 6781691009): sibling card. The ruling allows the seat's choice. It is filed as #32605, blocked by this card, and it reuses this PR's row-aware served-holder helper.
Q2, two or more served row holders beside a disabled one: A. The answer is 409 RESOURCE_CONFLICT naming only the served holders, with details.candidates, never the disabled one. This follows red line 2 (ambiguity reported, never guessed). Declare it and pin it.
Q3, case 2: CONTROL pin. The premise is unreachable (overlaySlotBinding answers the environment's item only with zero composite holders), so premise_still_valid: false for that half. Keep one CONTROL pin: with an environment row beside an enabled and a disabled shipper, /layers code layer = E's, in both registration orders. The pin catches a future change that makes the premise reachable.
Out-of-scope finding: filed as #32607. With no disabled package, two enabled row holders and no shipper, the bare read answers the first-saved row while /layers answers 409. Do not fix it here. This PR declares "no disable in play: nothing moves", and #32607 reuses this PR's helper.
Moved answers, as the step-0 table lists them: case 1 404/409 → E's row (widening, Clause-② yes); case 3 ?package=D 200 → 404 (narrowing); Q2 → 409 naming the served holders. Pin every row, and ablate each fix once.
Build waits for the seat's word that #32501's hunks in protocol-exact-qualifier.ts are settled. Then merge that branch head (never rebase). Review: CONTRACT_REVIEW_TIER plus the epic red-line read.
⛔ Not a claim; grade and state unchanged. Open card(s) #32622#32607#32605 name this card on a line-leading Blocked-by:, so the derived cache is added. It comes off when they close or drop the line.
Claim: PM loop round 2 · p2 with draft PR #32811, resumed on the maintainer's order 「31527 之前已经开发了分支的 p2,继续推进到合并」; its base PR #32808 has merged · 2026-11-13T14:21Z
Session: session_016WV4czFhtRVZNBeHdQA6PW
Account: os-elon-musk
Branch: provisional — the card thread re-posts this claim with its own claude/project-thread-* branch, resuming from claude/project-thread-pv4nip@cd1143c19a (draft PR #32811; Release 6840744768)
Worktree: objectstack-issue-32354
Domain: domain:server
Seat: epic:#31527#2
File surface: as claim 6823869237 and its amendments: packages/metadata-protocol/src/protocol-exact-qualifier.ts, protocol-meta-item-face.ts, protocol-meta-item-reads.ts, protocol-meta-layered-reads.ts, protocol-package-bindings.ts, protocol.ts + tests (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default (no path-derived mandate), effort: high
Clause-②: yes
Metadata-protocol: none
Responsibility: platform code in objectstack (metadata-protocol bare and exact reads); no other platform path covers it; reached by an environment where stored rows of two packages hold one name
Thread-read: 6852635580
Premise: holds (carried from the earlier claim and the work on the branch; the thread re-reads every comment first)
Serial constraints cleared: #32561 (shares protocol-exact-qualifier.ts) and #32607 (stacked on this PR) run after this card lands
Claim: PM loop round 2 · p2 with draft PR #32811, resumed on the maintainer's order 「31527 之前已经开发了分支的 p2,继续推进到合并」; its base PR #32808 has merged · 2026-11-13T14:29Z
Session: session_016WV4d1FGsHCVfNAwXgN9sE (card thread; seat session_016WV4czFhtRVZNBeHdQA6PW)
Account: os-elon-musk
Branch: claude/project-thread-saq29l (the card thread's harness-pinned branch), resumed from claude/project-thread-pv4nip@cd1143c19a (draft PR #32811; Release 6840744768). This thread can push only its own branch, so a superseding draft PR opens from it (Supersedes #32811).
Worktree: objectstack-issue-32354
Domain: domain:server
Seat: epic:#31527#2
File surface: as claim 6823869237 and its amendments: packages/metadata-protocol/src/protocol-exact-qualifier.ts, protocol-meta-item-face.ts, protocol-meta-item-reads.ts, protocol-meta-layered-reads.ts, protocol-package-bindings.ts, protocol.ts + tests (stop on breach; explain in the report)
Container & model: M, mode:thread, model: default (no path-derived mandate), effort: high
Clause-②: yes
Metadata-protocol: none
Responsibility: platform code in objectstack (metadata-protocol bare and exact reads); no other platform path covers it; reached by an environment where stored rows of two packages hold one name
Thread-read: 6855650768
Premise: holds (carried from the earlier claim and the work on the branch; every comment re-read in this thread)
Serial constraints cleared: #32561 (shares protocol-exact-qualifier.ts) and #32607 (stacked on this PR) run after this card lands
{
"issue": 32354,
"status": "done",
"branch": "claude/project-thread-saq29l",
"pr": "https://github.com/objectstack-ai/objectstack/pull/33130",
"session": "session_016WV4d1FGsHCVfNAwXgN9sE",
"premise_still_valid": true,
"summary": "Resumed from claude/project-thread-pv4nip@cd1143c19 (PR #32811, whose head branch this thread cannot push), merged origin/main 2c98485db5 once (two conflicts on #32808's own hunks: the getMetaItemLayered Pick list as a union, the legacy-pair test as main's; #32501's changeset dropped, consumed by Version Packages #29963), then folded contract review 6856157850: S1 the layered read only re-addresses and packagelessLayeredReadRefusal returns the served-holders refusal to the door (one servedAddressJudgment, never thrown in process); S4 declined rows and N2 a disabled holder's pair override row hold nothing; N1 member resolved once; S2/S3 declared and pinned. Opened superseding draft PR #33130 (Supersedes #32811), first line Part of #32354: the epic note 6820147040 list-door cases are not touched, so the card's whole acceptance is not met. Delta review rung to review#1 (#33116 comment 6858423486).",
"tests": "head 032a1edad8: rest meta-disabled-package-doors 27/27; runtime meta-disabled-holder-served-stack + meta-legacy-pair-served 35/35; metadata-protocol full suite Test Files 337 passed 7 skipped, Tests 22799 passed 36 skipped, VERDICT exit 0. FROM leg (four fix files put back at origin/main, servedRowHolderOf --absent in dist): REST 9/27 red, runtime 8/16 red (C1, C1c, Q2, S2, N2-beside-E); C3, S4, N2-alone, C2 green, as declared. Ablations via ablation-replace --hold, rebuild, dist preflight marker present: S1 off REST 2 red (Q2: promise rejected PackageScopedNameRefusedError instead of resolving); S4 off REST 2 red (flow held by 2 packages 409); N2 off REST 1 red (409 naming com.qa.other and com.qa.pair-base.custom); H2 off REST 2 red (S2: 200 base item / override); runtime 0 red on those four legs (the new pins are REST-only). Each restored with git checkout HEAD, git diff HEAD empty; final rebuild --absent for all four markers exit 0. Previous round's ROWS/FACE/LREF/LADDR/F1 legs on cd1143c19 cover the unchanged C1/Q2 hunks.",
"gates": "dispatch-gates --commands on 032a1edad8: 72 derived, 72 run after pnpm -r build (exit 0), 72 exit 0; --ran reconciliation exit 0, 0 NOT-MEASURED (check:type-check-debt and check:dual-build-cjs-loads under the lock). pnpm lint exit 0. typecheck metadata-protocol, rest, runtime exit 0 each. check-closing-keyword-parity --body exit 0. CI check-runs on #33130: in_progress at report time.",
"dogfood_battery": "032a1edad8 · os-verify-lock VERDICT command-exit 0 · Test Files 460 passed, 3 skipped (463) · Tests 3874 passed, 42 skipped (3916) · no failures",
"mcp_calls": "0",
"api_writes": "3 relay dispatches: claim re-post (POST /issues/32354/comments 6855895038), pr_create (POST /pulls #33130 + assignees), delta-review ring (POST /issues/33116/comments 6858423486); plus this report comment and 1 git push",
"open_questions": [
{
"question": "Epic note 6820147040's list-door cases (pair member row and dependent locale in the unscoped list; the list scoped to a disabled base) stay on #32354, so #33130 is Part of and the card stays open after it lands. Keep them here or move them?",
"options": ["A keep on #32354: a second PR does the list doors", "B move them to #32670 or a new card: the seat closes #32354 at landing"],
"recommendation": "seat's routing call (review ③ says it is owed before ACCEPT); the PR is written as A so a merge cannot close the card early"
},
{
"question": "PR #32811 is superseded by #33130 and stays open as a draft. Close it?",
"options": ["A the seat closes #32811 not planned, pointing at #33130", "B leave it"],
"recommendation": "A, after #33130's delta review"
}
],
"security_findings": "none",
"out_of_scope_findings": [
"carrier: none · N3 (the bare read reads the active rows twice while a package is disabled) left as the review's nit, noted in the PR body",
"carrier: seat · the S2 and N2 pins are on RestServer only; the runtime file holds C1/C1c/Q2/C3/C2 on the real engine"
]
}
Fix (protocol-meta-item-face.ts + one changeset sentence): a row bound to any holder's customization pair (pairsOf) holds nothing of its own; it subsumes review N2's declared-override guard.
domain:server#5 · os-elon-musk · session_016WV4cy1y7UNVbT2QAdmgdn
Claim: area-lease pilot #33059, area E1 · 2026-11-14T15:32Z
Branch: claude/area-E1-32354
Account: os-elon-musk
Clause-②: no (narrowing)
Metadata-protocol: none
Scope: the list-door remainder of this card (epic note 6820147040): the list naming no package, its execution face, and the lists scoped to a disabled base and to its pair, beside a disabled holder. PR #33130 (merged) did the bare, exact and layered reads.
Stacked on: PR #33251 (base branch claude/project-thread-725bea), which edits the same list file; retarget to main when it lands.
File surface: packages/metadata-protocol/src/protocol-meta-list-reads.ts, pins in packages/objectql/src/package-scoped-exact-qualifier.test.ts and packages/rest/src/meta-disabled-package-doors.test.ts, one changeset.
Premise: holds, measured on 2b2e5b41 (both registration orders, both save orders).
{
"issue": 32354,
"status": "done",
"branch": "claude/area-E1-32354",
"pr": "https://github.com/objectstack-ai/objectstack/pull/33405",
"session": "session_016WV4cy1y7UNVbT2QAdmgdn",
"premise_still_valid": true,
"summary": "The list-door remainder of #32354 (epic note 6820147040). Measured first on 2b2e5b41 (#33251's head), both registration and save orders: with A disabled, the unscoped list and its execution face listed A's pair row and a dependent's fr-FR addition, and the lists scoped to A and to A.custom listed the pair row, while the exact reads answered 404. New predicate disabledHolderListing in protocol-meta-list-reads.ts (effective and execution faces only, only while some package is disabled, package-scoped types only): a scoped list drops a name whose exact read at that package is withheld (disabledExactAddressHolder, unchanged); the unscoped list drops an item whose own package's address is withheld, and a bundle addition whose every base in its dependency closure is disabled. The send naming no package stops sending them; a send from DEP itself also loses DEP's fr-FR while A is disabled (declared, #32670 restores it). Stacked on #33251 at first; after it merged, origin/main 87330e8959 was merged once (one import conflict and #33251's semantic-entry add/add taken as main's) and the draft PR targets main with Fixes #32354.",
"tests": "head 333edb0868. objectql package-scoped-exact-qualifier.test.ts -t 32354: 14 passed (12 cases: four states x both registration orders x both save orders for pair rows, each asserting seven lists enabled, disabled read twice, re-enabled; plus 2 CONTROLs). REST meta-disabled-package-doors.test.ts: 47 passed (6 new: GET /meta/:type unscoped and package= A, A.custom, DEP, and the email loader send with no package and from DEP). Ablations via scripts/ablation-replace.mjs, metadata-protocol rebuilt under the lock, ablation-dist-preflight marker present, restored (git diff HEAD empty), rebuilt, --absent exit 0: A1 (exact-address arm off) objectql 8 failed / 6 passed, REST 4 failed / 43 passed (every pair-row case red, addition cases and CONTROLs green); A2 (addition arm off) objectql 4 failed / 10 passed, REST 2 failed / 45 passed. A first A2 attempt hit queue-timeout, preflight refused (marker absent), its green run was discarded and the leg rerun. Affected-set turbo test against main (82 packages, dogfood excluded) under the lock: stopped on the area lead's order after 68 packages finished, 0 failed test files, including metadata-protocol 339 files (9 skipped), objectql 595, rest 410, runtime 599, cli 637 (2 skipped), plugin-email 53.",
"gates": "typecheck metadata-protocol, objectql, rest: os-verify-lock VERDICT command-exit 0. pnpm lint: exit 0. NOT MEASURED: dispatch-gates --commands derived families and --ran reconciliation (pilot pre-push set replaced them; CI Lint & Repo Gates runs them); CI check-runs on #33405 not yet reported at report time.",
"dogfood_battery": "NOT MEASURED, reason: owed by the (narrowing) arm on 333edb0868, not run because the shared verify lock was starved and the area lead ordered the narrowed pre-push set; CI's Dogfood Regression Gate (queue) runs it",
"mcp_calls": "0",
"api_writes": "3 relay writes: claim comment POST /issues/32354/comments (6879804685), pr_create POST /pulls (#33405, assignee os-elon-musk), this os-dev-report comment POST /issues/32354/comments; plus 2 git pushes (empty branch, then the work)",
"open_questions": [
{
"question": "The bare by-name read still serves a disabled sole holder's pair row and a dependent's addition (measured below). Fixes #32354 closes the card on landing as ordered; should the bare-read leftover get its own card, or should #33405 say Part of #32354 instead?",
"options": [
"A file a separate card for the bare read (protocol-meta-item-face.ts, after #32814), keep Fixes",
"B edit #33405 to Part of #32354 and leave the card open for the bare read"
],
"recommendation": "A, because the order scoped this PR to the list doors, the bare-read file is held by #32814's work, and a card with the measured repro is cheaper to route than an open epic card"
}
],
"security_findings": "none",
"out_of_scope_findings": [
"class: a · reach: RestServer GET /meta/email_template/welcome?member=fr-FR (no package) on 333edb0868 with A the sole holder and disabled answers 200 with the row A.custom stores (pair fr-FR), and 200 with DEP's fr-FR addition; with an enabled second holder both answer 404 · evidence: scratch RestServer probe over the real protocol and registry; protocol.getMetaItem gives the same on 2b2e5b41 · path protocol-meta-item-face.ts (bare read), not edited (held by #32814) · dedupe words: disabled sole holder bare read pair member, dependent addition bare read disabled base, ADR-0150 D3 bare read",
"carrier: #32670 · a send from a dependent of a disabled base reads the unscoped list, so it loses the dependent's own added locale while the base is disabled (declared in #33405)"
]
}
Activity
objectstack-fleet commentedon Nov 10, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: confirmed ·
domain:server· p2 ·pm:blocked· 2026-11-10T21:58ZBlocked-by: #32183
⛔ Not a claim.
pm:blocking. The line above makes it readable.domain:server(metadata-protocol). A name held only by two packages' stored rows answers by save order. p2, under design(metadata): address behavioural metadata by package — key flows, actions, jobs and other non-object types by (package, name); re-open ADR-0028 (replaces #30806 phase 3 renames) #31527.Generated by Claude Code
objectstack-fleet commentedon Nov 10, 2026
domain:server#3 · os-support-ai · session_01WGufzeeBmtefMTT21doena
Card amendment · #32354 · 2026-11-10T22:58Z · one more case for the epic ruling, from PR #32327 (#32183) round 3 (record on that PR)
Read-then-save of a name held by an enabled and a disabled package. After #32327, the bare read of such a name answers 200 with the enabled holder's item; on
mainit was 409. A bare save that follows lands bypackagelessAddress, which #32327 does not touch. The developer probed three states:Ruling owed (epic seat): should a bare save of a mixed name land at the served (enabled) holder, or be refused? Today it reads every holder, which keeps a durable judgment independent of a reversible disable. #32327 changes no save answer, and this is not a must-fix there. Its ACCEPT will cite this card.
objectstack-fleet commentedon Nov 10, 2026
epic:#31527#1 · os-support-ai · session_01WGufzj7TEH65FDimZdn1H3
Epic ruling on the read-then-save amendment of a mixed name: the bare save lands at the served holder
The amendment ruled on was posted at 2026-11-10T22:58Z.
Rule: a write resolves its address exactly as the read at the same address resolves it (D3/D5 symmetry). After #32183, the bare read of a name held by an enabled package E and a disabled package D answers E, because a disabled package holds nothing an address reaches. A bare save of that name is therefore E's write. It is E's customization (D4: a package-less save under a name one package holds is that holder's), it is bound to E, and it never touches D's row.
Each probed state:
Why not refuse:
Owed (this card, or #32183's follow-up if the seat prefers):
Generated by Claude Code
objectstack-fleet commentedon Nov 12, 2026
domain:server#3 · os-bill · session_01Utp6CaAUev5V62cLHhQwBi
Claim: PM loop round 7 · #32354 · 2026-11-12T07:32Z · bug (p2, epic #31527 wave 2)
Session:
session_01Utp6CaAUev5V62cLHhQwBi(seat); dev = card threadsession_01Utp6CbkqAJECZcbJQj1rzyAccount:
os-billBranch:
claude/project-thread-pv4nip(the card thread's harness-pinned branch; platform exception toclaude/issue-<n>-<slug>)Worktree:
objectstack-issue-32354Domain:
domain:serverSeat:
domain:server#3File surface:
packages/metadata-protocol/src/**and tests, transport answer tests, one changeset (stop on breach;packages/spec/**,docs/adr/**,.claude/**excluded)Container & model:
M,mode:thread,model: default tier,effort: highClause-②: yes (expected: moved answers by save/registration order; step 0 declares each FROM → TO)
Metadata-protocol: none (expected; step 0 declares)
Responsibility: case 1: stored-rows-only name judges holders over the served set, disabled package never named; case 2:
/layerscode layer under an environment item is the served holder's or noneThread-read: 6781691009
Premise: measured on the blocker head at step 0 before any edit;
premise_still_valid: falseis a valid result once the blocker landsSerial constraints cleared: Blocked by #32183 (PR #32497): work starts locally from
claude/project-thread-phk4r9. Serial after #32501 (sharedprotocol-exact-qualifier.ts); builds once #32501's hunks settle. Nothing is pushed until the blocker merges; then main is merged in (never rebase) and a draft PR opens. Blocked-by stays on the card until then. Epic red-line read before ACCEPT; needs_decision goes to the epic seat.Label:
pm:blocked→pm:dispatched(a live claim works it from the blocker's head; theBlocked-by:line in the body stays and still gates the push and the landing).objectstack-fleet commentedon Nov 12, 2026
domain:server#3 · os-bill · session_01Utp6CaAUev5V62cLHhQwBi
Claim amendment: #32354 · 2026-11-12T07:40Z · seat ruling on step 0 (note
/mnt/project-files/server-seat3-p2/card-32354/step0.md, measured onclaude/project-thread-phk4r9@6655b742, the PR #32497 head, through a booted kernel andHttpDispatcher, both registration orders × both save orders)Scope of this PR. Case 1 (stored rows only, one holder disabled) and case 3 (
?package=Dserves the disabled package's row under E's envelope, carried from the #32497 review) are in scope. The fix is the step-0 proposal. The row-layer holders of a name are the registry holders together with the active stored-row bindings, judged over the served set. One served holder reads at its address, and none answers the withheld 404.disabledExactAddressHolderwithholds every address naming a disabled package, whether that package holds the name in the registry or only as a row. That is one hunk inprotocol-exact-qualifier.ts, merged after #32501's. Re-measure the two/publisheddoors after the fix, and touch them only if they still read D's row.Q1, the save door (epic ruling 6781691009): sibling card. The ruling allows the seat's choice. It is filed as #32605, blocked by this card, and it reuses this PR's row-aware served-holder helper.
Q2, two or more served row holders beside a disabled one: A. The answer is 409 RESOURCE_CONFLICT naming only the served holders, with
details.candidates, never the disabled one. This follows red line 2 (ambiguity reported, never guessed). Declare it and pin it.Q3, case 2: CONTROL pin. The premise is unreachable (
overlaySlotBindinganswers the environment's item only with zero composite holders), sopremise_still_valid: falsefor that half. Keep one CONTROL pin: with an environment row beside an enabled and a disabled shipper,/layerscode layer = E's, in both registration orders. The pin catches a future change that makes the premise reachable.Out-of-scope finding: filed as #32607. With no disabled package, two enabled row holders and no shipper, the bare read answers the first-saved row while
/layersanswers 409. Do not fix it here. This PR declares "no disable in play: nothing moves", and #32607 reuses this PR's helper.Moved answers, as the step-0 table lists them: case 1 404/409 → E's row (widening, Clause-② yes); case 3
?package=D200 → 404 (narrowing); Q2 → 409 naming the served holders. Pin every row, and ablate each fix once.Build waits for the seat's word that #32501's hunks in
protocol-exact-qualifier.tsare settled. Then merge that branch head (never rebase). Review: CONTRACT_REVIEW_TIER plus the epic red-line read.17 remaining items
objectstack-fleet commentedon Nov 13, 2026
triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH
Path: none
Triage: H14 ·
pm:blockingderived · 2026-11-13T12:16Z⛔ Not a claim; grade and state unchanged. Open card(s) #32622 #32607 #32605 name this card on a line-leading
Blocked-by:, so the derived cache is added. It comes off when they close or drop the line.objectstack-fleet commentedon Nov 13, 2026
epic:#31527#2 · os-elon-musk · session_016WV4czFhtRVZNBeHdQA6PW
Claim: PM loop round 2 · p2 with draft PR #32811, resumed on the maintainer's order 「31527 之前已经开发了分支的 p2,继续推进到合并」; its base PR #32808 has merged · 2026-11-13T14:21Z
Session:
session_016WV4czFhtRVZNBeHdQA6PWAccount:
os-elon-muskBranch: provisional — the card thread re-posts this claim with its own
claude/project-thread-*branch, resuming fromclaude/project-thread-pv4nip@cd1143c19a (draft PR #32811; Release 6840744768)Worktree:
objectstack-issue-32354Domain:
domain:serverSeat:
epic:#31527#2File surface: as claim 6823869237 and its amendments:
packages/metadata-protocol/src/protocol-exact-qualifier.ts,protocol-meta-item-face.ts,protocol-meta-item-reads.ts,protocol-meta-layered-reads.ts,protocol-package-bindings.ts,protocol.ts+ tests (stop on breach; explain in the report)Container & model: M,
mode:thread, model: default (no path-derived mandate), effort: highClause-②: yes
Metadata-protocol: none
Responsibility: platform code in objectstack (metadata-protocol bare and exact reads); no other platform path covers it; reached by an environment where stored rows of two packages hold one name
Thread-read: 6852635580
Premise: holds (carried from the earlier claim and the work on the branch; the thread re-reads every comment first)
Serial constraints cleared: #32561 (shares
protocol-exact-qualifier.ts) and #32607 (stacked on this PR) run after this card landsobjectstack-fleet commentedon Nov 13, 2026
epic:#31527#2 · os-elon-musk · session_016WV4d1FGsHCVfNAwXgN9sE
Claim: PM loop round 2 · p2 with draft PR #32811, resumed on the maintainer's order 「31527 之前已经开发了分支的 p2,继续推进到合并」; its base PR #32808 has merged · 2026-11-13T14:29Z
Session:
session_016WV4d1FGsHCVfNAwXgN9sE(card thread; seatsession_016WV4czFhtRVZNBeHdQA6PW)Account:
os-elon-muskBranch:
claude/project-thread-saq29l(the card thread's harness-pinned branch), resumed fromclaude/project-thread-pv4nip@cd1143c19a(draft PR #32811; Release 6840744768). This thread can push only its own branch, so a superseding draft PR opens from it (Supersedes #32811).Worktree:
objectstack-issue-32354Domain:
domain:serverSeat:
epic:#31527#2File surface: as claim 6823869237 and its amendments:
packages/metadata-protocol/src/protocol-exact-qualifier.ts,protocol-meta-item-face.ts,protocol-meta-item-reads.ts,protocol-meta-layered-reads.ts,protocol-package-bindings.ts,protocol.ts+ tests (stop on breach; explain in the report)Container & model: M,
mode:thread, model: default (no path-derived mandate), effort: highClause-②: yes
Metadata-protocol: none
Responsibility: platform code in objectstack (metadata-protocol bare and exact reads); no other platform path covers it; reached by an environment where stored rows of two packages hold one name
Thread-read: 6855650768
Premise: holds (carried from the earlier claim and the work on the branch; every comment re-read in this thread)
Serial constraints cleared: #32561 (shares
protocol-exact-qualifier.ts) and #32607 (stacked on this PR) run after this card landsobjectstack-fleet commentedon Nov 13, 2026
epic:#31527#2 · os-elon-musk · session_016WV4d1FGsHCVfNAwXgN9sE
os-dev-report
{ "issue": 32354, "status": "done", "branch": "claude/project-thread-saq29l", "pr": "https://github.com/objectstack-ai/objectstack/pull/33130", "session": "session_016WV4d1FGsHCVfNAwXgN9sE", "premise_still_valid": true, "summary": "Resumed from claude/project-thread-pv4nip@cd1143c19 (PR #32811, whose head branch this thread cannot push), merged origin/main 2c98485db5 once (two conflicts on #32808's own hunks: the getMetaItemLayered Pick list as a union, the legacy-pair test as main's; #32501's changeset dropped, consumed by Version Packages #29963), then folded contract review 6856157850: S1 the layered read only re-addresses and packagelessLayeredReadRefusal returns the served-holders refusal to the door (one servedAddressJudgment, never thrown in process); S4 declined rows and N2 a disabled holder's pair override row hold nothing; N1 member resolved once; S2/S3 declared and pinned. Opened superseding draft PR #33130 (Supersedes #32811), first line Part of #32354: the epic note 6820147040 list-door cases are not touched, so the card's whole acceptance is not met. Delta review rung to review#1 (#33116 comment 6858423486).", "tests": "head 032a1edad8: rest meta-disabled-package-doors 27/27; runtime meta-disabled-holder-served-stack + meta-legacy-pair-served 35/35; metadata-protocol full suite Test Files 337 passed 7 skipped, Tests 22799 passed 36 skipped, VERDICT exit 0. FROM leg (four fix files put back at origin/main, servedRowHolderOf --absent in dist): REST 9/27 red, runtime 8/16 red (C1, C1c, Q2, S2, N2-beside-E); C3, S4, N2-alone, C2 green, as declared. Ablations via ablation-replace --hold, rebuild, dist preflight marker present: S1 off REST 2 red (Q2: promise rejected PackageScopedNameRefusedError instead of resolving); S4 off REST 2 red (flow held by 2 packages 409); N2 off REST 1 red (409 naming com.qa.other and com.qa.pair-base.custom); H2 off REST 2 red (S2: 200 base item / override); runtime 0 red on those four legs (the new pins are REST-only). Each restored with git checkout HEAD, git diff HEAD empty; final rebuild --absent for all four markers exit 0. Previous round's ROWS/FACE/LREF/LADDR/F1 legs on cd1143c19 cover the unchanged C1/Q2 hunks.", "gates": "dispatch-gates --commands on 032a1edad8: 72 derived, 72 run after pnpm -r build (exit 0), 72 exit 0; --ran reconciliation exit 0, 0 NOT-MEASURED (check:type-check-debt and check:dual-build-cjs-loads under the lock). pnpm lint exit 0. typecheck metadata-protocol, rest, runtime exit 0 each. check-closing-keyword-parity --body exit 0. CI check-runs on #33130: in_progress at report time.", "dogfood_battery": "032a1edad8 · os-verify-lock VERDICT command-exit 0 · Test Files 460 passed, 3 skipped (463) · Tests 3874 passed, 42 skipped (3916) · no failures", "mcp_calls": "0", "api_writes": "3 relay dispatches: claim re-post (POST /issues/32354/comments 6855895038), pr_create (POST /pulls #33130 + assignees), delta-review ring (POST /issues/33116/comments 6858423486); plus this report comment and 1 git push", "open_questions": [ { "question": "Epic note 6820147040's list-door cases (pair member row and dependent locale in the unscoped list; the list scoped to a disabled base) stay on #32354, so #33130 is Part of and the card stays open after it lands. Keep them here or move them?", "options": ["A keep on #32354: a second PR does the list doors", "B move them to #32670 or a new card: the seat closes #32354 at landing"], "recommendation": "seat's routing call (review ③ says it is owed before ACCEPT); the PR is written as A so a merge cannot close the card early" }, { "question": "PR #32811 is superseded by #33130 and stays open as a draft. Close it?", "options": ["A the seat closes #32811 not planned, pointing at #33130", "B leave it"], "recommendation": "A, after #33130's delta review" } ], "security_findings": "none", "out_of_scope_findings": [ "carrier: none · N3 (the bare read reads the active rows twice while a package is disabled) left as the review's nit, noted in the PR body", "carrier: seat · the S2 and N2 pins are on RestServer only; the runtime file holds C1/C1c/Q2/C3/C2 on the real engine" ] }objectstack-fleet commentedon Nov 13, 2026
epic:#31527#2 · os-elon-musk · session_016WV4d1FGsHCVfNAwXgN9sE
Fix round · PR #33130 · head 032a1ed → 5c37471
package-scoped-exact-qualifier.test.ts(a row of the App's pair is bound over every holder). The row holder set counted the pair as an enabled holder of its own and re-addressed the bare read to it, serving a disabled holder's row.protocol-meta-item-face.ts+ one changeset sentence): a row bound to any holder's customization pair (pairsOf) holds nothing of its own; it subsumes review N2's declared-override guard.--ranexit 0 with 0 NOT-MEASURED;pnpm lintexit 0. Dogfood not re-run (one-file change inside the read path; CI runs it).objectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cy1y7UNVbT2QAdmgdn
Claim: area-lease pilot #33059, area E1 · 2026-11-14T15:32Z
Branch:
claude/area-E1-32354Account:
os-elon-muskClause-②: no (narrowing)
Metadata-protocol: none
Scope: the list-door remainder of this card (epic note 6820147040): the list naming no package, its execution face, and the lists scoped to a disabled base and to its pair, beside a disabled holder. PR #33130 (merged) did the bare, exact and layered reads.
Stacked on: PR #33251 (base branch
claude/project-thread-725bea), which edits the same list file; retarget tomainwhen it lands.File surface:
packages/metadata-protocol/src/protocol-meta-list-reads.ts, pins inpackages/objectql/src/package-scoped-exact-qualifier.test.tsandpackages/rest/src/meta-disabled-package-doors.test.ts, one changeset.Premise: holds, measured on
2b2e5b41(both registration orders, both save orders).objectstack-fleet commentedon Nov 14, 2026
domain:server#5 · os-elon-musk · session_016WV4cy1y7UNVbT2QAdmgdn
os-dev-report
{ "issue": 32354, "status": "done", "branch": "claude/area-E1-32354", "pr": "https://github.com/objectstack-ai/objectstack/pull/33405", "session": "session_016WV4cy1y7UNVbT2QAdmgdn", "premise_still_valid": true, "summary": "The list-door remainder of #32354 (epic note 6820147040). Measured first on 2b2e5b41 (#33251's head), both registration and save orders: with A disabled, the unscoped list and its execution face listed A's pair row and a dependent's fr-FR addition, and the lists scoped to A and to A.custom listed the pair row, while the exact reads answered 404. New predicate disabledHolderListing in protocol-meta-list-reads.ts (effective and execution faces only, only while some package is disabled, package-scoped types only): a scoped list drops a name whose exact read at that package is withheld (disabledExactAddressHolder, unchanged); the unscoped list drops an item whose own package's address is withheld, and a bundle addition whose every base in its dependency closure is disabled. The send naming no package stops sending them; a send from DEP itself also loses DEP's fr-FR while A is disabled (declared, #32670 restores it). Stacked on #33251 at first; after it merged, origin/main 87330e8959 was merged once (one import conflict and #33251's semantic-entry add/add taken as main's) and the draft PR targets main with Fixes #32354.", "tests": "head 333edb0868. objectql package-scoped-exact-qualifier.test.ts -t 32354: 14 passed (12 cases: four states x both registration orders x both save orders for pair rows, each asserting seven lists enabled, disabled read twice, re-enabled; plus 2 CONTROLs). REST meta-disabled-package-doors.test.ts: 47 passed (6 new: GET /meta/:type unscoped and package= A, A.custom, DEP, and the email loader send with no package and from DEP). Ablations via scripts/ablation-replace.mjs, metadata-protocol rebuilt under the lock, ablation-dist-preflight marker present, restored (git diff HEAD empty), rebuilt, --absent exit 0: A1 (exact-address arm off) objectql 8 failed / 6 passed, REST 4 failed / 43 passed (every pair-row case red, addition cases and CONTROLs green); A2 (addition arm off) objectql 4 failed / 10 passed, REST 2 failed / 45 passed. A first A2 attempt hit queue-timeout, preflight refused (marker absent), its green run was discarded and the leg rerun. Affected-set turbo test against main (82 packages, dogfood excluded) under the lock: stopped on the area lead's order after 68 packages finished, 0 failed test files, including metadata-protocol 339 files (9 skipped), objectql 595, rest 410, runtime 599, cli 637 (2 skipped), plugin-email 53.", "gates": "typecheck metadata-protocol, objectql, rest: os-verify-lock VERDICT command-exit 0. pnpm lint: exit 0. NOT MEASURED: dispatch-gates --commands derived families and --ran reconciliation (pilot pre-push set replaced them; CI Lint & Repo Gates runs them); CI check-runs on #33405 not yet reported at report time.", "dogfood_battery": "NOT MEASURED, reason: owed by the (narrowing) arm on 333edb0868, not run because the shared verify lock was starved and the area lead ordered the narrowed pre-push set; CI's Dogfood Regression Gate (queue) runs it", "mcp_calls": "0", "api_writes": "3 relay writes: claim comment POST /issues/32354/comments (6879804685), pr_create POST /pulls (#33405, assignee os-elon-musk), this os-dev-report comment POST /issues/32354/comments; plus 2 git pushes (empty branch, then the work)", "open_questions": [ { "question": "The bare by-name read still serves a disabled sole holder's pair row and a dependent's addition (measured below). Fixes #32354 closes the card on landing as ordered; should the bare-read leftover get its own card, or should #33405 say Part of #32354 instead?", "options": [ "A file a separate card for the bare read (protocol-meta-item-face.ts, after #32814), keep Fixes", "B edit #33405 to Part of #32354 and leave the card open for the bare read" ], "recommendation": "A, because the order scoped this PR to the list doors, the bare-read file is held by #32814's work, and a card with the measured repro is cheaper to route than an open epic card" } ], "security_findings": "none", "out_of_scope_findings": [ "class: a · reach: RestServer GET /meta/email_template/welcome?member=fr-FR (no package) on 333edb0868 with A the sole holder and disabled answers 200 with the row A.custom stores (pair fr-FR), and 200 with DEP's fr-FR addition; with an enabled second holder both answer 404 · evidence: scratch RestServer probe over the real protocol and registry; protocol.getMetaItem gives the same on 2b2e5b41 · path protocol-meta-item-face.ts (bare read), not edited (held by #32814) · dedupe words: disabled sole holder bare read pair member, dependent addition bare read disabled base, ADR-0150 D3 bare read", "carrier: #32670 · a send from a dependent of a disabled base reads the unscoped list, so it loses the dependent's own added locale while the base is disabled (declared in #33405)" ] }