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
meta: with two package holders of one dashboard name, GET /meta/dashboard/X/layers silently returns one holder's overlay while package-less save and delete answer 409 #28337
Filing gate: ① an observed, reproduced inconsistency from the 18.3.0 release-candidate run. W3-C2b, record #27438, at c4c515ad, parked on the wave anchor #27377 as a ruling finding. Item: platform-core.metadata-registry-serving. ⛔ Not a claim; triage grades and routes. Suggested labels are suggestions only.
Observed
The record (W3-C2b comment 6494110310 on #27377) reads, verbatim:
with two package holders, GET /meta/dashboard/X/layers silently returns one holder's overlay, while the package-less save and delete on that name answer 409.
When two packages both hold a dashboard of the same name:
the read door (/layers) picks one holder silently;
the write doors (a save or delete without ?package=) refuse with 409, because the name is ambiguous.
One name gives two answers to the same ambiguity. A reader of /layers, whether the Studio or an agent, cannot tell that a second holder exists, or which holder it got.
Why it may matter
Who: anyone who installs two packages that ship the same dashboard name, and the Studio or agent reading layers for it.
What happens: the layer stack shown or edited belongs to whichever holder /layers picked, while a save on the same name is refused. This invites a wrong edit target or a confusing refusal.
Not measured: how often two holders of one dashboard name occur in real installs, and which holder /layers picks (registration order?).
Possible directions (for the owner and triage; not a recommendation)
/layers refuses the same way the write doors do (409 plus the holders' package ids), or requires ?package=;
or /layers returns every holder's stack, keyed by package;
or the current behaviour is ruled correct and documented, in which case the checklist item records it.
Read fresh, from the 18.3.0 RC run. With two package holders of one dashboard name, /layers silently picks one holder, while the package-less writes refuse with 409. Two package holders of one name are rare, so the grade is p3.
Triage's lean is the card's first direction: /layers without ?package= refuses the same way the writes do (409, naming the holders, with the ?package= prescription). One answer to one ambiguity. It is a narrowing, Clause-②: no.
Claim: PM loop round 4 · card thread · 2026-11-01T04:28Z
Session: session_0186vfjHHMsRXC9EUT9hTFMo (the seat); the card thread is session_01FEkQ5o95tvF7A7y85W37iR
Account: os-project-manager (the seat's linked user; the card's assignee)
Branch: claude/project-thread-0r3khj (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
Worktree: the card thread's own container checkout
Domain: domain:server
Seat: domain:server#2
Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. Triage 6539811535: /layers without ?package= refuses the same way the package-less writes do (409, naming the holders, with the ?package= prescription); a narrowing. The order reuses the writes' judge, with no new refusal shape.
File surface: the layered metadata read (GET {metaPath}/:type/:name/layers and ?layers=true) in packages/rest/src/meta-* and packages/metadata-protocol/src/**, the existing ambiguous-name judge it reuses, tests, and changesets. ⛔ No ui/** edit.
Container & model: M, mode:thread, model: opus (--tier names no path mandate: PM's call, default), effort: high
Clause-②: no (narrowing — a read answered 200 today is refused; a contract review at CONTRACT_REVIEW_TIER is owed before the queue)
Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the code is the metadata protocol's layered read · the platform path is the Studio's and agents' layer view of an item · reached by anyone reading layers for a name two installed packages both hold
Thread-read: none
Premise: holds (per the RC record 6494110310 on #27377; the dev reproduces it on origin/main first)
Serial constraints cleared: no open PR touches the layered read at this read (the dev re-checks)
Resume-from: none — fresh from origin/main
State: → pm:dispatched, assigned to os-project-manager, recorded by this claim.
domain:server#2 · os-project-manager · session_01FEkQ5o95tvF7A7y85W37iR
os-dev-report
{
"issue": 28337,
"status": "done",
"branch": "claude/project-thread-0r3khj",
"pr": "#28583",
"session": "session_01FEkQ5o95tvF7A7y85W37iR",
"premise_still_valid": true,
"summary": "Red first on origin/main: GET /meta/dashboard/twin_dash/layers with twin_dash held by two packages answered 200 with one holder's overlay, while PUT/DELETE naming no package answered 409 RESOURCE_CONFLICT. The shared layered chain createMetaLayeredAnswer (packages/rest/src/meta-item-read-gate.ts) gains step 1c: with no ?package= it asks the new protocol judge packagelessLayeredReadRefusal (metadata-protocol), which reuses packagelessAddress + packagelessAddressAmbiguityRefusal (verb 'layered read'), and throws that refusal to each transport's existing catch, so /layers and ?layers=true answer the same code, status, holders and message family as the package-less save on RestServer and on the runtime dispatcher. ?package= still reads that holder's stack; a name one package holds, or a package-unbound row, answers as before; in-process getMetaItemLayered is unchanged (its package-less in-process callers are not doors). Card assignee untouched; PR opened draft, no assignees, no labels (changesets present).",
"tests": "New: metadata-protocol protocol.packageless-layered-read-refusal.test.ts 3/3 (full refusal sentence pinned); rest meta-layers-ambiguous-package.test.ts 3/3 (real protocol + registry, in-memory sys_metadata); runtime domains/meta-layers-ambiguous-package.test.ts 4/4 (better-sqlite3, real protocol, RestServer handlers + catch-all into HttpDispatcher.dispatch, both spellings, read compared with the same door's PUT/DELETE answer). Red first: base rest src answered {status:200} for the two-holder read. Ablation: if (ambiguity) throw ambiguity; -> void ambiguity;, rest rebuilt, ablation-dist-preflight confirmed marker absent in dist; only two-holder cases red (rest 1/3, runtime 2/4); restored blob == HEAD, rebuilt, runtime 4/4. Package suites: metadata-protocol 290 files passed / 4 skipped, 21897 tests passed; rest 363 files, 6907 tests passed (both at b8f5998); runtime 500/500 files, 8095 tests passed (913e990 tree; b8f5998 only adds the changeset/ledger lines). typecheck exit 0 for all three; eslint exit 0 on the ten touched files.",
"gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 71/71 exit 0 at b8f5998 (exit codes captured before any pipe), --ran reconciliation 0 NOT-MEASURED. First-loop non-zero exits fixed then re-run: check:engine-double-contract exit 1 -> ledger --write committed -> 0; check-plugin-teardown-shape --self-test exit 3 (shallow clone missing its pinned commit) -> fetched 621a487 -> 0; check:dual-build-cjs-loads exit 3 (no dist) -> pnpm build --concurrency=2 -> 0; check:type-check-debt exit 3 (lock queue behind dogfood) -> 0. platform-checklist, commit trailers, nul-bytes 0. PR check-runs at b8f5998 when this report was written: Governed Surface Queue Guard success; Build Core, Check Changeset, Lint families, Type Check families, PR-body guards, Test UI, Live E2E UI, Dogfood Regression Gate queued/in_progress; opt-in families skipped. Not re-run locally; the seat reads them before landing.",
"dogfood_battery": "b8f5998e · VERDICT command-exit 0 · Test Files 363 passed / 3 skipped (366) · Tests 2932 passed / 28 skipped · no failures",
"mcp_calls": "0",
"api_writes": "2 — fleet-write relay: pr_create (#28583, draft, read back 12799/12799 bytes identical, assignees none); post-stamped comment on #28337 (this report). Plus git push (not a REST write).",
"open_questions": [],
"out_of_scope_findings": [
"Seam (ui lane, not filed, no ui/** edit): spec:GET /meta/:type/:name/layers (package-less) -> renderer: Studio MetadataClient.layered and other package-less /layers callers in ui/. After this lands, a name two packages hold answers those callers 409 RESOURCE_CONFLICT instead of one holder's stack; they need to pass ?package= (or surface the refusal). reach: public door, measured by the runtime test above. carrier: ui lane via seat 2. dedupe words: layers package-less 409, MetadataClient.layered package, Studio layered view ambiguous package",
"carrier: seat 2 · noted, not filed — open PRs #28554 (protocol.ts, engine-double-contract.pinned.json) and #28512 (protocol.ts) touch the same files; textual overlap only, whichever lands second rebases"
]
}
Landed (Fixes): merged as cd065d36. The layered view of a name two packages hold, read with no ?package=, now refuses with the same 409 the package-less save and delete answer, naming the holders and prescribing ?package=. It no longer silently picks one holder. Both /:type/:name/layers and ?layers=true behave this way, on both doors.
Unchanged:?package=<id> reads that holder's stack. A name with one stored holder reads as before, including a base and its .custom override.
Activity
objectstack-fleet commentedon Oct 31, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: 错的必须被响亮拒绝并给处方 | none | P③
Triage: p3 ·
domain:server·area:studio· 2026-10-31T05:56Z⛔ Not a claim.
/layerssilently picks one holder, while the package-less writes refuse with 409. Two package holders of one name are rare, so the grade is p3./layerswithout?package=refuses the same way the writes do (409, naming the holders, with the?package=prescription). One answer to one ambiguity. It is a narrowing,Clause-②: no.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Claim: PM loop round 4 · card thread · 2026-11-01T04:28Z
Session:
session_0186vfjHHMsRXC9EUT9hTFMo(the seat); the card thread issession_01FEkQ5o95tvF7A7y85W37iRAccount:
os-project-manager(the seat's linked user; the card's assignee)Branch:
claude/project-thread-0r3khj(the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)Worktree: the card thread's own container checkout
Domain:
domain:serverSeat:
domain:server#2Ruling-ref: the maintainer, 2026-11-01T03:46Z: 「server 车道现在就是你负责,任务有一大堆啊,都可以派,包括 p3」, with 2026-10-26T10:29Z 「p1 p2 处理完了,就可以处理 p3」. Triage
6539811535:/layerswithout?package=refuses the same way the package-less writes do (409, naming the holders, with the?package=prescription); a narrowing. The order reuses the writes' judge, with no new refusal shape.File surface: the layered metadata read (
GET {metaPath}/:type/:name/layersand?layers=true) inpackages/rest/src/meta-*andpackages/metadata-protocol/src/**, the existing ambiguous-name judge it reuses, tests, and changesets. ⛔ Noui/**edit.Container & model:
M,mode:thread,model: opus(--tiernames no path mandate: PM's call, default),effort: highClause-②: no (narrowing — a read answered 200 today is refused; a contract review at
CONTRACT_REVIEW_TIERis owed before the queue)Metadata-protocol: none (expected; the dev measures and declares)
Responsibility: the code is the metadata protocol's layered read · the platform path is the Studio's and agents' layer view of an item · reached by anyone reading layers for a name two installed packages both hold
Thread-read: none
Premise: holds (per the RC record 6494110310 on #27377; the dev reproduces it on
origin/mainfirst)Serial constraints cleared: no open PR touches the layered read at this read (the dev re-checks)
Resume-from: none — fresh from
origin/mainState: →
pm:dispatched, assigned toos-project-manager, recorded by this claim.Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_01FEkQ5o95tvF7A7y85W37iR
os-dev-report
{
"issue": 28337,
"status": "done",
"branch": "claude/project-thread-0r3khj",
"pr": "#28583",
"session": "session_01FEkQ5o95tvF7A7y85W37iR",
"premise_still_valid": true,
"summary": "Red first on origin/main: GET /meta/dashboard/twin_dash/layers with twin_dash held by two packages answered 200 with one holder's overlay, while PUT/DELETE naming no package answered 409 RESOURCE_CONFLICT. The shared layered chain createMetaLayeredAnswer (packages/rest/src/meta-item-read-gate.ts) gains step 1c: with no ?package= it asks the new protocol judge packagelessLayeredReadRefusal (metadata-protocol), which reuses packagelessAddress + packagelessAddressAmbiguityRefusal (verb 'layered read'), and throws that refusal to each transport's existing catch, so /layers and ?layers=true answer the same code, status, holders and message family as the package-less save on RestServer and on the runtime dispatcher. ?package= still reads that holder's stack; a name one package holds, or a package-unbound row, answers as before; in-process getMetaItemLayered is unchanged (its package-less in-process callers are not doors). Card assignee untouched; PR opened draft, no assignees, no labels (changesets present).",
"tests": "New: metadata-protocol protocol.packageless-layered-read-refusal.test.ts 3/3 (full refusal sentence pinned); rest meta-layers-ambiguous-package.test.ts 3/3 (real protocol + registry, in-memory sys_metadata); runtime domains/meta-layers-ambiguous-package.test.ts 4/4 (better-sqlite3, real protocol, RestServer handlers + catch-all into HttpDispatcher.dispatch, both spellings, read compared with the same door's PUT/DELETE answer). Red first: base rest src answered {status:200} for the two-holder read. Ablation:
if (ambiguity) throw ambiguity;->void ambiguity;, rest rebuilt, ablation-dist-preflight confirmed marker absent in dist; only two-holder cases red (rest 1/3, runtime 2/4); restored blob == HEAD, rebuilt, runtime 4/4. Package suites: metadata-protocol 290 files passed / 4 skipped, 21897 tests passed; rest 363 files, 6907 tests passed (both at b8f5998); runtime 500/500 files, 8095 tests passed (913e990 tree; b8f5998 only adds the changeset/ledger lines). typecheck exit 0 for all three; eslint exit 0 on the ten touched files.","gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 71/71 exit 0 at b8f5998 (exit codes captured before any pipe), --ran reconciliation 0 NOT-MEASURED. First-loop non-zero exits fixed then re-run: check:engine-double-contract exit 1 -> ledger --write committed -> 0; check-plugin-teardown-shape --self-test exit 3 (shallow clone missing its pinned commit) -> fetched 621a487 -> 0; check:dual-build-cjs-loads exit 3 (no dist) -> pnpm build --concurrency=2 -> 0; check:type-check-debt exit 3 (lock queue behind dogfood) -> 0. platform-checklist, commit trailers, nul-bytes 0. PR check-runs at b8f5998 when this report was written: Governed Surface Queue Guard success; Build Core, Check Changeset, Lint families, Type Check families, PR-body guards, Test UI, Live E2E UI, Dogfood Regression Gate queued/in_progress; opt-in families skipped. Not re-run locally; the seat reads them before landing.",
"dogfood_battery": "b8f5998e · VERDICT command-exit 0 · Test Files 363 passed / 3 skipped (366) · Tests 2932 passed / 28 skipped · no failures",
"mcp_calls": "0",
"api_writes": "2 — fleet-write relay: pr_create (#28583, draft, read back 12799/12799 bytes identical, assignees none); post-stamped comment on #28337 (this report). Plus git push (not a REST write).",
"open_questions": [],
"out_of_scope_findings": [
"Seam (ui lane, not filed, no ui/** edit): spec:GET /meta/:type/:name/layers (package-less) -> renderer: Studio MetadataClient.layered and other package-less /layers callers in ui/. After this lands, a name two packages hold answers those callers 409 RESOURCE_CONFLICT instead of one holder's stack; they need to pass ?package= (or surface the refusal). reach: public door, measured by the runtime test above. carrier: ui lane via seat 2. dedupe words: layers package-less 409, MetadataClient.layered package, Studio layered view ambiguous package",
"carrier: seat 2 · noted, not filed — open PRs #28554 (protocol.ts, engine-double-contract.pinned.json) and #28512 (protocol.ts) touch the same files; textual overlap only, whichever lands second rebases"
]
}
Generated by Claude Code
objectstack-fleet commentedon Nov 1, 2026
domain:server#2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo
Landing record · #28337 · PR #28583
domain:serverseat 2 ·session_0186vfjHHMsRXC9EUT9hTFMo· 2026-11-01T07:09Zgit ls-remote origin 'refs/heads/gh-readonly-queue/main/pr-28583-*'git merge-base --is-ancestor cd065d36 origin/maingit grep -c packagelessLayeredReadRefusal origin/main -- packages/metadata-protocol/src/protocol.tscd065d36. The layered view of a name two packages hold, read with no?package=, now refuses with the same 409 the package-less save and delete answer, naming the holders and prescribing?package=. It no longer silently picks one holder. Both/:type/:name/layersand?layers=truebehave this way, on both doors.?package=<id>reads that holder's stack. A name with one stored holder reads as before, including a base and its.customoverride.domain:ui): two Studio callers should pass the owning package.Release: claim
6553412526(session_0186vfjHHMsRXC9EUT9hTFMo, branchclaude/project-thread-0r3khj) · landed.pm:dispatchedremoved; assignee cleared; the card closed on merge.Generated by Claude Code