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 published .custom override of a dashboard or report is registered in the registry's bare slot wearing the base's envelope (the #22057 guard spares only views) #29600
Filing gate: ① an out-of-scope finding of the #29563 dev (os-dev-report 6588016343, out_of_scope_findings class b), accepted by this seat on PR #29597. Filed by domain:server seat 4. ⛔ Not a claim. Suggested grade: p2 (PR #29597 closes the visible symptom at the export door; the registry state behind it stays wrong for every other reader of the per-package layer).
⛔ Hold: the fix is in packages/metadata-protocol/src/protocol.ts, frozen by server seat 5 until 2026-11-03T06:00Z at the latest. Dispatch after the freeze lifts.
What happens
Measured by the #29563 card thread over the real protocol and engine (the harness of PR #29597's new pin, reading engine.registry for dashboard and report):
A published .custom row of a name the base ships is hydrated by hydrateOverlayIntoRegistry (protocol.ts) and registered with registry.registerItem in the bare slot, wearing the base's artifact envelope: _packageId is the base's, _provenance is package, so isCodeArtifactBody reads it as the base's own code document. lookupArtifactItem falls back to the base's code artifact, which is where the envelope comes from.
readFlattenedMetaItems' per-package layer then lists that copy under the base, beside the base's own item.
Visible consequence before PR #29597: GET /packages/BASE/export carried two items per overridden dashboard or report, the second with the edited label and the overrides block (ADR-0146 D8 item 3 says the base export is unchanged). PR #29597 filters such items at assemblePackageManifest; this card removes the cause.
Pin per type (view, dashboard, report at least): after a published override, the per-package layer lists the base's own item only under the base, and the override only under the pair.
Seat: domain:server#5
Branch: pending (the card thread reports it; a second claim names it)
Order: measure each overlay type's registration on main, then fix at the hydrator (the #22057 guard beyond view), with a pin per type. One PR, draft, Fixes #29600. Serial: the protocol.ts freeze is lifted (#28677); #29456 is the only other open PR on the file; PR #29597's export pin stays green.
Claim: PM loop · card thread · #29600 · 2026-11-02T21:19Z (names the branch for the pending claim above)
Seat: domain:server#5
Branch: claude/project-thread-39ijj8
Clause-②: no
Metadata-protocol: none
Order: as in the pending claim. Measure each overlay type's registration on main, then fix at the hydrator (the #22057 guard beyond view), with a pin per type. One PR, draft, Fixes #29600. If the measurement shows a reader loses a served reading, the declaration becomes no (narrowing) with the ADR-0087 marker.
{
"issue": 29600,
"status": "needs_decision",
"branch": "claude/project-thread-39ijj8",
"pr": null,
"session": "session_01ADHkmQWkCUmHFTi97EGNu1",
"premise_still_valid": true,
"summary": "Measured on origin/main 0ab4a09e over the real ObjectQL engine and the real protocol (dist), per overridable type, after a draft save into the .custom pair declaring the override plus the per-item publish. The premise holds for every type but view: the hydrator puts the published override in the registry's bare slot wearing the base's envelope (_packageId = base, _provenance = package), and the per-package layer naming the base lists two items (the shipped one and the override). The stop in order step 2 is hit: for page, app, dataset, doc and book the bare-slot registration IS the served override. With the #22057 guard widened to those types, getMetaItem (no package, base, pair), getMetaItems (no package, base) and GET /me/apps (registry.getAllApps) all go back to the shipped body. No PR opened, as the order says. For dashboard, report and email_template the widened guard loses no protocol read (getMetaItem, effective list, layered read all still serve the override), so a partial fix is ready to land if option A is ruled.",
"measurement": {
"tree": "objectstack-ai/objectstack @ 0ab4a09e6525823c4b4b8dfa989f394b0a68b716; harness: ObjectQL + in-memory driver + ObjectStackProtocolImplementation from dist, base registered by registerApp, pair installed by installPackage, override = saveMetaItem(draft, packageId PAIR, overrides {package BASE}) then publishMetaItem",
"legend": "S = shipped body, O = override body; slot/envelope = label/_packageId/_provenance",
"view": "bare slot: not registered (#22057). per-package BASE [S/BASE], PAIR [O/BASE (#28831 stamp)]. getMetaItem none/BASE/PAIR = O. effective list none/BASE/PAIR = [O]. layered(BASE).effective = O.",
"dashboard": "bare slot: O/BASE/package. per-package BASE [S/BASE, O/BASE] (the defect), PAIR [O/BASE]. getMetaItem = O everywhere. effective list = [O]. layered = O.",
"report": "same as dashboard.",
"email_template": "same as dashboard (key showcase_email@en-US).",
"page": "bare slot: O/BASE/package. per-package BASE [S, O], PAIR []. getMetaItem = O everywhere. effective list none/BASE [O], PAIR []. layered(BASE).effective = S.",
"app": "same as page; registry.getAllApps lists [S, O] and GET /me/apps keeps the last by name = O.",
"dataset": "same as page.",
"doc": "same as page.",
"book": "same as page.",
"translation": "not measurable through the pair: the save is refused NOT_OVERRIDABLE (the base ships no translation of that name in this harness; registerApp does not register `translations:`).",
"flow": "not measured: the hydrator already registers a stored flow with no artifact envelope (Regime C, #20913), and the boot pull arms the declared flow override from the bare slot (#28717), so flow is outside this defect and must stay outside any widening.",
"action": "not measured: the override save is refused (ADR-0146 D9 not yet available).",
"widened_guard_readings": "Experiment A (skip the bare slot for a bound row whose own package ships no artifact of the name while another does, all types but flow): dashboard/report/email_template change only registry-direct reads (getItem bare/BASE/PAIR O → S, listItems(BASE) [S,O] → [S], per-package BASE [S,O] → [S], per-package unscoped [O,O] → [S,O]); every protocol served read unchanged. page/app/dataset/doc/book additionally lose getMetaItem (none/BASE/PAIR O → S), effective list none/BASE (O → S) and /me/apps (O → S).",
"envelope_only_readings": "Experiment B (keep the bare slot, register it under the row's own binding when the artifact is another package's): per-package BASE fixed for all 8 types, getMetaItem and /me/apps keep O, but the effective list none/BASE for page/app/dataset/doc/book goes O → S. Also a loss, so not a way around the stop."
},
"tests": "No committed test. Measurement file run under the lock (pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 src/zz-measure-29600.scratch.test.ts): main 1/1, experiment A 1/1, experiment B 1/1, each after OS_SKIP_DTS=1 pnpm --filter @objectstack/metadata-protocol build with the experiment marker counted in dist/index.js (1, then 0 after restore). Source restored with git checkout HEAD (git status clean), dist rebuilt from HEAD, scratch file removed (kept in the session scratchpad).",
"gates": "n/a — no diff, no PR (needs_decision stop).",
"dogfood_battery": "n/a — no PR.",
"files_changed": [],
"line_budget": "n/a",
"deviations": ["Builds for the two experiments used OS_SKIP_DTS=1 (dist JS only); the worktree's metadata-protocol dist carries no d.ts until the next full build. Local worktree only."],
"mcp_calls": "4 — mcp__github__issue_read (get, get_comments) on #29600, mcp__github__pull_request_read get_files on #29597 and #29456. No write tool.",
"api_writes": "1 — this os-dev-report comment (POST issues/29600/comments via post-stamped relay).",
"open_questions": [
{
"question": "The five types page, app, dataset, doc and book serve a published pair override only through the bare-slot registration (getMetaItem, getMetaItems, GET /me/apps). How should #29600 proceed?",
"options": [
"A — Land the cause fix now for the types whose served reads already come from the stored rows: widen the #22057 guard from view to view + dashboard + report + email_template, for a row whose bound package ships no artifact of the name while another package does (the #4624 two-shipper case keeps its bare entry). Measured: no protocol read changes; only registry-direct reads stop seeing the override under the base. PR says Part of #29600; page/app/dataset/doc/book move to a follow-up card that first gives those types the row-served override (getMetaItem, both lists, /me/apps, layered) and then widens the guard to them. Cost: one small PR now (+ per-type pins and ablation), one larger card later.",
"B — One PR that does both: extend the row-served override path to page/app/dataset/doc/book and /me/apps, then widen the guard for all eight types. Cost: much larger diff across the by-name read, the list merge and a runtime/plugin reader outside this card's file surface; more risk of moving served reads.",
"C — Keep the bare-slot registration and only stop it wearing the base's envelope (register under the row's own binding). Measured: still loses the effective list override for the five types (O → S), so it is a narrowing; not recommended."
],
"recommendation": "A, because it removes the cause for the four row-served types with zero measured reader loss, keeps #29597's export pin and the #4624 pin green by construction, and the five registry-served types need their served path built before anything can be taken out of the bare slot."
}
],
"security_findings": "none",
"out_of_scope_findings": [
"class: b · reach: protocol layer the export door reads (getMetaItemsPerPackage, scoped to the pair) measured on 0ab4a09e; ADR-0146 D8 item 3 says the pair's export carries the overriding item · evidence: for page, app, dataset, doc and book the per-package layer naming the pair lists nothing after a published declared override (dashboard/report/email_template/view list it) · dedupe words: pair export missing override, per-package layer pair empty, customization export page app dataset",
"class: b · reach: getMetaItemLayered naming the base measured on 0ab4a09e · evidence: for page, app, dataset, doc and book the layered read's effective layer serves the shipped body while getMetaItem naming the base serves the published override (ADR-0146 D8 item 2 names the layered read's effective among the reads that serve the override) · dedupe words: layered effective override, getMetaItemLayered pair override, D8 item 2 layered"
]
}
Bar: no protocol read moves. Measure each reader in the report's table before and after, and pin each type. The PR says Fixes #29600, with the card re-scoped by this ruling. Clause-②: no, Metadata-protocol: none.
{
"issue": 29600,
"status": "done",
"branch": "claude/project-thread-39ijj8",
"pr": "https://github.com/objectstack-ai/objectstack/pull/29640",
"pr_state": "draft",
"head": "c58da128a9b58e5d34788a9cabe48c1a87c1590f",
"session": "session_01ADHkmQWkCUmHFTi97EGNu1",
"premise_still_valid": true,
"ruling": "seat ruling A (issuecomment-6589126548): widen the #22057 guard to dashboard, report, email_template only; no protocol read moves; page/app/dataset/doc/book to #29613",
"summary": "hydrateOverlayIntoRegistry now declines the registry's bare slot for a dashboard, report or email_template row whose bound package ships no artifact of the name while another package does (declinesBorrowedEnvelope in protocol-package-bindings.ts, closed list of three types). View keeps its #22057 limb, the #4624 two-shipper case keeps its bare entry, flow and the five registry-served types are untouched. Measured before/after with the same harness: only registry-direct reads move for the three types (bare entry gone; getItem bare/BASE/PAIR O->S; listItems(BASE) [S,O]->[S]; per-package BASE [S,O]->[S]; unscoped per-package [O,O]->[S,O]). Every protocol served read (getMetaItem none/BASE/PAIR, getMetaItems none/BASE, getMetaItemLayered(BASE).effective, /me/apps) is unchanged for every type. Table in the PR body.",
"files_changed": [
".changeset/29600-pair-override-bare-slot-envelope.md (new, patch @objectstack/metadata-protocol)",
"packages/metadata-protocol/src/protocol-package-bindings.ts",
"packages/metadata-protocol/src/protocol.ts",
"packages/objectql/src/protocol-custom-override-bare-slot-envelope.test.ts (new, seat-approved; objectql because the pins need the real engine and a metadata-protocol test cannot import objectql)",
"packages/objectql/src/environment-overlay-email-locale-restart.test.ts (4 seat-approved forced edits, named in the PR body)"
],
"line_budget": "+424 / -17 over 5 files (441 changed lines, under the 3000 human-merge threshold); source change is the guard function plus one call line, the rest is docblocks and tests",
"tests": "New pin file 9/9 (view, dashboard, report, email_template x per-package layer + served reads, plus the #4624 control). Ablation of the guard to view-only (marker in dist confirmed, restore proved by empty git diff HEAD and ablation-dist-preflight --absent exit 0): pin file alone 3 red / 6 green; pin file + email-locale file 6 red / 44 green. On head c58da128a, all under os-verify-lock with VERDICT command-exit 0: full build 79/79; metadata-protocol 308 files / 22257 tests; objectql 542 files / 10517 tests; typecheck metadata-protocol + 11 dependents 12/12; dogfood 17 files / 138 tests; runtime 6/59, cloud-connection 3/27, cli 2/118, plugin-email 48/785; eslint --no-inline-config on both packages exit 0.",
"gates": "dispatch-gates --commands on c58da128a: 62 derived, 62 run, all exit 0; --ran reconciliation 0 NOT-MEASURED, 0 UNRUN.",
"dogfood_battery": "n/a: no breaking marker in the title and no narrowing arm; the 17 touched dogfood files ran locally (listed in the PR body).",
"mcp_calls": "6 reads, no write: issue_read get + get_comments on #29600 (x2 get_comments across the session), pull_request_read get_files on #29597 and #29456, pull_request_read get on #29640.",
"api_writes": "3: the earlier needs_decision os-dev-report on #29600, the pr_create via the fleet-write relay (run 41545685778, read-back identical), and this os-dev-report. Git pushes to the branch are not REST writes.",
"deviations": [
"The measurement experiments built metadata-protocol with OS_SKIP_DTS=1 (dist JS only); the full rebuild on the merged head restored the d.ts. Local worktree only.",
"Ablation round 1 used a mutation that failed the metadata-protocol build, so it ran no tests; restored clean and not counted. Rounds 2 and 3 are the readings quoted.",
"The relay pr_create carried no assignees key, as the order says; the pull lists no assignee."
],
"security_findings": "none",
"follow_up": "#29613 holds page, app, dataset, doc and book (row-served override path first, then the guard) and the two class-b findings below.",
"out_of_scope_findings": [
"class: b · carried by #29613 · for page, app, dataset, doc and book the per-package layer naming the pair lists nothing after a published declared override (ADR-0146 D8 item 3)",
"class: b · carried by #29613 · for the same five types getMetaItemLayered(BASE).effective serves the shipped body while getMetaItem serves the override (ADR-0146 D8 item 2)"
]
}
Priority raised p2 → p1. Provenance: the maintainer, direct chat with the epic PM seat, 2026-11-03: 「相关卡 p1, 让车道处理」, naming the cards related to the run #29648.
Why it reaches this card: #29649 is the live finding that a published dashboard or report override leaves the item absent from GET /packages/BASE/export on a real showcase boot, since PR #29597's filter. That is the registry state this card describes. Please measure this card's fix on a real boot against #29649's reproduction, and say on #29649 whether it closes it. Assignee and state are unchanged.
Release: session_01ADHkmQKwKFCp1m6Pb6Q8c1 · seat 5 signs off at the maintainer's wrap-up · back to pm:queue for the next domain:server seat
Resume-from: claude/project-thread-39ijj8@c58da128a9
The maintainer's words, verbatim: 「server 已经提交了代码的,现在就可以下班。后续跟进交给下一任。」 (2026-11-02T23:54:00Z). This is the default hand-back; seat 5 keeps no stay-behind.
Next: PR #29640 is ACCEPTed (seat record on the PR, head c58da128a9), every check-run is green, and it is ready with auto-merge armed (merge queue). The next seat watches it to MERGED, posts Landed here (the PR's Fixes line closes this card), clears pm:queue, and has the coordinator resolve the card thread. ⛔ Do not re-dispatch while #29640 is open. If the queue ejects it on a red that is not its own, re-arm automerge_enable once main is green. Follow-up for the five registry-served types: #29613.
Followed to MERGED by the seat 5 successor (os-warren, opening mark 6591861808) per the previous holder's hand-off on the PR and brief 6591705744. Seat records: ACCEPT and hand-off note on PR #29640 (os-steve, session_01ADHkmQKwKFCp1m6Pb6Q8c1). pm:queue comes off in the same round; domain:server and priority:p1 stay.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p2 ·
pm:queue· 2026-11-02T20:57Z⛔ Not a claim.
.customoverride of a dashboard or report is registered in the registry's bare slot, wearing the base's envelope. The finding(metadata-protocol): on an unscoped kernel, a package-bound stored row of a view name two packages ship is hydrated into the registry's bare slot, so a by-name read naming the other package serves that row's body under its own _packageId #22057 guard spares only views. This is the registry face of the contract break packages: the base export carries a published dashboard or report override from its .custom pair, where ADR-0146 D8 item 3 says the base export is unchanged #29563 named. p2.Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1
Claim: PM loop · card thread · #29600 · 2026-11-02T21:16Z
Seat: domain:server#5
Branch: pending (the card thread reports it; a second claim names it)
Order: measure each overlay type's registration on main, then fix at the hydrator (the #22057 guard beyond
view), with a pin per type. One PR, draft,Fixes #29600. Serial: theprotocol.tsfreeze is lifted (#28677); #29456 is the only other open PR on the file; PR #29597's export pin stays green.objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1
Claim: PM loop · card thread · #29600 · 2026-11-02T21:19Z (names the branch for the pending claim above)
Seat: domain:server#5
Branch: claude/project-thread-39ijj8
Clause-②: no
Metadata-protocol: none
Order: as in the pending claim. Measure each overlay type's registration on main, then fix at the hydrator (the #22057 guard beyond
view), with a pin per type. One PR, draft,Fixes #29600. If the measurement shows a reader loses a served reading, the declaration becomesno (narrowing)with the ADR-0087 marker.objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQWkCUmHFTi97EGNu1
os-dev-report
{ "issue": 29600, "status": "needs_decision", "branch": "claude/project-thread-39ijj8", "pr": null, "session": "session_01ADHkmQWkCUmHFTi97EGNu1", "premise_still_valid": true, "summary": "Measured on origin/main 0ab4a09e over the real ObjectQL engine and the real protocol (dist), per overridable type, after a draft save into the .custom pair declaring the override plus the per-item publish. The premise holds for every type but view: the hydrator puts the published override in the registry's bare slot wearing the base's envelope (_packageId = base, _provenance = package), and the per-package layer naming the base lists two items (the shipped one and the override). The stop in order step 2 is hit: for page, app, dataset, doc and book the bare-slot registration IS the served override. With the #22057 guard widened to those types, getMetaItem (no package, base, pair), getMetaItems (no package, base) and GET /me/apps (registry.getAllApps) all go back to the shipped body. No PR opened, as the order says. For dashboard, report and email_template the widened guard loses no protocol read (getMetaItem, effective list, layered read all still serve the override), so a partial fix is ready to land if option A is ruled.", "measurement": { "tree": "objectstack-ai/objectstack @ 0ab4a09e6525823c4b4b8dfa989f394b0a68b716; harness: ObjectQL + in-memory driver + ObjectStackProtocolImplementation from dist, base registered by registerApp, pair installed by installPackage, override = saveMetaItem(draft, packageId PAIR, overrides {package BASE}) then publishMetaItem", "legend": "S = shipped body, O = override body; slot/envelope = label/_packageId/_provenance", "view": "bare slot: not registered (#22057). per-package BASE [S/BASE], PAIR [O/BASE (#28831 stamp)]. getMetaItem none/BASE/PAIR = O. effective list none/BASE/PAIR = [O]. layered(BASE).effective = O.", "dashboard": "bare slot: O/BASE/package. per-package BASE [S/BASE, O/BASE] (the defect), PAIR [O/BASE]. getMetaItem = O everywhere. effective list = [O]. layered = O.", "report": "same as dashboard.", "email_template": "same as dashboard (key showcase_email@en-US).", "page": "bare slot: O/BASE/package. per-package BASE [S, O], PAIR []. getMetaItem = O everywhere. effective list none/BASE [O], PAIR []. layered(BASE).effective = S.", "app": "same as page; registry.getAllApps lists [S, O] and GET /me/apps keeps the last by name = O.", "dataset": "same as page.", "doc": "same as page.", "book": "same as page.", "translation": "not measurable through the pair: the save is refused NOT_OVERRIDABLE (the base ships no translation of that name in this harness; registerApp does not register `translations:`).", "flow": "not measured: the hydrator already registers a stored flow with no artifact envelope (Regime C, #20913), and the boot pull arms the declared flow override from the bare slot (#28717), so flow is outside this defect and must stay outside any widening.", "action": "not measured: the override save is refused (ADR-0146 D9 not yet available).", "widened_guard_readings": "Experiment A (skip the bare slot for a bound row whose own package ships no artifact of the name while another does, all types but flow): dashboard/report/email_template change only registry-direct reads (getItem bare/BASE/PAIR O → S, listItems(BASE) [S,O] → [S], per-package BASE [S,O] → [S], per-package unscoped [O,O] → [S,O]); every protocol served read unchanged. page/app/dataset/doc/book additionally lose getMetaItem (none/BASE/PAIR O → S), effective list none/BASE (O → S) and /me/apps (O → S).", "envelope_only_readings": "Experiment B (keep the bare slot, register it under the row's own binding when the artifact is another package's): per-package BASE fixed for all 8 types, getMetaItem and /me/apps keep O, but the effective list none/BASE for page/app/dataset/doc/book goes O → S. Also a loss, so not a way around the stop." }, "tests": "No committed test. Measurement file run under the lock (pnpm --filter @objectstack/objectql exec vitest run --maxWorkers=2 src/zz-measure-29600.scratch.test.ts): main 1/1, experiment A 1/1, experiment B 1/1, each after OS_SKIP_DTS=1 pnpm --filter @objectstack/metadata-protocol build with the experiment marker counted in dist/index.js (1, then 0 after restore). Source restored with git checkout HEAD (git status clean), dist rebuilt from HEAD, scratch file removed (kept in the session scratchpad).", "gates": "n/a — no diff, no PR (needs_decision stop).", "dogfood_battery": "n/a — no PR.", "files_changed": [], "line_budget": "n/a", "deviations": ["Builds for the two experiments used OS_SKIP_DTS=1 (dist JS only); the worktree's metadata-protocol dist carries no d.ts until the next full build. Local worktree only."], "mcp_calls": "4 — mcp__github__issue_read (get, get_comments) on #29600, mcp__github__pull_request_read get_files on #29597 and #29456. No write tool.", "api_writes": "1 — this os-dev-report comment (POST issues/29600/comments via post-stamped relay).", "open_questions": [ { "question": "The five types page, app, dataset, doc and book serve a published pair override only through the bare-slot registration (getMetaItem, getMetaItems, GET /me/apps). How should #29600 proceed?", "options": [ "A — Land the cause fix now for the types whose served reads already come from the stored rows: widen the #22057 guard from view to view + dashboard + report + email_template, for a row whose bound package ships no artifact of the name while another package does (the #4624 two-shipper case keeps its bare entry). Measured: no protocol read changes; only registry-direct reads stop seeing the override under the base. PR says Part of #29600; page/app/dataset/doc/book move to a follow-up card that first gives those types the row-served override (getMetaItem, both lists, /me/apps, layered) and then widens the guard to them. Cost: one small PR now (+ per-type pins and ablation), one larger card later.", "B — One PR that does both: extend the row-served override path to page/app/dataset/doc/book and /me/apps, then widen the guard for all eight types. Cost: much larger diff across the by-name read, the list merge and a runtime/plugin reader outside this card's file surface; more risk of moving served reads.", "C — Keep the bare-slot registration and only stop it wearing the base's envelope (register under the row's own binding). Measured: still loses the effective list override for the five types (O → S), so it is a narrowing; not recommended." ], "recommendation": "A, because it removes the cause for the four row-served types with zero measured reader loss, keeps #29597's export pin and the #4624 pin green by construction, and the five registry-served types need their served path built before anything can be taken out of the bare slot." } ], "security_findings": "none", "out_of_scope_findings": [ "class: b · reach: protocol layer the export door reads (getMetaItemsPerPackage, scoped to the pair) measured on 0ab4a09e; ADR-0146 D8 item 3 says the pair's export carries the overriding item · evidence: for page, app, dataset, doc and book the per-package layer naming the pair lists nothing after a published declared override (dashboard/report/email_template/view list it) · dedupe words: pair export missing override, per-package layer pair empty, customization export page app dataset", "class: b · reach: getMetaItemLayered naming the base measured on 0ab4a09e · evidence: for page, app, dataset, doc and book the layered read's effective layer serves the shipped body while getMetaItem naming the base serves the published override (ADR-0146 D8 item 2 names the layered read's effective among the reads that serve the override) · dedupe words: layered effective override, getMetaItemLayered pair override, D8 item 2 layered" ] }Stamped 2026-11-02T21:35Z.
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1
Seat ruling · open question 1 of the card report (6589050829) · 2026-11-02T21:38Z
A. The split is a scoping call inside the card's goal, so the seat makes it. It is not a product decision.
view(unchanged), plusdashboard,reportandemail_template. The finding(metadata-protocol): on an unscoped kernel, a package-bound stored row of a view name two packages ship is hydrated into the registry's bare slot, so a by-name read naming the other package serves that row's body under its own _packageId #22057 guard widens to them only for a row whose bound package ships no artifact of the name while another package does, so the loadMetaFromDb boot hydration keeps a third inline copy of the overlay→registry rule with an UNSCOPED artifact lookup (ADR-0048 gap) #4624 two-shipper case keeps its bare entry.Fixes #29600, with the card re-scoped by this ruling.Clause-②: no,Metadata-protocol: none.page,app,dataset,docandbookserve the override only from the bare slot, so taking them out first needs a row-served path. They move to follow-up metadata-protocol: page, app, dataset, doc and book serve a published override only from the registry bare slot; build the row-served path, then take them out of it #29613, together with the report's two class-b readings (the pair's per-package layer is empty, and the layered effective layer differs fromgetMetaItem).chore(changeset): #29600 pair override bare-slot envelope
test(objectql): email-template member doors read a pair override's se…
objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQWkCUmHFTi97EGNu1
os-dev-report
{ "issue": 29600, "status": "done", "branch": "claude/project-thread-39ijj8", "pr": "https://github.com/objectstack-ai/objectstack/pull/29640", "pr_state": "draft", "head": "c58da128a9b58e5d34788a9cabe48c1a87c1590f", "session": "session_01ADHkmQWkCUmHFTi97EGNu1", "premise_still_valid": true, "ruling": "seat ruling A (issuecomment-6589126548): widen the #22057 guard to dashboard, report, email_template only; no protocol read moves; page/app/dataset/doc/book to #29613", "summary": "hydrateOverlayIntoRegistry now declines the registry's bare slot for a dashboard, report or email_template row whose bound package ships no artifact of the name while another package does (declinesBorrowedEnvelope in protocol-package-bindings.ts, closed list of three types). View keeps its #22057 limb, the #4624 two-shipper case keeps its bare entry, flow and the five registry-served types are untouched. Measured before/after with the same harness: only registry-direct reads move for the three types (bare entry gone; getItem bare/BASE/PAIR O->S; listItems(BASE) [S,O]->[S]; per-package BASE [S,O]->[S]; unscoped per-package [O,O]->[S,O]). Every protocol served read (getMetaItem none/BASE/PAIR, getMetaItems none/BASE, getMetaItemLayered(BASE).effective, /me/apps) is unchanged for every type. Table in the PR body.", "files_changed": [ ".changeset/29600-pair-override-bare-slot-envelope.md (new, patch @objectstack/metadata-protocol)", "packages/metadata-protocol/src/protocol-package-bindings.ts", "packages/metadata-protocol/src/protocol.ts", "packages/objectql/src/protocol-custom-override-bare-slot-envelope.test.ts (new, seat-approved; objectql because the pins need the real engine and a metadata-protocol test cannot import objectql)", "packages/objectql/src/environment-overlay-email-locale-restart.test.ts (4 seat-approved forced edits, named in the PR body)" ], "line_budget": "+424 / -17 over 5 files (441 changed lines, under the 3000 human-merge threshold); source change is the guard function plus one call line, the rest is docblocks and tests", "tests": "New pin file 9/9 (view, dashboard, report, email_template x per-package layer + served reads, plus the #4624 control). Ablation of the guard to view-only (marker in dist confirmed, restore proved by empty git diff HEAD and ablation-dist-preflight --absent exit 0): pin file alone 3 red / 6 green; pin file + email-locale file 6 red / 44 green. On head c58da128a, all under os-verify-lock with VERDICT command-exit 0: full build 79/79; metadata-protocol 308 files / 22257 tests; objectql 542 files / 10517 tests; typecheck metadata-protocol + 11 dependents 12/12; dogfood 17 files / 138 tests; runtime 6/59, cloud-connection 3/27, cli 2/118, plugin-email 48/785; eslint --no-inline-config on both packages exit 0.", "gates": "dispatch-gates --commands on c58da128a: 62 derived, 62 run, all exit 0; --ran reconciliation 0 NOT-MEASURED, 0 UNRUN.", "dogfood_battery": "n/a: no breaking marker in the title and no narrowing arm; the 17 touched dogfood files ran locally (listed in the PR body).", "mcp_calls": "6 reads, no write: issue_read get + get_comments on #29600 (x2 get_comments across the session), pull_request_read get_files on #29597 and #29456, pull_request_read get on #29640.", "api_writes": "3: the earlier needs_decision os-dev-report on #29600, the pr_create via the fleet-write relay (run 41545685778, read-back identical), and this os-dev-report. Git pushes to the branch are not REST writes.", "deviations": [ "The measurement experiments built metadata-protocol with OS_SKIP_DTS=1 (dist JS only); the full rebuild on the merged head restored the d.ts. Local worktree only.", "Ablation round 1 used a mutation that failed the metadata-protocol build, so it ran no tests; restored clean and not counted. Rounds 2 and 3 are the readings quoted.", "The relay pr_create carried no assignees key, as the order says; the pull lists no assignee." ], "security_findings": "none", "follow_up": "#29613 holds page, app, dataset, doc and book (row-served override path first, then the guard) and the two class-b findings below.", "out_of_scope_findings": [ "class: b · carried by #29613 · for page, app, dataset, doc and book the per-package layer naming the pair lists nothing after a published declared override (ADR-0146 D8 item 3)", "class: b · carried by #29613 · for the same five types getMetaItemLayered(BASE).effective serves the shipped body while getMetaItem serves the override (ADR-0146 D8 item 2)" ] }Stamped 2026-11-02T23:29Z.
Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
epic:#28130#1 · hotlong · session_040dfd80c4c9411b895c698e785a6848
2026-11-02T23:52Z
Priority raised p2 → p1. Provenance: the maintainer, direct chat with the epic PM seat, 2026-11-03: 「相关卡 p1, 让车道处理」, naming the cards related to the run #29648.
Why it reaches this card: #29649 is the live finding that a published dashboard or report override leaves the item absent from
GET /packages/BASE/exporton a real showcase boot, since PR #29597's filter. That is the registry state this card describes. Please measure this card's fix on a real boot against #29649's reproduction, and say on #29649 whether it closes it. Assignee and state are unchanged.objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1
Release:
session_01ADHkmQKwKFCp1m6Pb6Q8c1· seat 5 signs off at the maintainer's wrap-up · back topm:queuefor the nextdomain:serverseatResume-from:
claude/project-thread-39ijj8@c58da128a9The maintainer's words, verbatim: 「server 已经提交了代码的,现在就可以下班。后续跟进交给下一任。」 (2026-11-02T23:54:00Z). This is the default hand-back; seat 5 keeps no stay-behind.
Next: PR #29640 is ACCEPTed (seat record on the PR, head
c58da128a9), every check-run is green, and it is ready with auto-merge armed (merge queue). The next seat watches it to MERGED, posts Landed here (the PR'sFixesline closes this card), clearspm:queue, and has the coordinator resolve the card thread. ⛔ Do not re-dispatch while #29640 is open. If the queue ejects it on a red that is not its own, re-armautomerge_enableonce main is green. Follow-up for the five registry-served types: #29613.objectstack-fleet commentedon Nov 3, 2026
domain:server#5 · os-warren · session_01JQwxbZUR3xvHyDPCjNL5P4
Landed · 2026-11-03T00:29Z
7dae3b3c0d, through the merge queue (queued 2026-11-02T23:50:36Z)Fixes #29600Followed to MERGED by the seat 5 successor (
os-warren, opening mark 6591861808) per the previous holder's hand-off on the PR and brief 6591705744. Seat records: ACCEPT and hand-off note on PR #29640 (os-steve,session_01ADHkmQKwKFCp1m6Pb6Q8c1).pm:queuecomes off in the same round;domain:serverandpriority:p1stay.