cross-tab-worker-databus 0.21.36 → 0.21.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/centrifuge-session.d.ts.map +1 -1
- package/dist/centrifuge.js +1 -1
- package/dist/centrifuge.js.map +2 -2
- package/dist/centrifuge.shared.worker.js.map +2 -2
- package/dist/centrifuge.worker.js.map +2 -2
- package/dist/{chunk-AWCFYLIT.js → chunk-VWFEH3OS.js} +2 -2
- package/dist/cjs/centrifuge.cjs +1 -1
- package/dist/cjs/centrifuge.cjs.map +2 -2
- package/dist/cjs/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/docs/release-checklist.md +2 -2
- package/docs/roadmap.md +15 -2
- package/docs/zh/release-checklist.md +2 -2
- package/docs/zh/roadmap.md +15 -2
- package/package.json +1 -1
- /package/dist/{chunk-AWCFYLIT.js.map → chunk-VWFEH3OS.js.map} +0 -0
package/dist/cjs/index.cjs
CHANGED
|
@@ -2570,7 +2570,7 @@ var SDK_VERSION = (
|
|
|
2570
2570
|
// declaration's type is `string | undefined` and the export's is `string`
|
|
2571
2571
|
// (dropping the conditional is TS2322, measured). Recorded here so the leg reads
|
|
2572
2572
|
// as a shape the harness cannot reach rather than as a case nobody exercised.
|
|
2573
|
-
true ? "0.21.
|
|
2573
|
+
true ? "0.21.38" : ""
|
|
2574
2574
|
);
|
|
2575
2575
|
|
|
2576
2576
|
// src/core/data-bus.ts
|
package/dist/index.js
CHANGED
|
@@ -42,6 +42,6 @@ For a manual release (no `NPM_TOKEN` in the workflow), run `npm publish --access
|
|
|
42
42
|
2. Install the published tarball or version in a clean consumer and import the root plus every public subpath.
|
|
43
43
|
3. Record the result in the release notes. Do not advance to `1.0.0` until the public API and protocol deprecation policy are explicitly frozen.
|
|
44
44
|
|
|
45
|
-
The tagged-release workflow already ran the consumer verification above. Run `PUBLISHED_VERSION=<version> pnpm verify:published` by hand only when you need an offline repeat. The workflow's 12-minute ceiling is not padding, and the number is a sum of two measured lags. First: the registry records the publish minutes after `npm publish` returns — the
|
|
45
|
+
The tagged-release workflow already ran the consumer verification above. Run `PUBLISHED_VERSION=<version> pnpm verify:published` by hand only when you need an offline repeat. The workflow's 12-minute ceiling is not padding, and the number is a sum of two measured lags. First: the registry records the publish minutes after `npm publish` returns — and **read that series off the runs rather than off a list in this file**. `node scripts/publication-lag.mjs` walks every release tag, subtracts the `Publish to npm` step's `completed_at` from `time[<version>]` on the packument, prints which attempt each non-first reading came from, and names every tag its denominator drops. Re-run there at `0.21.36`: **43** releases from `0.20.92` on, record lag **74.8–310.0 s**, none over 310 s. This note used to carry the per-version values, and two consecutive releases then refuted the regularity those values had been read as: three records at 76.1 / 75.5 / 75.8 s looked like a stable lag, then `0.21.35` came back at 127.3 s and `0.21.36` at 126.4 s. So the tight run was three samples in a wide distribution, and the enumeration was both a maintenance liability — it needs an edit every release, and it was stale the moment it shipped twice — and the vehicle of an inference the data never supported. The list is gone; the range above is what the ceiling is sized from, and it is re-derivable in one command. What the series does support is weaker and is all the ceiling needs: while the *record* lag spans four minutes, every green release whose consumer step actually waited took **301–309 s** (42 measurements inside 300–310 s, `0.21.30`'s 364 s exhausted budget the only outlier above it, and the two rows below it — `0.20.86` and `0.20.87` at 1.0 s — are the only pre-`0.20.92` releases the sweep measures at all, the other four of that window printing as `NEGATIVE` and so sitting outside the 45) — so the varying quantity is how long the reader stays blind to a record that already exists, which is the second lag, not this one. Second: the packument that `npm pack` resolves against is served with `cache-control: public, max-age=300`, so a copy of it anywhere in the path is allowed to be up to five minutes stale, and resolution cannot be trusted to beat one cache lifetime after a write that lands inside that window. Which copy — npm's local cache or an intermediate — served the stale views below is *not* established, and the counter-observation this note used to offer against a purely local account does not survive being read carefully, because it joins two machines: the 21:44:34Z "fresh fetch" was a `npm pack` run on a laptop, while the 1 s green at 21:47:10Z was a *new runner job*, and a new job's npm cache starts empty — which is what the local account predicts rather than what contradicts it. What a purely-local account still cannot explain is one specific reading: the runner's own `ETARGET` at 21:45:07Z — 364 s after the step that opened its first poll (21:39:03Z), so ~60 s *after* the point where a copy taken then must have gone stale (21:44:03Z, give or take the second the request actually left). The ceiling is therefore arithmetic rather than a model: worst-case ack→`time[]` gap plus one cache lifetime. That sum is not theoretical: the previous 6-minute ceiling was exhausted by a *successful* publish, the 0.21.30 tag run spending its whole 360 s budget (48 × 7.5 s) on `ETARGET` while that version's tarball HEAD and a local `npm pack` had both already succeeded, and the same step 123 s later taking 1 s. The 0.20.89 run had shown the same shape against that release's 2-minute budget. So a long retrying verify is normal propagation, not an unusually slow mirror — raise `PUBLISHED_VERIFY_ATTEMPTS` / `PUBLISHED_VERIFY_DELAY_MS` further only if the ack→`time[]` gap has itself grown. Note the asymmetry when repeating by hand: `verify-published-consumer.mjs` defaults to `6` attempts × `5_000` ms — 30 seconds, not 12 minutes — because the tag run passes the larger pair as env rather than the script owning it. So a manual repeat can report `ETARGET` on a version whose CI run was green, which reads like a failed publish and is not one; reproduce the CI budget explicitly with `PUBLISHED_VERSION=<version> PUBLISHED_VERIFY_ATTEMPTS=96 PUBLISHED_VERIFY_DELAY_MS=7500 pnpm verify:published`, or judge a manual failure against the 30 s budget you actually ran. Read the step's duration as a diagnostic rather than a mood: one 300 s cache lifetime plus a few seconds of command time predicts a tight cluster just above 300 s, and that is what the sweep prints — 42 of its 45 measurements land inside 300–310 s, `0.21.30`'s 364 s budget exhaustion is the only outlier above it, and every sub-2 s row belongs to a release before `0.20.92` where nothing had to propagate. Take the per-release numbers from that run's `Verify published npm consumers` step (`steps[].started_at` / `completed_at`, from the same `gh api` call the attempt selection above uses); this file no longer lists them, because its last enumeration named a 304–308 s band that the whole series widens to 301–309 s, and a number copied out of a subset is how a claim like that survives being false. 0.21.31 through 0.21.34 are the first four releases to run under the raised 720 s ceiling, and their lags split differently, which is the useful contrast: 127.2 s of record plus ~181 s of cache for the first, 76.1 s of record plus ~228 s before the runner saw it for the next, 75.5 s plus ~229 s for the third, and 75.8 s plus ~228 s for the fourth — on 0.21.32 a `no-cache` packument read from a laptop reported the new `latest` 151 s in, while the runner's own poll kept failing until 304 s, i.e. one lifetime after *its* first fetch. So the sample that set the previous ceiling has not been beaten: if the *ack→`time[]`* figure grows past 310 s, raise `PUBLISHED_VERIFY_ATTEMPTS` again; a verify that finishes in seconds means whatever copy it read already carried the new version.
|
|
46
46
|
|
|
47
|
-
**Do not adjudicate a publish from `dist-tags.latest`.** The package document endpoint and the tarball URL are two different read paths, and their timestamps are worth more than the impression they first give. Read during the 0.21.30 release, in order: `npm publish` returned success at `21:39:03Z`; a `curl -s -H "Cache-Control: no-cache" https://registry.npmjs.org/<pkg>` at `21:43:15Z` reported `latest` still on the previous version, no `0.21.30` in `versions`, and no `time['0.21.30']`; npm's own stamp for that version is `21:44:12.987Z` and the document's `last-modified` is `21:44:14 GMT`. So the 21:43:15 read was **not** a replica refusing an artifact that already existed — the registry had not finished recording the publish, and `no-cache` could not have made it see a version that did not exist yet. Absence from `versions` and from `latest`, minutes after a green publish step, is the expected state of a successful release from `0.20.92` on —
|
|
47
|
+
**Do not adjudicate a publish from `dist-tags.latest`.** The package document endpoint and the tarball URL are two different read paths, and their timestamps are worth more than the impression they first give. Read during the 0.21.30 release, in order: `npm publish` returned success at `21:39:03Z`; a `curl -s -H "Cache-Control: no-cache" https://registry.npmjs.org/<pkg>` at `21:43:15Z` reported `latest` still on the previous version, no `0.21.30` in `versions`, and no `time['0.21.30']`; npm's own stamp for that version is `21:44:12.987Z` and the document's `last-modified` is `21:44:14 GMT`. So the 21:43:15 read was **not** a replica refusing an artifact that already existed — the registry had not finished recording the publish, and `no-cache` could not have made it see a version that did not exist yet. Absence from `versions` and from `latest`, minutes after a green publish step, is the expected state of a successful release from `0.20.92` on — **43** of them as of `0.21.36`, every one recorded at least 74.8 s after its ack. Take the count from `CHANGELOG.md`'s version headings intersected with the packument's `time` map and the floor from the same sweep that yields the lag range above: that set gains a member at every release, which is the whole reason a value in this sentence is the wrong thing to memorize — while the five just before the window (`0.20.86`, `0.20.87`, `0.20.88`, `0.20.90`, `0.20.91`) recorded within ±0.6 s of their acks and resolved in 1 s. So the sentence describes this window and not npm; what to do when it holds is unchanged. The genuine read-path disagreement came 60 s later: between `21:44:14Z` and `21:44:35Z`, `curl -I …/-/<pkg>-0.21.30.tgz` returned `HTTP 200` and a local `npm pack <pkg>@0.21.30 --registry https://registry.npmjs.org` completed and wrote the tarball, while the workflow runner's own `npm pack` kept returning `ETARGET` until it exhausted its budget at `21:45:07Z`. Same version, two machines, opposite answers a minute apart. To answer "did the publish happen", HEAD the tarball URL and try the pack — those reach the artifact — and try it **from the place that is failing**, because "fetchable" is a per-machine answer; read `latest` only for the question "which version do consumers get by default", which is a different one and settles later. `npm view <pkg> version` adds a third path on top: it can be served from npm's *local* packument cache, so on a machine that queried the registry before the publish it can return the superseded version even after the global `latest` has moved (that is why this gate resolves its target from `PUBLISHED_VERSION` and refuses an inferred version that disagrees with `package.json`). Never re-push, move, or replace a tag because a metadata read looked stale; the tag is immutable once published.
|
package/docs/roadmap.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# Roadmap
|
|
2
2
|
|
|
3
|
-
0.21.
|
|
3
|
+
0.21.37 was released on September 25, 2026. The project is intentionally continuing through reliability-focused releases before a 1.0.0 stability freeze.
|
|
4
|
+
|
|
5
|
+
## 0.21.38 delivered scope
|
|
6
|
+
|
|
7
|
+
- **A ratio described backwards in one language and correctly in the other.** The `0.21.17` block of this file said the `storage-fail` interleaving reddens the sweep "from seed 414 onward, which is four times below the sweep's depth floor". The floor is `MIN_SEEDS = 100` in `tests/coordination-invariants.test.ts`, so 414 sits more than four times *above* it — and that is the sentence's own point: the finding needs depth past what the sweep asserts as a minimum, which makes it a finder rather than a guard. The Chinese mirror had the direction right, so the two languages agreed on every digit and disagreed on the relation. No value-by-value comparison can see that; the block-paired sweep that found it compares the Nth release block of each language, then the sentences inside it.
|
|
8
|
+
- **Both languages now carry the same two figures for the promoted sweep tool.** The English `0.21.37` block credited the tool with "a per-call timeout" where the Chinese block said 30 秒超时. `scripts/publication-lag.mjs` sets `CALL_TIMEOUT_MS = 30_000`, so the number is now in the English sentence as well.
|
|
9
|
+
- **Nothing else moved.** No library code, export, option, default, frame or storage key changed; the zero-count arm ledger and the coverage aggregates are `0.21.37`'s.
|
|
10
|
+
|
|
11
|
+
## 0.21.37 delivered scope
|
|
12
|
+
|
|
13
|
+
- **A shipped instruction pointed at a directory git never had.** Both release checklists told the reader to re-derive the publication-lag series from `.gate-logs/publication-pair.mjs`, and that path is gitignored — live on the one machine that wrote it, dead in every clone and in the published tarball's own docs. Nothing can gate it: the citation sweep resolves test *titles*, and a shell command is neither a title nor a symbol. The tool is now `scripts/publication-lag.mjs`, tracked, resolving the repository and the Release workflow id through `gh` instead of hardcoding either, with a 30 s per-call timeout after the previous sweep hung 18 minutes on one `gh api`, a `reading <version>` line so a stopped run names where it stopped, and a printed line for every member its denominator drops.
|
|
14
|
+
- **Running it corrected three numbers in the prose that quotes it.** The sub-second consumer steps inside the measured set are two (`0.20.86`, `0.20.87`), not the six both languages carried — the other four pre-`0.20.92` releases print as `NEGATIVE` and sit outside the 45, the exact distinction the tool draws and the copied sentence lost. The `0.20.92`-onward window holds 43 releases, not the 42 `AGENTS.md` still counted, and since that number moves every release the count became the lookup. "Prints the attempt each reading came from" over-stated a flag that fires only for a non-first attempt.
|
|
15
|
+
- **What the series confirmed, and what the instrument itself taught.** Every per-release sample the prose quotes re-read identical — 127.2 / 76.1 / 75.5 / 75.8 / 127.3 / 126.4 s of record lag across `0.21.31`–`0.21.36`, their steps at 304–308 s, `0.21.30` alone at 310.0 s and 364.0 s, 42 of 45 steps inside 300–310 s, no gap over 310 s — so the 720 s budget and its floor test are unchanged. And the promoted script first ran *broken*: a `const` formatter scoped inside the sweep loop killed it with a `ReferenceError` after all 45 tags had been read, printing four lines and exit 1 — the formatter moved to module scope, and what made the failure diagnosable at all was the non-zero exit, since four rows from a 49-tag sweep reads like a short series rather than a broken one.
|
|
16
|
+
- **A copied-forward count in the progress log had never been measured.** The `bench:browser` debt read "four releases", then "five", in successive `Next` lines; the newest `bench-results/browser-*.json` is `2026-09-24T13:40:52Z`, eight minutes before `0.21.22`'s release commit regenerated `docs/benchmarks.md`, so it is fourteen (`0.21.23` on). Neither number is in a shipped file, so the correction stays in the log, where both older lines now point at the two artifacts.
|
|
4
17
|
|
|
5
18
|
## 0.21.36 delivered scope
|
|
6
19
|
|
|
@@ -179,7 +192,7 @@
|
|
|
179
192
|
`confirmedAt`, a state no worker writes and precisely the shape the new pass releases, so its assertion was passing
|
|
180
193
|
by a mechanism other than the one it named.
|
|
181
194
|
- **The `storage-fail` fuzz interleaving that found this is measured and deliberately not shipped** — it reddens the
|
|
182
|
-
sweep on the pre-fix code from seed 414 onward, which is four times
|
|
195
|
+
sweep on the pre-fix code from seed 414 onward, which is more than four times the sweep's 100-seed depth floor, so it is a finder
|
|
183
196
|
rather than a guard; its knob (`MemoryStorage.failNextWrites`) and the recipe are committed.
|
|
184
197
|
- **A classification, comment-only:** `handoffAssignedTopics()`'s unreachable `if (!owner) continue;` now names the
|
|
185
198
|
four links that make it unreachable, the test that pins each, and the measured counterfactual — deleting it keeps
|
|
@@ -43,6 +43,6 @@
|
|
|
43
43
|
2. 在干净消费者中安装已发布版本或 tarball,并导入主入口及所有公开子路径。
|
|
44
44
|
3. 将结果记录到发布说明。在公开 API 和协议弃用策略明确冻结前,不进入 `1.0.0`。
|
|
45
45
|
|
|
46
|
-
打 tag 的发布工作流已自动执行上述消费者验证;仅在需要离线复验时才手动运行 `PUBLISHED_VERSION=<version> pnpm verify:published`。工作流的 12 分钟上限不是凑数,而是两段实测延迟之和。第一段:`npm publish` 返回成功后,registry
|
|
46
|
+
打 tag 的发布工作流已自动执行上述消费者验证;仅在需要离线复验时才手动运行 `PUBLISHED_VERSION=<version> pnpm verify:published`。工作流的 12 分钟上限不是凑数,而是两段实测延迟之和。第一段:`npm publish` 返回成功后,registry 还要几分钟才把这条版本记进去——而**这份序列要从运行记录里读,不要从本文件抄来的清单里读**。`node scripts/publication-lag.mjs` 会走一遍所有 release tag,用 packument 上的 `time[<version>]` 减去 `Publish to npm` 步骤的 `completed_at`,打印每条非首次读出的数取自第几次 attempt,并把它从分母里丢掉的 tag 逐个点名。在 `0.21.36` 处重跑的答案:从 `0.20.92` 起共 **43** 个发布,落库延迟 **74.8–310.0 秒**,没有一次越过决定预算的 310 秒。本段以前逐个抄录过这些数值,而紧接着的两次发布接连推翻由那串数值读出的规律:连续三次落在 76.1 / 75.5 / 75.8 秒,看着像"落库很稳",随后 `0.21.35` 回到 127.3 秒、`0.21.36` 是 126.4 秒。所以那段紧凑只是宽分布里的三个样本;而那份枚举既是维护负担(每次发布都要改,两次刚写下就已过期),也承载了一个数据从来不支持的推论。清单已删,上面这个区间才是预算的来源,而且一条命令就能重取。这套数据真正支持的结论更弱、也更够用:落库延迟横跨四分钟,可绿色发布里真正等待过的消费者步骤一律是 **301–309 秒**(45 个读数里 42 个落在 300–310 秒内,唯一的上方异常是 `0.21.30` 耗尽预算的 364 秒;下方两条各 1.0 秒,是 `0.20.86` 和 `0.20.87`,也正是 `0.20.92` 之前唯二被这条序列量到的发布——那个窗口里另外四条以 `NEGATIVE` 打印,不在这 45 条之内——那时根本没有东西需要传播)——会变的其实是"记录已经存在之后,读者还要瞎多久",那是第二段,不是这一段。第二段:`npm pack` 用来解析版本的 packument 是以 `cache-control: public, max-age=300` 提供的,也就是说路径上任何一份副本按设计都可以旧五分钟,落在这一窗口内写入的版本,解析不太可能快过一整个缓存生命周期。究竟是哪个副本(npm 本地缓存,还是中间的 CDN)在下面提供了过期视图**并未确立**,而这段文字此前用作"反对纯本地解释"的那个观测,仔细读过之后站不住,因为它把两台机器拼成了一句话:21:44:34Z 那次"新鲜读取"是在笔记本上跑 `npm pack`,而 21:47:10Z 一秒就绿的是一次*全新的 runner 任务*,新任务的 npm 缓存本来是空的——这恰好是纯本地模型预测的结果,不是反驳它的结果。纯本地模型仍然解释不了的,只有一个读数:runner 自己在 21:45:07Z 仍然报 `ETARGET`——距离开始轮询的那一步(21:39:03Z)已经 364 秒,也就是比"那一刻抓到的副本必然已过期"的时间点(21:44:03Z,误差在请求真正发出的那一秒之内)还要晚约 60 秒。因此上限靠的是算术而不是模型:最坏情况的"确认 → `time[]`"间隔,加上一个缓存生命周期。这个和并非理论值——上一个 6 分钟上限被一次*成功*的发布排空过:0.21.30 的 tag 运行把整整 360 秒预算(48 × 7.5 秒)花在 `ETARGET` 上,而那时该版本的 tarball HEAD 和本地 `npm pack` 都已经成功;123 秒后同一步骤只用了 1 秒。0.20.89 针对它当时的 2 分钟预算也是同一形状。所以长时间的反复重试是正常的传播延迟,不是镜像异常慢——只有"确认 → `time[]`"间隔本身变长了,才需要继续调大 `PUBLISHED_VERIFY_ATTEMPTS` 和 `PUBLISHED_VERIFY_DELAY_MS`。手动复验时要注意这个不对称:`verify-published-consumer.mjs` 的默认值是 `6` 次 × `5_000` ms——30 秒而不是 12 分钟——因为更大的那一对是由 tag 工作流以 env 传入、而非脚本自带。于是手动复跑可能在一个 CI 全绿的版本上报出 `ETARGET`,这看起来像发布失败而实际不是;要对齐 CI 预算就显式执行 `PUBLISHED_VERSION=<version> PUBLISHED_VERIFY_ATTEMPTS=96 PUBLISHED_VERIFY_DELAY_MS=7500 pnpm verify:published`,否则请按你实际跑到的 30 秒预算来判断手动失败。把这个步骤的耗时当诊断读数而不是情绪指标:整条序列自己取——`node scripts/publication-lag.mjs` 会打印每个发布运行里这一步的墙钟时间(`steps[].started_at`/`completed_at`,和上面选 attempt 用的是同一个 `gh api` 调用)。45 个读数里 42 个落在 300–310 秒内,`0.21.30` 耗尽预算的 364 秒是唯一的上方异常,1 秒以内的两条都属于 `0.20.92` 之前的发布——那时没有东西需要传播。这正是"一个 300 秒缓存生命周期 + 几秒命令时间"会预测出的形状,所以本文件不再抄录逐个数:上一份枚举写下的是 304–308 秒的区间,而整条序列把它放宽成 301–309 秒——从子集里抄一个数,就是这么让一个错说法活得比它的样本更久。0.21.31 到 0.21.34 是头四个跑在提高后的 720 秒上限下的发布,而它们几段延迟的切分方式不同,这个对照正是有用的地方:第一次是 127.2 秒落库 + 约 181 秒缓存;第二次是 76.1 秒落库 + 之后约 228 秒 runner 仍看不见它;第三次是 75.5 秒落库 + 约 229 秒;第四次是 75.8 秒落库 + 约 228 秒——在 0.21.32 上,笔记本在 151 秒时用 `no-cache` 读 packument 已经能看到新的 `latest`,而 runner 自己的轮询一直到 304 秒才成功,也就是从*它自己*首次抓取算起整整一个生命周期。所以当初定这个上限的那个样本至今没有被超过:如果*确认 → `time[]`*这一段自己长过了 310 秒,就再调大 `PUBLISHED_VERIFY_ATTEMPTS`;而几秒就结束的 verify 只说明它读到的那份副本已经带上了新版本。
|
|
47
47
|
|
|
48
|
-
**不要用 `dist-tags.latest` 来判断发布是否发生。** 包文档端点与 tarball URL 是两条不同的读取路径,而它们的时间戳比这两条路径给的第一手印象更值得读。0.21.30 发布期间按顺序读到:`npm publish` 在 `21:39:03Z` 返回成功;`21:43:15Z` 的一次 `curl -s -H "Cache-Control: no-cache" https://registry.npmjs.org/<pkg>` 仍报 `latest` 是上一个版本、`versions` 里没有 `0.21.30`、`time['0.21.30']` 也不存在;而 npm 自己给这个版本盖的时间戳是 `21:44:12.987Z`,文档的 `last-modified` 是 `21:44:14 GMT`。所以 21:43:15 那次读取**不是**一份副本在拒绝已经存在的产物——registry 当时确实还没把这次发布记完,`no-cache` 也不可能让它看见尚不存在的版本;在发布步骤全绿之后的几分钟里,`versions` 与 `latest` 里没有这个版本,对 `0.20.92`
|
|
48
|
+
**不要用 `dist-tags.latest` 来判断发布是否发生。** 包文档端点与 tarball URL 是两条不同的读取路径,而它们的时间戳比这两条路径给的第一手印象更值得读。0.21.30 发布期间按顺序读到:`npm publish` 在 `21:39:03Z` 返回成功;`21:43:15Z` 的一次 `curl -s -H "Cache-Control: no-cache" https://registry.npmjs.org/<pkg>` 仍报 `latest` 是上一个版本、`versions` 里没有 `0.21.30`、`time['0.21.30']` 也不存在;而 npm 自己给这个版本盖的时间戳是 `21:44:12.987Z`,文档的 `last-modified` 是 `21:44:14 GMT`。所以 21:43:15 那次读取**不是**一份副本在拒绝已经存在的产物——registry 当时确实还没把这次发布记完,`no-cache` 也不可能让它看见尚不存在的版本;在发布步骤全绿之后的几分钟里,`versions` 与 `latest` 里没有这个版本,对 `0.20.92` 起的每一次成功发布都是正常状态——截至 `0.21.36` 共 **43** 个,其中每一次被记下的延迟都不小于 74.8 秒(计数取 `CHANGELOG.md` 的版本标题与 packument `time` 映射的交集,下限由上面那条同一命令给出;这个集合每次发布都会 +1,所以值得记住的是取法而不是那个数)——而窗口之前的那五次(`0.20.86`、`0.20.87`、`0.20.88`、`0.20.90`、`0.20.91`)在 ack 前后 ±0.6 秒内就记录好了,1 秒即可解析。所以这句话描述的是这个窗口,而不是 npm 本身;当它成立时,该怎么判断并没有变。真正的读取路径分歧出现在 60 秒之后:`21:44:14Z` 到 `21:44:35Z` 之间,`curl -I …/-/<pkg>-0.21.30.tgz` 返回 `HTTP 200`,本地一次 `npm pack <pkg>@0.21.30 --registry https://registry.npmjs.org` 也成功写出了 tarball,而工作流 runner 自己的 `npm pack` 一直 `ETARGET` 到 `21:45:07Z` 把预算排空。同一个版本、两台机器、相隔一分钟给出相反答案。要回答"发布到底成没成",去 HEAD 那个 tarball URL 并试一次 pack——它们摸到的是产物本身——而且要从**正在失败的那台机器**上去试,因为"能取到"是一台机器才有的答案;`latest` 只回答"消费者默认拿到哪个版本",那是另一个问题,而且会更晚才稳定。`npm view <pkg> version` 在这之上还有第三条路径:它可能来自 npm 的**本地** packument 缓存,于是在发布前查过一次的机器上,即使全局 `latest` 已经前进,它仍会返回被取代的旧版本——这正是本门禁把目标版本固定取自 `PUBLISHED_VERSION`、并拒绝与 `package.json` 不一致的推断值的原因。不要因为一次元数据读取看起来过期就重推、移动或替换 tag;发布出去的 tag 是不可变的。
|
package/docs/zh/roadmap.md
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
# 路线图
|
|
2
2
|
|
|
3
|
-
0.21.
|
|
3
|
+
0.21.37 已于 2026 年 9 月 25 日发布。项目会先持续完成可靠性发布,再进入 1.0.0 稳定性冻结。
|
|
4
|
+
|
|
5
|
+
## 0.21.38 已完成范围
|
|
6
|
+
|
|
7
|
+
- **一个比例在一种语言里被写反,另一种语言写对了。** 本文 `0.21.17` 那段说 `storage-fail` 交错"从 seed 414 起就让 sweep 失败,这比 sweep 的深度下限低四倍"。下限是 `tests/coordination-invariants.test.ts` 里的 `MIN_SEEDS = 100`,而 414 是它的四倍*以上*——这正是那句话的本意:这条发现需要的深度超过了 sweep 自己断言的最小值,所以它是发现器而不是守卫。中文镜像的方向本来就是对的,于是两种语言每个数字都一致、关系却是反的。逐值比对看不见这种错;找到它的按块配对扫描比较的是两种语言的第 N 个发布块,再比块里的每一句。
|
|
8
|
+
- **两种语言现在写出同一个工具的同两个数。** 英文 `0.21.37` 那段只说"每次调用带一个超时",中文那段说 30 秒超时。`scripts/publication-lag.mjs` 里是 `CALL_TIMEOUT_MS = 30_000`,现在英文也带上了这个数值。
|
|
9
|
+
- **其余未动。** 库代码、导出、选项、默认值、帧格式与存储键均未改动;零计数分支账本与覆盖率聚合仍是 `0.21.37` 的。
|
|
10
|
+
|
|
11
|
+
## 0.21.37 已完成范围
|
|
12
|
+
|
|
13
|
+
- **一份已发布的操作说明指向了一个 git 里从来没有的目录。** 两份发版检查清单都告诉读者用 `.gate-logs/publication-pair.mjs` 重新推导发布延迟序列,而这个路径在 `.gitignore` 里——它只在写下这句话的那台机器上有效,在任何一份克隆里、在已发布压缩包自带的文档里都是死链。这一类问题无法被门禁看见:引用扫描解析的是测试*标题*,而一条 shell 命令既不是标题也不是符号。这个工具现在是 `scripts/publication-lag.mjs`,已被跟踪,仓库名与 Release workflow id 都通过 `gh` 解析而不再硬编码;上一版扫描曾卡在一次没有上限的 `gh api` 上 18 分钟且不打印任何东西,因此每次调用现在都有 30 秒超时、一行 `reading <version>` 进度,以及为分母丢掉的每个成员单独打印的一行。
|
|
14
|
+
- **跑一遍它,就改掉了引用它的正文里的三个数字。** 被测量的序列里耗时不足一秒的消费者步骤是两条(`0.20.86`、`0.20.87`),而不是两种语言都写的六条——`0.20.92` 之前另外四个发布以 `NEGATIVE` 打印,因而不在这 45 条之内,这正是工具自己的输出会做、而被抄下来的那句话丢掉的区分。`0.20.92` 起的窗口有 43 个发布,而不是 `AGENTS.md` 仍在计的 42;既然这个数每次发布都会动,它就被换成了查找方法(`measured=N of M tags`)。而"打印每条读数取自第几次 attempt"高估了这个标记——它只在非首次的 attempt 上出现。
|
|
15
|
+
- **序列确认了什么,工具本身又教了什么。** 正文引用的每个逐版本样本重读之后完全一致——`0.21.31`–`0.21.36` 的落库延迟 127.2 / 76.1 / 75.5 / 75.8 / 127.3 / 126.4 秒,对应的步骤耗时 304–308 秒,`0.21.30` 独自是 310.0 秒与 364.0 秒,45 条里 42 条落在 300–310 秒内,没有一次间隔越过 310 秒——因此 720 秒预算与钉住它的测试都原样不动。而被提升为正式工具的脚本第一次跑起来是*坏的*:一个作用域在扫描循环内的 `const` 格式化函数,让它在读完全部 45 个 tag 之后死于 `ReferenceError`,只打印了四行并以 1 退出——让这次失败可诊断的只是那个非零退出码,因为 49 个 tag 的扫描只返回四行,读起来像"序列短"而不是"工具坏了"。
|
|
16
|
+
- **进度日志里一个被抄来抄去的数,从来没有人量过。** `bench:browser` 的欠账在相邻两条 `Next` 里分别写成"四个发布"和"五个";而最新的 `bench-results/browser-*.json` 是 `2026-09-24T13:40:52Z`,比重新生成 `docs/benchmarks.md` 的 `0.21.22` 发版提交早八分钟,所以这个数是十四个(自 `0.21.23` 起)。两个错数都不在已发布文件里,因此修正留在日志中,而两条旧 `Next` 现在指向那两份产物本身。
|
|
4
17
|
|
|
5
18
|
## 0.21.36 已完成范围
|
|
6
19
|
|
|
@@ -176,7 +189,7 @@
|
|
|
176
189
|
- **一个既有测试的前提被改正**:它手写的"被接管"路由带着前任 owner 的 `confirmedAt`,而没有任何 Worker 会写出这种
|
|
177
190
|
状态——它恰好就是新清扫会释放的形状——所以那条断言其实是通过另一个机制成立的,而不是它声称的那一个。
|
|
178
191
|
- **找到这个问题的 `storage-fail` 交错被测量过,并且刻意没有留在 fuzz 里**:在修复前的代码上,它从 seed 414 起就让
|
|
179
|
-
sweep 失败,而这个深度是 sweep 自身 100-seed
|
|
192
|
+
sweep 失败,而这个深度是 sweep 自身 100-seed 下限的四倍多,所以它是发现器而不是守卫;它需要的开关
|
|
180
193
|
(`MemoryStorage.failNextWrites`)和复现配方已经提交。
|
|
181
194
|
- **一条纯注释的归类**:`handoffAssignedTopics()` 里那条走不到的 `if (!owner) continue;` 现在写清了使它不可达的四个
|
|
182
195
|
环节、每个环节各自被哪个测试固定,以及实测的反事实——删掉它整个测试套件的数字不变,而类型检查会报 5 个错误,所以它是
|
package/package.json
CHANGED
|
File without changes
|