From 3fb97210fb56bdf4a3affb96bca38d6e8926d3f5 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 10:09:50 +0000 Subject: [PATCH 1/2] fix: install beside the harness's 0.2.2 release candidate (cordis 4.1) The harness published 0.2.2-rc.1 on 2026-11-04. Its @deepseek-ai/dsh-typert-protocol build peers cordis ~4.1.0. npm resolves the plugin's typert peer to the newest admitted build (the `latest` tag, 0.1.0-rc.6, is outside it) and then needs that build's cordis, which the plugin's optional cordis peer stopped short of. A fresh install of the plugin therefore failed with ERESOLVE, and so did the bundle gate's consumer install on main and on every branch. The cordis peer now also admits ~4.1.0. A new harness-channel case holds the cordis peer to the cordis range of every published typert build the typert peer admits (recorded from the registry), and keeps the range stopping at the next tuple. The README pair says why the cordis peer follows the typert range. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD --- README.md | 9 ++++- README.zh-CN.md | 9 ++++- package.json | 2 +- test/harness-channel.test.ts | 68 ++++++++++++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a9a3fbf..b363ee8 100644 --- a/README.md +++ b/README.md @@ -428,7 +428,7 @@ These exist in the schema but render no control — each is a literal, a marker, **Verified on DeepSeek Harness `0.2.1` — both the `alpha` and `rc` channels (Node 24+)** -The harness publishes two **channels**, `alpha` and `rc`, and they are parallel tracks rather than a version ordering: semver sorts `0.2.1-rc.2` _above_ `0.2.1-alpha.5`. The plugin targets two lines on both channels: **`0.2.1`**, the `rc` channel's latest, and the **`0.2.2`** prereleases the `alpha` channel now carries (the test install runs `0.2.2-alpha.2`). The `@deepseek-ai/dsh-typert-protocol` peer range says so exactly: +The harness publishes two **channels**, `alpha` and `rc`, and they are parallel tracks rather than a version ordering: semver sorts `0.2.1-rc.2` _above_ `0.2.1-alpha.5`. The plugin targets two lines on both channels: **`0.2.1`**, the `rc` channel's latest, and the **`0.2.2`** prereleases on both channels: `alpha` is at `0.2.2-alpha.3`, and `rc` opened the line with `0.2.2-rc.1` (published under the `next` dist-tag; the test install runs `0.2.2-alpha.2`). The `@deepseek-ai/dsh-typert-protocol` peer range says so exactly: ``` >=0.2.1-alpha.1 <0.3.0 || >=0.2.2-0 <0.3.0 @@ -436,9 +436,16 @@ The harness publishes two **channels**, `alpha` and `rc`, and they are parallel The first clause covers the `0.2.1` line on both channels: its lower bound (`alpha.1`) sorts below every `rc` of the same line, so rc needs no separate entry. The second is **not** redundant — semver excludes prereleases unless a comparator in the same `major.minor.patch` tuple carries one, so `<0.3.0` alone would silently drop every `0.2.2-*` build, alpha and rc alike. Both clauses stop at `0.3.0`, which leaves the next line a separate decision rather than a silent widening. +The optional `@deepseek-ai/cordis` peer follows the typert range, because npm installs whichever cordis the **newest** admitted typert build peers on. Each line moved the host core: the `0.2.1` builds peer `~4.0.5` (or a `4.0.5` prerelease), the `0.2.2` alphas a `4.0.6` prerelease, and `0.2.2-rc.1` `~4.1.0`. A cordis peer that missed any of them makes a fresh install fail with `ERESOLVE`, so it admits all of them and stops at the next tuple: + +``` +~4.0.4 || >=4.0.5-0 <4.1.0 || >=4.0.6-0 <4.1.0 || ~4.1.0 +``` + | Surface | Target | | :-- | :-- | | **Harness line** | **`0.2.1`** and the **`0.2.2`** prereleases, `alpha` and `rc` channels alike (peer: the range above) | +| **Host core** | `@deepseek-ai/cordis` `4.0.5`, the `4.0.6` prereleases and `4.1.x` (optional peer: the range above) | | **Plugin package** | [`dsh-opencode-patch`](https://www.npmjs.com/package/dsh-opencode-patch) | | **Host profile** | DSH Web profile (`patchReload: live`) | | **Routes claimed** | `opencode`, `opencode-go`, `opencode-responses`, `opencode-anthropic` | diff --git a/README.zh-CN.md b/README.zh-CN.md index 3075eac..8ad098f 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -422,7 +422,7 @@ Zen 路线上不出现任何 Go 的数字:根本不画圆环(没有可量的 **已在 DeepSeek Harness `0.2.1` 上验证 —— `alpha` 与 `rc` 两个通道(Node 24+)** -Harness 按 `alpha` 与 `rc` 两个**通道**发布,它们是平行的发布线而非版本先后:semver 中 `0.2.1-rc.2` 排序在 `0.2.1-alpha.5` **之上**。本插件在两个通道上都针对两条线:**`0.2.1`**(`rc` 通道的最新版本),以及 `alpha` 通道目前发布的 **`0.2.2`** 预发布版本(测试安装运行的是 `0.2.2-alpha.2`)。`@deepseek-ai/dsh-typert-protocol` 的 peer 范围正是这么写的: +Harness 按 `alpha` 与 `rc` 两个**通道**发布,它们是平行的发布线而非版本先后:semver 中 `0.2.1-rc.2` 排序在 `0.2.1-alpha.5` **之上**。本插件在两个通道上都针对两条线:**`0.2.1`**(`rc` 通道的最新版本),以及两个通道上的 **`0.2.2`** 预发布版本:`alpha` 已到 `0.2.2-alpha.3`,`rc` 以 `0.2.2-rc.1` 开启了这条线(发布在 `next` dist-tag 下;测试安装运行的是 `0.2.2-alpha.2`)。`@deepseek-ai/dsh-typert-protocol` 的 peer 范围正是这么写的: ``` >=0.2.1-alpha.1 <0.3.0 || >=0.2.2-0 <0.3.0 @@ -430,9 +430,16 @@ Harness 按 `alpha` 与 `rc` 两个**通道**发布,它们是平行的发布 第一个子句覆盖两个通道上的 `0.2.1` 整条线:下界 `alpha.1` 排序低于同线的所有 `rc`,因此无需单独枚举 rc。第二个子句**并不多余**——除非同一 `major.minor.patch` 的某个比较符带有预发布号,semver 会把预发布版本排除在外,所以只写 `<0.3.0` 会悄悄丢掉所有 `0.2.2-*` 构建,alpha 与 rc 都一样。两个子句都止于 `0.3.0`,下一条线因此是一个单独的决定,而不是悄悄放宽。 +可选的 `@deepseek-ai/cordis` peer 跟随 typert 的范围,因为 npm 会安装**最新**被接纳的 typert 构建所依赖(peer)的那个 cordis。每条线都推进了宿主内核:`0.2.1` 的构建依赖 `~4.0.5`(或 `4.0.5` 的预发布版本),`0.2.2` 的 alpha 依赖 `4.0.6` 的预发布版本,`0.2.2-rc.1` 依赖 `~4.1.0`。只要 cordis peer 漏掉其中任何一个,全新安装就会以 `ERESOLVE` 失败,所以它接纳全部,并止于下一个版本元组: + +``` +~4.0.4 || >=4.0.5-0 <4.1.0 || >=4.0.6-0 <4.1.0 || ~4.1.0 +``` + | 层面 | 目标 | | :-- | :-- | | **Harness 版本线** | **`0.2.1`** 与 **`0.2.2`** 预发布版本,`alpha` 与 `rc` 通道均可(peer:见上方范围) | +| **宿主内核** | `@deepseek-ai/cordis` `4.0.5`、`4.0.6` 预发布版本与 `4.1.x`(可选 peer:见上方范围) | | **插件包** | [`dsh-opencode-patch`](https://www.npmjs.com/package/dsh-opencode-patch) | | **宿主 profile** | DSH Web profile(`patchReload: live`) | | **声明的路由** | `opencode`、`opencode-go`、`opencode-responses`、`opencode-anthropic` | diff --git a/package.json b/package.json index 82b45fd..21e767f 100644 --- a/package.json +++ b/package.json @@ -119,7 +119,7 @@ "yaml": "2.9.1" }, "peerDependencies": { - "@deepseek-ai/cordis": "~4.0.4 || >=4.0.5-0 <4.1.0 || >=4.0.6-0 <4.1.0", + "@deepseek-ai/cordis": "~4.0.4 || >=4.0.5-0 <4.1.0 || >=4.0.6-0 <4.1.0 || ~4.1.0", "@deepseek-ai/dsh-typert-protocol": ">=0.2.1-alpha.1 <0.3.0 || >=0.2.2-0 <0.3.0" }, "peerDependenciesMeta": { diff --git a/test/harness-channel.test.ts b/test/harness-channel.test.ts index 7898328..3974866 100644 --- a/test/harness-channel.test.ts +++ b/test/harness-channel.test.ts @@ -105,6 +105,7 @@ describe("harness channel alignment", () => { "0.2.1", // 0.2.2 line, both channels, and its stable release. "0.2.2-alpha.2", + "0.2.2-alpha.3", "0.2.2-rc.1", "0.2.2", ]; @@ -125,4 +126,71 @@ describe("harness channel alignment", () => { ).toBe(false); } }); + + it("the cordis peer meets the cordis range of every typert build the typert peer admits", () => { + // npm resolves the typert peer to the NEWEST build the range admits (the + // `latest` dist-tag, 0.1.0-rc.6, is outside it), then installs the cordis + // that build peers on. If the plugin's own cordis peer excludes that + // cordis, a fresh install fails with ERESOLVE — which is what happened the + // morning 0.2.2-rc.1 was published with `~4.1.0` while this peer stopped + // below 4.1.0. So the cordis peer must INTERSECT every admitted build's. + // + // Recorded from the registry on 2026-11-04 (`npm view + // @deepseek-ai/dsh-typert-protocol@ peerDependencies`): every published + // build on the 0.2.1 and 0.2.2 lines. A new build joins this table, with + // its own cordis range, when it is published. + const CORDIS_PEER_OF_TYPERT: Record = { + "0.2.1-alpha.1": "~4.0.5-alpha.1", + "0.2.1-alpha.2": "~4.0.5-alpha.1", + "0.2.1-alpha.3": "~4.0.5-alpha.2", + "0.2.1-alpha.4": "~4.0.5-alpha.2", + "0.2.1-alpha.5": "~4.0.5-alpha.2", + "0.2.1-rc.1": "~4.0.5", + "0.2.1-rc.2": "~4.0.5", + "0.2.1-rc.3": "~4.0.5", + "0.2.1-rc.4": "~4.0.5", + "0.2.1-rc.5": "~4.0.5", + "0.2.2-alpha.2": "~4.0.6-alpha.1", + "0.2.2-alpha.3": "~4.0.6-alpha.2", + "0.2.2-rc.1": "~4.1.0", + }; + const peers = manifest().peerDependencies ?? {}; + const typertPeer = peers["@deepseek-ai/dsh-typert-protocol"] ?? ""; + const cordisPeer = peers["@deepseek-ai/cordis"] ?? ""; + expect(cordisPeer).not.toBe(""); + + for (const [build, cordis] of Object.entries(CORDIS_PEER_OF_TYPERT)) { + // The table is about builds the typert peer admits; one it does not + // admit would make the assertion below vacuous. + expect( + semver.satisfies(build, typertPeer), + `typert ${build} is admitted by ${typertPeer}` + ).toBe(true); + expect( + semver.intersects(cordisPeer, cordis, { includePrerelease: false }), + `typert ${build} peers cordis ${cordis}, which ${cordisPeer} excludes` + ).toBe(true); + } + + // The concrete cordis each channel ships is admitted, and the range still + // stops at the next tuple: a 4.1.x prerelease or 4.2 is a reviewed + // widening, not a silent one. + for (const version of [ + "4.0.5", + "4.0.6-alpha.1", + "4.0.6-alpha.2", + "4.1.0", + ]) { + expect( + semver.satisfies(version, cordisPeer), + `cordis ${version} is admitted` + ).toBe(true); + } + for (const version of ["4.1.1-alpha.1", "4.2.0", "5.0.0"]) { + expect( + semver.satisfies(version, cordisPeer), + `cordis ${version} is outside the peer` + ).toBe(false); + } + }); }); From c4118a81065d3fc51573fe4d601b5e788bd7edd9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 4 Nov 2026 10:17:02 +0000 Subject: [PATCH 2/2] test: check the cordis peer against published versions, not range overlap semver.intersects ignores the prerelease-tuple rule npm resolves under, so the case would have passed a typert build that peers a 4.1.1 prerelease, or a peer without the 4.0.6 clause, while npm would fail with ERESOLVE. The case now records the published cordis releases and requires every one an admitted typert build can install to satisfy the peer, with two known answers that show it bites (the peer shipped before 0.2.2-rc.1, and a peer missing the 4.0.6 clause). The README pair no longer calls 0.2.1 the rc channel's latest, says a fresh install depends on the newest build's cordis and a host-first install on its own line's, and the Host core row matches the range. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0141fKp5k6hiaJcP5ovhGtSD --- README.md | 6 +-- README.zh-CN.md | 6 +-- test/harness-channel.test.ts | 72 ++++++++++++++++++++++++++++-------- 3 files changed, 62 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index b363ee8..3618a04 100644 --- a/README.md +++ b/README.md @@ -428,7 +428,7 @@ These exist in the schema but render no control — each is a literal, a marker, **Verified on DeepSeek Harness `0.2.1` — both the `alpha` and `rc` channels (Node 24+)** -The harness publishes two **channels**, `alpha` and `rc`, and they are parallel tracks rather than a version ordering: semver sorts `0.2.1-rc.2` _above_ `0.2.1-alpha.5`. The plugin targets two lines on both channels: **`0.2.1`**, the `rc` channel's latest, and the **`0.2.2`** prereleases on both channels: `alpha` is at `0.2.2-alpha.3`, and `rc` opened the line with `0.2.2-rc.1` (published under the `next` dist-tag; the test install runs `0.2.2-alpha.2`). The `@deepseek-ai/dsh-typert-protocol` peer range says so exactly: +The harness publishes two **channels**, `alpha` and `rc`, and they are parallel tracks rather than a version ordering: semver sorts `0.2.1-rc.2` _above_ `0.2.1-alpha.5`. The plugin targets two lines on both channels: **`0.2.1`**, whose `rc` builds `dsh@latest` still carries, and the **`0.2.2`** prereleases on both channels: `alpha` is at `0.2.2-alpha.3`, and `rc` opened the line with `0.2.2-rc.1` (published under the `next` dist-tag; the test install runs `0.2.2-alpha.2`). The `@deepseek-ai/dsh-typert-protocol` peer range says so exactly: ``` >=0.2.1-alpha.1 <0.3.0 || >=0.2.2-0 <0.3.0 @@ -436,7 +436,7 @@ The harness publishes two **channels**, `alpha` and `rc`, and they are parallel The first clause covers the `0.2.1` line on both channels: its lower bound (`alpha.1`) sorts below every `rc` of the same line, so rc needs no separate entry. The second is **not** redundant — semver excludes prereleases unless a comparator in the same `major.minor.patch` tuple carries one, so `<0.3.0` alone would silently drop every `0.2.2-*` build, alpha and rc alike. Both clauses stop at `0.3.0`, which leaves the next line a separate decision rather than a silent widening. -The optional `@deepseek-ai/cordis` peer follows the typert range, because npm installs whichever cordis the **newest** admitted typert build peers on. Each line moved the host core: the `0.2.1` builds peer `~4.0.5` (or a `4.0.5` prerelease), the `0.2.2` alphas a `4.0.6` prerelease, and `0.2.2-rc.1` `~4.1.0`. A cordis peer that missed any of them makes a fresh install fail with `ERESOLVE`, so it admits all of them and stops at the next tuple: +The optional `@deepseek-ai/cordis` peer follows the typert range. Each line moved the host core: the `0.2.1` builds peer `~4.0.5` (or a `4.0.5` prerelease), the `0.2.2` alphas a `4.0.6` prerelease, and `0.2.2-rc.1` `~4.1.0`. A fresh install takes the cordis the **newest** admitted typert build peers on, so a cordis peer that misses it fails with `ERESOLVE`; one that misses an older line's cordis fails beside a host already installed on that line. The peer therefore admits every one of them and stops at the next tuple: ``` ~4.0.4 || >=4.0.5-0 <4.1.0 || >=4.0.6-0 <4.1.0 || ~4.1.0 @@ -445,7 +445,7 @@ The optional `@deepseek-ai/cordis` peer follows the typert range, because npm in | Surface | Target | | :-- | :-- | | **Harness line** | **`0.2.1`** and the **`0.2.2`** prereleases, `alpha` and `rc` channels alike (peer: the range above) | -| **Host core** | `@deepseek-ai/cordis` `4.0.5`, the `4.0.6` prereleases and `4.1.x` (optional peer: the range above) | +| **Host core** | `@deepseek-ai/cordis` `4.0.4` up to `4.1.x`, including the `4.0.5` and `4.0.6` prereleases (optional peer: the range above) | | **Plugin package** | [`dsh-opencode-patch`](https://www.npmjs.com/package/dsh-opencode-patch) | | **Host profile** | DSH Web profile (`patchReload: live`) | | **Routes claimed** | `opencode`, `opencode-go`, `opencode-responses`, `opencode-anthropic` | diff --git a/README.zh-CN.md b/README.zh-CN.md index 8ad098f..c2ed8dd 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -422,7 +422,7 @@ Zen 路线上不出现任何 Go 的数字:根本不画圆环(没有可量的 **已在 DeepSeek Harness `0.2.1` 上验证 —— `alpha` 与 `rc` 两个通道(Node 24+)** -Harness 按 `alpha` 与 `rc` 两个**通道**发布,它们是平行的发布线而非版本先后:semver 中 `0.2.1-rc.2` 排序在 `0.2.1-alpha.5` **之上**。本插件在两个通道上都针对两条线:**`0.2.1`**(`rc` 通道的最新版本),以及两个通道上的 **`0.2.2`** 预发布版本:`alpha` 已到 `0.2.2-alpha.3`,`rc` 以 `0.2.2-rc.1` 开启了这条线(发布在 `next` dist-tag 下;测试安装运行的是 `0.2.2-alpha.2`)。`@deepseek-ai/dsh-typert-protocol` 的 peer 范围正是这么写的: +Harness 按 `alpha` 与 `rc` 两个**通道**发布,它们是平行的发布线而非版本先后:semver 中 `0.2.1-rc.2` 排序在 `0.2.1-alpha.5` **之上**。本插件在两个通道上都针对两条线:**`0.2.1`**(`dsh@latest` 仍停留在它的 `rc` 构建上),以及两个通道上的 **`0.2.2`** 预发布版本:`alpha` 已到 `0.2.2-alpha.3`,`rc` 以 `0.2.2-rc.1` 开启了这条线(发布在 `next` dist-tag 下;测试安装运行的是 `0.2.2-alpha.2`)。`@deepseek-ai/dsh-typert-protocol` 的 peer 范围正是这么写的: ``` >=0.2.1-alpha.1 <0.3.0 || >=0.2.2-0 <0.3.0 @@ -430,7 +430,7 @@ Harness 按 `alpha` 与 `rc` 两个**通道**发布,它们是平行的发布 第一个子句覆盖两个通道上的 `0.2.1` 整条线:下界 `alpha.1` 排序低于同线的所有 `rc`,因此无需单独枚举 rc。第二个子句**并不多余**——除非同一 `major.minor.patch` 的某个比较符带有预发布号,semver 会把预发布版本排除在外,所以只写 `<0.3.0` 会悄悄丢掉所有 `0.2.2-*` 构建,alpha 与 rc 都一样。两个子句都止于 `0.3.0`,下一条线因此是一个单独的决定,而不是悄悄放宽。 -可选的 `@deepseek-ai/cordis` peer 跟随 typert 的范围,因为 npm 会安装**最新**被接纳的 typert 构建所依赖(peer)的那个 cordis。每条线都推进了宿主内核:`0.2.1` 的构建依赖 `~4.0.5`(或 `4.0.5` 的预发布版本),`0.2.2` 的 alpha 依赖 `4.0.6` 的预发布版本,`0.2.2-rc.1` 依赖 `~4.1.0`。只要 cordis peer 漏掉其中任何一个,全新安装就会以 `ERESOLVE` 失败,所以它接纳全部,并止于下一个版本元组: +可选的 `@deepseek-ai/cordis` peer 跟随 typert 的范围。每条线都推进了宿主内核:`0.2.1` 的构建依赖 `~4.0.5`(或 `4.0.5` 的预发布版本),`0.2.2` 的 alpha 依赖 `4.0.6` 的预发布版本,`0.2.2-rc.1` 依赖 `~4.1.0`。全新安装会采用**最新**被接纳的 typert 构建所依赖的那个 cordis,所以 cordis peer 漏掉它就会以 `ERESOLVE` 失败;漏掉较早某条线的 cordis,则会在已安装该线宿主的环境旁安装失败。因此这个 peer 接纳其中每一个,并止于下一个版本元组: ``` ~4.0.4 || >=4.0.5-0 <4.1.0 || >=4.0.6-0 <4.1.0 || ~4.1.0 @@ -439,7 +439,7 @@ Harness 按 `alpha` 与 `rc` 两个**通道**发布,它们是平行的发布 | 层面 | 目标 | | :-- | :-- | | **Harness 版本线** | **`0.2.1`** 与 **`0.2.2`** 预发布版本,`alpha` 与 `rc` 通道均可(peer:见上方范围) | -| **宿主内核** | `@deepseek-ai/cordis` `4.0.5`、`4.0.6` 预发布版本与 `4.1.x`(可选 peer:见上方范围) | +| **宿主内核** | `@deepseek-ai/cordis` 从 `4.0.4` 到 `4.1.x`,包括 `4.0.5` 与 `4.0.6` 的预发布版本(可选 peer:见上方范围) | | **插件包** | [`dsh-opencode-patch`](https://www.npmjs.com/package/dsh-opencode-patch) | | **宿主 profile** | DSH Web profile(`patchReload: live`) | | **声明的路由** | `opencode`、`opencode-go`、`opencode-responses`、`opencode-anthropic` | diff --git a/test/harness-channel.test.ts b/test/harness-channel.test.ts index 3974866..4eef8ca 100644 --- a/test/harness-channel.test.ts +++ b/test/harness-channel.test.ts @@ -127,18 +127,36 @@ describe("harness channel alignment", () => { } }); - it("the cordis peer meets the cordis range of every typert build the typert peer admits", () => { + it("the cordis peer admits every cordis an admitted typert build can install", () => { // npm resolves the typert peer to the NEWEST build the range admits (the - // `latest` dist-tag, 0.1.0-rc.6, is outside it), then installs the cordis - // that build peers on. If the plugin's own cordis peer excludes that - // cordis, a fresh install fails with ERESOLVE — which is what happened the - // morning 0.2.2-rc.1 was published with `~4.1.0` while this peer stopped - // below 4.1.0. So the cordis peer must INTERSECT every admitted build's. + // `latest` dist-tag, 0.1.0-rc.6, is outside it), then installs the newest + // PUBLISHED cordis that build peers on. If the plugin's own cordis peer + // excludes it, a fresh install fails with ERESOLVE — which is what + // happened the morning 0.2.2-rc.1 was published with `~4.1.0` while this + // peer stopped below 4.1.0. Beside a host already installed on an older + // line, the cordis is whichever published one that line's build admits. + // So every published cordis an admitted build admits must satisfy the + // cordis peer. // - // Recorded from the registry on 2026-11-04 (`npm view - // @deepseek-ai/dsh-typert-protocol@ peerDependencies`): every published - // build on the 0.2.1 and 0.2.2 lines. A new build joins this table, with - // its own cordis range, when it is published. + // Checked against concrete PUBLISHED versions, never by range overlap: + // `semver.intersects` would call `~4.0.4 || ~4.1.0` compatible with + // `~4.0.6-alpha.2` although no 4.0.6 prerelease satisfies it, because the + // prerelease-tuple rule npm resolves under is not part of an overlap. + // + // Both tables are recorded from the registry on 2026-11-04 (`npm view + // @deepseek-ai/dsh-typert-protocol@ peerDependencies` for every build + // on the 0.2.1 and 0.2.2 lines; `npm view @deepseek-ai/cordis versions`). + // A new typert build joins the first with its cordis range, and a new + // cordis release joins the second, when they are published. + const CORDIS_PUBLISHED = [ + "4.0.4", + "4.0.5-alpha.1", + "4.0.5-alpha.2", + "4.0.5", + "4.0.6-alpha.1", + "4.0.6-alpha.2", + "4.1.0", + ]; const CORDIS_PEER_OF_TYPERT: Record = { "0.2.1-alpha.1": "~4.0.5-alpha.1", "0.2.1-alpha.2": "~4.0.5-alpha.1", @@ -159,18 +177,40 @@ describe("harness channel alignment", () => { const cordisPeer = peers["@deepseek-ai/cordis"] ?? ""; expect(cordisPeer).not.toBe(""); - for (const [build, cordis] of Object.entries(CORDIS_PEER_OF_TYPERT)) { - // The table is about builds the typert peer admits; one it does not - // admit would make the assertion below vacuous. + // Each `typert@build -> cordis@version` pair npm could install that the + // given cordis peer would refuse. + const refused = (peer: string): string[] => + Object.entries(CORDIS_PEER_OF_TYPERT).flatMap(([build, range]) => + CORDIS_PUBLISHED.filter( + (version) => + semver.satisfies(version, range) && !semver.satisfies(version, peer) + ).map((version) => `typert@${build} -> cordis@${version}`) + ); + + for (const [build, range] of Object.entries(CORDIS_PEER_OF_TYPERT)) { + // The table is about builds the typert peer admits, each of which has a + // published cordis to install; otherwise a row would check nothing. expect( semver.satisfies(build, typertPeer), `typert ${build} is admitted by ${typertPeer}` ).toBe(true); expect( - semver.intersects(cordisPeer, cordis, { includePrerelease: false }), - `typert ${build} peers cordis ${cordis}, which ${cordisPeer} excludes` - ).toBe(true); + semver.maxSatisfying(CORDIS_PUBLISHED, range), + `typert ${build} peers cordis ${range}, which has a published release` + ).not.toBeNull(); } + expect(refused(cordisPeer)).toEqual([]); + + // Known answers, so the check above is shown to bite: the peer this + // repository shipped before 0.2.2-rc.1 refuses that build's cordis, and a + // peer without the 4.0.6 clause refuses the alpha line's prereleases + // (semver admits a prerelease only through a comparator in its own tuple). + expect(refused("~4.0.4 || >=4.0.5-0 <4.1.0 || >=4.0.6-0 <4.1.0")).toEqual([ + "typert@0.2.2-rc.1 -> cordis@4.1.0", + ]); + expect(refused("~4.0.4 || >=4.0.5-0 <4.1.0 || ~4.1.0")).toEqual( + expect.arrayContaining(["typert@0.2.2-alpha.3 -> cordis@4.0.6-alpha.2"]) + ); // The concrete cordis each channel ships is admitted, and the range still // stops at the next tuple: a 4.1.x prerelease or 4.2 is a reviewed