mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-10-26 16:55:08 +00:00
docs(ci): correct the budget note's measurements and derive the hang guard
Fixes the review findings on the work-budget change: - unify the measured npm time range to 137-205 s in the note's problem statement, which had carried the older 153-190 s range - correct the peer-edge share to about three quarters (1874 of 2524), which the sentence had called two thirds - state the ratchet threshold as the packages-times-edges product, about 12% in packages and edges together - derive NPM_HANG_GUARD_MS from MAX_RESOLUTION_WORK_UNITS so a raised budget cannot shrink the guard's headroom, and state the guard's guarantee as covering a runner four times slower than the measured host - name the cost side of the hang guard in the note's consequences
This commit is contained in:
1 parent
39260067b5
commit
30a9770a58
4 files changed
+28
-20
No files matched your search
+8
-8
@@ -6,17 +6,17 @@
|
||||
en: 808f7c1d11ce15b5
|
||||
zh: 861c63dd2de66452
|
||||
/agent-note-dual-release-install-layout-work-budget/problem:
|
||||
en: 0b826a202c56f154
|
||||
zh: 547d73c2e488283d
|
||||
en: 46916488210ba493
|
||||
zh: 98107c3805a22b2c
|
||||
/agent-note-dual-release-install-layout-work-budget/decision:
|
||||
en: c99f5f32a5361965
|
||||
zh: 641a3a9dfdcf4fda
|
||||
en: c432b68c4ad1b3c1
|
||||
zh: a11e958fa68dc2f3
|
||||
/agent-note-dual-release-install-layout-work-budget/what-the-resolution-costs:
|
||||
en: ca5c1024209a9b96
|
||||
zh: a3ddc2d2ceea1989
|
||||
en: 36d3e3ef39cbba2f
|
||||
zh: 2480acf6260817b3
|
||||
/agent-note-dual-release-install-layout-work-budget/alternatives-considered:
|
||||
en: 29987b7634c84d28
|
||||
zh: a1469e4b6aaa46e2
|
||||
/agent-note-dual-release-install-layout-work-budget/consequences:
|
||||
en: 4749c1f7aac32fc1
|
||||
zh: 2780c9784058f547
|
||||
en: 8dffc0c3fa699980
|
||||
zh: 99ec25001e5aa716
|
||||
+4
-4
@@ -6,13 +6,13 @@ English | [中文](2026-09-28-dual-release-install-layout-work-budget.zh.md)
|
||||
|
||||
## Problem
|
||||
|
||||
The `Dependency layout` lane packs two incompatible synthetic DSH releases into a temporary consumer, runs one real npm resolution over them, and asserts the physical placement npm chose. It decided pass or fail with `TIMEOUT_MS = 300_000` on the npm child process. That deadline measures the runner, not the graph: the same commit resolves the same packages and internal edges in 153-190 s on a developer host and exceeded 300 s on the project's CI runner while the placement assertion reported no error. The diagnostic named only elapsed time, so a slow runner and a graph that had grown were indistinguishable.
|
||||
The `Dependency layout` lane packs two incompatible synthetic DSH releases into a temporary consumer, runs one real npm resolution over them, and asserts the physical placement npm chose. It decided pass or fail with `TIMEOUT_MS = 300_000` on the npm child process. That deadline measures the runner, not the graph: the same graph resolves in 137-205 s on an idle developer host and in 288.59 s on the CI runner, 4% below the deadline, while the placement assertion reported no error. The diagnostic named only elapsed time, so a slow runner and a graph that had grown were indistinguishable.
|
||||
|
||||
## Decision
|
||||
|
||||
`scripts/verify-npm-install-layout.ts` decides growth with `assertResolutionWorkBudget`, which bounds `dshPackagesPerVersion * checkedDshEdges` against `MAX_RESOLUTION_WORK_UNITS = 875_000`. Both counts come from the summary `assertDualDshInstallLayout` returns, so the budget applies to the graph npm actually produced rather than to a prediction of it. A graph above the budget fails with its own counts, the budget, and the instruction to measure the new resolution cost and raise the constant.
|
||||
|
||||
The npm child keeps a wall-clock limit, `NPM_HANG_GUARD_MS = 900_000`. It is a hang guard, not the growth criterion: the budgeted graph costs about 226 s at the measured 2.6e-4 s per work unit, and the guard allows four times that for slower runners and host load.
|
||||
The npm child keeps a wall-clock limit, `NPM_HANG_GUARD_MS`, derived as `4 * MAX_RESOLUTION_WORK_UNITS * SECONDS_PER_WORK_UNIT` (910 s). It is a hang guard, not the growth criterion: a runner up to four times slower than the measured host cannot decide the gate's outcome, and deriving it from the budget keeps the two values from drifting apart.
|
||||
|
||||
This restores the [published dependency faces](2026-08-26-published-dependency-faces.md) decision that `verify-npm-install-layout` does not enforce resolver duration; the 300 s deadline had contradicted it.
|
||||
|
||||
@@ -29,7 +29,7 @@ Measured 2026-09-28 on an idle M-series host, against `origin/master` (277 DSH p
|
||||
| Registry traffic | 682 requests, 383 KB of packument bodies |
|
||||
| Layout assertion and process startup | 4.4 s |
|
||||
|
||||
The same graph resolved in 1.12 s with `--legacy-peer-deps`, so peer placement is 152.7 s of the 153.8 s. `canPlacePeers` re-checks each internal edge against the incoming edges of its peer target, which makes the cost grow with placements times edge count; the nested release's copy of `@deepseek-ai/dsh-base` alone takes 48.8 s against 1.3 s for the identical package at the root of the same tree. Two thirds of the verified internal edges are peer edges (1874 of 2524), so this work is the assertion, not overhead around it.
|
||||
The same graph resolved in 1.12 s with `--legacy-peer-deps`, so peer placement is 152.7 s of the 153.8 s. `canPlacePeers` re-checks each internal edge against the incoming edges of its peer target, which makes the cost grow with placements times edge count; the nested release's copy of `@deepseek-ai/dsh-base` alone takes 48.8 s against 1.3 s for the identical package at the root of the same tree. About three quarters of the verified internal edges are peer edges (1874 of 2524), so this work is the assertion, not overhead around it.
|
||||
|
||||
Repeated runs of the same graph on one host span 137.8 s to 204.8 s of npm time, a factor of 1.5 with no input change, which is why a wall-clock threshold cannot separate a slow host from a larger graph.
|
||||
|
||||
@@ -47,4 +47,4 @@ Repeated runs of the same graph on one host span 137.8 s to 204.8 s of npm time,
|
||||
|
||||
## Consequences
|
||||
|
||||
The lane's failure now depends on the graph, so a pull request that adds a few DSH packages passes on any runner, and a graph that grows by more than about a quarter fails deterministically with its measured counts. The budget is a ratchet: raising it is a deliberate edit that must come with a new resolution measurement, and the constant's comment records the counts it was derived from. A graph inside the budget still spends its full resolution time, because the change moves the decision and not the work; nothing here reduces the 153 s npm needs to place the dual release. Growth that changes the shape of the graph without changing packages times edges stays inside the budget and is caught only if the hang guard expires.
|
||||
The lane's failure now depends on the graph, so a pull request that adds a few DSH packages passes on any runner, and a graph that grows the packages-times-edges product by more than about a quarter — about 12% in packages and internal edges together — fails deterministically with its measured counts. The budget is a ratchet: raising it is a deliberate edit that must come with a new resolution measurement, and the constant's comment records the counts it was derived from. A graph inside the budget still spends its full resolution time, because the change moves the decision and not the work; nothing here reduces the 153 s npm needs to place the dual release. A genuine npm hang now consumes up to 910 s of the lane before failing, where the old deadline capped it at 300 s. Growth that changes the shape of the graph without changing packages times edges stays inside the budget and is caught only if the hang guard expires.
|
||||
+4
-4
@@ -6,13 +6,13 @@ Status: implemented
|
||||
|
||||
## Problem
|
||||
|
||||
`Dependency layout` lane 把两个互不兼容的合成 DSH 发布打进临时消费者目录,对它们跑一次真实 npm 解析,并断言 npm 选定的物理摆放。它用 npm 子进程上的 `TIMEOUT_MS = 300_000` 判定通过或失败。这个期限度量的是 runner,而不是图:同一个 commit 在开发机上用 153–190 秒解析同一批包和内部边,在项目 CI runner 上超过 300 秒,而摆放断言没有报告任何错误。诊断信息只给出耗时,因此 runner 慢和依赖图变大无法区分。
|
||||
`Dependency layout` lane 把两个互不兼容的合成 DSH 发布打进临时消费者目录,对它们跑一次真实 npm 解析,并断言 npm 选定的物理摆放。它用 npm 子进程上的 `TIMEOUT_MS = 300_000` 判定通过或失败。这个期限度量的是 runner,而不是图:同一张图在空闲开发机上用 137–205 秒解析完成,在 CI runner 上用 288.59 秒,比期限低 4%,而摆放断言没有报告任何错误。诊断信息只给出耗时,因此 runner 慢和依赖图变大无法区分。
|
||||
|
||||
## Decision
|
||||
|
||||
`scripts/verify-npm-install-layout.ts` 用 `assertResolutionWorkBudget` 判定规模增长,它以 `dshPackagesPerVersion * checkedDshEdges` 为工作量单位,与 `MAX_RESOLUTION_WORK_UNITS = 875_000` 比较。两个计数都来自 `assertDualDshInstallLayout` 返回的汇总,因此预算作用于 npm 实际产出的图,而不是对图的预测。超过预算的图会带着自己的计数、预算值,以及「测量新的解析开销并调高该常量」的指示失败。
|
||||
|
||||
npm 子进程仍保留墙钟上限 `NPM_HANG_GUARD_MS = 900_000`。它是挂起保护,不是增长判据:按实测每个工作量单位 2.6e-4 秒计算,预算内的图约需 226 秒,该保护给出四倍余量以覆盖更慢的 runner 和主机负载。
|
||||
npm 子进程仍保留墙钟上限 `NPM_HANG_GUARD_MS`,由 `4 * MAX_RESOLUTION_WORK_UNITS * SECONDS_PER_WORK_UNIT` 推导(910 秒)。它是挂起保护,不是增长判据:比实测主机慢四倍以内的 runner 无法决定该门禁的结果,而由预算推导可避免两个数值彼此漂移。
|
||||
|
||||
这恢复了[发布依赖门面](2026-08-26-published-dependency-faces.zh.md)中「`verify-npm-install-layout` 不限制 resolver 耗时」的决定;300 秒期限与该决定相矛盾。
|
||||
|
||||
@@ -29,7 +29,7 @@ npm 子进程仍保留墙钟上限 `NPM_HANG_GUARD_MS = 900_000`。它是挂起
|
||||
| Registry 流量 | 682 次请求、383 KB packument 响应体 |
|
||||
| 布局断言与进程启动 | 4.4 s |
|
||||
|
||||
同一个依赖图加上 `--legacy-peer-deps` 后 1.12 s 解析完成,因此 peer 摆放占 153.8 s 中的 152.7 s。`canPlacePeers` 会把每条内部边与其 peer 目标的入边重新核对一遍,这使开销随「摆放次数 × 边数」增长;嵌套发布的 `@deepseek-ai/dsh-base` 副本单独耗时 48.8 s,而同一棵树上根位置的同一包只耗时 1.3 s。被校验的内部边有三分之二是 peer 边(2524 条中的 1874 条),所以这部分工作是断言本身,而不是断言之外的开销。
|
||||
同一个依赖图加上 `--legacy-peer-deps` 后 1.12 s 解析完成,因此 peer 摆放占 153.8 s 中的 152.7 s。`canPlacePeers` 会把每条内部边与其 peer 目标的入边重新核对一遍,这使开销随「摆放次数 × 边数」增长;嵌套发布的 `@deepseek-ai/dsh-base` 副本单独耗时 48.8 s,而同一棵树上根位置的同一包只耗时 1.3 s。被校验的内部边约有四分之三是 peer 边(2524 条中的 1874 条),所以这部分工作是断言本身,而不是断言之外的开销。
|
||||
|
||||
同一台主机上对同一张图的重复运行,npm 耗时在 137.8 s 到 204.8 s 之间波动,输入没有任何变化却有 1.5 倍差距,这正是墙钟阈值无法区分「主机慢」和「图更大」的原因。
|
||||
|
||||
@@ -47,4 +47,4 @@ npm 子进程仍保留墙钟上限 `NPM_HANG_GUARD_MS = 900_000`。它是挂起
|
||||
|
||||
## Consequences
|
||||
|
||||
lane 的失败判定如今取决于依赖图,因此新增少量 DSH 包的 pull request 在任何 runner 上都能通过,而增长超过约四分之一的图会带着实测计数确定性地失败。预算是棘轮:调高它是一次刻意修改,必须附带新的解析实测,该常量注释里记录了推导所用的计数。预算内的图仍会花掉完整的解析时间,因为这次改动移动的是判定位置而不是工作本身;这里没有任何东西能减少 npm 摆放双发布所需的 153 s。若图的增长改变了形状却没有改变「包数乘边数」,它仍留在预算内,只有在挂起保护到期时才被发现。
|
||||
lane 的失败判定如今取决于依赖图,因此新增少量 DSH 包的 pull request 在任何 runner 上都能通过,而「包数乘边数」增长超过约四分之一的图——即包数与内部边数同步增长约 12%——会带着实测计数确定性地失败。预算是棘轮:调高它是一次刻意修改,必须附带新的解析实测,该常量注释里记录了推导所用的计数。预算内的图仍会花掉完整的解析时间,因为这次改动移动的是判定位置而不是工作本身;这里没有任何东西能减少 npm 摆放双发布所需的 153 s。真正挂起的 npm 现在会消耗该 lane 最多 910 秒才失败,而旧期限把它限制在 300 秒。若图的增长改变了形状却没有改变「包数乘边数」,它仍留在预算内,只有在挂起保护到期时才被发现。
|
||||
@@ -32,14 +32,22 @@ const DEPENDENCY_FIELDS = ['dependencies', 'optionalDependencies', 'peerDependen
|
||||
*/
|
||||
export const MAX_RESOLUTION_WORK_UNITS = 875_000
|
||||
|
||||
/**
|
||||
* Measured npm seconds per resolution work unit on the reference host: 180.66 s
|
||||
* for the 699,148 units of the graph the budget was derived from.
|
||||
*/
|
||||
const SECONDS_PER_WORK_UNIT = 2.6e-4
|
||||
|
||||
/**
|
||||
* Wall-clock guard for the npm child process. This is a hang guard, not the
|
||||
* gate's growth criterion: {@link MAX_RESOLUTION_WORK_UNITS} decides whether the
|
||||
* graph is too large to verify. A budgeted graph costs about 226 s at the
|
||||
* measured 2.6e-4 s per work unit, and the guard allows four times that, so a
|
||||
* slower runner can never decide this gate's outcome.
|
||||
* graph is too large to verify, and a runner up to four times slower than the
|
||||
* measured host cannot decide this gate's outcome. Derived from the budget so a
|
||||
* raised budget cannot silently shrink the guard's headroom.
|
||||
*/
|
||||
const NPM_HANG_GUARD_MS = 900_000
|
||||
const NPM_HANG_GUARD_MS = Math.round(
|
||||
4 * MAX_RESOLUTION_WORK_UNITS * SECONDS_PER_WORK_UNIT * 1000,
|
||||
)
|
||||
|
||||
/** Synthetic incompatible versions used to expose cross-release placement errors. */
|
||||
export const SYNTHETIC_DSH_VERSIONS = ['0.1.0', '0.2.0'] as const
|
||||
|
||||
Reference in new issue
Block a user