Upgrade guides now pair guide.md with guide.zh.md and guide.i18n.yaml under
the ordinary translation-pairing gate. verify-upgrade-guides checks the
Chinese sibling's metadata and its 变更/迁移 sections; the 500-word ceiling
applies to the English source. Remove the session-log-otel-collector guide.
Resolves the semantic conflict with #5331: its ci-unit gate spread
coverageTestTimeoutArgs, which this branch retires; the gate is now a
plain vitest run and the darwin lane budget reaches vitest.config.ts
through the inherited DSH_COVERAGE_TEST_TIMEOUT_MS. The ci-unit spec
cases pin that shape under both budget values.
Introduce docs/upgrade-guide/v<version>/<item>/guide.md for externally
perceptible breaking changes. The dsh-create-upgrade-guide skill owns scope,
placement, maintenance, and format; verify-upgrade-guides enforces layout,
frontmatter, sections, and the 500-word ceiling. Guides are English-only and
registered as the upgrade-guide document kind.
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
The Dependency layout lane failed whenever the npm child process exceeded
a hardcoded 300 s deadline. That deadline measured the runner rather than
the graph: the same layout resolves in 137-205 s on an idle developer host
and exceeded 300 s on CI while the placement assertion reported no error,
so the failure carried no information about what had grown.
The gate now bounds the verified graph by resolution work units,
dshPackagesPerVersion * checkedDshEdges against MAX_RESOLUTION_WORK_UNITS,
and keeps the wall clock only as a hang guard derived from that budget.
Growth fails with the graph's own measured counts on any runner.
The resolution cost itself is unchanged. Measurement attributed 99.3% of
it to npm's peer-conflict placement, and cache reuse, graph splitting and
the placement flags were measured and rejected.
The fixture's poll case counts attempts instead of reading a clock, so a host
stall cannot turn a budget-ended poll into a pass; the control case reads the
poll's reported duration, which the 1000 ms default bounds from below. The
spawning spec acquires its temporary config in beforeAll, bounds the child
with a timeout and asserts no signal ended it, and counts the polled values it
inspects. CoverageTestTimeoutOptions is Vitest's own TestUserConfig members;
the rule's reach has one home in its JSDoc, which the config, gate, spec, and
note comments reference.
DSH_COVERAGE_TEST_TIMEOUT_MS expanded to --testTimeout, --hookTimeout, and
--expect.poll.timeout on the coverage and serial lanes, but Vitest forwards
only a fixed list of CLI overrides into inline projects and neither
hookTimeout nor expect is on it, so under the root config's two projects the
hook and expect.poll budgets stayed at Vitest's defaults on every lane.
vitest.config.ts now reads the variable through coverageTestTimeoutOptions and
spreads the three budgets into both projects; run-gates and the partition
coordinator pass no timeout flags, leaving one owner for the rule. A new spec
spawns vitest on the root config with a 200 ms budget and proves all three
waits end inside both projects, that unset keeps the defaults, and that a
malformed value fails at config load.
Fixes#5335
Related to #5325
run-gates.spec.ts clears DSH_COVERAGE_PARTITIONS and DSH_COVERAGE_MAX_WORKERS
before each case, so the coverage gates it builds take their shape from the
case, not from a partitioned lane that exports the variables to every child.
The ci-unit case derives its two gates from the `test` package script's
segments. The serial-reference note keeps only the lane fact; the mechanism
fact about inline-project inheritance is owned by the fix that changes it.
The unit-darwin job ran the whole unit inventory at Vitest's 5000 ms default
on a shared 3-vCPU macos-latest runner; the first two master runs after #5292
each timed out a different set of cases that pass in under a second on a quiet
host. Every other whole-inventory lane raises the budget through
DSH_COVERAGE_TEST_TIMEOUT_MS=90000.
The job now sets that variable and runs `pnpm run check:ci:unit`, a run-gates
aggregate that is `pnpm run test` (native build, then `vitest run`) through the
path that consumes it. ci-unit receives no CI worker settings, so the inventory
inherits the environment `pnpm run test` finds: on a 3-CPU host the defaults
would inject DSH_COVERAGE_PARTITIONS=2, which run-gates.spec.ts reads as a
partitioned coverage lane.
Fixes#5325
Five cases in scripts/oxlint-contract.spec.ts spawned oxlint or the
repository lint entrypoint on vitest's 5000 ms default while their nine
siblings carried the 90_000 ceiling from the Windows spawn-budget
alignment. The first darwin parity run on master (Sandbox run
36332053320) ran the file 2.2x slower than the passing run and timed out
`prints only the final diagnostics when a fix retry still fails` at
6309 ms. Give the five cases the same per-case ceiling and record the
decision in an Agent Note.
Fixes#2581
Related to #2677
The install registry picker used MenuSurface and overrode the theme-owned
menu material tokens, which the shared-menu-material gate rejects. Return
the picker to a fieldset (its native group role) and paint an opaque
bg-layer-2 surface so the form controls stay readable without touching
menu tokens. This also restores the group's radios to the accessible tree.
Align plugin-install-registry.e2e and its snapshots with the PR's visible
text: registry option names drop the parentheses around the host, the
custom address field is no longer disabled, and the custom hint spells out
http(s) and ~/.npmrc.
Hold the manual-refresh spinner to a 400ms minimum so a fast read does not
flash it, clearing to idle (or the failure toast) only after the minimum,
and dropping a refresh that settles after disposal.
Prune the retired no-unknown-casts baseline entry for browser-plugin.client.spec.
Reading Git's path text verbatim to keep trailing whitespace duplicated the
line-terminator helper that scripts/change-scope.ts already owns, which the
duplication gate rejects. Canonicalizing the fixture-side common directory
with realpathSync.native removes the text parsing entirely: short names,
junctions, and directory symlinks all collapse onto the physical directory
the installer resolves, and the injected path stays exact.
Drops the trailing-space case: with no text trimming left in the
derivation, that path already matched the installer before this change, so
the case could not fail and proved nothing.
git() trims its output, which also drops a worktree directory's own
trailing whitespace; the installer removes only the line terminator. Derive
the expected lock path through gitPath()/stripGitLineTerminator(), which
applies the installer's exact rule, so the same-string claim holds for
every path.
Adds the trailing-space injection case (skipped on Windows, which cannot
create such a directory); it fails with the same probe ENOENT under the
trimming derivation.
The five lock-access cases only diverged on a host whose temp directory
already carried a short name or directory alias. Route one case through an
aliased worktree root (a junction on Windows, a directory symlink
elsewhere) so the installer's resolved common directory necessarily differs
from the path this spec composes; the case fails with the same probe ENOENT
under the previous derivation on every platform.
The alias case shares the injection body through
expectInjectedLockAccessFailure, so the five existing case names and their
assertions are unchanged.
The lock-access cases injected a filesystem failure on a path this spec
predicted from the mkdtemp fixture directory. The installer resolves its
common directory against Git's own top-level path instead, and the host
spells that path differently: Git canonicalizes Windows 8.3 short names
and the macOS /var symlink. When the spellings diverged the injection
never fired, so the probe file was never written and all five cases
failed with ENOENT at the probe read - the signature seen in the Windows
coverage lane.
Resolving the relative common directory against Git's top-level, as the
installer does, makes the expected path identical to the one the
installer touches on every platform. The five cases fail deterministically
on macOS before this change and pass after it.