You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
docs(adr): ADR-0005 still states the overlay uniqueness key as four parts — since 5677add93f (#22877 stage 1) it carries bundle_member (Tier H, the maintainer's hand) #23006
Filing gate ①, class (b): an accepted record states the current overlay key, and since 5677add93f that statement is false. It is a governed-surface text (docs/adr/**, Tier H): the maintainer's hand edits it, and no seat does. reach: named producer 5677add93f (#22877 stage 1, PR #22954). Readers: every agent and author who reads ADR-0005 for the overlay's uniqueness key.
Filed by domain:engine seat 2 (#20966) · os-steve · session_01ADzJtzYTLUfgrRZHxkagkX · 2026-10-12T09:30Z, at landing, as the ACCEPT on #22877 (6120204973) recorded. The contract-tier review on PR #22954 named it: "ADR-0005's present-tense amendment still spells the current key as four parts — … an amendment line is Tier H, the maintainer's hand: file it". ⛔ Not a claim. Lane and grade are triage's.
What is false on main (read at 5677add93f)
docs/adr/0005-metadata-customization-overlay.md:833: "a plain DatabaseLoader boot already stores CREATE UNIQUE INDEX idx_sys_metadata_overlay_active ON sys_metadata (type, name, organization_id, package_id) — the declared index, with the current key". After 5677add93f the declared index carries a fifth column, bundle_member (packages/metadata-core/src/objects/sys-metadata.object.ts).
:865, under "What delivers overlay uniqueness today": "(type, name, organization_id, COALESCE(package_id, ''))WHERE state = 'active'". The runtime key is now (type, name, organization_id, COALESCE(package_id, ''), COALESCE(bundle_member, '')), active and draft (packages/metadata-protocol/src/migrations/overlay-index.ts).
Re-check: git show origin/main:docs/adr/0005-metadata-customization-overlay.md | grep -n -E "organization_id, package_id\)|COALESCE\(package_id, ''\)\)" against git show origin/main:packages/metadata-protocol/src/migrations/overlay-index.ts | grep -n bundle_member.
The remedy (the maintainer's)
One dated amendment line in ADR-0005's status header, plus the two sentences restated (or annotated) with the five-part key and its reason:
NULL is the canonical member, so name-only types are unchanged.
It can ride with any other ADR edit already owed to the maintainer. ADR-0139's E0 status line is one (#22788).
Dedupe
MCP search_issues, closed included: ADR-0005 overlay index key bundle_member four parts → 0 hits on this subject. #22877 (still open: its stage 2 remains) is the producer, not a duplicate.
Triage: first grade, documentation · priority:p3 · domain:skills · area:devpath, into pm:queue. Sequenced after PR #23011, which edits the same ADR
Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T11:08Z. ⛔ Not a claim, ⛔ not a dispatch.
Lane:docs/adr/** is the governed surface, so domain:skills takes it. A seat authors governed text under the Tier H terminal steps, and the maintainer approves the merge.
Why p3: two sentences in an accepted record name a four-part key, and the runtime key has five parts since 5677add93f. Nothing at runtime is wrong.
Claim: PM loop round 1 (#23006 — ADR-0005's present-tense overlay key gains bundle_member, Tier H) · 2026-10-12T11:35Z
Session: session_012dGTuJen61ECNHXYXKChoC
Account: os-justin (the seat's linked user as GET /user answers it; always the card's assignee)
Branch: claude/issue-23006-adr-0005-five-part-overlay-key
Worktree: objectstack-issue-23006
Domain: domain:skills
Seat: domain:skills#2
File surface: docs/adr/0005-metadata-customization-overlay.md (the status header's amendment list, and the present-tense statements of the current key in the "what is true today" block: the card's two lines plus the declared-index line beneath them, which the card does not name); conditionally scripts/adr-anchors/packages__metadata-protocol__src__migrations__overlay-index.ts.json and scripts/adr-anchors/packages__metadata-core__src__objects__sys-metadata.object.ts.json (the key spelling in their invariant text only, under the bounded in-place rule, if the dev measures them stale) (stop on breach; explain in the report)
Container & model: S, mode:subagent, model: opus — the default judgment tier; dispatch-gates --tier --repo objectstack-ai/objectstack on the ADR path at 3071d3e98 printed 「Model tier — no path-derived mandate」 (floor sonnet · default opus · ceiling fable); the seat's call is default, not floor, because a governed record's correctness is judged by reading, not by the gate farm
Clause-②: no
Responsibility: n/a — not a defect card (an accepted record's present-tense statement went stale; class (b) of the filing gate)
Thread-read: 6123056260
Ruling-ref: none on this card. The content follows #22877 ruling 6116165299 (letter A, maintainer 「同意」; fetched in this act), which put the bundled type's member into the overlay key.
Resume-from: none
Serial constraints cleared: PR #23011 (#22340 S3, seat 1) edits ADR-0005's status header, the region this card's amendment line lands in, so this card was held behind it until it read MERGED as e4a770d6b (2026-10-12T11:32Z). In-flight claims naming ADR-0005 across all 18 open pm:dispatched cards: only #22340 (that is the control hit). Open PRs changing ADR-0005 among all 19 open: only PR #23011. #22788 (ADR-0139's status line, pm:blocked, domain:engine) is named on the card as a possible rider. It does not ride: it is another card, in another lane, in another file.
Delivery shape: Fixes #23006; Tier H, so the PR stays draft until an authorized approval.
os-dev-report
{
"issue": 23006,
"status": "done",
"branch": "claude/issue-23006-adr-0005-five-part-overlay-key",
"pr": "#23037",
"session": "session_012dGTuJen61ECNHXYXKChoC (subagent: the PM session id; identity is the branch)",
"premise_still_valid": true,
"summary": "ADR-0005 now states the five-part overlay key. The status line gains one dated entry, '· Amended (2026-10-12, #22877 ruling A — …)', naming bundle_member, NULL as the canonical member, and producer 5677add (PR #22954). The #6771 measurement sentence is kept verbatim with a dated '2026-10-12 note' after it. Owner 1 states the runtime key (type, name, organization_id, COALESCE(package_id, ''), COALESCE(bundle_member, '')) with its reason. Owner 2 quotes the tree's declaration: five fields, unique: 'global'. H1 confirmed: the full re-grep found 3 present-tense sites at edecd44 (:835/:867/:878), not the card's 2. H2 confirmed from the tree. H3 confirmed stale: both anchor invariants spelled the four-part key, so each got the bounded in-place one-span fix. H4: the anchor citing ADR-0005:53-64 still points at byte-identical lines (BASE vs HEAD diff exit 0). Draft PR #23037 is open, assignee os-justin, label skip-changeset read back. It stays draft: Tier H, the maintainer's approval lands it. CI: in_progress, not waited on (PM owns convergence). Worktree cleanup (node_modules, then git worktree remove) is the step right after this comment.",
"tests": "Docs and anchor text only, so no package test or typecheck applies (the diff touches no package). Gates on HEAD a75f9f2: all 27 derived commands exit 0 (list in gates). dispatch-gates --ran: '27 derived famil(ies) accounted for — 27 run, 0 NOT-MEASURED (a DERIVED zero — all 27 recorded an exit code and none of them is 3)'. Measurement behind the ADR wording change (Acceptance notes 2): in-memory SQLite (better-sqlite3 12.11.1) with the declared five-column plain CREATE UNIQUE INDEX. Two identical packaged canonical rows (bundle_member NULL): both INSERTED. Two identical zh-CN rows: the second REFUSED with SQLITE_CONSTRAINT_UNIQUE. No ablation: no gate or code changed.",
"gates": [
{
"cmd": "node scripts/check-adr-links.mjs",
"exit": 0,
"verdict": "check-adr-links: 730 relative link destination(s) under docs/adr/ resolve"
},
{
"cmd": "node scripts/check-adr-links.mjs --self-test",
"exit": 0,
"verdict": "check-adr-links --self-test: discrimination, census, ADR-0046 pin and baseline staleness all verified"
},
{
"cmd": "node scripts/check-adr-symbol-anchors.mjs",
"exit": 0,
"verdict": "check-adr-symbol-anchors: 2319 anchors across 142 records resolve"
},
{
"cmd": "node scripts/check-adr-symbol-anchors.mjs --self-test",
"exit": 0,
"verdict": "check-adr-symbol-anchors --self-test: every finding class provoked, healthy anchors silent"
},
{
"cmd": "node scripts/check-ci-filter-parity.mjs",
"exit": 0,
"verdict": "OK: all 197 declared cross-package glob(s) (144 unique) are covered by core or crosspkg"
},
{
"cmd": "node scripts/check-closing-keyword-parity.mjs",
"exit": 0,
"verdict": "check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators)"
},
{
"cmd": "node scripts/check-closing-keyword-parity.mjs --self-test",
"exit": 0,
"verdict": "check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red"
},
{
"cmd": "node scripts/check-comment-mask-corpus.mjs",
"exit": 0,
"verdict": "comment-mask corpus sweep: 8857 files, 0 disagree, 0 unparseable"
},
{
"cmd": "node scripts/check-scripts-symbol-anchors.mjs",
"exit": 0,
"verdict": "check-scripts-symbol-anchors: 3837 anchors across 285 scripts resolve"
},
{
"cmd": "node scripts/check-scripts-symbol-anchors.mjs --self-test",
"exit": 0,
"verdict": "check-scripts-symbol-anchors --self-test: every finding class provoked"
},
{
"cmd": "pnpm --filter @objectstack/lint run check:doc-formula-expressions",
"exit": 0,
"verdict": "first run exit 3 (PREREQUISITE NOT MET: @objectstack/formula + @objectstack/lint unbuilt); built under os-verify-lock (turbo run build --concurrency=2 --filter=@objectstack/formula --filter=@objectstack/lint, VERDICT command-exit 0, 4/4 tasks); rerun exit 0: self-test 61 cases passed; 22 record-scoped formula example(s) across 473 files / 1388 TS blocks judged clean"
},
{
"cmd": "pnpm check:adr-anchors",
"exit": 0,
"verdict": "check-adr-anchors --self-test: 106 assertions; check-adr-anchors: OK (68 anchored file(s), every governing ADR still referenced; 44138 citation(s) across 5846 file(s) resolve)"
},
{
"cmd": "pnpm check:agent-test-spelling",
"exit": 0,
"verdict": "check-agent-test-spelling: 0 violations"
},
{
"cmd": "pnpm check:bash32-floor",
"exit": 0,
"verdict": "check-bash32-floor: 30 tracked shell file(s) name no bash 4+ construct"
},
{
"cmd": "pnpm check:cli-command-ids",
"exit": 0,
"verdict": "check-cli-command-ids: 814 command-id literal(s) across 253 file(s) all resolve"
},
{
"cmd": "pnpm check:cross-package-test-inputs",
"exit": 0,
"verdict": "OK: 30 package(s) read outside themselves, all declared"
},
{
"cmd": "pnpm check:doc-authoring",
"exit": 0,
"verdict": "doc authoring guard: 18262 customer-facing string(s) across 1356 spec sources clean"
},
{
"cmd": "pnpm check:driver-memory-census",
"exit": 0,
"verdict": "check-driver-memory-census: OK"
},
{
"cmd": "pnpm check:entry-guard",
"exit": 0,
"verdict": "check:entry-guard: 285 scripts/ file(s), every entry guard goes through invoked-as.mjs"
},
{
"cmd": "pnpm check:gitlink-declared",
"exit": 0,
"verdict": "check-gitlink-declared: OK (11048 index entries, 0 gitlink(s))"
},
{
"cmd": "pnpm check:nul-bytes",
"exit": 0,
"verdict": "check-nul-bytes: OK (scanned 11039 text file(s); no raw ASCII control bytes)"
},
{
"cmd": "pnpm check:parse-guard",
"exit": 0,
"verdict": "check:parse-guard: 284 scripts/ file(s), every TypeScript parse goes through ts-parse.mjs"
},
{
"cmd": "pnpm check:pm-governed-merges",
"exit": 0,
"verdict": "check-governed-merges --self-test: 476 assertions; live: the real generator declared 9 output(s) and certified this tree"
},
{
"cmd": "pnpm check:pm-prior-rulings",
"exit": 0,
"verdict": "check-prior-rulings self-test: 155 cases pass"
},
{
"cmd": "pnpm check:pnpm-filter-targets",
"exit": 0,
"verdict": "check:pnpm-filter-targets: 160/214 --filter occurrence(s) across 44 file(s) resolve"
},
{
"cmd": "pnpm check:refd-timer-probe",
"exit": 0,
"verdict": "check-refd-timer-probe: 8851 source file(s) swept"
},
{
"cmd": "pnpm check:watch-hint-literal",
"exit": 0,
"verdict": "check-watch-hint-literal: 73 declaration(s) across 4 rostered name(s)"
}
],
"extra_gates_outside_derivation": [
{
"cmd": "pnpm check:overlay-whitelist-table",
"exit": 0,
"verdict": "leg 1 0 divergence(s) over 13 type(s); leg 2 0 divergence(s) over 5 allowEnvironmentOverlay true type(s)"
},
{
"cmd": "node scripts/check-published-list-mirrors.mjs",
"exit": 0,
"verdict": "OK: 1 published list mirror(s) match their constants line for line"
},
{
"cmd": "pnpm check:dts-closure",
"exit": 0,
"verdict": "check-dts-closure: 4 built package(s) swept, 46/46 declared declaration file(s) present"
},
{
"cmd": "pnpm check:engine-double-contract",
"exit": 0,
"verdict": "check-engine-double-contract: OK, 999 pinned, 124 in the DEBT ledger, 3 exempt"
},
{
"cmd": "pnpm check:i18n-stale-fill",
"exit": 0,
"verdict": "check-i18n-stale-fill: OK (10 bundle set(s), no new stale fills)"
},
{
"cmd": "pnpm check:published-readme-exports",
"exit": 3,
"verdict": "NOT MEASURED, reason: prerequisite, needs a full pnpm build of ~40 packages; this diff touches no package and no README"
},
{
"cmd": "pnpm check:console-injection",
"exit": 0,
"verdict": "NOT MEASURED, reason: the gate skipped itself, no console dist at packages/console/dist"
}
],
"gate_derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) on a75f9f2: 3 paths vs merge base edecd44, 27 commands, the same 27 the dispatch listed. The 8 anchor-path-only families were owed because both anchor files changed, and all were run.",
"line_budget": {
"file": "docs/adr/0005-metadata-customization-overlay.md",
"before": 898,
"after": 908,
"insertions": 19,
"deletions": 9,
"net": 10,
"budget": "+10 max: within (at the cap)"
},
"files_changed": [
"docs/adr/0005-metadata-customization-overlay.md",
"scripts/adr-anchors/packages__metadata-protocol__src__migrations__overlay-index.ts.json",
"scripts/adr-anchors/packages__metadata-core__src__objects__sys-metadata.object.ts.json"
],
"deviations": [
"Owner 2 (③): beyond the suggested 'five fields + correct the unique value', the trailing sentence 'it still prevents duplicate active overlays … and it stays NULL-distinct on package_id' is restated as 'NULL-distinct on package_id and on bundle_member — NULL for every canonical member, so it holds no canonical row unique'. Reason: after 5677add the old sentence is false for canonical rows, and the SQLite probe in tests measures this. It is in the claim's file surface (a present-tense statement of the current key's effect). The PR body names it as the one sentence the maintainer should read closely.",
"Owner 2 (③) also gets a one-line parenthetical: "'global' is protocol 18's spelling of the bare true it retired, ADR-0120 D2" (the producer is ef1fcb2).",
"Commit trailers: AGENTS.md model-free pair (Claude-Session + Co-authored-by: Claude). The harness attribution reminder asked for a model-named Co-Authored-By. os-dev gives AGENTS.md precedence, so the model-named one was not used.",
"PR body footer: the AGENTS.md session-URL form ('Generated by Claude Code'), not the harness reminder's two-line block. Read back: the relay stored 10783 bytes, identical to what was sent."
],
"mcp_calls": "0 (no MCP tool used, read or write)",
"api_writes": "3 relay strokes (each one POST /repos/objectstack-ai/objectstack/dispatches as the session, executed by fleet-write.yml as objectstack-fleet[bot]): (1) pr_create, i.e. POST /repos/objectstack-ai/objectstack/pulls (draft forced) + POST /repos//issues/23037/assignees [os-justin], run 38245730528; (2) label-write labels_add, i.e. POST /repos//issues/23037/labels [skip-changeset], run 38245815359, read back MATCHES; (3) this os-dev-report comment, i.e. POST /repos//issues/23006/comments. Also 2 git pushes (the empty-branch probe, then a75f9f2), which are not REST. The card itself got no write: no assignee, no label.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: named producer 5677add (PR #22954), the same reach as this card · family: present-tense four-part overlay key in governed records after bundle_member; fold into ONE family closure card, not single-point cards · evidence: at edecd44, docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md:669 ('the overlay-uniqueness index keys on (type, name, organization_id, COALESCE(package_id, ''))') and docs/adr/0126-packaged-metadata-customization-model.md:313 (same key), vs OVERLAY_INDEX_COLUMNS at packages/metadata-protocol/src/migrations/overlay-index.ts:169 · Seam: spec: none (ADR text) → runtime: packages/metadata-protocol/src/migrations/overlay-index.ts#buildOverlayIndexSql · dedupe words: ADR-0029 overlay key bundle_member; ADR-0126 uniqueness index four parts; overlay key family closure",
"carrier: 承接者:无 (the family closure card above, if opened, can carry it) · noted, not filed · skills/objectstack-data/rules/indexing.md:165, the published skill's partial-index example, quotes the platform's runtime SQL with the four-part key. Drift in an illustration: authors do not write sys_metadata indexes, so it is not class c.",
"carrier: 承接者:无 · noted, not filed · docs/qa/platform-checklist/areas/cli.json:1125 recreates 'the declared NULL-distinct form' as a four-column CREATE UNIQUE INDEX. The step still seeds the duplicates it needs (both forms are NULL-distinct), so this is unexercised drift only.",
"carrier: 承接者:无 · noted, not filed · after 5677add the declared coarse fallback (sys-metadata.object.ts:250-254) holds no canonical row unique: it is NULL-distinct on bundle_member, which is NULL for canonical rows (SQLite probe in tests). Its code comment at sys-metadata.object.ts:244-249 still says 'it still prevents duplicate ACTIVE overlays'. No reach measured: no composition was shown to get only the declared tier, so it is not filed. The ADR text in this PR now states the measured fact.",
"carrier: 承接者:无 · noted, not filed · read-only observation: both overlay indexes keep organization_id bare and NULL-distinct, and environment rows are written with organization_id NULL (ADR-0131 D6; sys-metadata-repository.ts environment-rows read, organization_id null). So the DB-level key does not constrain environment rows on either tier. The overlay-index.ts module header (:117) already names the bare organization_id part as 'a separate question with its own ADR-0120 D4 ceremony'."
]
}
Checked against GitHub and origin/main, not the report (os-dev-report 6123800633):
Shape: draft, base main, first line Fixes #23006, second line Clause-②: no. No other closing keyword in the body. Assignee os-justin; labels skip-changeset, documentation, size/s. The file list matches the claim's surface: ADR-0005, plus the two conditional anchor JSONs, one span each.
Content, read on the tree:
The runtime key matches OVERLAY_INDEX_COLUMNS / overlayIndexKeyParts() (overlay-index.ts).
The declared index matches sys-metadata.object.ts (fields five, unique: 'global').
'global' is the byte-identical conversion of bare true (ADR-0120 D2; the driver builds the listed columns verbatim, NULL-distinct, schema-drift.ts). So the restated Owner 2 sentence ("holds no canonical row unique") follows.
Changeset:skip-changeset is right; the diff publishes nothing.
CI on this head: all 43 check-runs completed, success or skipped. Lint & Repo Gates, TypeScript Type Check and Governed Surface Queue Guard all succeeded. Check Documentation Links first failed in the lychee binary download before any link was checked; the one re-run on this head succeeded.
Contract review: PASS at CONTRACT_REVIEW_TIER on this head, comment 6123969188 on the PR, by an isolated subagent of this seat.
Landing: Tier H (check-governed-merges --pr 23037: docs/adr/**, 32 changed lines). The PR stays draft until an authorized APPROVED review; then this seat lands it.
Deviations accepted (four, as the review judged): the Owner 2 restatement; the 'global' parenthetical; the model-free trailer pair; the session-URL footer.
Landed — PR #23037MERGED as 38d98d8d8 (merged by os-zhuang through the queue: APPROVED review 5491092315 on a75f9f2258, flipped ready, auto-merge, enqueued) · seat domain:skills#2 · session_012dGTuJen61ECNHXYXKChoC · 2026-10-12T13:11Z
Content read on origin/main after the merge: ADR-0005 carries COALESCE(bundle_member, '') (1 hit) and the #22877 ruling A amendment (3 hits); the overlay-index anchor invariant spells the five-part key.
Activity
objectstack-fleet commentedon Oct 12, 2026
Triage: first grade,
documentation·priority:p3·domain:skills·area:devpath, intopm:queue. Sequenced after PR #23011, which edits the same ADRTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T11:08Z. ⛔ Not a claim, ⛔ not a dispatch.docs/adr/**is the governed surface, sodomain:skillstakes it. A seat authors governed text under the Tier H terminal steps, and the maintainer approves the merge.5677add93f. Nothing at runtime is wrong.:833,:865) restated with the five-part key and its reason ([finding] email_template: a Studio save of the same template in a second locale replaces the first locale's overlay at the next boot (sys_metadata keeps one overlay row per type and name) #22877, ruling6116165299, letter A).allowOrgOverrideto an environment-overlay key with an ADR-0087 load-time conversion (ADR-0131 C5's spec half, split from #15206 per #22007 ruling C) #22340 S3, in flight) edits ADR-0005 now. This card sequences after it. Whether to carry it in that PR is the holder's call.docs/adr/0005-metadata-customization-overlay.md(domain:skills); rationale: governed text.objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 1 (#23006 — ADR-0005's present-tense overlay key gains
bundle_member, Tier H) · 2026-10-12T11:35ZSession:
session_012dGTuJen61ECNHXYXKChoCAccount:
os-justin(the seat's linked user asGET /useranswers it; always the card's assignee)Branch:
claude/issue-23006-adr-0005-five-part-overlay-keyWorktree:
objectstack-issue-23006Domain:
domain:skillsSeat:
domain:skills#2File surface:
docs/adr/0005-metadata-customization-overlay.md(the status header's amendment list, and the present-tense statements of the current key in the "what is true today" block: the card's two lines plus the declared-index line beneath them, which the card does not name); conditionallyscripts/adr-anchors/packages__metadata-protocol__src__migrations__overlay-index.ts.jsonandscripts/adr-anchors/packages__metadata-core__src__objects__sys-metadata.object.ts.json(the key spelling in theirinvarianttext only, under the bounded in-place rule, if the dev measures them stale) (stop on breach; explain in the report)Container & model:
S,mode:subagent,model: opus— the default judgment tier;dispatch-gates --tier --repo objectstack-ai/objectstackon the ADR path at3071d3e98printed 「Model tier — no path-derived mandate」 (floor sonnet · default opus · ceiling fable); the seat's call is default, not floor, because a governed record's correctness is judged by reading, not by the gate farmClause-②: no
Responsibility:
n/a — not a defect card(an accepted record's present-tense statement went stale; class (b) of the filing gate)Thread-read: 6123056260
Ruling-ref: none on this card. The content follows #22877 ruling
6116165299(letter A, maintainer 「同意」; fetched in this act), which put the bundled type's member into the overlay key.Resume-from: none
Serial constraints cleared: PR #23011 (#22340 S3, seat 1) edits ADR-0005's status header, the region this card's amendment line lands in, so this card was held behind it until it read MERGED as
e4a770d6b(2026-10-12T11:32Z). In-flight claims naming ADR-0005 across all 18 openpm:dispatchedcards: only #22340 (that is the control hit). Open PRs changing ADR-0005 among all 19 open: only PR #23011. #22788 (ADR-0139's status line,pm:blocked,domain:engine) is named on the card as a possible rider. It does not ride: it is another card, in another lane, in another file.Delivery shape:
Fixes #23006; Tier H, so the PR stays draft until an authorized approval.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{
"issue": 23006,
"status": "done",
"branch": "claude/issue-23006-adr-0005-five-part-overlay-key",
"pr": "#23037",
"session": "session_012dGTuJen61ECNHXYXKChoC (subagent: the PM session id; identity is the branch)",
"premise_still_valid": true,
"summary": "ADR-0005 now states the five-part overlay key. The status line gains one dated entry, '· Amended (2026-10-12, #22877 ruling A — …)', naming bundle_member, NULL as the canonical member, and producer 5677add (PR #22954). The #6771 measurement sentence is kept verbatim with a dated '2026-10-12 note' after it. Owner 1 states the runtime key (type, name, organization_id, COALESCE(package_id, ''), COALESCE(bundle_member, '')) with its reason. Owner 2 quotes the tree's declaration: five fields, unique: 'global'. H1 confirmed: the full re-grep found 3 present-tense sites at edecd44 (:835/:867/:878), not the card's 2. H2 confirmed from the tree. H3 confirmed stale: both anchor invariants spelled the four-part key, so each got the bounded in-place one-span fix. H4: the anchor citing ADR-0005:53-64 still points at byte-identical lines (BASE vs HEAD diff exit 0). Draft PR #23037 is open, assignee os-justin, label skip-changeset read back. It stays draft: Tier H, the maintainer's approval lands it. CI: in_progress, not waited on (PM owns convergence). Worktree cleanup (node_modules, then git worktree remove) is the step right after this comment.",
"tests": "Docs and anchor text only, so no package test or typecheck applies (the diff touches no package). Gates on HEAD a75f9f2: all 27 derived commands exit 0 (list in gates). dispatch-gates --ran: '27 derived famil(ies) accounted for — 27 run, 0 NOT-MEASURED (a DERIVED zero — all 27 recorded an exit code and none of them is 3)'. Measurement behind the ADR wording change (Acceptance notes 2): in-memory SQLite (better-sqlite3 12.11.1) with the declared five-column plain CREATE UNIQUE INDEX. Two identical packaged canonical rows (bundle_member NULL): both INSERTED. Two identical zh-CN rows: the second REFUSED with SQLITE_CONSTRAINT_UNIQUE. No ablation: no gate or code changed.",
"gates": [
{
"cmd": "node scripts/check-adr-links.mjs",
"exit": 0,
"verdict": "check-adr-links: 730 relative link destination(s) under docs/adr/ resolve"
},
{
"cmd": "node scripts/check-adr-links.mjs --self-test",
"exit": 0,
"verdict": "check-adr-links --self-test: discrimination, census, ADR-0046 pin and baseline staleness all verified"
},
{
"cmd": "node scripts/check-adr-symbol-anchors.mjs",
"exit": 0,
"verdict": "check-adr-symbol-anchors: 2319 anchors across 142 records resolve"
},
{
"cmd": "node scripts/check-adr-symbol-anchors.mjs --self-test",
"exit": 0,
"verdict": "check-adr-symbol-anchors --self-test: every finding class provoked, healthy anchors silent"
},
{
"cmd": "node scripts/check-ci-filter-parity.mjs",
"exit": 0,
"verdict": "OK: all 197 declared cross-package glob(s) (144 unique) are covered by core or crosspkg"
},
{
"cmd": "node scripts/check-closing-keyword-parity.mjs",
"exit": 0,
"verdict": "check-closing-keyword-parity: OK (3 parsers agree on all 9 keywords and both measured separators)"
},
{
"cmd": "node scripts/check-closing-keyword-parity.mjs --self-test",
"exit": 0,
"verdict": "check-closing-keyword-parity --self-test: 40 assertions, 5 mutations of the shipped parsers each driven to red"
},
{
"cmd": "node scripts/check-comment-mask-corpus.mjs",
"exit": 0,
"verdict": "comment-mask corpus sweep: 8857 files, 0 disagree, 0 unparseable"
},
{
"cmd": "node scripts/check-scripts-symbol-anchors.mjs",
"exit": 0,
"verdict": "check-scripts-symbol-anchors: 3837 anchors across 285 scripts resolve"
},
{
"cmd": "node scripts/check-scripts-symbol-anchors.mjs --self-test",
"exit": 0,
"verdict": "check-scripts-symbol-anchors --self-test: every finding class provoked"
},
{
"cmd": "pnpm --filter @objectstack/lint run check:doc-formula-expressions",
"exit": 0,
"verdict": "first run exit 3 (PREREQUISITE NOT MET: @objectstack/formula + @objectstack/lint unbuilt); built under os-verify-lock (turbo run build --concurrency=2 --filter=@objectstack/formula --filter=@objectstack/lint, VERDICT command-exit 0, 4/4 tasks); rerun exit 0: self-test 61 cases passed; 22 record-scoped formula example(s) across 473 files / 1388 TS blocks judged clean"
},
{
"cmd": "pnpm check:adr-anchors",
"exit": 0,
"verdict": "check-adr-anchors --self-test: 106 assertions; check-adr-anchors: OK (68 anchored file(s), every governing ADR still referenced; 44138 citation(s) across 5846 file(s) resolve)"
},
{
"cmd": "pnpm check:agent-test-spelling",
"exit": 0,
"verdict": "check-agent-test-spelling: 0 violations"
},
{
"cmd": "pnpm check:bash32-floor",
"exit": 0,
"verdict": "check-bash32-floor: 30 tracked shell file(s) name no bash 4+ construct"
},
{
"cmd": "pnpm check:cli-command-ids",
"exit": 0,
"verdict": "check-cli-command-ids: 814 command-id literal(s) across 253 file(s) all resolve"
},
{
"cmd": "pnpm check:cross-package-test-inputs",
"exit": 0,
"verdict": "OK: 30 package(s) read outside themselves, all declared"
},
{
"cmd": "pnpm check:doc-authoring",
"exit": 0,
"verdict": "doc authoring guard: 18262 customer-facing string(s) across 1356 spec sources clean"
},
{
"cmd": "pnpm check:driver-memory-census",
"exit": 0,
"verdict": "check-driver-memory-census: OK"
},
{
"cmd": "pnpm check:entry-guard",
"exit": 0,
"verdict": "check:entry-guard: 285 scripts/ file(s), every entry guard goes through invoked-as.mjs"
},
{
"cmd": "pnpm check:gitlink-declared",
"exit": 0,
"verdict": "check-gitlink-declared: OK (11048 index entries, 0 gitlink(s))"
},
{
"cmd": "pnpm check:nul-bytes",
"exit": 0,
"verdict": "check-nul-bytes: OK (scanned 11039 text file(s); no raw ASCII control bytes)"
},
{
"cmd": "pnpm check:parse-guard",
"exit": 0,
"verdict": "check:parse-guard: 284 scripts/ file(s), every TypeScript parse goes through ts-parse.mjs"
},
{
"cmd": "pnpm check:pm-governed-merges",
"exit": 0,
"verdict": "check-governed-merges --self-test: 476 assertions; live: the real generator declared 9 output(s) and certified this tree"
},
{
"cmd": "pnpm check:pm-prior-rulings",
"exit": 0,
"verdict": "check-prior-rulings self-test: 155 cases pass"
},
{
"cmd": "pnpm check:pnpm-filter-targets",
"exit": 0,
"verdict": "check:pnpm-filter-targets: 160/214 --filter occurrence(s) across 44 file(s) resolve"
},
{
"cmd": "pnpm check:refd-timer-probe",
"exit": 0,
"verdict": "check-refd-timer-probe: 8851 source file(s) swept"
},
{
"cmd": "pnpm check:watch-hint-literal",
"exit": 0,
"verdict": "check-watch-hint-literal: 73 declaration(s) across 4 rostered name(s)"
}
],
"extra_gates_outside_derivation": [
{
"cmd": "pnpm check:overlay-whitelist-table",
"exit": 0,
"verdict": "leg 1 0 divergence(s) over 13 type(s); leg 2 0 divergence(s) over 5 allowEnvironmentOverlay true type(s)"
},
{
"cmd": "node scripts/check-published-list-mirrors.mjs",
"exit": 0,
"verdict": "OK: 1 published list mirror(s) match their constants line for line"
},
{
"cmd": "pnpm check:dts-closure",
"exit": 0,
"verdict": "check-dts-closure: 4 built package(s) swept, 46/46 declared declaration file(s) present"
},
{
"cmd": "pnpm check:engine-double-contract",
"exit": 0,
"verdict": "check-engine-double-contract: OK, 999 pinned, 124 in the DEBT ledger, 3 exempt"
},
{
"cmd": "pnpm check:i18n-stale-fill",
"exit": 0,
"verdict": "check-i18n-stale-fill: OK (10 bundle set(s), no new stale fills)"
},
{
"cmd": "pnpm check:published-readme-exports",
"exit": 3,
"verdict": "NOT MEASURED, reason: prerequisite, needs a full pnpm build of ~40 packages; this diff touches no package and no README"
},
{
"cmd": "pnpm check:console-injection",
"exit": 0,
"verdict": "NOT MEASURED, reason: the gate skipped itself, no console dist at packages/console/dist"
}
],
"gate_derivation": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) on a75f9f2: 3 paths vs merge base edecd44, 27 commands, the same 27 the dispatch listed. The 8 anchor-path-only families were owed because both anchor files changed, and all were run.",
"line_budget": {
"file": "docs/adr/0005-metadata-customization-overlay.md",
"before": 898,
"after": 908,
"insertions": 19,
"deletions": 9,
"net": 10,
"budget": "+10 max: within (at the cap)"
},
"files_changed": [
"docs/adr/0005-metadata-customization-overlay.md",
"scripts/adr-anchors/packages__metadata-protocol__src__migrations__overlay-index.ts.json",
"scripts/adr-anchors/packages__metadata-core__src__objects__sys-metadata.object.ts.json"
],
"deviations": [
"Owner 2 (③): beyond the suggested 'five fields + correct the unique value', the trailing sentence 'it still prevents duplicate active overlays … and it stays NULL-distinct on package_id' is restated as 'NULL-distinct on package_id and on bundle_member — NULL for every canonical member, so it holds no canonical row unique'. Reason: after 5677add the old sentence is false for canonical rows, and the SQLite probe in tests measures this. It is in the claim's file surface (a present-tense statement of the current key's effect). The PR body names it as the one sentence the maintainer should read closely.",
"Owner 2 (③) also gets a one-line parenthetical: "'global' is protocol 18's spelling of the bare true it retired, ADR-0120 D2" (the producer is ef1fcb2).",
"Commit trailers: AGENTS.md model-free pair (Claude-Session + Co-authored-by: Claude). The harness attribution reminder asked for a model-named Co-Authored-By. os-dev gives AGENTS.md precedence, so the model-named one was not used.",
"PR body footer: the AGENTS.md session-URL form ('Generated by Claude Code'), not the harness reminder's two-line block. Read back: the relay stored 10783 bytes, identical to what was sent."
],
"mcp_calls": "0 (no MCP tool used, read or write)",
"api_writes": "3 relay strokes (each one POST /repos/objectstack-ai/objectstack/dispatches as the session, executed by fleet-write.yml as objectstack-fleet[bot]): (1) pr_create, i.e. POST /repos/objectstack-ai/objectstack/pulls (draft forced) + POST /repos//issues/23037/assignees [os-justin], run 38245730528; (2) label-write labels_add, i.e. POST /repos//issues/23037/labels [skip-changeset], run 38245815359, read back MATCHES; (3) this os-dev-report comment, i.e. POST /repos//issues/23006/comments. Also 2 git pushes (the empty-branch probe, then a75f9f2), which are not REST. The card itself got no write: no assignee, no label.",
"open_questions": [],
"out_of_scope_findings": [
"class: b · reach: named producer 5677add (PR #22954), the same reach as this card · family: present-tense four-part overlay key in governed records after bundle_member; fold into ONE family closure card, not single-point cards · evidence: at edecd44, docs/adr/0029-kernel-object-ownership-and-platform-objects-decomposition.md:669 ('the overlay-uniqueness index keys on (type, name, organization_id, COALESCE(package_id, ''))') and docs/adr/0126-packaged-metadata-customization-model.md:313 (same key), vs OVERLAY_INDEX_COLUMNS at packages/metadata-protocol/src/migrations/overlay-index.ts:169 · Seam: spec: none (ADR text) → runtime: packages/metadata-protocol/src/migrations/overlay-index.ts#buildOverlayIndexSql · dedupe words: ADR-0029 overlay key bundle_member; ADR-0126 uniqueness index four parts; overlay key family closure",
"carrier: 承接者:无 (the family closure card above, if opened, can carry it) · noted, not filed · skills/objectstack-data/rules/indexing.md:165, the published skill's partial-index example, quotes the platform's runtime SQL with the four-part key. Drift in an illustration: authors do not write sys_metadata indexes, so it is not class c.",
"carrier: 承接者:无 · noted, not filed · docs/qa/platform-checklist/areas/cli.json:1125 recreates 'the declared NULL-distinct form' as a four-column CREATE UNIQUE INDEX. The step still seeds the duplicates it needs (both forms are NULL-distinct), so this is unexercised drift only.",
"carrier: 承接者:无 · noted, not filed · after 5677add the declared coarse fallback (sys-metadata.object.ts:250-254) holds no canonical row unique: it is NULL-distinct on bundle_member, which is NULL for canonical rows (SQLite probe in tests). Its code comment at sys-metadata.object.ts:244-249 still says 'it still prevents duplicate ACTIVE overlays'. No reach measured: no composition was shown to get only the declared tier, so it is not filed. The ADR text in this PR now states the measured fact.",
"carrier: 承接者:无 · noted, not filed · read-only observation: both overlay indexes keep organization_id bare and NULL-distinct, and environment rows are written with organization_id NULL (ADR-0131 D6; sys-metadata-repository.ts environment-rows read, organization_id null). So the DB-level key does not constrain environment rows on either tier. The overlay-index.ts module header (:117) already names the bare organization_id part as 'a separate question with its own ADR-0120 D4 ceremony'."
]
}
objectstack-fleet commentedon Oct 12, 2026
ACCEPT — PR #23037 @
a75f9f2258· seatdomain:skills#2·session_012dGTuJen61ECNHXYXKChoC· 2026-10-12T12:09ZChecked against GitHub and
origin/main, not the report (os-dev-report 6123800633):main, first lineFixes #23006, second lineClause-②: no. No other closing keyword in the body. Assigneeos-justin; labelsskip-changeset,documentation,size/s. The file list matches the claim's surface: ADR-0005, plus the two conditional anchor JSONs, one span each.OVERLAY_INDEX_COLUMNS/overlayIndexKeyParts()(overlay-index.ts).sys-metadata.object.ts(fieldsfive,unique: 'global').'global'is the byte-identical conversion of baretrue(ADR-0120 D2; the driver builds the listed columns verbatim, NULL-distinct,schema-drift.ts). So the restated Owner 2 sentence ("holds no canonical row unique") follows.skip-changesetis right; the diff publishes nothing.Lint & Repo Gates,TypeScript Type CheckandGoverned Surface Queue Guardall succeeded.Check Documentation Linksfirst failed in the lychee binary download before any link was checked; the one re-run on this head succeeded.CONTRACT_REVIEW_TIERon this head, comment 6123969188 on the PR, by an isolated subagent of this seat.check-governed-merges --pr 23037:docs/adr/**, 32 changed lines). The PR stays draft until an authorized APPROVED review; then this seat lands it.'global'parenthetical; the model-free trailer pair; the session-URL footer.Out-of-scope findings, one line each:
skills/objectstack-data/rules/indexing.md:165: filed docs(adr,skills): ADR-0029, ADR-0126 and the published objectstack-data indexing rule still state the overlay uniqueness key as four parts — bundle_member since 5677add93f (family closure for #23006) #23039 (family closure, one card for every remaining position, with an enumeration pin).docs/qa/platform-checklist/areas/cli.json:1125: Acceptance notes (unexercised drift; the step still seeds its duplicates). Named on docs(adr,skills): ADR-0029, ADR-0126 and the published objectstack-data indexing rule still state the overlay uniqueness key as four parts — bundle_member since 5677add93f (family closure for #23006) #23039 as not in the family.sys-metadata.object.ts:244-249code comment ("still prevents duplicate ACTIVE overlays"): Acceptance notes. Pointed at docs(adr,skills): ADR-0029, ADR-0126 and the published objectstack-data indexing rule still state the overlay uniqueness key as four parts — bundle_member since 5677add93f (family closure for #23006) #23039 as an optional rider for whoever carries it.organization_idbare on both tiers: dropped — pre-existing, and the module header already names it as its own ADR-0120 D4 ceremony.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Landed — PR #23037 MERGED as
38d98d8d8(merged byos-zhuangthrough the queue: APPROVED review 5491092315 ona75f9f2258, flipped ready, auto-merge, enqueued) · seatdomain:skills#2·session_012dGTuJen61ECNHXYXKChoC· 2026-10-12T13:11Zorigin/mainafter the merge: ADR-0005 carriesCOALESCE(bundle_member, '')(1 hit) and the#22877 ruling Aamendment (3 hits); the overlay-index anchor invariant spells the five-part key.skills/objectstack-data/rules/indexing.md). ADR-0005's site left the pin with this merge, as expected.Fixes;pm:dispatchedis stripped in this act. Lane re-inventory after the merge: no other card closed unexpectedly.Generated by Claude Code