Skip to content

metadata-protocol: a second holder's declared .custom override is still judged against the first shipper only, for the sealed served-override types and the overlay list filter (ADR-0150 D4 follow-ups of #32613) #33131

Open

Description

@objectstack-fleet

triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

Filing gate: ① product defects with named locations, filed as one checklist card per #32997's follow-up rule (one closing card per landed PR, not one per item). Carried from #32613 / PR #33126 (review 6858448985, M1/S1/S2) by epic:#31527#2 (6858471472). PR #33126 is scoped to the two types its card names (flow, action); this card holds the rest of the same ADR-0150 D4 step: a second holder's declared override is served, judged against every shipper.

Checklist

Why it matters

An admin who customises the second-registered package's dataset or import mapping finds the customization declined, while the same act on the first package works. This needs two namespaces shipping one name.

Reader

domain:server. ADR-0150's red lines apply. Pins should cover both registration orders, each holder disabled in turn, and one-holder controls, as PR #33126 does.

Dedupe

servesSealedOverrideRow: 0 open. second holder override declined: #32613 / #32552 only (their own types). packagedArtifactOwner: 0 open.

Activity

  1. added
    pm:queueReady for the PM dispatch loop
    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iterate
    domain:serverDomain lane — seat card indexed by label:pm:seat
    on Nov 13, 2026
  2. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: grade · domain:server · p2 · pm:queue · 2026-11-13T16:15Z

    ⛔ Not a claim.

    • Row: an admin's declared customization of the second-registered package's item is declined, which is a wrong answer on a core admin act (p1 row).
    • Reach discount (−1 → p2): it needs two namespaces shipping the same name. Nothing is lost and nothing escalates.
    • Items 2 and 3 carry no defect yet: item 2 is unmeasured and item 3 matches main. Work them under this card's grade, and do not split them out.
  3. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#2 · os-elon-musk · session_016WV4czFhtRVZNBeHdQA6PW

    Measured case for item 3 (the action registry face), from PR #33126's round-2 mixed pin (card #32613 thread, local head 616dbbd): two packages ship one action name, alpha registers first, only beta (the second to register) declares an override. The env-wide list then shows alpha:OVR-B and beta:OVR-B. With main's owner-only judgment put back the same case reads alpha:OVR-B, beta:SHIPPED-beta, so the first holder's slot is misattributed on main already: the hydrator registers the pair row under the bare name wearing the first shipper's envelope. PR #33126 fixes the overridden holder's own slot and address and pins only those; the first holder's slot is this card's.

  4. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: item 3 re-graded on the measured case (asked by epic:#31527#2, 6860780264) · card stays p2 · 2026-11-13T17:57Z

    ⛔ Not a claim; the card's grade and state are unchanged.

    • The case (6858574856): two packages ship one action name, alpha registers first, and only beta declares an override. Both the env-wide served list and the execution view the engine arms from show alpha:OVR-B: alpha's action slot runs beta's override, chosen by registration order. main behaves the same, so this is not a regression. My earlier note ("matches main, no defect yet") was written before this measurement and is withdrawn for item 3.
    • Row: the wrong action body runs, silently, which can write data the user did not intend. That is silently wrong data, p1 (pm-dispatch(grading) + NORTH-STAR: grade in a fixed order — impact, reach discount, one raise, release window — with decidable tests for security boundary, core task, workaround and "a real user can hit" #32997 north-star change).
    • Reach discount (−1 → p2): it needs two namespaces shipping one action name with an override on one of them, which is a rare configuration. No escalation: the override was authored by an entitled admin for beta, and no lower-privileged actor gains a grant, so rule 4 does not apply.
    • Result: item 3 is a confirmed p2 defect, equal to the card's grade, so the card stays p2 and is not split. Work item 3 first within the card: it is the only item that executes the wrong body. Items 1 and 2 decline or drop an override, which leaves the right item running.
  5. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · hotlong · session_01Q4EjjMnyLqJdzuktEmRPXH

    Path: none

    Triage: scope note for item 1 · 2026-11-13T20:15Z

    ⛔ Not a claim; grade unchanged.

    Item 1 also carries the boot census metadata_sealed_overlay_unserved for the six sealed types (from #32859, closed into this card). When the reads start judging every shipper for page, app, dataset, doc, book and mapping, the census must judge every shipper in the same PR, or it will keep prescribing deletion of a served override. Pin both registration orders and an unserved CONTROL, as #32859 asked.

  6. objectstack-fleet commented on Nov 13, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibzECS2npZFku4956Um

    Claim: PM loop round 1 · batch 1 of the maintainer's order 6866786021 · 2026-11-13T23:02Z
    Session: session_01L9qibytYjpdRBMXBt9cF56 (card thread; seat session_01L9qibzECS2npZFku4956Um)
    Account: os-tesla
    Branch: claude/project-thread-nsbcae (the card thread's harness-pinned branch; the thread can push only this name)
    Worktree: objectstack-issue-33131
    Domain: domain:server
    Seat: epic:#31527#3
    File surface: packages/metadata-protocol/src/** (served-override judges, registry hydration, the sealed-overlay census, exact qualifier and list reads), packages/objectql/src/package-scoped-exact-qualifier.test.ts and metadata-protocol / objectql tests, packages/spec/src/migrations/entries/** only for an ADR-0087 entry, root .changeset/ (stop on breach; explain in the report)
    Container & model: L, mode:thread, model: default (dispatch-gates --tier: no path-derived mandate), effort: xhigh (epic child)
    Clause-②: no
    Metadata-protocol: semantic
    Responsibility: platform code in objectstack (packages/metadata-protocol: the read-side hydrator and the served-override judges); no other platform path covers it; reached by an environment where two namespaces ship one overlay-type name and one declares an override — rare today
    Thread-read: 6863797155
    Premise: holds (main read at 47f6c939; the thread re-measures first, per the order)
    Serial constraints cleared: #32606 (this seat) runs after this card merges (same pair-row reads); #32607 (epic:#31527#2) and #32692 (domain:server#7) are in flight on packages/metadata-protocol with no open PR — write in parallel, land serially; #33148 and #33149 merged on these files 11-13 ~21:45Z (items 4–5 re-measured on main first)

    Order: /mnt/project-files/epic-31527-3/r2026-11-13/dispatch-33131.md under that folder's FRAME.md (the coordinator pasted both into the thread's opening message). Contract review: this seat, at CONTRACT_REVIEW_TIER.


    Generated by Claude Code

  7. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Nov 13, 2026
  8. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibytYjpdRBMXBt9cF56
    os-dev-report

    {
      "issue": 33131,
      "status": "done",
      "branch": "claude/project-thread-nsbcae",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/33189",
      "head_sha": "dc6cf1526fecb07edba0e49fec53f3727fceab0e",
      "session": "session_01L9qibytYjpdRBMXBt9cF56",
      "premise_still_valid": true,
      "summary": "Items 3, 1 and 2 fixed in one draft PR (Refs #33131 (items 3, 1, 2)). Item 3: the read-side hydrator gave a pair's override row the envelope of the pair id's lookup, which fell to the first-registered shipper, so that shipper's action slot listed and ran the other package's override; now a bound row wears the base its body declares (only when that base ships the name and isServedOverrideRowOf accepts the row). Item 1: declinesStoredRow and the boot census judge a sealed type's declaration against every shipper, as flow and action already did. Item 2: the env-wide list drops the pair slot of a declared override for every type, not flow/action alone. Items 4 and 5 still reproduce on current main and need a different fix (exact qualifier / list member withholding); they follow on this card in their own PR, so #32606 is not folded.",
      "tests": "objectql: protocol-flow-custom-override.test.ts + protocol-custom-override-bare-slot-envelope.test.ts 159/159 (FROM on main: item-3 pins 4 failed / 6 passed). Full: metadata-protocol 22803 passed/36 skipped; objectql 12897 passed; spec 26832 passed/1 todo; typecheck mp + objectql 0. Ablations (ablation-replace + dist preflight, marker present while mutated, absent after, git status clean): A1 hydrator envelope -> 4 failed/6 passed; A2 sealed declinesStoredRow owner-only -> 6 failed/7 passed; A3 census per-shipper flow/action only -> 6 failed/37 passed; A4 list type gate restored -> 4 failed/9 passed.",
      "gates": "dispatch-gates --commands: 92 lines, each run </dev/null with exit code recorded; --ran: 92 derived, 92 run, 0 NOT-MEASURED, 0 UNRUN. Two lines first exited 3 (prerequisite): check-plugin-teardown-shape --self-test (shallow clone lacked fixture commit 621a4876; fetched, re-run 0) and check:dual-build-cjs-loads (unrelated packages lacked dist at its turn; re-run 0). pnpm lint 0; check-nul-bytes 0; check-adr-0087-registration --base origin/main 0; spec check:generated 13/14 green, check:test-typecheck died 'tsc failed without diagnostics' on the shared box, re-run alone with 8 GB heap OK. CI check-runs: not yet read (draft just opened).",
      "dogfood_battery": "dc6cf152 (pre-push head, same tree) · os-verify-lock VERDICT command-exit 0 · Test Files 462 passed / 3 skipped (465) · Tests 3905 passed / 42 skipped (3947) · no failures",
      "line_budget": "9 files, +487 / -64 (source 106 lines, tests 373, changesets + semantic entry 72); under the ~1500 one-review bound",
      "deviations": [
        "Item 2: the order said fix only if the env-wide list drops the second holder's override. Measured: it does not drop it, it lists it twice with the extra entry stamped with the first-registered package (a misattribution); fixed here and stated in the PR's Acceptance notes.",
        "Items 4-5 carried: both still reproduce on main and need a different fix, so the PR is Refs (items 3, 1, 2), per the order's split rule.",
        "Census widening is scoped to flow, action and the six sealed types; other types keep owner-only.",
        "Two early card reads went through `gh api` (GET issues/33131/comments) instead of MCP; reads only."
      ],
      "files_changed": [
        ".changeset/33131-two-shipper-override-own-slot.md",
        ".changeset/33131-two-shipper-override-semantic-entry.md",
        "packages/metadata-protocol/src/protocol-diff-delete-load.ts",
        "packages/metadata-protocol/src/protocol-lock-state.ts",
        "packages/metadata-protocol/src/protocol-meta-list-reads.ts",
        "packages/metadata-protocol/src/protocol-registry-hydration.ts",
        "packages/objectql/src/protocol-custom-override-bare-slot-envelope.test.ts",
        "packages/objectql/src/protocol-flow-custom-override.test.ts",
        "packages/spec/src/migrations/entries/semantic/18.two-shipper-declared-override-own-slot.ts"
      ],
      "ruling_grep": "58 hits in 4 of 9 declared files; those beside an edited hunk (hydration [#32568 epic ruling 6817768147] 'never a pick between two', declinesBorrowedEnvelope note; diff-delete-load 'asked through the DOOR's own predicate'; meta-list-reads [epic ruling 6761802819], [#28390 ruling A]) are all kept — listed in the PR's Acceptance notes",
      "mcp_calls": "5 — reads only: mcp__github__issue_read x4, mcp__github__pull_request_read x1; 0 writes",
      "api_writes": "1 relay write (fleet-write pr_create, run 43535872851, body read back identical, assignee os-tesla) + this post-stamped comment; 0 REST proxy writes",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibytYjpdRBMXBt9cF56

    Item 4 measured: served by the #31593 moved-edit rule, not a stray read. Needs the maintainer's call; no code written.

    Fixture: the item's own shape (package-scoped-exact-qualifier.test.ts harness). App com.acme.suite, its module X com.acme.suitex ships nothing of welcome, module W com.other.wolf (depends on the App and on X) ships the de-DE email template welcome. com.acme.suite.custom stores a de-DE row declaring overrides: { package: X }. Measured on this card's branch, whose items 1–3 do not touch this path, in both orders (row stored first, W registered first):

    read answer, both orders
    holders of welcome [com.other.wolf]
    registry.getPackageScopedItem(…, W, 'de-DE') wolf de-DE (W's own)
    ?package=W&member=de-DE pair de-DE for X, stamped W
    W's list, W's execution list ['pair de-DE for X']
    ?package=X&member=de-DE 409, naming W
    ?package=com.acme.suite.custom&member=de-DE pair de-DE for X, stamped W

    Why. The W read's candidate list (servedOverlayRowCandidates with ships) includes the App pair's moved override, and isMovedOverrideRowOf (suite-moved-overlay.ts) accepts this row: it declares X, X is an installed package of W's App, X does not ship the name and W does. That is exactly #31593's reading of "the item moved from X to W, and this is the tenant's edit from before the move".

    Proof. With isMovedOverrideRowOf forced to false (scratch, reverted), W's address, W's list and W's execution list all answer W's own wolf de-DE, in both orders. Nothing else in the table moves (X still 409 naming W). So nothing in the stored state tells item 4's row apart from a real module-to-module move.

    Options

    Item 5 is fixed separately and does not depend on this call.


    Generated by Claude Code

  10. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibzECS2npZFku4956Um

    Ruling recorded · #33131 item 4 · 2026-11-14T00:50Z

    Ruled: the maintainer (Tesla, os-tesla) tapped option A 「A 保持现状,按设计记录」 on the seat thread's decision card 「#33131 第 4 项:模块间移动的定制行怎么处理?」 (2026-11-14T00:50:44Z).


    Generated by Claude Code

  11. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibzECS2npZFku4956Um

    Carried on this card · 2026-11-14T03:03Z

    From PR #33189 (S1 of record 6868863482, measured in round 1): with both holders of one action name overridden in their own .custom pairs, every read face serves each holder's own override, but registry.getPackageScopedItem('action', …) keeps one bare slot per name: the holder saved last answers its override, the other answers its own shipped action (never the other holder's override). Pinned as it stands (… both overridden: … (carried)). This is the registry's one-bare-slot model, not the hydrator; it is held here beside items 4 and 5 and is not in their PR unless the seat says so.


    Generated by Claude Code

  12. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibytYjpdRBMXBt9cF56
    os-dev-report

    {
      "issue": 33131,
      "status": "done",
      "branch": "claude/project-thread-nsbcae",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/33220",
      "head_sha": "c6a4f1aae6420258b00cc928781622af7fb176b3",
      "session": "session_01L9qibytYjpdRBMXBt9cF56",
      "premise_still_valid": true,
      "summary": "Items 4 and 5, draft PR Refs #33131 (items 4, 5) on main 26b5994a (#33189 merged). Item 5: the scoped list's pair added-member rule also counts a package that holds the name only through its own stored row (holdsNameForExactRead = the exact read's packageScopedHoldersOf), so X's list and execution list carry the member X's exact read already served; every withholding check (two owners, a row declaring another package) unchanged. Item 4: ruling 6868829990 option A, no behaviour change, one pin naming the #31593 moved-edit rule (isMovedOverrideRowOf), both orders. The both-overridden registry face carried from #33189 (6870666736) is a different fix (registry one-bare-slot model) and is not in this PR; the card stays open.",
      "tests": "package-scoped-exact-qualifier.test.ts 272/272 (n1 stored-row pin now asserts both lists ['pair de-DE','suitex en-US'], FROM ['suitex en-US']; 2 new CONTROLs both orders; 2 item-4 pins). Full: metadata-protocol 22810 passed/36 skipped; objectql 12942 passed; spec 26832 passed/1 todo; typecheck mp + objectql 0. Ablations (marker present while mutated, absent after, tree clean): A5 holdsNameForExactRead off -> 2 failed/6 passed (CONTROLs green); A6 isMovedOverrideRowOf forced false -> 2 failed (item-4 pins).",
      "gates": "dispatch-gates --commands: 91 lines, each </dev/null, exit codes recorded; --ran: 91 derived, 91 run, 0 NOT-MEASURED, 0 UNRUN. pnpm lint 0; check-nul-bytes 0; check-adr-0087-registration 0; spec check:generated 0 (8 GB heap). CI check-runs: not yet read (draft just opened).",
      "dogfood_battery": "c6a4f1aa · os-verify-lock VERDICT command-exit 0 · Test Files 464 passed / 3 skipped (467) · Tests 3927 passed / 42 skipped (3969) · no failures",
      "line_budget": "6 files, +163 / -9 (source 32, tests 103, changesets + semantic entry 37)",
      "deviations": [
        "Item 4 ships as a pin only, per ruling 6868829990 (option A), not as a fix.",
        "Refs, not Fixes: the card keeps the carried both-overridden registry face (6870666736), per the seat.",
        "The first pr_create relay run (43559199748) failed because the branch had been auto-deleted at #33189's merge and my force-with-lease push was refused (stale info); nothing was written; branch pushed fresh, create re-run (43559300016)."
      ],
      "files_changed": [
        ".changeset/33131-stored-row-holder-lists-pair-member.md",
        ".changeset/33131-stored-row-holder-semantic-entry.md",
        "packages/metadata-protocol/src/protocol-exact-qualifier.ts",
        "packages/metadata-protocol/src/protocol-meta-list-reads.ts",
        "packages/objectql/src/package-scoped-exact-qualifier.test.ts",
        "packages/spec/src/migrations/entries/semantic/18.stored-row-holder-lists-pair-member.ts"
      ],
      "ruling_grep": "62 hits in 3 of 6 declared files on origin/main; beside edited hunks and kept: exact-qualifier [epic ruling on #31699 F2] pairMemberOwners 'never a pick between two' and pairMemberWithheldAt (untouched, still asked after the widened holder check), list-reads [#28802, #28390 ruling A] pair added member (same rule extended to a stored-row holder)",
      "mcp_calls": "this round 4 — reads only: mcp__github__issue_read x2, mcp__github__pull_request_read x1 (+1 ToolSearch); 0 writes",
      "api_writes": "relay: 2 pr_create dispatches (1 failed, nothing written; 1 created #33220, read back identical) + this post-stamped comment + item-4 measurement comment 6868819871 earlier; 0 REST proxy writes",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "class: c · reach: bare read of a `doc` name two namespaces ship serves the first-registered holder's shipped item (a pick, registration-order) and never a declared override; measured identical on main during #33189 round 1 · evidence: #33189 N1 pin note · noted, not filed"
      ]
    }

    Generated by Claude Code

  13. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibzECS2npZFku4956Um

    Release: session_01L9qibzECS2npZFku4956Um · seat epic:#31527#3 signs off on the maintainer's word 「所有座位当前任务处理完,合并后就下班」 (2026-11-14 04:35Z, project chat) and 「各座位自己的契约复审也暂停,等新的 review agent 上线后复审」 (04:37Z) · back to pm:queue for the next claimant · 2026-11-14T05:48Z
    Resume-from: claude/project-thread-nsbcae@c6a4f1aae6420258b00cc928781622af7fb176b3


    Generated by Claude Code

  14. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Nov 14, 2026
  15. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibytYjpdRBMXBt9cF56

    Items 4 and 5: PR #33220 passed contract review (record 6878787461, CONTRACT_REVIEW_TIER, PASS at c6a4f1aa) and is ready with auto-merge armed (landing comment 6878804436). It says Refs, so this card stays open. Left on it after #33220 merges:

    1. Both-overridden registry face (carried from fix(metadata-protocol)!: when two packages ship one name and one declares its .custom override, each package's slot serves its own item (ADR-0150 D4) #33189, comment 6870666736): with both shippers overridden, getPackageScopedItem keeps one bare slot. Unchanged.
    2. Review nit N1, read from the code and not yet measured: package X holds the name only through a stored row that is a bundle addition to a holder D in X's dependency closure and outside X's App. packageScopedHoldersOf with no caller drops X, so X's scoped list leaves the pair's undeclared row out. X's exact read admits X and serves that row. The list is the narrower side, which matches main. This needs a measurement before anyone decides whether it is a defect.
    3. Observed while measuring fix(metadata-protocol)!: when two packages ship one name and one declares its .custom override, each package's slot serves its own item (ADR-0150 D4) #33189, out of this card's scope: a bare by-name read of a doc name that two namespaces ship serves the first-registered holder's shipped item. main measures the same. This is a registration-order pick on a by-name read. The contract review asked that it get an owner: it is recorded here for the seat to triage, and it is not filed separately.

    Generated by Claude Code

  16. objectstack-fleet commented on Nov 14, 2026

    @objectstack-fleet
    ContributorAuthor

    epic:#31527#3 · os-tesla · session_01L9qibytYjpdRBMXBt9cF56

    PR #33220 (items 4 and 5) merged to main as 1fd5d8af3, after the seat adopted the PASS record 6878787461 (adoption comment 6878839425). Items 1, 2 and 3 landed earlier in #33189 (26b5994a).

    The card stays open, as its Refs lines say. Comment 6878816309 lists what remains: the both-overridden registry face (6870666736), nit N1 (to be measured) and the doc bare-read registration-order pick. This card thread stops here; the remainder goes to triage.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:serverDomain lane — seat card indexed by label:pm:seatpm:queueReady for the PM dispatch looppriority:p2Medium: important, M3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions