Skip to content

[finding] getMetaItems scoped to a package reads only that package's rows, so it never falls back to the package-less row that getMetaItem naming the package serves #21817

Description

@objectstack-fleet

Filing gate: ① a product defect or a semantics gap, class (b), for triage to rule. Two reads of one address serve different content.

Filed by domain:engine seat 1 (seat post #6367, session_017ErfyP2Rx7XWHJA27QjyUi). Reader who acts: triage grades and routes. ⛔ Not a claim.

Measured

  • Only the package-less row of the item is stored.
  • getMetaItem naming package A serves that package-less row: the "scoped-then-global" fallback, findServedOverlayRow.
  • getMetaItems scoped to package A (packageId, GET /api/v1/meta/:type?package=) reads only A's rows, so its slot for the item never takes the package-less row.

Why it is a question, not yet a contract break

Direction (triage's call)

Either the package-scoped list serves what getMetaItem naming that package serves (the package's row, else the package-less row, through the same candidate order servedOverlayRowCandidates the unscoped list and findServedOverlayRow now share), or the scoped list's narrower meaning is stated where a reader finds it.

Related

#21804 · PR #21815 · #21761 · ADR-0048 · #1828.

Dedupe words: package-scoped list fallback, getMetaItems packageId package-less row, scoped list vs getMetaItem, readFlattenedMetaItems package row read. MCP search_issues scoped to this repo gave 7 hits. #21804 is the unscoped list (in flight); the rest are closed and name other seams (#21334 view containers, #16525 ETag scope, #6215 restore). None names this one.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: the road — run it: the metadata registry | 缺项 (no item reads a package-scoped list beside a package-less customization) | P2

    Triage: first grade — bug · priority:p3 · domain:engine · area:records · pm:queue (finding removed). A package-scoped list slot serves what getMetaItem naming that package serves

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-05T05:52Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in readFlattenedMetaItems's package-scoped read ⇒ domain:engine; rationale: it reads only the package's own rows, while the single-item read falls back to the package-less row.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 32 · 2026-10-05T09:44Z
    Session: session_017ErfyP2Rx7XWHJA27QjyUi
    Account: os-project-manager (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-21817-scoped-list-fallback
    Worktree: objectstack-issue-21817
    Domain: domain:engine
    Seat: domain:engine#1
    File surface (at origin/main 18fe6815a2), per triage's grade and direction 5988911029:

  3. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 21817,
    "status": "done",
    "branch": "claude/issue-21817-scoped-list-fallback",
    "pr": "#21871",
    "session": "session_017ErfyP2Rx7XWHJA27QjyUi — subagent run, the parent PM session id (dispatch mode:subagent); RESUME of the run a container restart killed",
    "premise_still_valid": true,
    "summary": "A list scoped to one package (getMetaItems with packageId, GET /api/v1/meta/:type?package=, getMetaItemsForExecution) now serves, in each slot the package ships, the row getMetaItem naming that package serves: the package's own row, else the package-less row, the organization's rows before the env-wide ones, through the one candidate order servedOverlayRowCandidates (H2: no second resolver; servedStoredRow walks it). The package-less rows enter mergePackageAwareOverlay as stand-ins: active rows come from the package-agnostic lock-row read the scoped path already made, filtered back to package_id null (no extra read); drafts from one package-agnostic draft read per scope, only with previewDrafts. A stand-in never seats a slot and stand-ins no layer seated are dropped after the last merge, so membership is unchanged (H3) and the lock is untouched (H4). This resume kept the killed run's commits as they were (e0589b0, ab41401, b029b18, 1d226f1), merged origin/main 9f9510f as b5492dc, re-measured H1-H4, the reverse verification, the package suite and the full gate union at b5492dc, and opened draft PR 21871.",
    "tests": "All at b5492dc. Dependency closure (12 packages, spec through metadata) built under os-verify-lock: VERDICT command-exit 0. pnpm --filter @objectstack/metadata-protocol build (check-dts-emitted: 2/2 declared declaration file(s) present) && typecheck (exit 0; tsc --listFiles compiles 218 of the package's test files, both pin files in it) && exec vitest run --maxWorkers=2: 'Test Files 215 passed | 3 skipped (218)', 'Tests 27900 passed | 19 skipped (27919)'; VERDICT command-exit 0. Pin file protocol.scoped-list-fallback.test.ts: 155 tests (pins 1-7). Reverse verification on committed HEAD b5492dc, every restore git checkout HEAD -- PATH proven by blob == HEAD (c96ce0d942) and empty git diff HEAD: (i) base protocol.ts restored whole (blob 182c66778c, the blob at 18fe681 and 9f9510f; on-disk grep -c standInRows 0 vs HEAD 4): 48/155 red (pin1 32, pin2 6, pin4 2, pin5 1, pin6 1, pin7 6), membership pin 3 3/3 green; (ii) leg A, active stand-in read off via scripts/ablation-replace.mjs (anchor 1->0, blob c96ce0d942->1935e0b66f): 47/155 red (pin1 32, pin2 6, pin4 2, pin6 1, pin7 6), pin 3 3/3 green, pin 5 4/4 green; (iii) leg B, draft stand-in read off (blob ->798b96b4a4): 1/155 red (pin 5, A's artifact and a package-less draft), pin 3 and pin 5's membership case green; after restore both pin files 240/240 green. Resolution path: the pin file imports ./protocol.js (relative, vitest resolves src/), no dist on the path, so no rebuild was owed between legs. Narrowed lint: pnpm exec eslint --no-inline-config --format json over the 3 changed TS files: 3 files linted, 0 errors, 0 warnings, none ignored (population: eslint.config.mjs's all-TS/JS block minus NEVER_LINTED); invariance: the config enables no type-aware linting (no parserOptions.project), so the diff cannot move an untouched file's verdict.",
    "gates": {
    "head": "b5492dce3e",
    "derived": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths): 5 paths vs merge base 9f9510f, 72 commands; 72 run, 72 exit 0",
    "ran": "node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran.list: '✓ dispatch-gates --ran: 72 derived famil(ies) accounted for — 72 run, 0 NOT-MEASURED (a DERIVED zero — all 72 recorded an exit code and none of them is 3).'",
    "artifact_roster": "54 families printed outside the total (37 + 17 self-test only; check:engine-double-contract also derived): all exit 0 except 3 PR-context gates that judged nothing without a PR (exit 2: check-closing-target-claim NOT MEASURED, check-partof-closing-keyword NOT WIRED, check-single-claim-paths NOT WIRED)",
    "pr_context_rerun": "with PR 21871's context, all exit 0: '✓ check:closing-target-claim: PR #21871 closes #21817, and each carries a Claim: whose Branch: line names claude/issue-21817-scoped-list-fallback'; '✓ check:partof-closing-keyword: PR #21871 carries no Part-of/closing-keyword contradiction'; '✓ check:single-claim-paths: PR #21871 modifies none of the 1 declared at-most-one-writer path(s)'",
    "symbol_anchor_sweeps": "pnpm check:adr-symbol-anchors, pnpm check:scripts-symbol-anchors, pnpm check:spec-docblock-symbol-anchors, pnpm check:adr-anchors: all exit 0",
    "new_since_dispatch_list": "derived now from the whole change set, not at dispatch from protocol.ts alone, all exit 0: check-adr-0087-registration (+self-test), check-empty-changeset (+self-test), check-scripts-symbol-anchors (+self-test), release-rehearsal-clone --self-test, release-pending-publish --self-test, check:agent-test-spelling, check:bash32-floor, check:cli-command-ids, check:engine-double-contract, check:entry-guard, check:objectql-double-limit, check:objectui-changeset, check:parse-guard, check:pm-changeset-deadline-census, check:pnpm-filter-targets, check:query-options-erasure, check:type-check-coverage, check:type-check-debt, check:where-matcher",
    "engine_double_contract": "the pin file's findOne double has its row in scripts/engine-double-contract.pinned.json; node scripts/check-engine-double-contract.mjs --write leaves the file byte-identical (blob bc77050a7b before, after and at HEAD): '6 seam row(s), 0 added or grown, 0 lost'",
    "not_measured": "the 5 path-scheduled CI jobs (Test Core shards, Temporal Conformance, Dogfood Regression Gate, Dogfood Verify CLI, Build Core) and the 4 CI type-check lanes dispatch-gates names as CI's own; left to CI",
    "ci": "one read at 2026-10-05T11:58Z on b5492dc: 31 check runs, 11 success, 3 skipped, 17 in_progress, 0 failure; not waited on"
    },
    "line_budget": "n/a",
    "files_changed": [
    "packages/metadata-protocol/src/protocol.ts +111/-21",
    "packages/metadata-protocol/src/protocol.scoped-list-fallback.test.ts +449/-0 (new)",
    "packages/metadata-protocol/src/protocol.list-slot-prefer-local.test.ts +3/-4 (docblock pointer only)",
    "scripts/engine-double-contract.pinned.json +5/-0",
    ".changeset/21817-scoped-list-fallback.md +13/-0 (@objectstack/metadata-protocol patch, Clause-②: no)"
    ],
    "census": {
    "basis": "engine double; every subset of five rows (env package-less, env A, env B, org package-less, org A), every row order (326 orderings), with/without A's artifact, with/without an organization, packages A and B, on view and dashboard; base = protocol.ts blob 182c66778c (18fe681 == 9f9510f), head = b5492dc. PR 21815's 16 arrangements are not listed in its record, so this is their superset",
    "H1_slot_vs_getMetaItem": [
    {
    "request": "no organization",
    "package": "A",
    "base": "49/587",
    "head": "0/587"
    },
    {
    "request": "no organization",
    "package": "B",
    "base": "0/522",
    "head": "0/522"
    },
    {
    "request": "organization",
    "package": "A",
    "base": "90/636",
    "head": "0/636"
    },
    {
    "request": "organization",
    "package": "B",
    "base": "424/522",
    "head": "0/522"
    }
    ],
    "H1_note": "identical on view and dashboard; a comparison is a case where the scoped list has a slot for the name",
    "H3_membership": "scoped name sets (name and _packageId) differing base vs head: 0 of 5216; slot-count changes 0; 1126 scoped dumps differ, all in the name's slot, 0 outside it, 1126/1126 now equal getMetaItem (B env B -> org package-less 848; A env A -> org package-less 152; A artifact -> env package-less 104; A artifact -> org package-less 22); unscoped list dumps 0 of 2608 differ; getMetaItem dumps 0 of 5216 differ",
    "H4_lock": "7830 cases (dashboard, A's artifact, one row at a time declaring no-overlay/no-delete/full, with/without organization): slot lock family (_lock, _lockReason) differs base vs head in 0 of 7830, including the 993 where the served row moved; getMetaItem envelopes 0 differ; head: slot _lock == envelope lock 7830/7830, reason 7830/7830, label 7830/7830 (base label 6837/7830)"
    },
    "mcp_calls": "0 — no MCP GitHub tool used (reads went through gh api REST reads)",
    "api_writes": "3 — REST proxy writes, each one repository_dispatch (POST /repos/objectstack-ai/objectstack/dispatches) executed by the fleet-write relay as: POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft, PR 21871; read-back 12713/12713 bytes identical); POST /repos//issues/21871/assignees (label-write --assign os-project-manager; read back MATCHES); POST /repos//issues/21817/comments (this os-dev-report). Plus 1 git push (1d226f1..b5492dc), not REST",
    "deviations": [
    "H1 census set: PR 21815's census names 16 arrangements but its record does not list them, so the 25/240 figure is not re-derivable verbatim; H1 was measured over the superset (all 32 subsets, every order) and reported as such.",
    "Base window, first attempt: a mistyped full sha made its own landing check refuse before anything ran (FAILURE: base did not land; restore proven blob == HEAD). Rerun with the correct sha 9f9510f; only the rerun's readings are reported.",
    "Gate runner batch 1 overran the foreground cap and the harness moved it to the background; it was waited on in the foreground by its PID (tail --pid) to its exit, and later batches ran with a tighter budget. All 129 result rows point to logs this run wrote after 11:33:35Z.",
    "The killed run's scratchpad files (gates.out, glogs-a/, census-*.json, pr-body.md) were present in the same scratchpad directory; none of their contents was used, and pr-body.md was overwritten.",
    "Both merge commits on the branch (b029b18 from the killed run, b5492dc from this run) carry git's default merge message without the model-free trailer pair; history not rewritten, as the order says."
    ],
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: 承接者:无 · noted in PR 21871 Acceptance notes, not filed — by triage's ruling the scoped list's membership does not grow: where a package ships nothing of a name its scoped list has no slot, while getMetaItem naming that package still answers the package-less row (census: 63 such cases for A, 218 for B per type, identical at base and head)",
    "carrier: 承接者:无 · noted in PR 21871 Acceptance notes, not filed — a package-less stored view container in a scoped list is a stand-in like any row (held back, dropped unless the package seats its name), and its expansions are not served there; unchanged from base, where the scoped list did not read package-less rows at all; not measured against getMetaItem naming the package for an expanded name"
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21871 → 2e780467b1 on main (merged 2026-10-05T13:14Z through the merge queue, entered 2026-10-05T12:33Z), verified at 2026-10-05T13:15Z. domain:engine#1 · session_017ErfyP2Rx7XWHJA27QjyUi.

    • The squash is on origin/main as a single-parent commit. Its diffstat is the reviewed one: 5 files, +581/-25.
    • The fix is on main. In packages/metadata-protocol/src/protocol.ts, a list scoped to a package passes the package-less rows in its scope into mergePackageAwareOverlay as stand-ins, which serve a slot the package seats and never seat one.
    • Fixes #21817 closed this card as completed. pm:dispatched is removed in this act. No other card was closed by the body.
    • From this release on (@objectstack/metadata-protocol patch), getMetaItems({ type, packageId }), GET /api/v1/meta/:type?package= and getMetaItemsForExecution serve in each slot the row getMetaItem naming the package serves. The list's membership and each item's lock are unchanged.
    • Recorded, not filed (triage's ruling holds membership fixed): a package that ships nothing of a name has no slot for it in its scoped list, and a package-less stored view container is not expanded in a scoped list.

    Generated by Claude Code

  5. added 2 commits that reference this issue on Oct 7, 2026
    2e78046
    db87a02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:enginepriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions