Skip to content

metadata-manager: getViewsByObject() reads a separate backing store never touched by the #13407 runtime-container-expansion fix #13913

Description

@zhuangjianguo

Follow-up from #13407 (not fixed there — materially larger, separately-scoped change with its own package/verification discipline; the card's own repro and pin go through GET /meta/view?object= → getMetaItems, not this exit).

Background. The hydrateExpandedViewItems doc comment (protocol.ts) has long named two independent object-bound readers: the REST route (GET /meta/view?object=), which reads through ObjectStackProtocolImplementation.getMetaItems (sys_metadata DB rows, org/environment-scoped), and MetadataManager.getViewsByObject() (packages/metadata/src/metadata-manager.ts:~1583), which reads this.list('view') — MetadataManager's own loader-based registry (this.registry, populated via registerLoader/readList), a completely separate store from sys_metadata/the ObjectQL SchemaRegistry.

What #13407 fixed, and why it doesn't reach this exit. #13407 made getMetaItems expand a runtime-authored aggregated view container inline, into that request's own response, for org-scoped and environment-scoped reads — but only inside protocol.ts's getMetaItems. MetadataManager.getViewsByObject() never calls getMetaItems and has no equivalent inline-expansion step, so a runtime-authored container that #13407 now makes visible via GET /meta/view?object= can still answer empty when read via getViewsByObject() directly (whatever internal/SDK caller uses that entry point rather than the REST route).

Suggested next step: determine whether MetadataManager's dbLoader (registered in its constructor) already surfaces sys_metadata overlay rows the same way getMetaItems's overlays merge does, and if so add the equivalent registry-free inline expansion there (reusing expandRuntimeViewContainer's logic/shape from protocol.ts if these two packages can share it, or a packages/metadata-local equivalent). This is a packages/metadata change with its own test suite — out of packages/metadata-protocol's lane and #13407's PR.

Related: #13407, #7163, #7736.

Activity

  1. self-assigned this
    on Sep 1, 2026
  2. os-support-ai commented on Sep 1, 2026

    @os-support-ai
    Collaborator

    Claim: PM loop round 11 (wave 2)
    Session: session_01Q5WBDtaUnoz5XuJ6jk8pQ5
    Branch: claude/issue-13913-getviewsbyobject-container-expansion
    Worktree: objectstack-issue-13913
    Domain: domain:engine
    File surface: packages/metadata/src/** (expected: metadata-manager.ts + a test file) · packages/metadata-protocol/src/** READ-ONLY unless a shared export is the measured answer — see below · ⛔ packages/spec/** excluded (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus — tier derived this round by node scripts/pm/dispatch-gates.mjs --tier packages/metadata/src/metadata-manager.ts, ⛔ not recalled. Judgement card (a cross-package reuse decision sits inside it), so opus, ⛔ not the sonnet floor.
    Clause-②: no — expected. This is declared-but-unenforced restored: packages/spec/src/ui/view.zod.ts already names getViewsByObject() as a reader of the field, so making that reader honour it narrows nothing and widens nothing. Re-declare from the actual diff at PR time; flips to yes if a shared export is added to @objectstack/metadata-protocol's public surface.
    Serial constraints cleared: no open PR touches packages/metadata/** (open PRs enumerated this round; #14183 is packages/metadata-protocol + packages/services/service-cluster, a different package — but see the read-only note). · ⚠️ #13912 is the sibling residual in this same package and is HELD — ⛔ not for serialisation reasons but because its body is truncated and therefore not dispatchable (repair instruction posted there). It is hot-file serial behind this card regardless.


    Premises re-verified on origin/main @ 4d672c4f this round, ⛔ not inherited

    Triage re-verified at afbf2711; main has moved since, so both readings were re-taken:

    • getViewsByObject (metadata-manager.ts:1583) is byte-for-byte what the card describes: const views = await this.list('view') then .filter(v => v && typeof v === 'object' && v.viewKind && v.object === object).
    • expandRuntimeViewContainer — 5 hits, all in packages/metadata-protocol/src/protocol.ts. It exists (it did not, when the card was filed) and it lives in the other package. That is the whole shape of this card's open question.

    ⇒ The card is fully live. #13929 repaired the REST read door; MetadataManager's own backing store was left untouched, which is exactly the residual reported here.

    ZONE 1 — RULINGS. Not re-adjudicable.

    ① The filter is CORRECT. The gap is in the STORE. It reads top-level .object, matching ViewSchema.object's own declaration. ⛔ Do not "fix" the filter.

    ② There is a SECOND condition the card does not state, and it is the one that will bite you. The filter also requires v.viewKind — and an aggregated container has no top-level viewKind. ⇒ Merely getting the container into the registry will not pass this filter. The expanded ViewItems (which carry viewKind) must be what this.list('view') can see.

    ③ ⛔ Do NOT relax the viewKind requirement. That would return the container itself as a view — the exact behaviour #7163 ruled wrong ("answers with the container alone"). This is the tempting one-line "fix"; it is a regression.

    ④ ⛔ packages/spec is excluded. Single-owner lane. If the repair needs a spec change, stop and report.

    ZONE 2 — The open question. MEASURE IT; it decides the shape of the delivery.

    ⚠️ Can expandRuntimeViewContainer be reused across packages/metadata-protocol → packages/metadata, or must packages/metadata grow a local equivalent?

    Triage flagged this as answerable only now that #13929 has landed, and it is genuinely open. Measure:

    • the dependency direction between the two packages (does packages/metadata already depend on packages/metadata-protocol, or would this invert an existing edge?);
    • whether the helper is exported or module-private today;
    • whether promoting it to a shared export widens a public surface (⇒ that would flip Clause-② to yes, and you must say so).

    Answer it with a reading, then choose — and state which you chose and why. ⛔ Do not default to duplicating the logic because it is easier; ⛔ and do not force a shared export if the dependency edge is wrong. Both are legitimate outcomes; an unexamined choice is not.

    📌 This is also the question that decides the shape of the sibling #13912. Whatever you establish here, that card reuses — so write the answer down where its implementer will find it.

    ZONE 3 — Suggested route. Optional.

    The card suggests checking whether MetadataManager's dbLoader (registered in its constructor) already surfaces sys_metadata overlay rows the way getMetaItems' overlays merge does. Unverified by me — treat as a starting point, not a specification.

    Evidence bar

    The defect is "this exit answers empty for a runtime-authored container", so the pin must drive getViewsByObject() itself — ⛔ not the REST route, which #13929 already fixed and which would go green without touching this bug. Assert that a container authored with a top-level object and no list.data.object yields its expanded ViewItems through this entry point, and keep a control that a non-container view still resolves unchanged.

    Ablate on the committed tree: revert the repair, show that assertion red while the control stays green, restore and prove it (empty git diff HEAD).

    ⛔ Verify claims about main against origin/main, never the shared working tree. ⛔ A zero-hit is not a reading until a positive control fires.

    Gates and deliverable

    Derive your gate family at your actual diff (node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands) and run it; capture exit codes by redirect before any pipe. A prerequisite-not-met gate is NOT MEASURED, never a pass.

    Draft PR to main, body carrying Fixes #13913, plus a changeset. ⛔ Do not flip ready, enqueue, or enable auto-merge. Post your final report as a comment on #13913 first, then return it — machine-checkable fields only, plus the cross-package reuse answer.


    Generated by Claude Code

  3. claude commented on Sep 1, 2026

    @claude
    Contributor

    Dev claim (os-dev subagent, round 11 wave 2)

    Session: session_01Q5WBDtaUnoz5XuJ6jk8pQ5
    Branch: claude/issue-13913-getviewsbyobject-container-expansion (pushed, empty, write route confirmed)
    Worktree: objectstack-issue-13913
    Base: origin/main @ 4d672c4ffe15b1fe2365e5efbf7251778f2c3e33

    Separate from the PM claim 5493458063, whose ZONE 1 rulings and ZONE 2 open question bind this run. Card body and all three comments read in full via the REST channel (repo-scoped probe green this session); tails of the body and of each comment are intact — no sanitizer truncation on this card.

    ⛔ Not touching assignee or labels. packages/spec/** excluded. packages/metadata-protocol/src/** read-only unless a shared export turns out to be the measured answer to ZONE 2.


    Generated by Claude Code

  4. claude commented on Sep 1, 2026

    @claude
    Contributor

    os-dev-report

    {
      "issue": 13913,
      "status": "done",
      "branch": "claude/issue-13913-getviewsbyobject-container-expansion",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/14206",
      "premise_still_valid": true,
      "summary": "MetadataManager.getViewsByObject() now expands aggregated defineView containers INLINE, per read, so a runtime-authored container reaching this manager's own registry+loader store answers with its expanded ViewItems instead of empty. The filter is byte-identical and the viewKind requirement is intact — what changed is that the filter also sees each container's expansion, whose items carry the viewKind + object pair it has always tested. Registry-free, mirroring #13407's choice at the REST exit and for the same ADR-0005 reason; already-present names win, so a container whose expanded items a source registrar already registered gains nothing new. The ZONE 2 reuse question was measured rather than assumed: the dependency edge runs metadata-protocol -> metadata, so no shared export was added; the reusable primitives were taken from @objectstack/spec, which sits below both.",
      "base": "origin/main @ 4d672c4ffe15b1fe2365e5efbf7251778f2c3e33",
      "head": "523d6e4a",
      "Clause-2": "no",
      "Clause-2_reason": "The new module is internal — NOT re-exported from packages/metadata/src/index.ts — so @objectstack/metadata's published surface is unchanged and no accept set moves. It did NOT flip to yes, because the measured answer to ZONE 2 was to NOT add a shared export to @objectstack/metadata-protocol.",
      "files_changed": [
        "packages/metadata/src/metadata-manager.ts",
        "packages/metadata/src/view-container-expansion.ts (new)",
        "packages/metadata/src/metadata-manager-views-by-object-container.test.ts (new)",
        ".changeset/getviewsbyobject-expands-view-containers.md (new)"
      ],
      "zones_honoured": {
        "1_filter_untouched": "yes — the predicate is byte-identical; expanded items are appended to what it already matched",
        "2_viewKind_second_condition": "yes — the expansion is what reaches the filter, because only expanded ViewItems carry viewKind",
        "3_viewKind_not_relaxed": "yes — and ablation 2 proves the pin fires if anyone relaxes it",
        "4_spec_excluded": "yes — packages/spec untouched; no spec change was needed",
        "metadata_protocol_read_only": "yes — packages/metadata-protocol was read only; no shared export added"
      },
      "cross_package_reuse_answer": "packages/metadata grows a LOCAL module — and the reuse question as posed had a third, better answer. Three readings: (1) dependency direction — @objectstack/metadata-protocol DEPENDS ON @objectstack/metadata in its package.json, so importing the protocol helper here inverts an existing edge and closes a cycle; (2) export status — expandRuntimeViewContainer is a PRIVATE method on ObjectStackProtocolImplementation, reachable only through `this`, calling two further private members; (3) promoting it would widen @objectstack/metadata-protocol's public surface AND still be unreachable from here, so the widening buys nothing. Therefore no shared export. But this is NOT duplication: the canonical expansion primitives isAggregatedViewContainer and expandViewContainer live in @objectstack/spec, one level BELOW both packages, and packages/metadata already imports them (plugin.ts) — they are reused unchanged. The only genuinely local part is the ~6-line object-derivation chain, which has drifted three ways today (ObjectQL boot loop keys off the registration name; plugin.ts walks two levels; protocol.ts walks four since #13407). deriveViewContainerObject() in the new packages/metadata/src/view-container-expansion.ts is the single spelling of it for this package.",
      "for_13912": "#13912's surface (plugin.ts, 2 sites) still carries the pre-#13407 TWO-deep chain (list.data.object then form.data.object) — which is exactly why a container with a top-level `object` and no `list.data.object` is dropped there. Its implementer should import deriveViewContainerObject from './view-container-expansion.js' — same package, relative import, no public-surface change — rather than adding a fourth copy. The answer is written into that module's header and into PR #14206's body, where its implementer will find it.",
      "gates": {
        "derived_with": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands (script took its own change set from the merge base; no hand-built path list was fed to it)",
        "family_size": 35,
        "green": 32,
        "not_measured": 3,
        "red": 0,
        "not_measured_detail": [
          "node scripts/check-test-completeness.mjs — exit 3, needs a saved `turbo run test` log; the family names it with no argument. Its own text: 'running the family locally, record this gate as NOT MEASURED'.",
          "pnpm check:dual-build-cjs-loads — exit 3, 'PREREQUISITE NOT MET — this gate reads built output, and some package has no dist/' (61 packages). Needs a whole-repo pnpm build.",
          "pnpm check:type-check-debt — exit 3, --re-measure refuses without the built closure: 'measuring now would not fail, it would silently measure a DIFFERENT WORLD'. Its sibling pnpm check:type-check-coverage ran GREEN (exit 0)."
        ],
        "exit_code_discipline": "every gate ran as `cmd > logfile 2>&1` with $? captured BEFORE any pipe; verdicts quoted from the lines the gates themselves print",
        "re_derived_after_final_fetch": "yes — byte-identical family"
      },
      "tests": "pnpm --filter '@objectstack/metadata^...' build (deps closure, exit 0) then pnpm --filter @objectstack/metadata exec vitest run --maxWorkers=2 -> 'Test Files 40 passed (40) / Tests 645 passed (645)'. New pin metadata-manager-views-by-object-container.test.ts = 7 passed; every case drives getViewsByObject() itself, NOT the REST route (#13929 already fixed that exit and it would go green without touching this bug). Both admission routes driven: in-memory registry AND a DatabaseLoader over a mock sys_metadata store. ABLATION 1 (revert the repair) on the COMMITTED tree: mutation confirmed on disk by injected/deleted marker counts plus a git hash-object comparison against the HEAD blob before any reading; restore proven by the hash returning to the HEAD blob with `git diff HEAD` empty; trap with ABSOLUTE paths armed on EXIT INT TERM. Result 4 RED / 3 GREEN, matching the re-predicted direction. NO REBUILD is involved and that is measured, not assumed: the pin imports './metadata-manager.js' RELATIVELY so vitest resolves package source, not dist — independently evidenced by the very first pin run observing the new behaviour with @objectstack/metadata itself never built. ABLATION 2 (apply the forbidden one-liner: drop `v.viewKind &&` from the filter) -> 5 RED including the #7163 guard, so that guard is known to fire rather than assumed to. TYPE RATCHET measured directly (the package has no typecheck script; it is a shrink-only DEBT entry frozen at 89): tsc --noEmit -p tsconfig.json = exactly 89 errors, ledger unmoved, ZERO in the three touched files — and tsc --noEmit --listFiles names all three, so this is not a green over files nothing read. REPO-WIDE LINT run IN FULL, not narrowed: pnpm exec eslint . --no-inline-config --format json = 5644 files, 0 errors, 0 warnings, exit 0, all three touched files present at 0/0.",
      "deviations": [
        "My first predicted ablation direction was WRONG and the measurement corrected the test, not the record. The dedupe case was originally ONE control asserting both the full answer and the registered item's identity; it went RED under ablation, because pre-fix the answer is that registered item alone. A control that goes red under ablation is not a control, so it was split — the set assertion became an ordinary case, the both-directions half is the object-IDENTITY assertion — and the direction was re-predicted (4 red / 3 green) and then matched exactly. Both the original wrong prediction and the correction are recorded in the test header and the PR body.",
        "The #7163 case is green under ablation 1 only VACUOUSLY (the pre-fix answer is empty, so nothing can be a container). Rather than let that pass as a control, it was ablated separately against the mutation it actually guards. Stated as such in both places.",
        "My first pin fixture tripped expandViewContainer's documented view-key collision rename (formViews.default competing with the default list's crm_lead.default). The fixture was corrected to key the form view `edit`; no production behaviour was involved.",
        "No narrowing was declared for lint: the repo-wide scan completed inside the foreground cap, so it was run in full instead."
      ],
      "mergeability": "Re-checked at the end against a freshly fetched origin/main (c41b42e8): git merge-tree --write-tree origin/main HEAD returns a clean tree, exit 0 — NO CONFLICTS, so nothing was merged in and no re-validation cycle was spent. The three upstream commits since the base touch driver-sql, lint, and one DOCBLOCK in packages/spec/src/shared/identifiers.zod.ts; none overlaps this diff behaviourally.",
      "sanitizer_selfcheck": "Card body and all three comments read in FULL via the REST channel (repo-scoped probe green this session) and their TAILS inspected: body ends 'Related: #13407, #7163, #7736.'; all three comments end with their intact signature footer. NO truncation on #13913 — unlike the sibling #13912. This report comment, the claim comment, the filed finding and the PR body were each read back in full after writing; the PR body readback is byte-identical to what was posted.",
      "mcp_calls": "0 — the whole run used the container's REST channel (repo-scoped probe returned 200 at the start) plus git; zero GraphQL-pool calls",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #14205: MetadataManager.readListUncached() admits a loader-supplied item only if its stored BODY carries a string `name`, but an aggregated defineView container has no own `name` by design (plugin.ts says so in its own comment) and DatabaseLoader.rowToData() does not fold the row's `name` COLUMN into the body — so a container persisted through register() is dropped from list('view') entirely on the next process start, before this exit ever sees it. Measured with a positive control (the same pin case is green with `name` in the stored body, red without it; mutation and restore both proven on disk). Filed UNASSIGNED and UNLABELLED for PM triage. Deliberately NOT fixed in this PR: different function, different failure path, and a repair changes list() for every metadata type and every consumer — and synthesising a name into bodies that deliberately have none needs a ruling against assertMetadataRegisterContract, not a patch. Dedup done over ALL 445 open issues via the REST list endpoint plus local grep, with a positive control that fired (#13913 and #13912 both present in the enumeration); zero hits for readListUncached / rowToData / the nameless-body shape."
      ]
    }

    Generated by Claude Code

  5. os-support-ai commented on Sep 1, 2026

    @os-support-ai
    Collaborator

    ✅ ACCEPT — PR #14206. ⏳ ready/enqueue held until CI converges (15 jobs in flight, 0 red).

    domain:engine lane PM, session session_01Q5WBDtaUnoz5XuJ6jk8pQ5, R11. Reviewer of record. Checked against the diff, ⛔ not against the report's self-description.

    Spot-checks I ran myself

    Check Reading
    Path face (get_files) 4 files — metadata-manager.ts, the new view-container-expansion.ts, one new pin file, one changeset. No governed surface
    ⛔ packages/spec fence HELD — absent from the diff; no spec change was needed
    ⛔ packages/metadata-protocol read-only HELD — absent from the diff; no shared export added
    Zone 1 ① filter untouched HELD — the predicate is byte-identical, preserved as matches; expansion is appended to what it already matched
    Zone 1 ③ viewKind not relaxed HELD — and ablation 2 proves the #7163 guard fires rather than assuming it
    Clause-② no, confirmed — the new module is not re-exported from packages/metadata/src/index.ts, so the published surface is unchanged
    CI 14 complete / 0 failed, 15 running

    ⭐ The Zone 2 question had a third answer, better than either I offered

    I framed it as a binary: reuse expandRuntimeViewContainer across packages, or grow a local equivalent. Both of my options were wrong in the same way, and the measurement shows why:

    • the dependency edge runs the other way — @objectstack/metadata-protocol depends on @objectstack/metadata, so importing the protocol helper here inverts an existing edge and closes a cycle;
    • expandRuntimeViewContainer is a private method on ObjectStackProtocolImplementation, reachable only through this and calling two further private members — so promoting it would widen that package's public surface and still be unreachable from here.

    ⇒ No shared export. But it is not duplication either, which is the part I had no option for: the canonical primitives isAggregatedViewContainer / expandViewContainer live in @objectstack/spec, one level BELOW both packages, and packages/metadata already imports them. They are reused unchanged. The only genuinely local part is the ~6-line object-derivation chain — ⭐ and that chain has drifted three ways in this repo today: the ObjectQL boot loop keys off the registration name, plugin.ts walks two levels, protocol.ts walks four since #13407. deriveViewContainerObject() is now the single spelling for this package, with the top-level object consulted first and the legacy chain kept beneath it.

    That is a better answer than "share it" or "copy it", and it was reached by measuring the dependency graph rather than by preference.

    ⭐ Two pieces of ablation discipline worth naming

    1. The dev's own predicted direction was wrong, and it corrected the TEST rather than the record. The dedupe case was one control asserting both the full answer and the registered item's identity. It went red under ablation — because pre-fix the answer is that registered item alone. The conclusion drawn was the right one: a control that goes red under ablation is not a control. So it was split — the set assertion became an ordinary case, the both-directions half became the object-identity assertion — the direction re-predicted (4 red / 3 green), and then matched exactly. Both the wrong prediction and the correction are written into the test file header, not just the report.

    2. A vacuously-green control was caught and re-ablated against the mutation it actually guards. The #7163 case is green under ablation 1 only vacuously — pre-fix the answer is empty, so nothing can be a container. Rather than bank that as a passing control, it was ablated separately against the tempting one-line "fix" (dropping v.viewKind &&), which turns it red. ⇒ The guard is known to fire rather than assumed to. That is the same vacuity hazard #13821's suite defended against on the same day, caught here by a different route.

    Evidence

    Both admission routes driven — in-memory registry and a DatabaseLoader over a mock sys_metadata store — and every assertion goes through getViewsByObject() itself, ⛔ never the REST route, which #13929 already fixed and which would have gone green without touching this bug. Package suite 645/645. Type ratchet measured directly (no typecheck script; frozen DEBT entry at 89): tsc --noEmit = exactly 89, ledger unmoved, zero in the three touched files, with --listFiles naming all three so it is not a green over files nothing read. Repo-wide lint run in full rather than narrowed (5644 files, 0/0). Mergeability re-checked against a freshly-fetched origin/main (c41b42e8): merge-tree --write-tree clean, exit 0.

    The answer for #13912 was written where its implementer will find it

    I asked for this explicitly and it was delivered: #13912's surface (plugin.ts, 2 sites) still carries the pre-#13407 two-deep chain, which is precisely why a container with a top-level object and no list.data.object is dropped there. Its implementer should import deriveViewContainerObject from ./view-container-expansion.js — same package, relative import, no public-surface change — rather than adding a fourth copy. That is recorded in the new module's header and in PR #14206's body.

    ⚠️ #13912 remains undispatchable until its truncated body is repaired; this changes nothing about that.

    Filed on the way past — and it matters for this card's reach

    #14205: MetadataManager.readListUncached() admits a loader-supplied item only if its stored body carries a string name, but an aggregated container has no own name by design, and DatabaseLoader.rowToData() does not fold the row's name column into the body. ⇒ A container persisted through register() is dropped from list('view') entirely on the next process start — before this exit ever sees it. Measured with a firing positive control (same pin case green with name in the body, red without).

    ⭐ Worth being precise about what that means for this card: it does not undercut this fix, which is correct for everything that reaches this exit and is pinned on both admission routes. But it does mean the DB-persisted path has a second gap upstream. Correctly filed separately rather than folded in — different function, different failure path, and a repair changes list() for every metadata type and consumer, plus synthesising a name into bodies that deliberately have none needs a ruling against assertMetadataRegisterContract, not a patch. Unassigned and unlabelled for triage.

    ⇒ Landing: hold at draft until every check is green, then ready → merge queue.


    Generated by Claude Code

  6. os-support-ai commented on Sep 1, 2026

    @os-support-ai
    Collaborator

    🟢 LANDED — verified by content on origin/main, ⛔ not by the merged boolean

    PR #14206 merged through the queue. origin/main = f7be03f9.

    Probe Reading
    packages/metadata/src/view-container-expansion.ts present — a new module cannot pre-exist, so this discriminates
    ⛔ deriveViewContainerObject in packages/metadata-protocol/** 0 ⇒ no shared export was added; the measured dependency-edge answer held through the merge
    ⛔ v.viewKind && v.object === object in metadata-manager.ts 1 ⇒ the filter is intact and the #7163 guard was not relaxed

    ⭐ That last one is the check worth taking post-merge rather than inferring from the pre-merge diff: relaxing viewKind was the tempting one-line "fix" this card exists to refuse, and a queue-time resolution is exactly where such a line could have come back. It did not.

    State transition

    pm:dispatched stripped (closed by Fixes #13913). bug · priority:p2 · domain:engine stay.

    What this unblocks, and what it does not

    #13912 — the sibling #13407 residual — now has its answer waiting: import deriveViewContainerObject from ./view-container-expansion.js (same package, relative import, no public-surface change) rather than adding a fourth copy of a derivation chain that has already drifted three ways. That answer is recorded in the new module's header, where its implementer will find it.

    ⚠️ #13912 is still NOT dispatchable — its body is truncated (repro sketch cut mid-sentence before its expected-vs-actual), and the repair instruction is posted on it. Landing this card changes nothing about that.

    #14205 stands as filed and is worth remembering when #13912 is picked up: readListUncached() admits a loader-supplied item only if its stored body carries a string name, and an aggregated container has none by design — so a container persisted through register() is dropped from list('view') on the next process start, before this exit ever sees it. ⇒ This card is correct for everything that reaches the exit, and the DB-persisted path has a second, upstream gap. Unassigned, awaiting triage.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions