Repository navigation
Commit 665db00
fix(runtime,cli): a newcomer's first boot is quiet — the empty stub declares its protocol range, and a scaffold's os dev composes one MetadataPlugin (#30333)
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgBgqBcs88QEaQ8R1f3pax9S)_
domain:server#3 · os-bill · session_01Utp6CZgQTno2oPVD2GLd2n
Fixes #29937
Fixes #29936
Clause-②: no — boot diagnostics only; nothing accepted or published
changes
Metadata-protocol: none
## 维护者速读
- **改了什么:** ① 空内核存根 `com.objectstack.empty` 现在声明 `engines.protocol:
^18`(写它的运行时自己的大版本);旧 CLI 写过的存根(无范围、或别的大版本)在下次 `os start`
时就地补上,只改这一个键,且只改 OS_HOME 下仍是存根的文件。② `os serve` / `os dev` 的 dev artifact
door 与 host-config door 共用一个 `hasMetadataPlugin` 判定(先认插件名
`com.objectstack.metadata`,再认类名),dev door 不再在已有 `MetadataPlugin`
的栈上再加一个。
- **为什么改:** 文档首页一行命令 `npm i -g @objectstack/cli && os start`
的首启诊断报「`com.objectstack.empty` 没声明 engines.protocol」,新人既不能修也找不到这个包;`os
init -t app` 脚手架上 `os dev` 每次启动都报「Plugin superseded:
'com.objectstack.metadata'」,怪用户配错了一个他没写过的插件。后者的根因:发布的
`@objectstack/metadata` 打包产物写成 `var MetadataPlugin = class
_MetadataPlugin`,`constructor.name` 是 `_MetadataPlugin`,dev door
只比类名,所以认不出 standalone stack 已组好的那个;源码跑的测试看不到这个改名。
- **风险与回滚:** 只动启动组装与存根文件。存根刷新只在 OS_HOME 的 `dist/objectstack.json` 且
`manifest.id` 仍是 `com.objectstack.empty` 时发生,别处的同形文件、非 JSON 文件一律不碰(有
pin)。dev door 的判定只比原来多认一种已有插件的写法,host config 没有自己的 `MetadataPlugin` 时照旧组
dev door。两个包各一条 patch changeset。回滚即撤 PR。
- **先看:** `packages/runtime/src/default-host.ts` 的 `ensureEmptyBootStub`
与 `createDefaultHostConfig`
里按路径传入时的刷新分支;`packages/cli/src/utils/stack-collections.ts` 的
`hasMetadataPlugin`;`packages/cli/src/commands/serve.ts` 两处门控。
- **两分钟验证:** 空目录、空 HOME 下跑 `os start`:首启诊断里不再出现 `declares no
engines.protocol range`,`~/.objectstack/dist/objectstack.json` 带
`"engines": { "protocol": "^18" }`。
- **需要你做的:** 无,席位落地。
## What changes
**#29937 — the empty kernel's stub declares its range**
(`@objectstack/runtime`, commits 4a5bb32 and 8e3cead)
- `ensureEmptyBootStub(stubPath)` (new, in `default-host.ts`; not
re-exported from the package index) owns the stub. Absent: it is written
with `manifest.engines.protocol` = `^PROTOCOL_MAJOR` (from
`@objectstack/spec/kernel`), the major of the runtime that writes it, so
it is compatible by construction. Present and still the stub
(`manifest.id` is `com.objectstack.empty`) with no range or another
major's: only `manifest.engines.protocol` is rewritten. Present and not
the stub, or not JSON: left alone; the loader reports it.
- The re-stamp of another major's range is deliberate: a stub stamped
`^18` by this CLI would otherwise be refused as
`OS_PROTOCOL_INCOMPATIBLE` the day the runtime moves to 19, failing the
one boot that has nothing in it.
- **Found by the before/after measurement, not in the card:** the
empty-boot branch of `createDefaultHostConfig` runs only on the FIRST
`os start`. From the second on, the `os start` supervisor resolves
`HOME_DIR/.objectstack/dist/objectstack.json` as an artifact rung
(`resolveArtifactBootSource`, rung `home-dist`) and hands it down as
`artifactPath`, so a stub an older CLI wrote was never reached by the
first commit and kept warning (measured, log below). The second commit
refreshes the stub on that path too, keyed on the resolved path being
exactly the home stub path; a stub-shaped file named anywhere else is
left alone.
**#29936 — one `MetadataPlugin` on a scaffold's `os dev`**
(`@objectstack/cli`, commit 028a043)
- `hasMetadataPlugin(plugins)` (new, `utils/stack-collections.ts`,
beside `hasObjectQLPlugin` / `hasStorageDriverPlugin`): a plugin named
`com.objectstack.metadata`, or a class named `MetadataPlugin`.
- `serve.ts`: the dev artifact door's gate was `!plugins.some((p) =>
p?.constructor?.name === 'MetadataPlugin')`; the host-config door's was
the name-or-class form. Both now read `!hasMetadataPlugin(plugins)`.
`createStandaloneStack` is untouched, as the dispatch asked.
- Why only the dev door missed: the published bundle (checked on
`@objectstack/metadata@18.3.0` `dist/index.js` and on this branch's own
build of `packages/metadata/dist/index.js` and `node.js`, one hit each)
declares `var MetadataPlugin = class _MetadataPlugin {`. The host-config
door already checked the name, so it was immune; the dev door was not.
## Tests
- `packages/runtime/src/default-host-empty-stub.test.ts` (new, 9 cases):
a fresh stub passes the handshake (`checkProtocolCompat(...).status ===
'ok'`); a legacy stub (exactly the 18.3.0 bytes' shape) is refreshed
with everything else kept; another major's range is re-stamped; a
current stub is left byte for byte; a non-stub artifact and a non-JSON
file are untouched; through `createDefaultHostConfig`: the legacy stub
named as `artifactPath` at the home location is refreshed, the empty
boot writes the range, and a stub-shaped file named elsewhere is
untouched.
- `packages/cli/src/utils/stack-collections.test.ts`: three
`hasMetadataPlugin` cases, one built on the bundle's shape (`class
_MetadataPlugin { name = 'com.objectstack.metadata' }`).
- Source pins updated:
`serve-host-config-security-registrar.pin.test.ts` (the dev door's gate
string) and `serve-host-config-metadata-door.pin.test.ts` (both doors
ask `!hasMetadataPlugin(plugins)`, count 2, and no class-name-only
spelling is left in `serve.ts`).
## Verification
All readings on head 2041627 (gates: the 61-family run on 8e3cead,
then the 17 families that read the last commit's file re-run on
2041627; the last commit adds one `SERVE_ONLY` entry to a cli test).
<details><summary>Real boot, before/after (#29937: os start, empty
directory, empty HOME)</summary>
Built CLI of this branch (`node packages/cli/bin/run.js start`, `HOME` a
fresh temp dir).
- **Before** (`default-host.ts` restored from a26abbc, runtime rebuilt;
`ensureEmptyBootStub` count in dist 0): `Artifact: none (empty kernel
…)`, then `ℹ Boot diagnostics — 1 informational: WARN [AppPlugin]
[protocol] package 'com.objectstack.empty' declares no engines.protocol
range; loading under protocol 18.0.0 without a compatibility check
(ADR-0087).`
- **After, fresh home:** `Server is ready`, no `Boot diagnostics` block;
the stub on disk carries `"engines": { "protocol": "^18" }`.
- **After commit 1 only, legacy stub** (the 18.3.0 stub bytes
pre-seeded): banner `Artifact:
HOME_DIR/.objectstack/dist/objectstack.json` (the `home-dist` rung), the
same WARN, stub unchanged. This is what commit 8e3cead closes.
- **After commit 2, legacy stub:** no `Boot diagnostics`; the stub now
carries `"engines": { "protocol": "^18" }`.
- Restore leg: `git diff HEAD` empty, runtime rebuilt from HEAD (dist
`ensureEmptyBootStub(` count 3).
</details>
<details><summary>Real boot, before/after (#29936: os dev on an os init
my-app -t app scaffold)</summary>
- **Before** (`serve.ts` restored from a26abbc, cli rebuilt): `ℹ Boot
diagnostics — 1 informational: WARN Plugin superseded:
'com.objectstack.metadata' — the later registration (v1.0.0) REPLACED
the earlier one (v1.0.0). …`
- **After** (cli rebuilt from HEAD): `Server is ready`, `superseded`
count 0, no `Boot diagnostics` block; `Plugins: 41 loaded` lists
`com.objectstack.metadata` once.
- Restore leg: `git diff HEAD` empty.
</details>
<details><summary>Ablations (scripts/ablation-replace.mjs; each
restored, blob == HEAD, git diff HEAD empty)</summary>
- `hasMetadataPlugin` name clause dropped (`return ctor ===
'MetadataPlugin';`): `stack-collections.test.ts` 1 failed / 21 passed —
`finds the plugin by its name when the bundle renamed the class`.
- Stub `engines: { protocol: range },` removed:
`default-host-empty-stub.test.ts` 3 failed / 6 passed (fresh stub,
current-stub-left-alone, empty boot writes the range).
- Named-path refresh disabled (path compared to a sentinel): 1 failed /
8 passed — `refreshes a legacy stub handed in as artifactPath at the
home location`.
</details>
<details><summary>Tests and typecheck</summary>
- `pnpm --filter @objectstack/runtime exec vitest run --maxWorkers=2`:
Test Files 545 passed (545), Tests 9840 passed, 19 skipped (9859); lock
VERDICT command-exit 0.
- `pnpm --filter @objectstack/cli exec vitest run --project unit
--maxWorkers=2` on 8e3cead: 1 failed / 5429 passed —
`boot-preparation-parity.test.ts` asked for `hasMetadataPlugin` to be
listed; fixed in 2041627 (`SERVE_ONLY` entry with its reason), that
file then 37/37. The cli `integration` tier is declared to CI.
- `pnpm --filter @objectstack/runtime typecheck`, `pnpm --filter
@objectstack/cli typecheck`: VERDICT command-exit 0 both.
</details>
<details><summary>Derived gates (dispatch-gates --commands, 61
families)</summary>
- 59 exit 0. 2 exit 3, NOT MEASURED (prerequisite: a whole-workspace
build): `check:dual-build-cjs-loads`, `check:i18n-coverage`; left to CI.
- `dispatch-gates --ran`: 61 derived, 59 run, 2 NOT-MEASURED, 0 UNRUN.
- Re-run on 2041627, all exit 0: closing-keyword-parity,
comment-mask-adoption, comment-mask-corpus, issue-citations (script and
pnpm), closed-ceremony-text, cross-package-test-inputs,
keyed-text-bounds, logger-receiver-detach, nul-bytes, refd-timer-probe,
registry-log-declared, rest-log-spy-declared, test-source-alias,
tier-file-adoption, type-check-debt, undeclared-dep-imports.
</details>
## Acceptance notes
- The seat asked for one commit per card. #29937 has two (4a5bb32,
8e3cead): the second is the named-path refresh the measurement found
after the first was pushed. The branch is `claude/project-thread-*`, not
`claude/issue-*`, so AGENTS.md §3 forbids rewriting it; they stay two
commits. #29936 likewise gains 2041627, the boot-parity census entry
its unit run asked for.
- The scaffold measurement for #29936 ran this branch's CLI against an
`os init my-app -t app` scaffold whose `@objectstack/spec`, `runtime`
and `objectql` were linked to this worktree's packages, so both copies
of the boot read this branch's builds.
- Not changed: the ADR-0087 `no-range` warning itself, and
`createStandaloneStack`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Utp6CZgQTno2oPVD2GLd2n)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 47226e6 commit 665db00
10 files changed
Lines changed: 345 additions & 37 deletions
File tree
- .changeset
- packages
- cli/src
- commands
- utils
- runtime/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
71 | 71 | | |
72 | 72 | | |
73 | 73 | | |
74 | | - | |
75 | | - | |
76 | | - | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
77 | 81 | | |
78 | 82 | | |
79 | 83 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
116 | | - | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
117 | 119 | | |
118 | | - | |
| 120 | + | |
119 | 121 | | |
120 | 122 | | |
121 | 123 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
125 | 125 | | |
126 | 126 | | |
127 | 127 | | |
| 128 | + | |
128 | 129 | | |
129 | 130 | | |
130 | 131 | | |
| |||
3511 | 3512 | | |
3512 | 3513 | | |
3513 | 3514 | | |
3514 | | - | |
| 3515 | + | |
3515 | 3516 | | |
3516 | 3517 | | |
3517 | 3518 | | |
| |||
3652 | 3653 | | |
3653 | 3654 | | |
3654 | 3655 | | |
3655 | | - | |
| 3656 | + | |
3656 | 3657 | | |
3657 | 3658 | | |
3658 | 3659 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
155 | 155 | | |
156 | 156 | | |
157 | 157 | | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
158 | 162 | | |
159 | 163 | | |
160 | 164 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
17 | 17 | | |
18 | 18 | | |
19 | 19 | | |
| 20 | + | |
20 | 21 | | |
21 | 22 | | |
22 | 23 | | |
| |||
268 | 269 | | |
269 | 270 | | |
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 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
125 | 147 | | |
126 | 148 | | |
127 | 149 | | |
| |||
| 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 | + | |
0 commit comments