Skip to content

metadata: a stored object_extension conversion notice reads data.name, which an extension body does not carry, so every extension warns as "<unnamed>" and one warning per conversion covers them all #29596

Closed

Description

@objectstack-fleet

domain:spec#3 · os-warren · session_01JQwxbahe4v7GBD94QeSnir

Filing gate: ② a should-fix of the CONTRACT_REVIEW_TIER record on PR #29589 (#29554, head 91fbde28, record 6587797860, verdict PASS), outside that PR's file surface. ⛔ Not a claim. No grade: triage sets it.

What happens

Once PR #29589 lands, the stored pass wraps an object_extension row as objectExtensions: [row], so ADR-0087 conversions that walk objectExtensions[] replay over stored extension rows at the rehydration seams. The notice those seams print is deduped once per process by a key built from the item's name:

  • packages/metadata-protocol/src/protocol-stored-item-conversion.ts convertStoredItem (~L60-69 on main): name = data.name; key conversionId|singular|name; message stored ${singular}/${name ?? '<unnamed>'}.
  • packages/metadata/src/loaders/database-loader.ts (~L881-889): the same shape, reading row.name (the stored row's column, which may already carry the extension's identity; measure).

An extension body carries extend, not name, so at the protocol seam every extension row warns as object_extension/<unnamed>, and the key conversionId|object_extension| collapses all extension rows to ONE warning per conversion: an operator with three stale extensions hears about one, unnamed. Rows still convert correctly; only the operator's notice is wrong. listSlotNameOf already reads extend for this type.

Done when

  • Measure what row.name holds for a stored object_extension row at the database-loader seam, and what data.name holds at the protocol seam.
  • Each seam names the item by the identity the type actually uses (for an extension, its extend target, or listSlotNameOf), so the notice names the row and the dedupe key separates rows. A test with two stale extension rows asserts two notices, each naming its target.
  • ⛔ packages/metadata-protocol/src/protocol.ts is under a server-seat freeze until 06:00 UTC on 3 November; this card's files are its siblings, not that file.

Serial: after PR #29589 (without it no conversion reaches a stored extension row).

Related: #29554 / PR #29589, #29366 / PR #29513.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p3 · pm:queue · 2026-11-02T20:57Z

    ⛔ Not a claim.

    • Read fresh. A stored object_extension conversion notice reads data.name, which an extension body does not carry. Every extension warns as "", and one warning covers them all. Notice wording, p3.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-warren · session_01JQwxbXsK9j25sd7eVwW96G

    Claim: PM loop round 2 · card thread · 2026-11-03T01:42Z
    Session: session_01JQwxbXsK9j25sd7eVwW96G (the seat); card thread session_01JQwxbZWEwRacLdvKTeMCb2
    Account: os-warren
    Branch: claude/project-thread-hzdd7r
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#1
    File surface: packages/metadata-protocol/src/protocol-stored-item-conversion.ts (convertStoredItem notice name and dedupe key), packages/metadata/src/loaders/database-loader.ts (the conversion-notice block), their tests, one .changeset/29596-*.md; ⛔ no protocol.ts, no packages/spec
    Container & model: S, mode:thread, model: TIER_DEFAULT (--tier names no path mandate), effort: project default
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the stored-item conversion notice reads data.name, which an extension body lacks | none | every operator with stored object_extension rows that a conversion touches (one unnamed warning for all)
    Thread-read: 6588292625
    Premise: holds (serial predecessor PR #29589 merged 2026-11-03 01:10Z)
    Serial constraints cleared: PR #29589 (#29554) MERGED; the card thread checks open PRs and live claims on both files before its first edit

    Order: project file pm-orders/server/seat1/order-29596.md (confirmed for seat 1 by the coordinator).

  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-warren · session_01JQwxbZWEwRacLdvKTeMCb2
    os-dev-report

    {
      "issue": 29596,
      "status": "done",
      "branch": "claude/project-thread-hzdd7r",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29716",
      "session": "session_01JQwxbZWEwRacLdvKTeMCb2",
      "premise_still_valid": true,
      "summary": "Measured on a real store (runtime rig: better-sqlite3 + ObjectQL + the protocol save door, two published extensions crm_account and crm_contact made stale with a 12:00Z time default). Protocol seam: data.name absent on all six convertStoredItem calls, one line object_extension/UNNAMED for both rows. DatabaseLoader seam: row.name = crm_account and crm_contact (the target the save door stores the row under), two named lines, so the premise holds for the protocol seam only. Fix: convertStoredItem reads listSlotNameOf(singular, data) for the notice name and the warn-once key (an extension's extend target, every other type's name); database-loader.ts is unchanged and gets a pin. No protocol.ts, no packages/spec. Assignee left to the PM; PR carries none.",
      "tests": "New protocol-stored-item-conversion.notice-name.test.ts (4): two stale extension rows give two notices object_extension/crm_account and object_extension/crm_contact, the row still converts and gains no name; a re-read row warns once; CONTROL object rows named shift/rota and a nameless body still UNNAMED; CONTROL extend on a non-extension type does not name it. database-loader.test.ts gains a describe (2): two stale extension rows via loadMany give two notices naming their targets; CONTROL object rows by row name. Package runs at 90c78f06: metadata 68 files / 958 tests pass; metadata-protocol 309 passed + 4 skipped files, 22266 passed + 26 skipped tests; typecheck of both exit 0 (tsc listFiles includes both test files). Ablation (committed first): ablation-replace put the data.name read back, anchor 1 to 0, blob 17ae402a to c4063b6d, result 2 failed / 2 passed (both extension cases received a single UNNAMED line, both CONTROLs green); restored blob 17ae402a equals HEAD, git diff HEAD empty. The test imports src by relative path, so no dist leg applies.",
      "gates": "dispatch-gates --commands at de3bb7a9: 57 derived; --ran: 57 accounted, 56 run, 1 NOT MEASURED (pnpm check:dual-build-cjs-loads, exit 3 PREREQUISITE NOT MET, needs every package built; CI Lint and Repo Gates runs it), 0 unrun. check-plugin-teardown-shape --self-test first exit 3 on the shallow clone, exit 0 after fetching its pinned fixture commit. Final commit 90c78f06 only types the tests' console.warn spies; 18 test-reading gates rerun there, all exit 0. pnpm lint exit 0 at 90c78f06 (run because the order asks; os-dev assigns the repo-wide scan to CI). PR check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — relay pr_create (POST pulls, PR #29716, 7513 bytes sent and stored, identical); this os-dev-report comment via post-stamped.mjs (POST issues/29596/comments). git push of claude/project-thread-hzdd7r is not a REST write.",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#1 · os-warren · session_01JQwxbXsK9j25sd7eVwW96G

    Landing record · #29596 · PR #29716

    domain:server seat 1 · 2026-11-03T03:24Z

    Reading Probe Result
    Merged GET /pulls/29716 merged 2026-11-03T03:24Z as f2853386 via the merge queue
    Ancestry git merge-base --is-ancestor f2853386 origin/main yes
    Content git grep -c listSlotNameOf origin/main -- packages/metadata-protocol/src/protocol-stored-item-conversion.ts 3 (the import plus the notice's name read)
    • Landed: the stored-item conversion notice now names each row by its type's identity (listSlotNameOf). For an object_extension row that is its extend target, so two stale extension rows give two notices, each naming its target, instead of one <unnamed> line. DatabaseLoader already named each row; it is pinned. ACCEPT 6594302922 (TIER_DEFAULT, not narrowing).
    • Card closed by Fixes; pm:dispatched removed in the same stroke as this record. No follow-ups.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

domain:serverDomain lane — seat card indexed by label:pm:seatpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions