Repository navigation
refactor(tooling): shard the ADR-anchor registry one file per anchor - #7301
Conversation
…6957) scripts/adr-anchors.json — a single append-only JSON array every card adding an anchor had to edit — becomes scripts/adr-anchors/<slug>.json, assembled in id order at read time by scripts/adr-anchors.mjs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KJATVrh6V2ysutYUJigh3B
…-anchors-per-entry
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
📓 Docs Drift CheckThis PR changes 1 package(s): 20 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also reference the affected code. These are read-only:
|
…eset) Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KJATVrh6V2ysutYUJigh3B
一处冲突:`scripts/adr-anchors.json` —— main 的 #7301 把 ADR 锚点注册表 按文件分片(`scripts/adr-anchors/*.json`)并删除了整块 JSON,本分支同时 改了其中两条锚点的内容。按**并集**处置,不是二选一:采用 main 的分片布局, 把两条锚点的新内容移植进对应分片。 - `packages__objectql__src__registry.ts.json` —— invariant 由「D9 是 DESIGN ONLY,不要实现」改写为已落地的模型 - `packages__metadata-protocol__src__protocol.ts.json` —— 依 D9 §8 加上 ADR-0029;移植前逐字节校验了 main 侧 ADR-0119 那句未变,确保是并集而非覆盖 生成物 `content/docs/references/**` 取 main 一侧后用 `gen:schema` + `gen:docs` 重新生成,未手工合并。 其余全部自动合并。main 的 #7260 把**记录**所有权枚举扩成 `user | business_unit | org | none`,与 D9 的**贡献**种类 (`own | extend | overlay`)是两个枚举,两侧改动均完整保留。 main 对 `registry.ts` 的改动是 `applySystemFields` 内的纯注释,与 D9 模型 无交集;`registerObject` / `resolveObject` / `getArtifactItem` / 两个 hydration 缝 / delete heal 均未被 main 触碰。任何钉子都未移动。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01W6bLax4KMrSfnE1ydFU8Dw
…to per-entry files (objectstack-ai#7297) (objectstack-ai#7454) * refactor(spec): split the migration registry's three append tables into per-entry files (objectstack-ai#7297) The registry half of objectstack-ai#6957's 2026-08-10 ruling, option (a): per-card entry files concatenated by a generator, the `.changeset/*.md` shape. `registry.ts` carried three hand-authored APPEND tables — each step's `semantic` list, `RETIRED_KEYS_BY_MAJOR` and `RETIRED_DEFS_BY_MAJOR`. Every retirement card appended to the same tail line of the same two of them, so two cards in one window were a textual conflict by construction: `step17`'s semantic list and `RETIRED_KEYS_BY_MAJOR[17]` conflicted in 6 of 11 contended re-merge laps, 613 hand-resolved lines in four days. Both tables are consumed as SETS, so a resolution that drops a sibling's entry produces no error anywhere — that silent drop, not wall-clock, is what this removes. Entries now live one file per entry under `src/migrations/entries/` (59 semantic + 16 retired keys + 45 retired defs), concatenated into `registry.ts`'s `<os-generated …>` regions by `gen:migration-registry` and verified by `check:migration-registry`. The filename is a pure function of the entry id; order is derived by sorting on it; there is deliberately no index. This commit is MECHANICAL: every exported value is identical entry-for-entry, and the two projections reorder without changing a byte of content (their line multisets are unchanged). `scripts/adr-anchors/` (objectstack-ai#7301) is the pilot mirrored. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Py3V8MDCEEYhZrR3NvNVu5 * docs(spec): re-point the migration registry's positional cross-references at entry ids (objectstack-ai#7297) Twelve notes in the split-out entries located a sibling by POSITION — "the entry above", "the notification pair above", "the trio at the top of this list", "`etl-pipeline-layer-retired` below". Position was a fact about append order, and append order is exactly what the split replaced with a derived sort, so each of these is now either wrong or about to be. Each is rewritten to name what it means: the sibling's id, the table it lives in, or — for the three copies of the "no backticks in `surface`" note, which pointed at whichever entry happened to carry the long form — the reason itself, inline. Content-only; the id set, every table's membership and the public API are untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Py3V8MDCEEYhZrR3NvNVu5 --------- Co-authored-by: Claude <noreply@anthropic.com>
Part of #6957 — this is the
scripts/adr-anchors.jsonhalf only.packages/spec/src/migrations/registry.tsbelongs to thedomain:specseat and is the file their in-flight retirement cards are appending to right now; restructuring it from this lane mid-window would cause the exact collision the card documents. It is being transferred to that seat separately, soPart ofrather thanFixes.Ruling this implements
Maintainer ruling of 2026-08-10, quoted verbatim and untranslated:
Option (a) adopted, (b) rejected, (c) is the interim mitigation. None re-opened here.
What changed
scripts/adr-anchors.json— a single 343-line append-only array that every card adding an anchor had to edit — becomesscripts/adr-anchors/, one JSON file per anchor, 47 of them, named for the path each anchors (packages/objectql/src/engine.ts→packages__objectql__src__engine.ts.json). A new modulescripts/adr-anchors.mjsassembles them in id order at read time;scripts/check-adr-anchors.mjsconsumes that instead of parsing one file.Also updated: the three live pointers at the old path (
AGENTS.mdPD #13, thelint.ymlstep comment, two runtime code comments). Records underdocs/adr/, historical changesets andcontent/docs/releases/are deliberately untouched — and the path prefixscripts/adr-anchorsstill resolves for a reader who greps it.Consumer verdict is unchanged
check:adr-anchorsverdict--self-testassertionsThe only figures that move are the citation-scan denominators (20837 → 20853 across 3418 → 3469 files): the same anchor text now lives in 47 tracked files instead of 1, which is inherent to the split and not a verdict change. Every failure message is byte-for-byte the same except that each now names the exact entry file to edit instead of the shared blob.
The de-conflicting claim, demonstrated rather than asserted
Two simulated concurrent appends, replayed under both layouts with
git merge-tree --merge-base— old baseorigin/main, new base this branch:The control is the half that is easy to skip and cannot be: a layout in which two edits to one entry also merge clean is a layout that silently loses one of them. Harness proven non-blind before any of this was believed — split-then-reassemble is byte-identical over all 47 entries, and flipping a single character in one invariant breaks that equality.
Reverse verification of the gate itself: deleting
ADR-0091frompackages/core/src/security/grant-validity.tsturnscheck:adr-anchorsred with the invariant text and the shard path; restoring it returns green.Why a sharded directory and not a committed concatenated artifact
Because the card's subject is the merge queue, and this repo has already measured what that rules out.
merge=os-regen(#4675) is a local git facility; the GitHub merge queue rebuilds each PR server-side where no custom merge driver runs, which is why #5837 had to shard the three hottest spec artifacts one file per category rather than merely route them. A checked-in aggregate here would be exactly that server-side conflict surface, and it would carry no review information the entry files do not already carry.spec-changes.json/ the upgrade guide are not touched by this PR at all.Two properties enforced, not assumed
assembleAnchorsrejects a shard whose name disagrees with itsfile, so a rename cannot quietly re-open the losing half.Verification
All four re-run after merging
origin/main(no commit on main since the fork point touched the old registry, so nothing was dropped). Nocheck:/gen:script entry was added or renamed, so the #4203 meta-gate surface is untouched;.gitattributesandregen-artifacts.mjsare likewise unchanged — this registry is hand-authored, not generator-owned.Generated by Claude Code