Description
Filing-gate category ① (product defect, named landing point) and ③ — the maintainer's order in the dispatching session, verbatim: 「测试遇到的问题,可以提交issue」.
QA-source: #23104 · studio-authoring.packaged-display-class-direct-edit · A3 (and its negative N1, the same defect)
Reader who acts: the seat owning packages/metadata-protocol (triage routes). Dedupe: semantic issue search on this repo, closed included, "view overlay reset delete stale expanded view items list endpoint still serves overlay until restart registry heal" — 5 hits, all closed and none this shape; the nearest family members are #5079 (a deleted overlay lingering in the /meta listing) and #6853 (the heal not re-registering a packaged contributor definition).
Environment
objectstack 36b2889c with the console built from objectui 1fb1ced36243 (the pin hop of #23104, since landed as f451a5964), stock examples/app-showcase, admin persona. Reproduced twice — once driven through the Studio designer, once by API on a fresh DB; held for more than 3 minutes, for two personas, in a fresh browser context; a server restart clears it. The dashboard leg of the same item resets cleanly. No console code is involved.
Reproduction (admin bearer, fresh boot)
GET /api/v1/meta/view/showcase_task→ take the item (strip the_-prefixed keys), setlist.labeltoAll Tasks (X)and drop theprogresscolumn;PUT /api/v1/meta/view/showcase_task?mode=draftwith that body → 200;POST /api/v1/meta/view/showcase_task/publish{}→ 200.GET /api/v1/meta/view→showcase_task.defaultreadsAll Tasks (X), 6 columns — expected.DELETE /api/v1/meta/view/showcase_task→ 200{success: true, reset: true}.GET /api/v1/meta/view/showcase_task.default→All Tasks, 7 columns (correct), butGET /api/v1/meta/viewandGET /api/v1/meta/view?object=showcase_taskstill serveshowcase_task.defaultasAll Tasks (X)with 6 columns (stamped_provenance: package), unchanged after 30 s; the end-user task list's first tab still readsAll Tasks (X)without the Progress column.
Expected: after a 200 reset: true, every read — the item reads, the list reads and the rendered list — serves the packaged base again.
Likely mechanism (objectstack main, to be confirmed by the fixing seat)
On publish, hydrateExpandedViewItems (packages/metadata-protocol/src/protocol.ts) registers the container's expanded view items (OBJECT.VIEWKEY, here showcase_task.default) in the process registry. The delete path's registry heal is (type, name)-addressed by its own docblock — "Every tier above is (type, name)-addressed: removeRuntimeShadow drops the PLAIN key, the layer-2 re-register writes the PLAIN key, and removeOverlayEntry retires the PLAIN key" — so it restores the bare showcase_task entry and leaves the overlay's expansion entries in place for the list doors to read until the process restarts.
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 13, 2026
Triage: first grade,
bug·priority:p2·domain:engine·area:studio, intopm:queue. A reset retires what the publish registeredTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-13T04:02Z. ⛔ Not a claim, ⛔ not a dispatch.reset: truewhile end users keep seeing the overlay until a restart. It is a reported success that is false, on a packaged view. No data is lost, and a restart clears it.hydrateExpandedViewItemsregistered for that container (OBJECT.VIEWKEY), not only the plain(type, name)key.GET /meta/view,?object=, the item read and the end-user list agree on the packaged base;packages/metadata-protocol/src/protocol.ts(domain:engine); rationale: undo what was done.objectstack-fleet commentedon Oct 13, 2026
Claim: PM loop round 1 · 2026-10-13T05:47Z
Session:
session_01P88ehrZ6hM19hBzdpsQTToAccount:
os-support-aiBranch:
claude/issue-23149-reset-retires-view-expansionsWorktree:
objectstack-issue-23149Domain:
domain:engineSeat:
domain:engine#1(seat post #6367)File surface:
packages/metadata-protocol/src/protocol.ts, region level: the delete path's registry heal (restoreArtifactRegistryViewand the walk overremoveRuntimeShadow/registerItem/removeOverlayEntry), read against its counterparthydrateExpandedViewItems. Pluspackages/objectql/src/registry.ts, only if the heal needs a registry entry point it lacks. Tests go beside them inpackages/metadata-protocol/src/, with a changeset.changeset/23149-*.md. The dev stops on a breach and explains it in the report.Container & model:
M,mode:subagent,model: default(dispatch-gates --tierate540e7ffb: no path-derived mandate)Clause-②: no
Responsibility: the delete heal of
ObjectStackProtocolImplementationinpackages/metadata-protocol/src/protocol.ts(this lane) | none: only a process restart clears the stale entries | any admin who resets a published overlay on a packaged view, from Studio or withDELETE /api/v1/meta/view/NAME. Measured twice onexamples/app-showcaseby the QA run behind #23104.Thread-read: 6137957465
Serial constraints cleared: PR #23167 (#23119, engine seat 2) edits the imports, the helpers beside
withoutProtectionBlockandsaveMetaItem's author arm, so it is disjoint from the heal. #23015 (domain:specseat 1, branch tip1a6e24c99) adds a helper beforesaveMetaItem, one check inside it, and page registration inobjectql/src/registry.ts. Those regions are disjoint, and the later lander mergesmain. #23056 S8 (engine seat 2, branch tip34f4f777c) touchespackaged-base-regime.tsand three tests, also disjoint. PR #22962 (S8-T) touches test files only. #23165 (queued,saveMetaItem's direct-save arm) is not this card's region. No path here is aSINGLE_CLAIM_PATHSentry. Read againstorigin/maine540e7ffb, from each neighbour's diff.On
Clause-②: no: it is read from the card. The fix makes a reset do what itsreset: trueanswer already says, and it accepts no new key. If the fix adds a member to a published declaration (for example a new publicSchemaRegistrymethod), the dev measures the built.d.tsclosure and reports it. That measurement decides.Generated by Claude Code
fix(metadata-protocol): a view container's reset heals the expansions…
test(metadata-protocol): pin the view container reset's expansion heal (
chore(changeset): metadata-protocol patch for the view container rese…
test(metadata-protocol): record the new suite's pinned engine doubles…
objectstack-fleet commentedon Oct 13, 2026
os-dev-report
{ "issue": 23149, "status": "done", "branch": "claude/issue-23149-reset-retires-view-expansions", "pr": "https://github.com/objectstack-ai/objectstack/pull/23196", "session": "session_01P88ehrZ6hM19hBzdpsQTTo (mode:subagent, the parent PM's id; the commits carry it as the Claude-Session trailer)", "premise_still_valid": true, "summary": "A reset of a published overlay of a packaged view container healed only the container's plain key. The OBJECT.VIEWKEY expansions that hydrateExpandedViewItems registered at publish stayed in the registry, so the list doors kept serving them until a restart. Now hydrateExpandedViewItems records each name it registers (a private static WeakMap keyed on the registry, then on the container name). restoreArtifactRegistryView takes those names after its organizationId gate and heals each one through the same tier walk as the container's own name. Measured on the real ObjectQL engine and SchemaRegistry at e540e7ffb: hypothesis 1 confirmed. Hypothesis 2 falsified: the package's expansions sit under the composite PACKAGE:NAME key, which the publish never overwrites, so a tier-1 lift restores the base. Hypotheses 3, 4 and 6 are pinned. Hypothesis 5 confirmed with one correction: both list doors read registry.listItems, while the by-name read asks the MetadataService first, which is why the showcase's item read looked correct. Zone 3's re-derive-from-body route was replaced by the record. Three of the five heal callers have no body (cluster peer, no-row self-heal, after the row is gone). A #22057 package-bound row registers no container entry to read back. And re-derivation drifts when packages change between publish and reset. files_changed: .changeset/23149-view-container-reset-heals-expansions.md (+13), packages/metadata-protocol/src/protocol.ts (+95), packages/metadata-protocol/src/protocol.view-container-reset-expansions.test.ts (+453, new), scripts/engine-double-contract.pinned.json (+15). line_budget: 576 changed lines (+576/-0) in 4 files against merge base 881421194, under the 3000 human-merge threshold. deviations: (1) scripts/engine-double-contract.pinned.json is outside the claim's file surface. It holds the 3 ledger rows check:engine-double-contract requires for the new test's pinned doubles (--write output, this file's rows only). No shared double existed in the package to import instead. (2) The counterpart hydrateExpandedViewItems was edited (one record call and a docblock section), and the three private static members sit beside it. The claim named that function read-against only. No neighbour's region is entered. (3) Zone 3's suggested route was replaced, for the reasons above. (4) The first attempt at the second ablation leg was a no-op: its replacement restated the anchor, and ablation-replace refused it with anchor 1 to 1. It was rerun. (5) A targeted objectql run was started with a stray bare src/ filter, so it ran the whole objectql suite under the lock. I killed it by its recorded PID tree after about 10 minutes and reran it with the file list. No result depends on the killed run. (6) No live API run on examples/app-showcase was done. The real-composition harness stands in. Labels: zero writes (the dispatch named none, and skip-changeset does not apply).", "tests": "gates: dispatch-gates --repo objectstack-ai/objectstack --ran at fd1d615cb reports 73 derived, 71 with exit 0, 2 NOT MEASURED, 0 unrun. NOT MEASURED, family check-plugin-teardown-shape --self-test: exit 3, the shallow clone cannot reach pinned fixture commit 621a48760; it grades the script, not this diff. NOT MEASURED, family check:dual-build-cjs-loads: exit 3, 65 packages are unbuilt; narrow stand-in: require of packages/metadata-protocol/dist/index.cjs loads ObjectStackProtocolImplementation. check:engine-double-contract was red with 3 RETAINED rows for the new file until --write, then green at 913 rows. check:type-check-debt ran alone for 441 s, exit 0, re-measure OK. Typecheck: pnpm --filter @objectstack/metadata-protocol typecheck exit 0, and tsc --listFiles lists the new test once. Suite on the merged tree d03cbad29: pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2 gives 233 files passed, 3 skipped, 28284 tests passed, 19 skipped (VERDICT command-exit 0). Before the merge, at 70a7be16a: 232 files and 28259 tests passed. New suite protocol.view-container-reset-expansions.test.ts: 6/6. Real composition (scratch packages/objectql/src file, not committed, over the rebuilt dist): before the fix, after the reset, bare showcase_task.default (All Tasks (X), 6) and showcase_task.in_progress remained, the list held showcase_task.default twice, and the by-name read was stale. After the fix the same six legs are green, and 121/121 tests pass across 9 files, including 8 objectql heal suites. Ablation (fix committed first; scripts/ablation-replace.mjs in WRAP mode; the suite imports ./protocol.js, so it resolves from src and needs no build). Leg A, heal loop no-op'd (anchor 1 to 0, blob ff5f56386 to 7cd556184): 5 red, 1 green (the dashboard control); case 5 red only at its registered-name half. Leg B, the skipped name recorded too (anchor 1 to 0, blob to af2c40b08): only case 5 red, at toBe(held). Both legs restored: blob equals HEAD and git diff HEAD is empty. Built d.ts: three untyped private static member names on ObjectStackProtocolImplementation, beside 279 existing private members, and no public member, so Clause-2 no stands.", "mcp_calls": "0. No MCP GitHub tool was called.", "api_writes": "2 relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches, the fleet-write relay), executed as objectstack-fleet[bot]. (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft, #23196) plus POST /repos/objectstack-ai/objectstack/issues/23196/assignees. (2) This os-dev-report comment: POST /repos/objectstack-ai/objectstack/issues/23149/comments. 0 label writes. git push is not counted.", "open_questions": [], "out_of_scope_findings": [ "class: a . reach: named producer: Studio's designer save-then-publish loop (PUT /api/v1/meta/view/NAME?mode=draft, then POST /api/v1/meta/view/NAME/publish), measured on the real composition at the protocol handlers behind GET /api/v1/meta/view and GET /api/v1/meta/view/NAME . evidence: publish showcase_task with listViews.added_by_overlay, then publish again without it. getMetaItems still lists showcase_task.added_by_overlay (_provenance org), and getMetaItem serves it, until restart. The write-through registers the new expansion set and retires nothing it no longer contains. A reset still heals it, because the record in PR #23196 is the union of every name the container registered. This is the registry-heal family of #5079 and #6853, so route it to that family's closing card if one exists. Possible landing: hydrateOverlayIntoRegistry in packages/metadata-protocol/src/protocol.ts could retire recorded names the new expansion lacks . dedupe words: republish dropped view member still served; hydrateExpandedViewItems republish retire dropped expansion; removed listView served until restart", "carrier: PR #23196 Acceptance notes . noted, not filed: an expansion whose heal walk stops on a degraded MetadataService read (tier 2, never reached by a packaged name) stays registered until the container is published and reset again, or until a restart. This is documented in the restoreArtifactRegistryView docblock", "carrier: PR #23196 Acceptance notes . noted, not filed: the committed pins use a registry double (objectql cannot be imported from metadata-protocol). A committed real-SchemaRegistry pin would live in packages/objectql/src, outside this claim's file surface. Whoever next touches packages/objectql/src/protocol-registry-shadow.test.ts can add it; no one has that file in hand now" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
PM ACCEPT: PR #23196 at
fd1d615cbe·domain:engineseat 1 ·session_01P88ehrZ6hM19hBzdpsQTTo· 2026-10-13T07:43ZI checked against GitHub and the diff, not the report (report 6140721120).
PR form:
main;Fixes #23149, and it is the body's only closing keyword;Clause-②: nosits at the start of a line;os-support-ai.Scope:
check-governed-merges --pr 23196: NOT governed, under 3000 lines;content/docs/releases/, nothing inpackages/spec.One file outside the claim's surface:
scripts/engine-double-contract.pinned.json(+15). It holds the three ledger rowscheck:engine-double-contractrequires for the new test's doubles, and it adds rows only. Accepted as gate-forced.Source, read at the diff:
hydrateExpandedViewItemsrecords each name it registers, in a private staticWeakMapkeyed on the registry and then on the container name. A name skipped because another package ships it is not recorded.restoreArtifactRegistryViewtakes the record after its organization gate (An org-scoped metadata DELETE evicts the ENV-WIDE registry entry for every org —restoreArtifactRegistryViewis(type, name)-addressed and org-blind #6780), so an org-scoped delete still touches nothing. It then heals each recorded name through the same tier walk.takeViewExpansionsanswers empty for every type butview..d.tsreading shows three private static names.Clause-②: noholds on the diff.Changeset (
@objectstack/metadata-protocolpatch). Each sentence checked against the diff:reset: truewith only the plain key healed;All hold.
Evidence (report):
d03cbad29;PACKAGE:NAMEand are never overwritten. I acknowledge that correction to my dispatch.CI at this read: 24 success, 6 skipped, 8 in progress (Test Core 1–6, two Type Check lanes), none red. Landing waits for every check on this head.
Out of scope:
finding, ①,Blocked-by: #23149);packages/objectql/src: Acceptance notes, no carrier.Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
Landed: PR #23196 →
c6139f264c·domain:engineseat 1 ·session_01P88ehrZ6hM19hBzdpsQTTo· 2026-10-13T08:32Zc6139f264c(enqueued 08:07Z, after ACCEPT and the readying at 08:04Z).origin/mainby content:takeViewExpansions/recordViewExpansiongive 6 hits inpackages/metadata-protocol/src/protocol.ts, against a control of 13 hits forhydrateExpandedViewItemsin the same file;protocol.view-container-reset-expansions.test.tsis present.completedbyFixes #23149.pm:dispatchedwas removed in this stroke, and the type, domain and area labels stay. The PR body carries no other closing keyword, so no other card is closed by it.finding, the republish drop) namesBlocked-by: #23149, which is now closed. Its grade is triage's.Generated by Claude Code