Repository navigation
Commit 63acf35
feat(cli,metadata-protocol): os migrate packageless-overlays moves package-less overlay rows into .custom as declared overrides (#28689)
domain:server#3 · os-project-manager · session_01FEkQ5kE5BrPUPNMMyv6oCH
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X4SFjuGUkFbJFHhsi2qJCMo)_
Fixes #28413
Clause-②: yes (widening)
Metadata-protocol: added
Skills-docs: none — the one taught line this touches,
`skills/objectstack-platform/SKILL.md`'s "a package-unbound Setup row
still wins over the base's until D11", stays true: the ceremony moves
such rows when an operator runs it, and the package-less write that
makes new ones stays open until #28576, which is the change that retires
that line. No file under `skills/**` teaches the `os migrate` operator
ceremonies.
## 维护者速读
- 新增运维命令 `os migrate packageless-overlays`:默认只列出,`--apply`(配
`--yes`)才搬迁;不是启动步骤。
- 搬迁对象:五种覆盖类型中、恰好一个只读代码包发布的同名、未绑定包的行,移入 基础包配对的 `.custom` 包,正文写入
`overrides:{package, basedOn}`。
- 顺序:配对包只经 N-13 的 ensure 门创建;写入经 N-09
的门且保留草稿/生效状态;新行读回为已服务的覆盖之后才删除旧行;可重复运行,按基础包报告。
- 不动:无人发布、多包发布、权限集/岗位、已被配对包覆盖(列出两条出路)的行;缺 `basedOn` 的旧声明会补上 `basedOn`。
- 在 #28576 之前:Setup 不带包名的保存落到配对行时保留该行的 `overrides`,不再被 403 拒绝;不关闭无包写入、不碰
console、不加重定向。
- adopt-orphans 早已跳过发布同名行(#23198),本 PR 加了钉住测试;它的响应是否要点名本命令,见报告中的待决问题。
## What changes
- **`os migrate packageless-overlays`**
(`packages/cli/src/commands/migrate/packageless-overlays.ts`), modelled
on `os migrate security-catalog-overlays`: lists by default, moves with
`--apply` (`--yes` or the prompt), `--json`, `--force`,
`--database-url`, and `serve`'s `--preset` / `--dev`. With `--apply` it
boots a live `PackageServicePlugin`, so a pair it creates persists to
`sys_packages`. Exit 1 only when `--apply` leaves a failed row (or on an
error).
- **The ceremony**
(`packages/metadata-protocol/src/protocol-packageless-overlay-migration.ts`,
exposed as `listPackagelessOverlays()` / `migratePackagelessOverlays({
actor })` on the protocol):
- **Population.** Every `sys_metadata` row bound to no package, of the
five overlay types, active or draft, over a name exactly one installed
read-only package ships.
- **The move**, per row:
1. The pair is ensured through N-13's ensure door, once per base.
2. The body gains `overrides: { package, basedOn }`, naming the base and
its installed `manifest.version`.
3. It is saved into the pair through the save door, so N-09's gate
judges it, in the row's own state.
4. The pair's row is read back and must satisfy `isServedOverrideRowOf`.
5. Only then is the unbound row deleted, through the repository
addressed by `package_id` NULL, with its history tombstone. A failed
read-back keeps the unbound row and reports the row as failed.
- **Left alone, and listed.** A name several packages ship
(`multi_shipped`), a body declaring another package
(`foreign_declaration`), and a name the pair already overrides
(`shadowed`). Shadowed rows carry two ways out: delete the package-less
row, or "Restore package original" in Studio and re-run. Names no
package ships are counted as environment metadata. Permission sets and
positions are not overlay types.
- **`basedOn` completion.** A pair row declaring `overrides: { package
}` with no `basedOn` gains the base's installed version, and is read
back.
- **Setup keeps working on a moved item** (`saveMetaItemUnaudited`,
until #28576). A package-less authoring save whose address is a pair row
declaring the override is treated as the write into that pair:
- Carrying `overrides`, it is judged as the write into the pair at the
`declared_outside_pair` refusal.
- Carrying none, it gains the row's declaration at the late
`undeclared_same_name` re-judgement.
- The landing is read only at those two refusal points. No admitted save
reads an extra row, and #5706's lock gate stays the first store reader.
- The package-less write is not closed, `ui/**` is not touched, and no
Setup redirect is added.
- **Census lists.** The one-shot family, the confirmation-exit pin and
the JSON-stdout purity roster each gain the new command. The durability
gate declares the ceremony's per-row `fail()` report as its failure
delivery. The cli vitest config resolves `@objectstack/service-package`
to source (`check:test-source-alias`).
## Tests
- `packages/objectql/src/protocol-packageless-overlay-migration.test.ts`
(10):
- THE MOVE (active and draft, pair created, `basedOn` 1.2.0, five reads
unchanged, a re-run moves 0).
- LEFT ALONE (environment, multi-shipped, shadowed with
`shadowDeclares`, an unbound draft beside an active override).
- READ BACK FIRST.
- `basedOn` completion, over every overridable type; flow and action
rows missing `basedOn` are reported failed with the save door's ADR-0146
D9 refusal.
- Package-less save with and without `overrides` landing on the pair
(draft, publish, publish-mode).
- Package-less DELETE restores the base document.
- CONTROL: a package-less save carrying `overrides` over an unmoved row
is still `403 NOT_OVERRIDABLE`.
- adopt-orphans skips the shipped-name row.
-
`packages/cli/src/commands/migrate/packageless-overlays.integration.test.ts`
(3), on a real booted stack:
- The preview writes nothing.
- `--apply` moves the active and draft rows, persists the pair to
`sys_packages`, keeps the controls, serves the same content after a
fresh boot, and a re-run moves 0.
- `--apply --json` without `--yes` gives `confirmation_required` and
moves nothing.
- **Red first, on main.** The Wanted 4 cases are red with the real
refusals (`undeclared_same_name` without `overrides`,
`declared_outside_pair` with them). The other cases are red because the
ceremony does not exist.
- **Ablations.** Each leg rebuilt `metadata-protocol`'s dist and proved
the marker with `ablation-dist-preflight` (objectql resolves it from
dist). Each was red as predicted, then restored to the HEAD blob:
- shadowed guard → LEFT ALONE red;
- read-back check → READ BACK FIRST red;
- adopt-orphans `isArtifactBacked` skip → adopt-orphans red;
- the early pair-landing judgement (body carrying `overrides`) → that
Wanted 4 case red;
- the late declaration graft (body carrying none) → both Wanted 4 cases
red (each case's last save carries none).
## Acceptance notes
- **Wanted 3 (walled postures).** No HTTP door is added: the ceremony
runs only from the operator's CLI. The ensure door's walled `403` is
unchanged and stays pinned by N-13's own tests.
- **Wanted 5.** `reassignOrphanedMetadata` has skipped artifact-backed
names since #23198. This PR pins that with a test and ablates it. Naming
this ceremony in the adopt-orphans response would change
`ReassignOrphanedMetadataResponseSchema` in `packages/spec`, so it is
raised on the card as an open question rather than done here.
- **Seat 2's reading.** A legacy `overrides: { package }` without
`basedOn` gains `basedOn`.
- **Delta `5865a0ce` (review S1, S2, N1).** S1: a pair row of the item
in either state shadows an unbound row; the bundle member stays in the
item identity, so one translation locale does not shadow another. S2:
the `basedOn` completion covers every overridable type, and flow and
action rows are reported failed with the gate's refusal, so `--apply`
exits 1 on a deployment holding one. N1: both types are exported
type-only from the index, and the CLI imports them.
- **Seat 1's flow finding** (#28413 comment 6559382296) is not covered
here: flow is no overlay type (`allowEnvironmentOverlay: false`), a
package-less row beside the pair's row is the shadowed shape this
ceremony leaves alone, and a declared flow write is refused by N-09
until D9. Routed by the seat.
## Verification
- On the delta head `5865a0ce` (os-dev-report 6559681417 on #28413): 86
of 86 derived gates exit 0, `--ran` reconciles; `metadata-protocol`
21944, `objectql` 9913 and cli unit 5166 tests pass, plus 184 targeted;
typecheck and lint pass. The readings below were taken on `34c1aa5d`.
- Package suites, on `34c1aa5d`:
- `@objectstack/metadata-protocol` full suite: 291 files, 21944 tests
passed.
- `@objectstack/objectql` full suite: 514 files, 9912 tests passed.
- `@objectstack/cli` `--project unit`: 5165 of 5166 passed. The one red,
`setup-integrations-order.pin`, read a `service-automation` dist built
before the rebase onto #28651; it passes after rebuilding that dist.
- The cli integration test, `migrate-confirmation-exit.pin`,
`one-shot-family`, `package-table` and `security-catalog-overlays`: 184
tests passed.
- The `metadata-protocol` suite first caught the lock-gate ordering
(#5706 pins). The landing read now sits only at the two refusal points.
- Typecheck for `metadata-protocol`, `cli` and `objectql` (with
`check:test-typecheck`).
- `eslint` over the three packages.
- The gates from `dispatch-gates.mjs --commands`, each run with its exit
code captured and reconciled with `--ran`. The figures are in the
os-dev-report on #28413.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5pKMJFQjFx8NCVZb62)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent c16040d commit 63acf35
12 files changed
Lines changed: 1947 additions & 2 deletions
File tree
- .changeset
- packages
- cli
- src
- commands/migrate
- utils
- test
- metadata-protocol/src
- objectql/src
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
0 commit comments