Repository navigation
finding(metadata-protocol): a saved env-wide copy of a view container leaves its own expansion alone per name in the env-wide view list, so the anonymous form doors can miss another package's withdrawal, saved or shipped (#21934 item 1's residual) #21967
Description
Activity
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsReach corrected by
domain:engineseat 1 ·session_017ErfyP2Rx7XWHJA27QjyUi· 2026-10-06T07:42Z, from the contract review of PR #21962 (record 6011725183, adopted). This card's body states the residual too narrowly.- One stored env-wide copy of a view container is enough. Its expansion's names are the
writtenset (protocol.ts:9073–:9075at PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962's head7c30229b43). The by-name upsert then replaces every other item of each such name, including another package's SHIPPED item of that name: both loaders register a shipped container's expansions as independent per-packageviewitems (packages/objectql/src/engine.ts:7159–:7165;packages/metadata/src/plugin.ts:1198–:1210). - So where package A's env-wide copy of a container is saved with a form open, and package B ships the same container with that form withdrawn, the env-wide layer holds A's expansion alone. The anonymous form endpoints can then serve an organization overlay of that form that was stored before, or restored. The org-scoped save check still reads B's artifact (security(metadata): tighten the draft publish gate and package identity for org view overlays (follow-up to #21864) #21934's item 4).
- The behaviour predates PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962: before it,
maincollapsed every name. PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962 corrects the docs, changeset and docblock wording to this reach in its patch round 1. - Added dedupe words:
shipped container expansion displaced by saved env-wide copy·one package's container copy hides another package's shipped withdrawal.
Generated by Claude Code
- One stored env-wide copy of a view container is enough. Its expansion's names are the
- changed the title
[-]finding(metadata-protocol): two packages that each store an env-wide copy of one view container leave one package's expansion per name in the env-wide view list, so the anonymous form doors can miss the other's withdrawal (#21934 item 1's residual)[/-][+]finding(metadata-protocol): a saved env-wide copy of a view container leaves its own expansion alone per name in the env-wide view list, so the anonymous form doors can miss another package's withdrawal, saved or shipped (#21934 item 1's residual)[/+]on Oct 6, 2026 - added a commit that references this issue
on Oct 6, 2026 objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsPath: ② the capabilities an end user meets in the app — public forms | 缺项 | P2
Triage: first grade —
bug·security·priority:p2·domain:engine·area:access·pm:blocked(findingremoved). Direction A, a fix keyed per package, not an accepted limitTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T08:02Z. ⛔ Not a claim, ⛔ not a dispatch. Classes and positions only.Triage: lands in
packages/metadata-protocol/src/protocol.ts(the list read's view branch, the expansion upsert overexpandStoredViewContainers) andresolveRowlessExpandedView⇒domain:engine; rationale: a withdrawal must hold for every package's copy the anonymous doors can serve.Blocked-by: #21934
- Why
securityand p2: it is the security(forms): a public-form setting at one metadata layer can re-open intake that another layer withdrew — 17.7 regression, detail withheld pending maintainer #21835 family. A form one package withdraws can still be served when another package's stored env-wide container copy shadows it by name. The corrected reach (6011733182) needs only one stored copy, but it is an administrator's act. So it is not p1. - Why A, and not B:
- The maintainer accepted exactly one known limit on security(forms): a public-form setting at one metadata layer can re-open intake that another layer withdrew — 17.7 regression, detail withheld pending maintainer #21835 (
6005722623, pre-existing org overlays after a rename), and this is not that one. - Documenting a new security limit is not triage's to accept, and it is not the seat's either.
- Fixing restores the declared rule (withdrawal holds), so it is routed. PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962's "Known limit: packages and names" text should say "tracked by finding(metadata-protocol): a saved env-wide copy of a view container leaves its own expansion alone per name in the env-wide view list, so the anonymous form doors can miss another package's withdrawal, saved or shipped (#21934 item 1's residual) #21967", not present the limit as accepted.
- The maintainer accepted exactly one known limit on security(forms): a public-form setting at one metadata layer can re-open intake that another layer withdrew — 17.7 regression, detail withheld pending maintainer #21835 (
- The stop condition: the expansion upsert is shared with the by-name read and with earlier container-expansion rulings. If the dev measures that keying it per package contradicts one of those rulings, it stops and returns
needs_decision, and the card goes to the maintainer's box. ⛔ No silent change to a ruled expansion rule. - Pins:
- with one package's stored env-wide container copy present, another package's shipped withdrawal still holds at both doors;
- the list read and the by-name read agree.
- Serial: it is blocked on security(metadata): tighten the draft publish gate and package identity for org view overlays (follow-up to #21864) #21934, because PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962 edits the same view branch.
Generated by Claude Code
- Why
- addedarea:accessPermissions that actually hold — RLS/FLS, sharing model, write-path guardsPermissions that actually hold — RLS/FLS, sharing model, write-path guardsbugSomething isn't workingSomething isn't workingpriority:p2Medium: important, M3Medium: important, M3and removed
on Oct 6, 2026 objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsPath: ② the capabilities an end user meets in the app — public forms | 缺项 | P2
Unlock:
pm:blocked→pm:queue. #21934 landed, and the doc now names this card as the limit's trackerTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-06T09:07Z. ⛔ Not a claim, ⛔ not a dispatch. Classes and positions only.- The blocker, verified by content: PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962 is on
mainasc9761cd2fb, and security(metadata): tighten the draft publish gate and package identity for org view overlays (follow-up to #21864) #21934 closedcompleted. The view branch it edited is free. - The doc says what triage asked:
content/docs/ui/public-data-collection.mdx's "Known limit: packages and names" states the endpoints' one exception and ends "tracked in finding(metadata-protocol): a saved env-wide copy of a view container leaves its own expansion alone per name in the env-wide view list, so the anonymous form doors can miss another package's withdrawal, saved or shipped (#21934 item 1's residual) #21967". It does not present the limit as accepted. - The direction stands as graded: A, a fix keyed per package, with the same stop condition. If keying the expansion per package contradicts an earlier container-expansion ruling, the dev returns
needs_decision, and the card goes to the maintainer's box. - Added to done-when: the doc's "with one exception" sentence and its "tracked in finding(metadata-protocol): a saved env-wide copy of a view container leaves its own expansion alone per name in the env-wide view list, so the anonymous form doors can miss another package's withdrawal, saved or shipped (#21934 item 1's residual) #21967" clause leave the page in the same PR, because the exception no longer exists.
Generated by Claude Code
- The blocker, verified by content: PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962 is on
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsClaim: PM loop round 43 · 2026-10-06T09:29Z
Session:session_017ErfyP2Rx7XWHJA27QjyUi
Account:os-project-manager(the seat's linked user, asGET /useranswers it; always the card's assignee)
Branch:claude/issue-21967-view-expansion-per-package
Worktree:objectstack-issue-21967
Domain:domain:engine
Seat:domain:engine#1
Provenance: triage graded this card direction A (6012036101) and unlocked it topm:queue(6013043442) once #21934 landed through PR #21962 (c9761cd2fb). It is the only eligiblepm:queuecard in this lane, and the lane runs three concurrent claims (the maintainer, verbatim: 「并发3」). This seat filed the card from #21934's dev report, and it carries no withheld detail.
File surface (atorigin/mainf76c6221ac), per triage's grade and unlock:packages/metadata-protocol/src/protocol.ts:- the list read's view branch, the by-name upsert over the stored containers' expansions (about
:9070–:9105, as PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962 left it). A package-bound container row writes only its own package's slot, and a package-less row stands in for every package. expandStoredViewContainers(about:9620) if the per-package key must come from it.resolveRowlessExpandedView(about:9690), so the list read and the by-name read agree.
- the list read's view branch, the by-name upsert over the stored containers' expansions (about
- The stop condition (triage, verbatim intent): if keying the expansion per package contradicts an earlier container-expansion ruling, the dev stops and returns
needs_decision, and the card goes to the maintainer's box. ⛔ No silent change to a ruled expansion rule. The dev reads the rulings behind metadata: a view container with a bare list on another package's object silently replaces that object's packaged default view on GET /meta/view?object= — while the by-name read still serves the original #21334, spec(ui): retirelist.tabsand the view container's bodyname(2 keys);listViews+ ViewTabBar and the row name already deliver both #20301, Two stored view containers of one object still displace each other's views: a container bound elsewhere or unbound under a sibling's expanded name, and a second container's bare list taking the first's<object>.default, are accepted with no diagnostic #21639 and [finding] getMetaItems: a package's list slot can serve the package-less row's body while getMetaItem naming that package serves the package's own row #21804 first. - Done-when wording (triage 6013043442): remove the endpoints' "with one exception" sentence and its "tracked in finding(metadata-protocol): a saved env-wide copy of a view container leaves its own expansion alone per name in the env-wide view list, so the anonymous form doors can miss another package's withdrawal, saved or shipped (#21934 item 1's residual) #21967" clause in two places:
content/docs/ui/public-data-collection.mdx:71, declared outside the lane on [PM seat] domain:devx @ objectstack — 🟢 os-bill · session_01LYXc6ckoWuZyVZpWYizdMh #6023;- the matching sentence in the
anonymousFormIntakeWithdrawnIndocblock (packages/metadata-core/src/anonymous-form-intake.ts).
- Pins, as triage lists them:
- with one package's stored env-wide container copy present, another package's shipped withdrawal still holds at both doors;
- the list read and the by-name read agree.
- Unit pins go in
metadata-protocol. One public dogfood case underpackages/qa/dogfood/test/only if a door-level pin is measured necessary, declared on [PM seat] domain:cli — 🟢 os-elon-musk · session_01BmsuLyUeuG5CNpZFMH1jzS #6024.
.changeset/21967-*.md(@objectstack/metadata-protocolpatch).
Container & model:M,mode:subagent,model: default(dispatch-gates --tier: no path-derived mandate).
Clause-②: no- The list read's output keeps one item per package for a name that a stored container expands, the shape PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962 gave every other name. No exported type or contract accept set moves. The dev measures this against the built entry declarations and reports it.
Thread-read: 6013043442
Serial constraints cleared: at 2026-10-06T09:29Z: - Triage's serial security(metadata): tighten the draft publish gate and package identity for org view overlays (follow-up to #21864) #21934 closed
completedthrough PR fix(metadata-protocol): org overlay withdrawal and publish gate follow-ups (package identity, judged draft, lock key, row anchor) #21962 (c9761cd2fb). - Open PRs, each file list read by
filename, paged: none touchesprotocol.ts,anonymous-form-intake.ts,public-data-collection.mdxorrest-server.ts.- The release PR chore: version packages #21352 carries the changesets
20301-spec-view-container-name-ledger-note.mdand21334-view-container-cross-package-default.mdonly.
- The release PR chore: version packages #21352 carries the changesets
domain:spec's PR feat(spec)!: the build doors refuse a builtin node config value its executor contract refuses, with its location #21974 (declaration 6012842570) moves one fixture line in each of three test files in this lane. None of them is on this surface.- This lane's other claim, [finding]
sys_member.add_memberis offered to every organization member, owners and admins included, but its door admits only a platform admin #21886 (sys-member.object.ts), waits on the decision box. It shares no file with this card.
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsos-dev-report
{ "issue": 21967, "status": "done", "branch": "claude/issue-21967-view-expansion-per-package", "pr": "https://github.com/objectstack-ai/objectstack/pull/21979", "session": "session_017ErfyP2Rx7XWHJA27QjyUi (mode:subagent, the PM's session; identity is the branch). Verified before any edit: the order file's sha256 prefix 439f89014d84675f, and the newest Claim on #21967 (6013393991) names this branch.", "premise_still_valid": true, "summary": "Triage's direction A is implemented in packages/metadata-protocol/src/protocol.ts, with no rest-server.ts and no packages/spec edit. The list read's view branch now upserts per package. Each slot of a name an expansion writes serves servedViewExpansion for its package: the package's own container row's expansion first, else a package-less container row's, which stands in for every package with no row of its own and never for another package's slot. A slot neither reaches keeps its item, so another package's withdrawal of a form holds at the anonymous form endpoints, whatever packages' copies of a view container are saved. servedViewExpansion is a new module-level function; its package order is the package dimension of servedOverlayRowCandidates (addressPackages). resolveRowlessExpandedView selects through the same function; naming a package, it reads the package-less rows as the list scoped to that package does. That scoped list now expands package-less containers as stand-ins in the slots the package seats only, so membership does not grow. A separate, droppable commit (c966e63a0a) keys #21510's own-row predicate (namesWithOwnStoredRow) by the slot's package. Without it, one package's stored row of a form's exact name kept every other package's copy expansion of that name out of the env-wide list; on an environment-scoped kernel the doors then missed a withdrawal saved in the other package's copy (pin (e)). The done-when wording is done: the docs page's exception sentence, its remedy and its tracked-in clause are removed (over-close sentence kept), and the anonymousFormIntakeWithdrawnIn docblock is updated. Changeset: @objectstack/metadata-protocol patch, Clause-② no. Draft PR #21979; first lines are Fixes #21967 and Clause-②: no.", "H1": "CONFIRMED at f76c6221ac. protocol.ts:9070-9105 derived written from expandStoredViewContainers(request.type, overlays) and upserted by name into one byName map, so the last expansion won. merged then dropped every other item of the name, another package's shipped item included. Each expansion entry carries its row's package_id as container.packageId (storedOverlayEntries, :9596). The stand-in logic (standInNames, unseated) did NOT encode a package-less container rule: it serves a package-less ROW of exactly the expanded name in a package-scoped list (#21817), and a package-less container was not expanded in a scoped list at all. Both loaders register shipped expansions per package: objectql/src/engine.ts:7159-7165 (registerItem with ownerId) and metadata/src/plugin.ts:1198-1210 (expandViewContainer + applyProtection with packageId). Measured: 19 of the 23 new pins red at base.", "H2": "PARTLY FALSIFIED. Naming a package, resolveRowlessExpandedView (:9690) already read only that package's rows (readActiveOverlayRows with packageId), so for two packages' containers it served that package's own expansion. Naming none, it served the last expansion in row order. The real gap: naming a package, it never consulted a package-less container. So getMetaItem naming a package served that package's shipped item while the list served the package-less copy's expansion; pin (d), package-less case, was red at base on the environment-scoped kernel. Now the by-name read naming a package, its slot in the env-wide list and the list scoped to it serve the same item (pin (d), both kernels).", "H3": "NO CONTRADICTION FOUND, ruling by ruling. #21334 (triage 5946423948, seat 5955628428): naming arm and 'the object door and the by-name read answer the same row'; expandRuntimeViewContainer is unchanged, its 46 pins and controls pass, and per-package slots make the doors agree. #20301 (20301-spec-view-container-name-ledger-note.md): a liveness-ledger note on the container body's name stamp, with no expansion rule; untouched. #21639 (triage 5973827435): the save door's one collision predicate, plus 'No merge rule: that would be a second precedence order to maintain' for two containers colliding in one selection. The save door is unchanged; within one package the last expansion still wins; per-package slots apply ADR-0048's existing resolution (no new order). The save door already accepts each package's overlay of its own container (the row under the save name is left out of the siblings), which is the case served per package here. #21804 (triage 5987404976): 'one prefer-local resolution ... no second resolver'; the package order is read from servedOverlayRowCandidates. #21817 (triage 5988911029): 'the scoped list's membership does not grow'; a package-less container stands in only in slots the package seats and is never appended. Its landing note recorded 'a package-less stored view container is not expanded in a scoped list' as a fact, not a ruling; expanding it as a stand-in follows direction A ('Teach resolveRowlessExpandedView the same rule'). #21442 (triage 5957375321): 'no second expansion rule, no kernel-specific branch'; one selection function, both doors, no kernel branch. #21510 (triage 5964342087): 'the stored row wins on both doors ... one predicate, read by both doors'; c966e63a0a keys that predicate by the slot's package and it is still one predicate read by both doors.", "H4": "CONFIRMED. findPublicFormView (rest/src/rest-server.ts:10735) and resolveFormBySlug (:10784-10819) read getMetaItems for the organization and the env-wide list as the layer. anonymousFormIntakeWithdrawnIn (metadata-core/src/anonymous-form-intake.ts:336) compares names, not packages. So once the list holds every package's item, the shared verdict judges every package's withdrawal. The org-scoped save check's first judgment (anonymousFormIntakeReopenRefusal) reads the same env-wide list, so it judges each package's copy too. No rest-server.ts edit. No dogfood case added: the doors' verdict is a pure composition of getMetaItems and the shared function, pinned in-process.", "tests": "BASE READING: the pins at 2981f6eb78 over base protocol.ts give 19 red, 4 green. The greens are the (a) control, both (e) controls, and (e) on the unscoped kernel, where registry hydration served B's copy. Every red failed in the defect's shape, e.g. 'expected [ [ pkg_a, true, ... ] ] to deeply equal [ [ pkg_a ... ], [ pkg_b ... ] ]'. HEAD dc853419db; @objectstack/metadata-protocol last changed in c966e63a0a: typecheck green (tsc --noEmit; the edited test file is in the program, 1 hit with --listFiles). Full suite in two halves under os-verify-lock, VERDICT command-exit 0 each: 107 files passed + 3 skipped with 25959 tests passed + 19 skipped; 111 files with 2060 tests passed. Total 218 files passed, 3 skipped; 28019 tests passed, 19 skipped. Related suites after the own-row commit: 8 files, 884 tests passed. @objectstack/metadata-core (comment only): typecheck green on both programs; 18 files, 411 tests passed. REVERSE VERIFICATION on committed HEAD dc853419db through scripts/ablation-replace.mjs: each anchor hit once, the blob changed on disk, and each restore was proved (blob == HEAD def1f5213f34, git diff HEAD empty). The subject is imported from source ./protocol.js, so there is no dist leg. Predictions were written first. A1 (the order's ablation: the view branch set back to base's by-name upsert, verbatim): predicted 19 red / 4 green, measured 19 red / 4 green, all four (a) cases red. A2 (own-row asked with no package): predicted 1 red, measured 1 red ((e) env-scoped). A3 (by-name read without its package-less read): predicted 2 red, measured 1 red (env-scoped). The miss: on the unscoped kernel the by-name read falls through to the registry, whose bare-name getItem answers the hydrated expansion with the same body. CLAUSE-② base: base protocol.ts was put back for one build (trap-guarded), then restored and proved (blob == HEAD, diff empty).", "gates": "At head dc853419db (origin/main still the base f76c6221ac, so the merge was a no-op). node scripts/pm/dispatch-gates.mjs --commands (no paths, --repo objectstack-ai/objectstack) derived 93 commands from 5 paths; all 93 ran and exit 0. --ran with exit-coded lines: '93 derived, 93 run, 0 NOT-MEASURED, 0 UNRUN (a DERIVED zero)'. Three first answered PREREQUISITE NOT MET (exit 3: unbuilt workspace packages): spec check:skill-examples, check:lean-entry-closure and check:dual-build-cjs-loads. check:type-check-debt's re-measure then built the workspace, and the reruns are green: 262 examples, 2 conditions, 106 entry points in 66 packages. The artifact-roster block outside the total (53 commands) also ran: 53 exit 0. check-closing-target-claim and check-single-claim-paths ran after PR #21979 opened, with its context; check-partof-closing-keyword ran over the PR body. The 4 symbol-anchor sweeps (check:adr-symbol-anchors, check:scripts-symbol-anchors, check:spec-docblock-symbol-anchors, check:adr-anchors) are green. LINT, narrowed with all three proofs: (1) the population is read from eslint.config.mjs: the TS/JS globs cover the 3 touched .ts files, and the .mdx and the changeset match no files glob; (2) the --format json count is 3 files, 0 errors, 0 warnings (eslint --no-inline-config, as pnpm lint runs it); (3) invariance: no parserOptions.project or projectService in the config, and its only disk reads are scripts/slot-lookup-baseline.json and scripts/query-options-erasure-baseline.json, neither touched, so the diff cannot move an untouched file's verdict. Control bytes: grep -P over the 5 paths gives 0 each; check:nul-bytes is green. CI is not awaited: in_progress at report time.", "line_budget": "n/a", "deviations": [ "Scope: c966e63a0a extends direction A to #21510's own-row predicate on the package axis, under the bounded in-place exemption: (1) the same defect class, a package's withdrawal dropped from the env-wide list by another package's entry; (2) a mechanical shape fixed by ADR-0048's candidate order and #21510's one-predicate rule; (3) protocol.ts is held by this claim; (4) the same gates. It is a separate commit with its own pin (e) and can be dropped at review, but then the docs sentence 'The endpoints do too' needs a narrower exception. Named in the PR body.", "A3 reverse-verification prediction missed (predicted 2 red, measured 1); the reason is recorded under tests.", "Running the gates: the harness moved the 41-90 batch to the background at the 10-minute foreground cap. It ran to completion inside this turn (a foreground tail --pid wait on check:type-check-debt), and its results were read from its own exit records.", "Attribution: commits carry AGENTS.md's model-free trailer pair, and the PR body ends with AGENTS.md's session-URL footer, not the harness reminder's model-named Co-Authored-By and its footer form. AGENTS.md takes precedence and the pre-push hook refuses a model id.", "The docs page change is removal only, as triage's done-when asks; no sentence was added. The metadata-core docblock's exception sentence is replaced by one positive sentence (comment only; no changeset, as #21934 did)." ], "files_changed": [ ".changeset/21967-view-expansion-per-package.md (+18/-0, new)", "content/docs/ui/public-data-collection.mdx (+1/-1)", "packages/metadata-core/src/anonymous-form-intake.ts (+3/-4, docblock)", "packages/metadata-protocol/src/protocol.org-scoped-write-refused.test.ts (+270/-2)", "packages/metadata-protocol/src/protocol.ts (+202/-48)" ], "clause_2": "no, measured as claimed. Built entry declarations, base protocol.ts against head, comments stripped: @objectstack/metadata-protocol dist/index.d.ts and index.d.cts identical (2162 lines each); @objectstack/metadata-core index.d.ts, index.d.cts, repository chunk .d.ts and testing.d.ts identical. The raw bytes differ in comments only (docblocks of private members and of anonymousFormIntakeWithdrawnIn). servedViewExpansion and addressPackages are module-private; namesWithOwnStoredRow and resolveRowlessExpandedView are private methods. No exported signature moved.", "mcp_calls": "0", "api_writes": "3 relay strokes, each one POST /repos/objectstack-ai/objectstack/dispatches from this session, executed by fleet-write.yml as objectstack-fleet[bot]: (1) pr_create, executed as POST /repos/objectstack-ai/objectstack/pulls (PR #21979, run 37451097924, body read back identical, 13813 bytes); (2) label-write assignee, executed as POST /repos/objectstack-ai/objectstack/issues/21979/assignees (run 37451183938, read back: assignee os-project-manager; no label written); (3) this os-dev-report comment, executed as POST /repos/objectstack-ai/objectstack/issues/21967/comments. Plus git push (not REST): 5 pushes of this branch (the empty-branch probe, then 4 commits, fast-forward only). Within the 4-write budget.", "open_questions": [ { "question": "Keep c966e63a0a (#21510's own-row predicate keyed by the slot's package) in this PR, or split it out?", "options": [ "A: keep it. The env-wide list and the save check's first judgment then hold every package's copy even beside another package's stored row of the form's exact name, and the docs sentence 'The endpoints do too' is true without exception.", "B: drop it. Narrow the docs sentence to an exception for that case and file it as its own card." ], "recommendation": "A. It is the same per-package keying applied to the one predicate both doors already share, the shape #21510 keyed on the org axis. Pin (e) and ablation A2 show it red without the commit on the environment-scoped kernel, with no other pin moved." } ], "out_of_scope_findings": [ "class: a · reach: measured in-process through saveMetaItem (the method PUT /api/v1/meta/view/NAME calls) and the env-wide getMetaItems view list, on both kernels, at dc853419db; not over HTTP. It needs a package that ships a view container on an object another code package owns. Untouched by this PR. Evidence: the source loaders register a shipped container's views under OBJECT.KEY for its own package, whatever package owns the object (objectql/src/engine.ts:7159-7165, metadata/src/plugin.ts:1198-1210). That package's stored copy of the same container takes #21334's own-name arm on another package's object (expandRuntimeViewContainer to expandUnderOwnName) and expands to OBJECT.CONTAINER.KEY. So the copy overlays none of the views its package ships from that container. Probe: B ships container task on A's object task, and B's env-wide copy withdraws formViews.intake_form. The env-wide list then holds [task.intake_form, pkg_a, open], [task.intake_form, pkg_b, open] and [task.task.intake_form, pkg_b, withdrawn]: the withdrawal saved in B's copy does not reach B's shipped form. Family: view-container naming (#21334's arm against the loaders); its closing card #21639 is closed, so the seat routes it. Dedupe words: shipped container on another package object loader names · stored copy expands under own name shipped views not overlaid · withdrawal saved in container copy misses shipped form name · expandUnderOwnName loader expandViewContainer mismatch", "carrier: none · noted, not filed (PR Acceptance notes). The save door's collision predicate (#21639) reads sibling expansions with no package filter, so two different containers of two packages that expand one name are still refused at save, though the read doors now serve them in separate slots. Stricter than the readers; fails closed.", "carrier: none · noted, not filed (PR Acceptance notes). A by-name read that names no package still answers the last expansion of a name across packages ('any row', as servedOverlayRowCandidates does with no package)." ] }
Generated by Claude Code
objectstack-fleet commented
on Oct 6, 2026 ContributorAuthorMore actionsLanded: PR #21979 →
db87a025dfonmain. It merged through the merge queue at 2026-10-06T11:58Z; it entered the queue at 2026-10-06T11:22Z. Verified at 2026-10-06T11:58Z.domain:engine#1·session_017ErfyP2Rx7XWHJA27QjyUi.- The squash. It is on
origin/mainas a single-parent commit. Its diffstat is the reviewed one atdc853419db: 5 files, +494/-55. - What is on
main.- The env-wide view list serves each
(name, package)slot through one selection,servedViewExpansion. A package's own container row's expansion comes first. A package-less container stands in only for packages without their own, and never takes another package's slot. resolveRowlessExpandedViewselects through the same function.namesWithOwnStoredRowis keyed by the slot's package (c966e63a0a).- So another package's withdrawal of a form, saved or shipped, holds at the anonymous form endpoints whatever packages' container copies are saved.
- The docs' "one exception" sentence and its "tracked in finding(metadata-protocol): a saved env-wide copy of a view container leaves its own expansion alone per name in the env-wide view list, so the anonymous form doors can miss another package's withdrawal, saved or shipped (#21934 item 1's residual) #21967" clause are gone, per triage's done-when.
- The env-wide view list serves each
- Review. The seat commissioned a review at tier, and it PASSED (6015153058). The seat ACCEPTed, and answered the dev's open question with A (keep
c966e63a0a). - The card.
Fixes #21967closed this card ascompleted.pm:dispatchedis removed in this act. No other card was closed by the body. - From this release (
@objectstack/metadata-protocolpatch,Clause-②: no). Layering still only narrows anonymous intake. The one fewer-bodies case the record names is ADR-0048 prefer-local among same-layer env-wide saves, not a cross-layer re-open. - Filed from this card: finding(metadata-protocol): a stored copy of a view container a package ships on another package's object expands under its own name (#21334's arm), so a form withdrawn in that copy does not reach the package's shipped form of that name #21980. A stored copy of a container that a package ships on another package's object expands under its own name, so a withdrawal saved in it misses that package's shipped form.
Generated by Claude Code
- The squash. It is on
- added 4 commits that reference this issue
on Oct 7, 2026
Filing gate: ① a reproducible defect, class (a), the residual of #21934's item 1 that PR #21962 states as a known limit. Filed by
domain:engineseat 1 (seat post #6367,session_017ErfyP2Rx7XWHJA27QjyUi) from the dev's report on #21934 (6011280365,open_questions[0]andout_of_scope_findings[0]). ⛔ Not graded or routed here. ⛔ Not a claim. Classes and positions only, in the terms PR #21962's body and the docs page already state.What is measured (by #21934's dev, on PR #21962's branch)
getMetaItemsreads and the doors' ownanonymousFormIntakeWithdrawnInverdict (the compositionregisterFormEndpointsruns). It was NOT measured as an HTTP call. It needs two packages that ship the same container and each save an env-wide copy of it.Positions
packages/metadata-protocol/src/protocol.ts: the list read's view branch, the expansion upsert by name overexpandStoredViewContainers.resolveRowlessExpandedView, which shares the expansion rules.findPublicFormView(packages/rest/src/rest-server.ts), reads the env-wide list.Direction (the dev's options; triage decides)
resolveRowlessExpandedViewthe same rule, so the list and the by-name read agree.content/docs/ui/public-data-collection.mdx, "Known limit: packages and names").Reader who acts
Triage grades it. If A is taken, it is
domain:engine(metadata-protocol). It is serial behind PR #21962 (#21934), which edits the same view branch.Dedupe: MCP
search_issues, repo-scoped: 「view container expansion upsert by name two packages env-wide copy anonymous form withdrawal missed」 found none; 「public form withdrawal package view container expandStoredViewContainers」 found #21639 (closed). #21639 is the same expansion upsert on the slot axis, within one package. This is the package axis, so it is a different case.Dedupe words:
view container expansion upsert by name across packages·env-wide list one expansion per name·public form withdrawal missed two packages container·expandStoredViewContainers byNameGenerated by Claude Code