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
Commit 60fe44f
Browse filesBrowse the repository at this point in the historyBrowse files
feat(cloud-connection,metadata-core): an install the protocol handshake admitted unchecked says so in its answer (#30409)
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgXzMmGY8jy4ddsrnh83rUgi)_
domain:server#5 · os-bill · session_01Utp6CYVV6fcAQrNTDQRvPb
## 维护者速读
- 改了什么:从市场或文件安装一个没声明平台协议版本(`engines.protocol`)的应用时,安装成功的应答里多了
`protocolCheckSkipped`:说明没做兼容性检查、按哪个协议版本装的,并带一句给管理员看的话;声明了版本范围、检查通过的包,应答和以前一字不差。
- 为什么改:兼容性检查被跳过时,只有服务器日志里有一行 warn,点"安装"的管理员看不到;这是卡 #30326 的 server
半,页面上怎么展示是之后的 ui 卡。
- 风险与回滚:只在成功应答里加一个可选键,不改任何拒绝路径,日志行照旧;`assertProtocolCompat`
从无返回值改为返回它本来就算出的判决,旧调用方不受影响。回滚即撤本 PR,无数据迁移。
- 先看:`packages/cloud-connection/src/marketplace-install-local-plugin.ts`
的 `protocolCheckSkippedOf` 和步骤 1c
里接住判决的那几行;`packages/metadata-core/src/protocol-handshake.ts` 的
`assertProtocolCompat` 返回值。
- 两分钟验证:`pnpm --filter @objectstack/cloud-connection exec vitest run
src/marketplace-install-local-protocol-handshake.test.ts -t 30326`,预期 5
条全绿;在 main 的代码上其中 4 条是红的(对照那条本来就绿)。
- 需要你做的:无,席位落地。
Part of #30326
Clause-②: yes (widening) — the three success answers of `POST
/api/v1/marketplace/install-local` gain the optional
`data.protocolCheckSkipped`; `@objectstack/metadata-core`'s
`assertProtocolCompat` returns `ProtocolCompatAdmitted` (new exported
type) where it returned `void`, and the `no-range` / `unparsed-range`
members of the exported `ProtocolCompatResult` gain `protocolVersion`.
Nothing accepted or answered is taken away.
Metadata-protocol: none — an install answer and a runtime helper's
return value, not anything a metadata author writes
Skills-docs: none — `git grep -n -i "install-local\|declares no
engines\|without a compatibility check\|protocolCheck\|engines.protocol"
-- skills` (evals excluded) hits four lines:
`objectstack-platform/SKILL.md:118` (a declared range is checked and an
out-of-range app refused, still true),
`objectstack-platform/references/operations.md:106` and `:111` (what `os
package install` and the plugin are), `objectstack-upgrade/SKILL.md:87`
(where the declared range is read). None describes what an install
answers for a package with no range.
## What changes
The card: "The install answer carries this, and the page shows it in
plain words". The triage (6652014530) puts the server half in
`marketplace-install-local-plugin.ts`; the UI half is a later
`domain:ui` card, so #30326 stays open after this PR (the seat releases
it at landing).
**The handshake hands its verdict back.** `assertProtocolCompat`
(ADR-0087 D1) already computed a verdict and threw on `incompatible`;
for `ok`, `no-range` and `unparsed-range` it returned nothing, so a door
that answers a caller could only log. It now returns the verdict
`checkProtocolCompat` gave (`ProtocolCompatAdmitted` = every member but
`incompatible`), and the `no-range` / `unparsed-range` members carry
`protocolVersion`, the version they were judged against (the
`incompatible` member and its diagnostic already did). No new judgement:
the range is read once, by the handshake.
**The install answer carries the skipped check.** Step 1c of
`handleInstall` keeps the verdict, and `protocolCheckSkippedOf` turns a
`no-range` or `unparsed-range` verdict into
```
protocolCheckSkipped: { reason, packageId, protocolVersion, message } // + requiredRange, rangeSource for unparsed-range
```
`reason` is the handshake's own `status` value, the stable machine code;
`packageId` is the id the door's id gate parsed; `protocolVersion` is
the protocol the package was installed under unchecked; `message` says
it in plain words for the person who pressed Install. It rides all three
success answers: managed, `unmanaged` (`installUnmanaged`) and a paired
customization package (`installCustomizationPair`), passed down the way
`withheldMaps` is. It is omitted, not nulled, when the range was
checked, so that answer's key set is unchanged. The `warn` line
`[MarketplaceInstallLocal] [protocol] package '…' declares no
engines.protocol range; …` is unchanged.
**Why the code is in `reason`, not `code`.** A `code:` literal in the
answer would be read by `check:dispatcher-error-vocabulary` as an
ADR-0112 error code and would need a row in the spec ledger. This is a
notice on a `200`, not an error code (the D6c family
`check:error-code-casing` describes), and the handshake's own status
value is the code the ruling asks for.
## Contract stop: measured, not reached
The order: stop if carrying the notice needs a `packages/spec` change.
Measured on `fdad1786` and again on `870ebce3`: no schema in
`packages/spec/src` describes the install-local success answer. The
spec's `withheldMaps` (`PackageExportManifestSchema`) is the export
manifest's, not the answer's; `git grep -n
"hotLoaded\|upgradedFrom\|credentialNote" -- packages/spec/src` (three
keys only this answer carries) hits nothing. The answer is a
cloud-connection-internal REST shape, so the field is added there.
## Tests
- `marketplace-install-local-protocol-handshake.test.ts`, new top-level
`describe('[#30326] …')`: an inline manifest with no range answers
`protocolCheckSkipped` `{ reason: 'no-range', packageId, protocolVersion
}` with the plain-words message, is registered, and logs exactly one
`[protocol]` warn line; the compiled artifact `os package install FILE`
sends answers the same; a range the handshake cannot read
(`workspace:*`) answers `unparsed-range` with `requiredRange` and
`rangeSource`; an `unmanaged` install of the same package carries it;
control: under `^CURRENT_MAJOR` the answer has no `protocolCheckSkipped`
key. The harness's `mount` gained an optional protocol
`importUnmanagedPackage` stub for the unmanaged case.
- `marketplace-install-local-customization-pair-install.test.ts`, new
top-level `describe`: a pair export with no range answers `no-range`;
with `^CURRENT_MAJOR` no key.
- `protocol-handshake.test.ts`, new top-level `describe`:
`assertProtocolCompat` returns the `no-range` and `unparsed-range`
verdicts with `protocolVersion`, and the `ok` verdict equal to
`checkProtocolCompat`'s.
- Red first, on `fdad1786` with the fix reverted and the pins in: the 5
notice cases red (`200` with no `protocolCheckSkipped`), the 2 controls
green. With the fix: 43/43 in the two files.
- `marketplace-install-local-jobs.test.ts`: its fixture now declares
`engines.protocol: ^CURRENT_MAJOR`, as a scaffolded app does. Its
jobs-free case pins the answer's exact key set, and the fixture declared
no range, so with this change the set gained `protocolCheckSkipped`;
with a declared range the pin keeps meaning "the jobs gate adds
nothing".
<details><summary>Suites and typecheck on 4d926a7</summary>
`os-verify-lock` VERDICT command-exit 0: `@objectstack/metadata-core`
typecheck exit 0, `@objectstack/cloud-connection` typecheck exit 0;
`@objectstack/metadata-core` test Test Files 23/23, Tests 911/911;
`@objectstack/cloud-connection` test Test Files 70/70, Tests 877/877.
</details>
## Ablation
One leg, through `scripts/ablation-replace.mjs` on `4d926a74`: deleting
`protocolCheckSkipped = protocolCheckSkippedOf(admitted, manifestId);`
(anchor 1 → 0, blob `8e7fdb92` → `5f6c1432`) turns the 5 notice cases
red, 38 green; restored to blob == HEAD `8e7fdb92`, `git diff HEAD`
empty. The cloud-connection suite resolves `@objectstack/metadata-core`
to `src/` (vitest alias), and the plugin is imported from `src/`, so no
`dist/` leg applies.
## Acceptance notes
- The other install door, `POST /api/v1/packages`
(`packages/runtime/src/domains/packages.ts`,
`assertProtocolCompat(manifest)`), still answers success with no notice
for a package with no range. It is outside this order's surface; with
`assertProtocolCompat` now returning the verdict, the same spread there
is a small follow-up. carrier: seat 5.
- `os package install` prints the answer's `note`; whether the CLI also
prints `protocolCheckSkipped` is the CLI's call. carrier: seat 5.
- Whether publishing should warn or refuse such a package is out of
scope (the card says so).
## Verification
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` on the final head `6c1d2ef22` (after merging
`origin/main` at `8fad7b193`): 60 families, the same list as on
`4d926a749`. All 60 run, exit codes captured before any pipe, all `exit
0`; `--ran` reconciliation: 60 derived, 60 run, 0 NOT-MEASURED, 0 UNRUN.
On `4d926a749` the same 60 were all `exit 0` after `git fetch origin
621a487` gave `check-plugin-teardown-shape --self-test` its pinned
fixture (it exits 3 on a shallow clone).
- `pnpm lint` exit 0 on `4d926a749`; the merge brought no file of this
diff's packages.
- The merge from `origin/main` (#30380, #30368) touched
`metadata-protocol`, `cli` and `spec`, none of this diff's packages, so
the suites and typechecks above were not re-run on `6c1d2ef22`.
- No `!` in the title and no `(narrowing)` arm: no full dogfood run
owed.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Utp6CZ35sjTKgyrvdkytCz)_
<!-- signed: domain:server#5 · os-bill ·
session_01Utp6CYVV6fcAQrNTDQRvPb -->
Co-authored-by: Claude <noreply@anthropic.com>
feat(cloud-connection,metadata-core): an install the protocol handshake admitted without checking says so in its answer, not only in the server log
7
+
8
+
Clause-②: yes (widening)
9
+
Metadata-protocol: none
10
+
11
+
-**`@objectstack/cloud-connection`: `POST /api/v1/marketplace/install-local` answers `data.protocolCheckSkipped`** when the ADR-0087 handshake admitted the package without checking it: `{ reason, packageId, protocolVersion, message }`, plus `requiredRange` and `rangeSource` for `reason: 'unparsed-range'`. `reason` is the handshake's own verdict: `no-range` (the package declares no `engines.protocol`) or `unparsed-range` (it declares a range the handshake cannot read). `protocolVersion` is the protocol the package was installed under unchecked, and `message` says so in plain words for the person who pressed Install. It is on all three success answers (managed, `unmanaged`, and a paired customization package), and omitted, not nulled, when the range was checked, so that answer's key set is unchanged. The `warn` log line stays as it was.
12
+
-**`@objectstack/metadata-core`: `assertProtocolCompat` returns the verdict it admitted the package under** (new exported type `ProtocolCompatAdmitted`; it returned `void`), and the `no-range` and `unparsed-range` verdicts of `checkProtocolCompat` carry `protocolVersion`, the version they were judged against. A door that answers a caller reads the skipped check from the handshake itself instead of judging the range a second time.
0 commit comments