Repository navigation
Commit 91f6a0b
fix(metadata-protocol): os migrate packageless-overlays also moves overlay rows bound to the read-only base itself into its .custom pair (#29477)
<!-- claude-projects-attribution: {"github_login":"os-steve"} -->
_Requested by **Steve** · [project
thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi9RJBhhH7Lot8tR4dpMhoecu)_
Fixes #29392
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:`os migrate packageless-overlays`
的盘点现在也列出「绑定在只读基础包本身」的视图、仪表盘、报表、翻译、邮件模板行(#28905 关门前用 `?package=基础包`
保存留下的),`--apply` 把它们像无包行一样搬进 `.custom` 配对包并声明
`overrides`(或作为配对包自己的语言成员),结果词不变。
- 为什么改:这类行一直盖住基础包文档,但盘点只读无包行看不到它们,唯一出路是删除,删除会丢掉定制。
- 风险与回滚:只多搬行、不拒绝任何写入;同一项既有无包行又有绑定行时先搬无包行,绑定行保留并报 failed,下次预览列为
shadowed,绝不覆盖。回滚即撤销本 PR。
-
先看:`packages/metadata-protocol/src/protocol-packageless-overlay-migration.ts`
的 `listPackagelessOverlays`(`binding` 判定)与
`migratePackagelessOverlays`(先后顺序与 `movedFrom`
防覆盖);`packages/cli/src/commands/migrate/packageless-overlays.ts` 的渲染。
- 两分钟验证:`pnpm --filter @objectstack/objectql exec vitest run
src/protocol-packageless-overlay-migration.test.ts -t 29392`(需先 build
metadata-protocol),应见 6 个用例全过。
- 需要你做的:无,席位落地。
## What changes
**The census** (`listPackagelessOverlays`,
`protocol-packageless-overlay-migration.ts`). Besides the package-less
rows, every row of the five overlay types whose `package_id` is a
READ-ONLY code package that ships the name is now in the population: a
row bound to the base itself, as a save naming the base stored it before
#28905 closed that write. "Read-only package that ships the name" is the
reading the #28905 close calls packaged (`overlayBaseShippers` =
`readOnlyShippingPackages` over `shippedArtifactsOf`), the same function
the census already reads for a package-less row. Such a row:
- is classified by the same `classifyPackagelessRow`, with its binding
as the one shipper, so a name several packages ship is never
`multi_shipped` here (the binding names the base);
- carries `boundToBase: true` (a new optional field on the census row
and in the cli `--json` rows);
- takes `addedMember` exactly as a package-less row does (an email
template locale the base does not ship).
A row bound to a writable package (the pair included) or to a read-only
package that does not ship the name is not listed. Package-less rows are
classified exactly as before.
**The move** (`migratePackagelessOverlays`). Unchanged steps: ensure the
pair, save the declared body (or the undeclared own member) into the
pair through the save door, read it back, then delete the source row by
its own address, now `packageId: BASE` for a bound row. Same outcomes
(`moved` with `basedOn`, or `moved` with `addedMember`); no new outcome
word.
**One item, two bindings.** A package-less row and a row bound to the
base of the same item would both land on the pair's one row. The move
takes the package-less rows first; a row of an item this run already
moved a row of the other binding into is kept, reported `failed`
("'PAIR' now holds this item … kept beside it, never merged"), and the
next preview lists it `shadowed` with that disposition's two ways out.
Nothing is overwritten.
**The cli** (`packageless-overlays.ts`, render only): the preview names
a bound row ("bound to PACKAGE → PAIR"), `--json` rows carry
`boundToBase`, and a bound `foreign_declaration` row's remedy names the
delete naming the base and the save into the pair (a save naming the
base is closed now, so the package-less row's "remove the key in place"
remedy does not apply). Help text and three wording spots no longer say
"package-less" where the row may be bound.
Changeset: `.changeset/29392-packageless-overlays-base-bound.md`,
`patch` for `@objectstack/metadata-protocol` and `@objectstack/cli`.
## Tests
-
`packages/objectql/src/protocol-packageless-overlay-migration.test.ts`,
new describe `[#29392]` (6 tests, in-memory topology, rows laid down
through the engine as an older release stored them):
- the dry run lists active and draft rows bound to the base, `movable`,
with base and pair, writing nothing; `--apply` moves both with
`overrides: { package: BASE, basedOn: '1.2.0' }` in their own state; the
layered read at the base shows the base's document as the code layer and
the customization as effective; the five reads serve the customization;
a re-run moves 0;
- a name two read-only packages ship, bound to one: `movable` into that
base's pair, not `multi_shipped`;
- a bound `foreign_declaration` and a bound `shadowed` row: listed and
left;
- a package-less row and a bound row of one item: the package-less one
moves, the bound one is kept `failed`, nothing overwritten, next census
lists it `shadowed`;
- CONTROL: a package-less row still moves as before; rows bound to a
writable package and to a read-only package that does not ship the name
are not listed.
-
`packages/objectql/src/environment-overlay-email-locale-restart.test.ts`,
one new case in the #28904 describe: a `zh-CN` row of a template the
package ships `en-US` only, bound to the package: listed `movable` +
`addedMember` + `boundToBase`, moved as the pair's own member with no
`overrides`, still sent in `zh-CN` at once and after a restart.
-
`packages/cli/src/commands/migrate/packageless-overlays.integration.test.ts`
(SQLite topology): a second template database with a row bound to the
package; the preview lists it and writes nothing; `--apply` moves it
with the declaration, keeps the package-less control, a fresh boot
serves the customization at all four reads, a re-run moves 0. The
seeding moved into one `insertRows` helper (both templates use it); the
existing three cases are unchanged.
- No forced edits to existing tests.
## Acceptance notes
- **The #28905 predicate (measured).** `namedBaseCloseSubject` is not
the census's predicate and is not called: its first step (a read-only
package among `overlayBaseShippers`) is the population test here, read
through the same `readOnlyShippingPackages` the census host already
carries. Its remaining steps (pair id, ensure door, base version, the D2
gate admitting a declared body) would, as a census filter, hide again a
bound row whose fix cannot be taken, and drop the unshipped-locale rows
this card moves as the pair's own member (the gate refuses their
declared body, so the close answers `null`). The census keeps its
package-less precedent: classify, then let the move's own steps answer
`failed` with the reason. The two close predicates are not folded here
(#29397).
- **Comments now stale in files outside this card's surface** (carrier
#29397, which edits them next): `protocol.ts`
`namedBaseOverlayWriteRefusal` docblock ("its census reads package-less
rows only", "the only way to clear such a row … the ceremony moves
package-less rows only") and the `listPackagelessOverlays` docblock
("bound to no package"); `protocol-packaged-base-refusal.ts`
`NamedBaseWriteOperation` and refusal docblocks;
`protocol.named-base-overlay-write.test.ts` header.
- **JSON shape.** `boundToBase` is a new optional field in the census
rows and `--json`; additive.
## Verification
Red, green and ablations measured on `d74ab15d`..`7ebc8019` (the
implementation is unchanged since); suites, typecheck, gates and lint
re-run on the final head `30bfafa62` (main merged at `a64416366`), tree
`objectstack-ai/objectstack`.
<details><summary>Red on main, then green</summary>
`protocol-packageless-overlay-migration.ts` restored from `origin/main`
7f277a8 in the worktree, metadata-protocol rebuilt (`boundToBase` in
dist: 0), objectql file run: the 5 bound-row pins red, the dry run
answering `[]` for the bound rows (`+ []` against the two expected
`movable … bound` lines). The CONTROL case was red in that run too, from
an expected-order slip in the test itself (`[OTHER, WORKSPACE]` sorted),
fixed before the green run; the email bound case was written after.
Restored to HEAD, rebuilt (dist hits 3):
`protocol-packageless-overlay-migration.test.ts` +
`environment-overlay-email-locale-restart.test.ts` 68/68.
</details>
<details><summary>Ablations (rebuild + dist preflight each
leg)</summary>
1. The bound arm dropped (`if (binding !== undefined &&
!shippers.includes(binding)) continue;` → every bound row skipped), via
`scripts/ablation-replace.mjs`, marker in both dist files: objectql 6
failed / 63 passed (the 5 bound-row pins plus the email bound case;
CONTROL stays green); cli integration 2 failed / 3 passed (both
bound-row cases). Restored: blob == HEAD, `git diff HEAD` empty,
rebuilt, `--absent` preflight clean.
2. The collision guard dropped (`movedFrom` check → never true):
objectql 1 failed / 68 passed, the two-bindings case (`AssertionError …
['package-less','moved'], …` second outcome no longer `failed`).
Restored the same way, `--absent` clean.
</details>
<details><summary>Suites and typecheck (under os-verify-lock, after a
full `./packages/**` + `./examples/**` build)</summary>
Final head `30bfafa62`, after `pnpm install --frozen-lockfile` and
`turbo run build --filter='./packages/**' --filter='./examples/**'`
(VERDICT command-exit 0, held 41m42s for the whole round, shared box):
- `pnpm --filter @objectstack/metadata-protocol typecheck` exit 0;
`@objectstack/objectql` exit 0; `@objectstack/cli` exit 0
- metadata-protocol `vitest run`: 22161 passed, 26 skipped (22187)
- objectql `vitest run`: 10326 passed (10326)
- cli `--project unit`: 5267 passed (5267)
- cli `--project integration
src/commands/migrate/packageless-overlays.integration.test.ts`: 5 passed
(5). The rest of the integration tier is declared to CI.
</details>
<details><summary>Derived gates</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` on `30bfafa62`: 62 commands, every one exit
0 (the same list as before the merge). `--ran` reconciliation: "62
derived famil(ies) accounted for — 62 run, 0 NOT-MEASURED".
`check:type-check-debt` re-measured 0 raw tsc errors, none above its
record. `check-plugin-teardown-shape --self-test` needs its pinned
fixture commit fetched first (exit 3 before, 48 cases pass after).
`pnpm lint` (repo-wide eslint, `--no-inline-config`): exit 0.
</details>
Dogfood: not owed (no `!`, no narrowing arm).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01ADHkmQZSg4zWtKMdRnKmKS)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 09abc05 commit 91f6a0b
6 files changed
Lines changed: 353 additions & 36 deletions
File tree
- .changeset
- packages
- cli/src/commands/migrate
- metadata-protocol/src
- objectql/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
27 | 30 | | |
28 | 31 | | |
29 | 32 | | |
| |||
78 | 81 | | |
79 | 82 | | |
80 | 83 | | |
81 | | - | |
| 84 | + | |
82 | 85 | | |
83 | 86 | | |
84 | 87 | | |
| |||
89 | 92 | | |
90 | 93 | | |
91 | 94 | | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
92 | 105 | | |
93 | 106 | | |
| 107 | + | |
94 | 108 | | |
95 | 109 | | |
96 | 110 | | |
97 | 111 | | |
98 | 112 | | |
99 | 113 | | |
100 | | - | |
| 114 | + | |
101 | 115 | | |
102 | 116 | | |
103 | 117 | | |
104 | | - | |
| 118 | + | |
105 | 119 | | |
106 | 120 | | |
107 | 121 | | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
108 | 141 | | |
109 | 142 | | |
110 | 143 | | |
| |||
215 | 248 | | |
216 | 249 | | |
217 | 250 | | |
218 | | - | |
219 | | - | |
220 | | - | |
221 | | - | |
222 | | - | |
223 | | - | |
224 | | - | |
225 | | - | |
226 | | - | |
227 | | - | |
228 | | - | |
229 | | - | |
230 | | - | |
231 | | - | |
232 | | - | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
233 | 255 | | |
234 | 256 | | |
235 | 257 | | |
| |||
311 | 333 | | |
312 | 334 | | |
313 | 335 | | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
65 | 65 | | |
66 | 66 | | |
67 | 67 | | |
68 | | - | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
69 | 73 | | |
70 | 74 | | |
71 | 75 | | |
| |||
94 | 98 | | |
95 | 99 | | |
96 | 100 | | |
| 101 | + | |
97 | 102 | | |
98 | 103 | | |
99 | 104 | | |
| |||
106 | 111 | | |
107 | 112 | | |
108 | 113 | | |
109 | | - | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
110 | 117 | | |
111 | 118 | | |
112 | 119 | | |
| |||
125 | 132 | | |
126 | 133 | | |
127 | 134 | | |
128 | | - | |
| 135 | + | |
129 | 136 | | |
130 | 137 | | |
131 | 138 | | |
| |||
158 | 165 | | |
159 | 166 | | |
160 | 167 | | |
161 | | - | |
162 | | - | |
| 168 | + | |
| 169 | + | |
163 | 170 | | |
164 | 171 | | |
165 | 172 | | |
| |||
242 | 249 | | |
243 | 250 | | |
244 | 251 | | |
245 | | - | |
| 252 | + | |
246 | 253 | | |
247 | 254 | | |
248 | 255 | | |
| |||
381 | 388 | | |
382 | 389 | | |
383 | 390 | | |
384 | | - | |
| 391 | + | |
| 392 | + | |
385 | 393 | | |
386 | 394 | | |
387 | 395 | | |
| |||
413 | 421 | | |
414 | 422 | | |
415 | 423 | | |
416 | | - | |
| 424 | + | |
417 | 425 | | |
418 | 426 | | |
419 | 427 | | |
| |||
0 commit comments