From a6eb6473287a9101599de20c43dce5848ad9eb3e Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 16 Oct 2026 21:55:37 -0700 Subject: [PATCH 1/8] v1.91.118.0 test: held-install recovery fixture no longer assumes the checkout has no local main (#3237) * test: held-install recovery fixture no longer assumes the checkout has no local main actions/checkout leaves push runs on a local main branch, so the fixture's clone already had main and 'checkout --orphan main' failed. Build the root commit on an orphan held-fixture branch and push HEAD:refs/heads/main; add a regression covering a source on main and a detached source with no branch. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * v1.91.118.0 test: held-install recovery fixture no longer assumes the checkout has no local main Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- CHANGELOG.md | 10 ++++++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- package.json | 2 +- test/held-install-recovery.test.ts | 28 +++++++++++++++++++++++----- 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f83e5000..8711235b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [1.91.118.0] - 2026-10-17 + +**Free Tests is green on pushes to main again.** Since v1.91.106.0, every push to main failed `test/held-install-recovery.test.ts`, while pull request runs passed. + +### Fixed +- **The held-install recovery fixture no longer assumes the checkout has no `main` branch.** On a push, `actions/checkout` leaves the checkout on a local `main`, so the fixture's clone already had `main` and `git checkout --orphan main` failed with `a branch named 'main' already exists`. Pull request runs check out a detached merge ref and never hit it. The fixture now builds on its own orphan branch and pushes `HEAD:refs/heads/main`, and a new test builds it from a source on `main` and from a detached source with no branch. + +### If you… +- **…write a test fixture that clones this repository:** don't create a branch with a fixed name such as `main` in the clone. Push runs and pull request runs leave different local branches behind. + ## [1.91.117.0] - 2026-10-17 **Pregate understands bats repositories and says why a fingerprint failed, `gstack-doctor` lists rescued edits and pasted skill lists, oversized SKILL.md files can no longer grow, and hosts without plan mode drop the plan-mode preamble.** The last PR of the 2026-10-15 fix wave (`docs/designs/FIX_WAVE_2026_10_15.md`, PR 5), built after #3190. diff --git a/VERSION b/VERSION index cb81a8e33..7aa026bb8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.117.0 +1.91.118.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index ca4169130..0db45b15b 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.117.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.118.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/package.json b/package.json index 4decba857..e10343092 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.117", + "version": "1.91.118", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/test/held-install-recovery.test.ts b/test/held-install-recovery.test.ts index f7250ad18..3604370e2 100644 --- a/test/held-install-recovery.test.ts +++ b/test/held-install-recovery.test.ts @@ -36,15 +36,16 @@ const CONFLICT_LINE = 'THROTTLE_SECONDS=3600 # 1 hour'; * install sits one commit behind it, at the same tree without * bin/gstack-ff-update (an install that predates it), with VERSION 1.91.101.0. */ -function makeFixture() { +function makeFixture(source = ROOT) { const base = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-held-'))); bases.push(base); const origin = path.join(base, 'origin.git'); const work = path.join(base, 'work'); - execFileSync('git', ['clone', '-q', '--shared', ROOT, work], { timeout: 60_000 }); + execFileSync('git', ['clone', '-q', '--shared', source, work], { timeout: 60_000 }); // A root commit of this tree: the checkout may be shallow, and a bare - // origin refuses a shallow push. - git(work, 'checkout', '-q', '--orphan', 'main'); + // origin refuses a shallow push. The clone already has a local main when + // the source is on main (actions/checkout runs `checkout -B main` on a push). + git(work, 'checkout', '-q', '--orphan', 'held-fixture'); fs.writeFileSync(path.join(work, 'VERSION'), '1.91.101.0\n'); fs.rmSync(path.join(work, 'bin', 'gstack-ff-update'), { force: true }); git(work, 'add', '-A'); @@ -59,7 +60,7 @@ function makeFixture() { git(work, 'commit', '-q', '-m', 'the fixed release'); const fixed = git(work, 'rev-parse', 'HEAD'); execFileSync('git', ['init', '-q', '--bare', '-b', 'main', origin], { timeout: 60_000 }); - git(work, 'push', '-q', origin, 'main'); + git(work, 'push', '-q', origin, 'HEAD:refs/heads/main'); return { base, origin, held, fixed }; } type Fx = ReturnType; @@ -126,6 +127,23 @@ describe.skipIf(process.platform === 'win32')('held-install recovery (Git Bash f expect(form('recovery-powershell')).toContain('d=$(mktemp -d)'); }); + for (const checkout of ['on main', 'detached with no branch'] as const) { + test(`the fixture builds from a source checkout ${checkout}`, () => { + const src = path.join(fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'gstack-held-src-'))), 'src'); + bases.push(path.dirname(src)); + execFileSync('git', ['clone', '-q', '--shared', ROOT, src], { timeout: 60_000 }); + if (checkout === 'on main') git(src, 'checkout', '-q', '-B', 'main'); + else { + git(src, 'checkout', '-q', '--detach'); + for (const b of git(src, 'for-each-ref', '--format=%(refname:short)', 'refs/heads').split('\n').filter(Boolean)) git(src, 'branch', '-q', '-D', b); + } + const fx = makeFixture(src); + expect(git(fx.origin, 'rev-parse', 'refs/heads/main')).toBe(fx.fixed); + expect(git(fx.origin, 'rev-parse', `${fx.fixed}^`)).toBe(fx.held); + expect(git(fx.origin, 'rev-list', '--max-parents=0', fx.fixed)).toBe(fx.held); + }, 60_000); + } + for (const state of ['clean', 'dirty', 'unmerged'] as const) { test(`a ${state} prefix-mode install reaches the fixed release; a planted symlink is never followed`, async () => { const fx = makeFixture(); From f47321e6158f37d1393d8e58d5725fb161cc8ffa Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 16 Oct 2026 22:14:19 -0700 Subject: [PATCH 2/8] v1.91.119.0 test(seed): refresh the free-suite duration seed (#3224) (#3238) * test(seed): refresh the free-suite duration seed from a Ubicloud recording (#3224) 54 free test files had landed since the 2026-10-15 recording, so CEO-10 failed again (limit 5). Recorded with `bun run test:ubicloud --record-durations` (standard-16, recorder exit 0, no failed files) on origin/main cadbd0af: 1219 -> 1273 durations, none removed. test/setup-codex-scope.test.ts is back under the 60 s ceiling (58.9 s), so its allowlist entry is removed as the shrink-only ratchet requires. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(changelog): seed refresh entry Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore(release): stamp v1.91.119.0 Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- CHANGELOG.md | 10 + VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- package.json | 2 +- scripts/free-test-durations.json | 2386 +++++++++++++------------ scripts/free-test-seed-allowlist.json | 3 +- 6 files changed, 1234 insertions(+), 1171 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8711235b2..805415a3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## [1.91.119.0] - 2026-10-17 + +**The weekly health check's seed check passes again.** 54 free test files had landed since the 2026-10-15 recording, so CEO-10 in `bun run test:health` failed and CI packed those files at the 99th-percentile guess (#3224). + +### Fixed +- **Free-suite duration seed refreshed.** `scripts/free-test-durations.json` was re-recorded on a CI-mirrored Ubicloud VM (`bun run test:ubicloud --record-durations`, no failed files): 1219 to 1273 durations, none removed. `test/setup-codex-scope.test.ts` is back under the 60 s ceiling, so its seed allowlist entry is removed. + +### If you… +- **…see CEO-10 fail in the weekly health issue:** new test files outran the seed again. With `UBICLOUD_API_KEY` set, run `bun run test:ubicloud --record-durations` and commit the seed; otherwise leave it to a maintainer. A standing recorder is planned. + ## [1.91.118.0] - 2026-10-17 **Free Tests is green on pushes to main again.** Since v1.91.106.0, every push to main failed `test/held-install-recovery.test.ts`, while pull request runs passed. diff --git a/VERSION b/VERSION index 7aa026bb8..00430b049 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.118.0 +1.91.119.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 0db45b15b..0b558c8a9 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.118.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.119.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/package.json b/package.json index e10343092..94cdfacbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.118", + "version": "1.91.119", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/scripts/free-test-durations.json b/scripts/free-test-durations.json index 5be4284f9..1401d7962 100644 --- a/scripts/free-test-durations.json +++ b/scripts/free-test-durations.json @@ -1,1225 +1,1279 @@ { "version": 1, - "recordedAt": "2026-10-15T23:37:39.698Z", + "recordedAt": "2026-10-17T04:13:10.728Z", "durations": { - "browse/test/activity.test.ts": 55, - "browse/test/adversarial-security.test.ts": 47, - "browse/test/batch.test.ts": 1770, - "browse/test/bridge-chromium-e2e.test.ts": 728, - "browse/test/browse-client.test.ts": 102, - "browse/test/browse-eval-wrapping.test.ts": 72, - "browse/test/browser-manager-custom-chromium.test.ts": 313, - "browse/test/browser-manager-unit.test.ts": 435, - "browse/test/browser-skill-commands.test.ts": 1161, - "browse/test/browser-skill-write.test.ts": 76, - "browse/test/browser-skills-e2e.test.ts": 111, - "browse/test/browser-skills-storage.test.ts": 83, - "browse/test/build-command-response.test.ts": 354, - "browse/test/build.test.ts": 138, - "browse/test/bun-child-config.test.ts": 69, - "browse/test/bun-polyfill.test.ts": 1281, - "browse/test/busy-daemon-iron-rule.test.ts": 15837, - "browse/test/busy-daemon-recovery.test.ts": 609, - "browse/test/cdp-allowlist.test.ts": 19, - "browse/test/cdp-e2e.test.ts": 564, - "browse/test/cdp-inspector-history-cap.test.ts": 24, - "browse/test/cdp-mutex.test.ts": 673, + "browse/test/activity.test.ts": 62, + "browse/test/adversarial-security.test.ts": 51, + "browse/test/batch.test.ts": 1780, + "browse/test/bridge-chromium-e2e.test.ts": 812, + "browse/test/browse-client.test.ts": 82, + "browse/test/browse-eval-wrapping.test.ts": 64, + "browse/test/browser-manager-custom-chromium.test.ts": 310, + "browse/test/browser-manager-unit.test.ts": 461, + "browse/test/browser-skill-commands.test.ts": 1178, + "browse/test/browser-skill-write.test.ts": 85, + "browse/test/browser-skills-e2e.test.ts": 96, + "browse/test/browser-skills-storage.test.ts": 85, + "browse/test/build-command-response.test.ts": 341, + "browse/test/build.test.ts": 103, + "browse/test/bun-child-config.test.ts": 79, + "browse/test/bun-polyfill.test.ts": 1200, + "browse/test/busy-daemon-iron-rule.test.ts": 15865, + "browse/test/busy-daemon-recovery.test.ts": 617, + "browse/test/cdp-allowlist.test.ts": 20, + "browse/test/cdp-e2e.test.ts": 580, + "browse/test/cdp-inspector-history-cap.test.ts": 26, + "browse/test/cdp-mutex.test.ts": 660, "browse/test/cdp-session-cleanup.test.ts": 34, - "browse/test/chromium-profile-isolation.test.ts": 13140, - "browse/test/claude-bin.test.ts": 13, - "browse/test/cli-chain-stdin.test.ts": 144, - "browse/test/cli-config-mismatch-message.test.ts": 84, - "browse/test/cli-lock.test.ts": 25, - "browse/test/cli-loopback-no-proxy.test.ts": 80, - "browse/test/cli-setsid-daemonize.test.ts": 15, - "browse/test/cli-start-final-healthcheck.test.ts": 21, - "browse/test/cli-supervisor.test.ts": 31, - "browse/test/commands.test.ts": 31047, - "browse/test/compare-board.test.ts": 994, - "browse/test/config.test.ts": 130, - "browse/test/content-security.test.ts": 751, - "browse/test/cookie-auth-verification.test.ts": 7524, - "browse/test/cookie-credential-deadline.test.ts": 292, - "browse/test/cookie-database.test.ts": 411, - "browse/test/cookie-fixture-delete-lease.test.ts": 31, - "browse/test/cookie-import-browser.test.ts": 136, - "browse/test/cookie-import-native-job.test.ts": 517, - "browse/test/cookie-import-native.test.ts": 3623, - "browse/test/cookie-import-node.test.ts": 200, - "browse/test/cookie-import-operation.test.ts": 1110, - "browse/test/cookie-import-reliability.test.ts": 1661, - "browse/test/cookie-import-transport.test.ts": 32, - "browse/test/cookie-picker-binding-browser.test.ts": 2346, - "browse/test/cookie-picker-binding.test.ts": 255, - "browse/test/cookie-picker-csrf-browser.test.ts": 603, - "browse/test/cookie-picker-routes.test.ts": 294, - "browse/test/cookie-picker-ui.test.ts": 10759, - "browse/test/daemon-log-hygiene.test.ts": 44, - "browse/test/daemon-mismatch-refuse.test.ts": 174, - "browse/test/data-platform.test.ts": 80, - "browse/test/dia-gui-readiness.test.ts": 589, - "browse/test/dia-launch-comparison.test.ts": 2739, - "browse/test/dia-macos-qualification.test.ts": 2761, - "browse/test/domain-skills-e2e.test.ts": 493, - "browse/test/domain-skills-storage.test.ts": 208, - "browse/test/dotenv-isolation.test.ts": 378, - "browse/test/dual-listener.test.ts": 362, - "browse/test/dx-polish.test.ts": 23, - "browse/test/error-handling.test.ts": 13, - "browse/test/extension-sender-auth.test.ts": 37, - "browse/test/extension-token.test.ts": 289, - "browse/test/file-drop.test.ts": 23, - "browse/test/file-permissions.test.ts": 27, - "browse/test/fill-change-event.test.ts": 1571, - "browse/test/find-browse.test.ts": 15, - "browse/test/findport.test.ts": 391, - "browse/test/from-file-path-validation.test.ts": 15, - "browse/test/gstack-config.test.ts": 1179, - "browse/test/gstack-update-check.test.ts": 3339, - "browse/test/handoff.test.ts": 8373, - "browse/test/headless-gpu-and-reap.test.ts": 1625, - "browse/test/headless-launch-options.test.ts": 1822, - "browse/test/launch-signal-flags.test.ts": 10, - "browse/test/learnings-injection.test.ts": 85, - "browse/test/media-extract-unit.test.ts": 13, - "browse/test/memory-command.test.ts": 294, - "browse/test/memory-leak-reproducer.test.ts": 359, - "browse/test/navigation-guard.test.ts": 6575, - "browse/test/output-path-symlinks.test.ts": 37, - "browse/test/pair-agent-e2e.test.ts": 1726, - "browse/test/pair-agent-optin-gate.test.ts": 353, - "browse/test/pair-agent-tunnel-eval.test.ts": 7806, - "browse/test/path-security-realpath.test.ts": 66, - "browse/test/path-validation.test.ts": 1862, - "browse/test/pdf-flags.test.ts": 24, - "browse/test/platform.test.ts": 19, - "browse/test/playwright-core-patch.test.ts": 31, - "browse/test/poisoned-bundle-probe.test.ts": 285, - "browse/test/process-liveness-windows.test.ts": 64, - "browse/test/proxy-config.test.ts": 22, - "browse/test/proxy-env-daemon.test.ts": 2817, - "browse/test/proxy-env.test.ts": 25, + "browse/test/chromium-profile-isolation.test.ts": 13228, + "browse/test/claude-bin.test.ts": 14, + "browse/test/cli-chain-stdin.test.ts": 151, + "browse/test/cli-config-mismatch-message.test.ts": 75, + "browse/test/cli-lock.test.ts": 23, + "browse/test/cli-loopback-no-proxy.test.ts": 93, + "browse/test/cli-setsid-daemonize.test.ts": 13, + "browse/test/cli-start-final-healthcheck.test.ts": 31, + "browse/test/cli-supervisor.test.ts": 28, + "browse/test/commands.test.ts": 32240, + "browse/test/compare-board.test.ts": 1162, + "browse/test/config.test.ts": 123, + "browse/test/content-security.test.ts": 918, + "browse/test/cookie-auth-verification.test.ts": 7671, + "browse/test/cookie-credential-deadline.test.ts": 401, + "browse/test/cookie-database.test.ts": 474, + "browse/test/cookie-fixture-delete-lease.test.ts": 43, + "browse/test/cookie-import-browser.test.ts": 198, + "browse/test/cookie-import-native-job.test.ts": 602, + "browse/test/cookie-import-native.test.ts": 3853, + "browse/test/cookie-import-node.test.ts": 345, + "browse/test/cookie-import-operation.test.ts": 1204, + "browse/test/cookie-import-reliability.test.ts": 1855, + "browse/test/cookie-import-transport.test.ts": 24, + "browse/test/cookie-picker-binding-browser.test.ts": 2424, + "browse/test/cookie-picker-binding.test.ts": 313, + "browse/test/cookie-picker-csrf-browser.test.ts": 579, + "browse/test/cookie-picker-routes.test.ts": 302, + "browse/test/cookie-picker-ui.test.ts": 11344, + "browse/test/daemon-log-hygiene.test.ts": 49, + "browse/test/daemon-mismatch-refuse.test.ts": 176, + "browse/test/data-platform.test.ts": 53, + "browse/test/dia-gui-readiness.test.ts": 613, + "browse/test/dia-launch-comparison.test.ts": 2680, + "browse/test/dia-macos-qualification.test.ts": 2987, + "browse/test/domain-skills-e2e.test.ts": 487, + "browse/test/domain-skills-storage.test.ts": 220, + "browse/test/dotenv-isolation.test.ts": 354, + "browse/test/dual-listener.test.ts": 327, + "browse/test/dx-polish.test.ts": 29, + "browse/test/error-handling.test.ts": 10, + "browse/test/extension-sender-auth.test.ts": 34, + "browse/test/extension-token.test.ts": 339, + "browse/test/file-drop.test.ts": 32, + "browse/test/file-permissions.test.ts": 43, + "browse/test/fill-change-event.test.ts": 1770, + "browse/test/find-browse.test.ts": 14, + "browse/test/findport.test.ts": 371, + "browse/test/from-file-path-validation.test.ts": 13, + "browse/test/gstack-config.test.ts": 1453, + "browse/test/gstack-update-check.test.ts": 3815, + "browse/test/handoff.test.ts": 8712, + "browse/test/headless-gpu-and-reap.test.ts": 1608, + "browse/test/headless-launch-options.test.ts": 1848, + "browse/test/launch-signal-flags.test.ts": 12, + "browse/test/learnings-injection.test.ts": 134, + "browse/test/media-extract-unit.test.ts": 19, + "browse/test/memory-command.test.ts": 339, + "browse/test/memory-leak-reproducer.test.ts": 338, + "browse/test/navigation-guard.test.ts": 6700, + "browse/test/output-path-symlinks.test.ts": 76, + "browse/test/pair-agent-e2e.test.ts": 1829, + "browse/test/pair-agent-optin-gate.test.ts": 348, + "browse/test/pair-agent-tunnel-eval.test.ts": 7609, + "browse/test/path-security-realpath.test.ts": 72, + "browse/test/path-validation.test.ts": 1822, + "browse/test/pdf-flags.test.ts": 23, + "browse/test/platform.test.ts": 17, + "browse/test/playwright-core-patch.test.ts": 40, + "browse/test/poisoned-bundle-probe.test.ts": 267, + "browse/test/process-liveness-windows.test.ts": 62, + "browse/test/proxy-config.test.ts": 31, + "browse/test/proxy-env-daemon.test.ts": 2762, + "browse/test/proxy-env.test.ts": 46, "browse/test/proxy-redact.test.ts": 10, - "browse/test/pty-inject-scan.test.ts": 567, - "browse/test/pty-session-lease.test.ts": 25, - "browse/test/rebrand-signed-bundle.test.ts": 18, - "browse/test/regression-pr1169-pdf-from-file-invalid-json.test.ts": 29, - "browse/test/restart-env.test.ts": 18, - "browse/test/runtime-root-server-bundle.test.ts": 30, - "browse/test/sanitize.test.ts": 12, - "browse/test/screenshot-size-guard.test.ts": 468, + "browse/test/pty-inject-scan.test.ts": 615, + "browse/test/pty-session-lease.test.ts": 31, + "browse/test/rebrand-signed-bundle.test.ts": 13, + "browse/test/regression-pr1169-pdf-from-file-invalid-json.test.ts": 35, + "browse/test/restart-env.test.ts": 20, + "browse/test/runtime-root-server-bundle.test.ts": 32, + "browse/test/sanitize.test.ts": 14, + "browse/test/screenshot-size-guard.test.ts": 498, "browse/test/security-adversarial-fixes.test.ts": 16, - "browse/test/security-adversarial.test.ts": 18, - "browse/test/security-audit-r2.test.ts": 318, - "browse/test/security-bench.test.ts": 11, - "browse/test/security-classifier-download-cleanup.test.ts": 41, - "browse/test/security-classifier.test.ts": 17, + "browse/test/security-adversarial.test.ts": 23, + "browse/test/security-audit-r2.test.ts": 271, + "browse/test/security-bench.test.ts": 14, + "browse/test/security-classifier-download-cleanup.test.ts": 89, + "browse/test/security-classifier.test.ts": 25, "browse/test/security-integration.test.ts": 21, - "browse/test/security-live-playwright.test.ts": 631, - "browse/test/security-sidecar-client.test.ts": 50, - "browse/test/security.test.ts": 21, - "browse/test/server-auth.test.ts": 324, - "browse/test/server-embedder-terminal-port.test.ts": 4022, - "browse/test/server-factory.test.ts": 1068, - "browse/test/server-flush-trackers.test.ts": 11, - "browse/test/server-launch-resolution.test.ts": 24, - "browse/test/server-lock-errors.test.ts": 25, - "browse/test/server-no-import-side-effects.test.ts": 602, - "browse/test/server-proxy-fail-fast.test.ts": 1356, - "browse/test/server-pty-lease-routes.test.ts": 347, - "browse/test/server-route-auth-blackbox.test.ts": 407, - "browse/test/server-route-dispatch-ratchet.test.ts": 260, - "browse/test/server-route-table.test.ts": 361, - "browse/test/server-sanitize-surrogates.test.ts": 290, - "browse/test/server-tmp-state-path.test.ts": 11, - "browse/test/session-cookie-store.test.ts": 46, - "browse/test/session-persist.test.ts": 778, - "browse/test/sidebar-tabs.test.ts": 309, - "browse/test/sidebar-ux.test.ts": 320, - "browse/test/sidepanel-font-size.test.ts": 25, - "browse/test/sidepanel-patient-autoconnect.test.ts": 12, - "browse/test/sidepanel-reattach.test.ts": 14, - "browse/test/sidepanel-restart-dispose.test.ts": 14, - "browse/test/skill-token.test.ts": 19, - "browse/test/snapshot.test.ts": 8022, - "browse/test/socks-bridge.test.ts": 469, + "browse/test/security-live-playwright.test.ts": 681, + "browse/test/security-sidecar-client.test.ts": 29, + "browse/test/security.test.ts": 27, + "browse/test/server-auth.test.ts": 381, + "browse/test/server-embedder-terminal-port.test.ts": 4014, + "browse/test/server-factory.test.ts": 974, + "browse/test/server-flush-trackers.test.ts": 14, + "browse/test/server-launch-resolution.test.ts": 20, + "browse/test/server-lock-errors.test.ts": 28, + "browse/test/server-no-import-side-effects.test.ts": 591, + "browse/test/server-proxy-fail-fast.test.ts": 1372, + "browse/test/server-pty-lease-routes.test.ts": 316, + "browse/test/server-route-auth-blackbox.test.ts": 401, + "browse/test/server-route-dispatch-ratchet.test.ts": 264, + "browse/test/server-route-table.test.ts": 331, + "browse/test/server-sanitize-surrogates.test.ts": 291, + "browse/test/server-tmp-state-path.test.ts": 12, + "browse/test/session-cookie-store.test.ts": 51, + "browse/test/session-persist.test.ts": 650, + "browse/test/sidebar-tabs.test.ts": 308, + "browse/test/sidebar-ux.test.ts": 292, + "browse/test/sidepanel-font-size.test.ts": 16, + "browse/test/sidepanel-patient-autoconnect.test.ts": 14, + "browse/test/sidepanel-reattach.test.ts": 21, + "browse/test/sidepanel-restart-dispose.test.ts": 19, + "browse/test/skill-token.test.ts": 20, + "browse/test/snapshot.test.ts": 8283, + "browse/test/socks-bridge.test.ts": 471, "browse/test/sse-helpers.test.ts": 156, - "browse/test/sse-session-cookie.test.ts": 18, - "browse/test/state-ttl.test.ts": 11, - "browse/test/stealth-extended.test.ts": 11, - "browse/test/stealth-layer-c.test.ts": 11, - "browse/test/stealth-webdriver.test.ts": 1556, - "browse/test/stop-ack-before-shutdown.test.ts": 130, - "browse/test/stop-dead-daemon.test.ts": 233, - "browse/test/tab-each.test.ts": 34, - "browse/test/tab-guardrail.test.ts": 294, - "browse/test/tab-isolation.test.ts": 272, + "browse/test/sse-session-cookie.test.ts": 17, + "browse/test/state-ttl.test.ts": 12, + "browse/test/stealth-extended.test.ts": 15, + "browse/test/stealth-layer-c.test.ts": 12, + "browse/test/stealth-webdriver.test.ts": 1640, + "browse/test/stop-ack-before-shutdown.test.ts": 129, + "browse/test/stop-dead-daemon.test.ts": 182, + "browse/test/tab-each.test.ts": 30, + "browse/test/tab-external-close-dispatch.test.ts": 652, + "browse/test/tab-external-close.test.ts": 496, + "browse/test/tab-guardrail.test.ts": 284, + "browse/test/tab-isolation.test.ts": 277, "browse/test/tab-session-frame-detach.test.ts": 9, - "browse/test/telemetry-optout.test.ts": 22, - "browse/test/telemetry.test.ts": 22, - "browse/test/temp-dirs.test.ts": 44, - "browse/test/terminal-agent-detach-reattach.test.ts": 15, - "browse/test/terminal-agent-import.test.ts": 4392, - "browse/test/terminal-agent-integration.test.ts": 738, - "browse/test/terminal-agent-keepalive.test.ts": 12, - "browse/test/terminal-agent-lifecycle.test.ts": 4754, - "browse/test/terminal-agent-native-observation.test.ts": 19, - "browse/test/terminal-agent-owner-watchdog.test.ts": 113, - "browse/test/terminal-agent-pid-identity.test.ts": 27, - "browse/test/terminal-agent-port-range.test.ts": 30, - "browse/test/terminal-agent-publication-lock.test.ts": 1647, - "browse/test/terminal-agent-ring-buffer-runtime.test.ts": 49, - "browse/test/terminal-agent-session-routing.test.ts": 23, - "browse/test/terminal-agent-watchdog.test.ts": 18, - "browse/test/terminal-agent.test.ts": 291, - "browse/test/terminal-pty-lifecycle.test.ts": 11, - "browse/test/token-registry.test.ts": 22, - "browse/test/tunnel-gate-unit.test.ts": 259, - "browse/test/tunnel-revoke-cli.test.ts": 937, - "browse/test/url-validation.test.ts": 75, - "browse/test/watch.test.ts": 297, - "browse/test/watchdog.test.ts": 2991, - "browse/test/welcome-page.test.ts": 14, + "browse/test/telemetry-optout.test.ts": 23, + "browse/test/telemetry.test.ts": 24, + "browse/test/temp-dirs.test.ts": 42, + "browse/test/terminal-agent-detach-reattach.test.ts": 13, + "browse/test/terminal-agent-import.test.ts": 4376, + "browse/test/terminal-agent-integration.test.ts": 790, + "browse/test/terminal-agent-keepalive.test.ts": 13, + "browse/test/terminal-agent-lifecycle.test.ts": 5047, + "browse/test/terminal-agent-native-observation.test.ts": 51, + "browse/test/terminal-agent-owner-watchdog.test.ts": 114, + "browse/test/terminal-agent-pid-identity.test.ts": 26, + "browse/test/terminal-agent-port-range.test.ts": 22, + "browse/test/terminal-agent-publication-lock.test.ts": 1689, + "browse/test/terminal-agent-ring-buffer-runtime.test.ts": 93, + "browse/test/terminal-agent-session-routing.test.ts": 11, + "browse/test/terminal-agent-signal-cleanup.test.ts": 15589, + "browse/test/terminal-agent-watchdog.test.ts": 10, + "browse/test/terminal-agent.test.ts": 270, + "browse/test/terminal-pty-lifecycle.test.ts": 16, + "browse/test/token-registry.test.ts": 23, + "browse/test/tunnel-gate-unit.test.ts": 267, + "browse/test/tunnel-revoke-cli.test.ts": 907, + "browse/test/url-validation.test.ts": 56, + "browse/test/watch.test.ts": 290, + "browse/test/watchdog.test.ts": 3042, + "browse/test/welcome-page.test.ts": 13, "browse/test/windows-spawn-hide.test.ts": 25, - "browse/test/xprotect-heal.test.ts": 761, - "browse/test/xvfb.test.ts": 16287, - "browser-skills/hackernews-frontpage/script.test.ts": 14, - "design/test/approval.test.ts": 35, - "design/test/auth.test.ts": 27, - "design/test/brief.test.ts": 12, - "design/test/cli-persistence.test.ts": 6612, - "design/test/cli-version.test.ts": 31, - "design/test/daemon-discovery.test.ts": 11317, + "browse/test/xprotect-heal.test.ts": 778, + "browse/test/xvfb.test.ts": 16129, + "browser-skills/hackernews-frontpage/script.test.ts": 13, + "design/test/approval.test.ts": 30, + "design/test/auth.test.ts": 15, + "design/test/brief.test.ts": 9, + "design/test/cli-persistence.test.ts": 6971, + "design/test/cli-version.test.ts": 32, + "design/test/daemon-discovery.test.ts": 11676, "design/test/daemon.test.ts": 154, - "design/test/feedback-roundtrip-daemon.test.ts": 339, - "design/test/feedback-roundtrip.test.ts": 3020, + "design/test/feedback-roundtrip-daemon.test.ts": 388, + "design/test/feedback-roundtrip.test.ts": 2922, "design/test/gallery.test.ts": 16, - "design/test/image-args.test.ts": 52, - "design/test/image-gen-pairing.test.ts": 49, - "design/test/models.test.ts": 197, - "design/test/persist.test.ts": 43, - "design/test/receipted-fetch.test.ts": 25, - "design/test/serve.test.ts": 173, - "design/test/variants-briefs.test.ts": 3634, - "design/test/variants-retry-after.test.ts": 8211, - "ios-qa/daemon/test/allowlist.test.ts": 17, - "ios-qa/daemon/test/audit.test.ts": 30, - "ios-qa/daemon/test/auth-mint.test.ts": 24, - "ios-qa/daemon/test/cli-mint.test.ts": 217, - "ios-qa/daemon/test/daemon-integration.test.ts": 3846, - "ios-qa/daemon/test/proxy-classify.test.ts": 20, - "ios-qa/daemon/test/proxy-transport.test.ts": 1747, - "ios-qa/daemon/test/session-tokens.test.ts": 14, - "ios-qa/daemon/test/single-instance.test.ts": 15, - "ios-qa/daemon/test/tailscale-localapi.test.ts": 46, - "ios-qa/daemon/test/tunnel-bootstrap.test.ts": 407, - "ios-qa/scripts/gen-accessors.test.ts": 51, + "design/test/image-args.test.ts": 35, + "design/test/image-gen-pairing.test.ts": 53, + "design/test/models.test.ts": 55, + "design/test/persist.test.ts": 41, + "design/test/receipted-fetch.test.ts": 23, + "design/test/serve.test.ts": 177, + "design/test/variants-briefs.test.ts": 3575, + "design/test/variants-retry-after.test.ts": 8381, + "ios-qa/daemon/test/allowlist.test.ts": 34, + "ios-qa/daemon/test/audit.test.ts": 29, + "ios-qa/daemon/test/auth-mint.test.ts": 38, + "ios-qa/daemon/test/cli-mint.test.ts": 219, + "ios-qa/daemon/test/daemon-integration.test.ts": 3909, + "ios-qa/daemon/test/devicectl-launch-env.test.ts": 27, + "ios-qa/daemon/test/proxy-classify.test.ts": 41, + "ios-qa/daemon/test/proxy-transport.test.ts": 1759, + "ios-qa/daemon/test/session-tokens.test.ts": 15, + "ios-qa/daemon/test/single-instance.test.ts": 16, + "ios-qa/daemon/test/tailscale-localapi.test.ts": 25, + "ios-qa/daemon/test/tunnel-bootstrap.test.ts": 420, + "ios-qa/scripts/gen-accessors.test.ts": 50, "make-pdf/test/asideClient.test.ts": 19, "make-pdf/test/cli-args.test.ts": 10, - "make-pdf/test/cli-exit-codes.test.ts": 305, - "make-pdf/test/diagram-prepass.test.ts": 65, - "make-pdf/test/e2e/ci-prereqs.test.ts": 23, - "make-pdf/test/e2e/combined-gate.test.ts": 802, - "make-pdf/test/e2e/diagram-gate.test.ts": 2550, - "make-pdf/test/e2e/emoji-gate.test.ts": 845, - "make-pdf/test/e2e/format-gate.test.ts": 4652, - "make-pdf/test/e2e/landscape-gate.test.ts": 3129, - "make-pdf/test/e2e/toc-gate.test.ts": 5807, - "make-pdf/test/image-policy.test.ts": 13, - "make-pdf/test/pdftotext.test.ts": 34, - "make-pdf/test/render-offline-sanitize.test.ts": 27, - "make-pdf/test/render.test.ts": 38, - "make-pdf/test/setup-smoke.test.ts": 91, + "make-pdf/test/cli-exit-codes.test.ts": 322, + "make-pdf/test/diagram-prepass.test.ts": 98, + "make-pdf/test/e2e/ci-prereqs.test.ts": 37, + "make-pdf/test/e2e/combined-gate.test.ts": 926, + "make-pdf/test/e2e/diagram-gate.test.ts": 2673, + "make-pdf/test/e2e/emoji-gate.test.ts": 891, + "make-pdf/test/e2e/format-gate.test.ts": 4823, + "make-pdf/test/e2e/landscape-gate.test.ts": 3251, + "make-pdf/test/e2e/toc-gate.test.ts": 5810, + "make-pdf/test/image-policy.test.ts": 19, + "make-pdf/test/pdftotext.test.ts": 36, + "make-pdf/test/render-offline-sanitize.test.ts": 32, + "make-pdf/test/render.test.ts": 40, + "make-pdf/test/setup-smoke.test.ts": 104, "make-pdf/test/toc-anchors.test.ts": 28, - "make-pdf/test/toc-pages.test.ts": 31, - "test/agent-sdk-runner.test.ts": 8223, - "test/agents-digest.test.ts": 14, - "test/analytics.test.ts": 15, + "make-pdf/test/toc-pages.test.ts": 56, + "test/agent-sdk-runner.test.ts": 8251, + "test/agents-digest.test.ts": 20, + "test/analytics.test.ts": 29, "test/anthropic-preflight.test.ts": 11, - "test/archaeology-lint.test.ts": 1732, - "test/arm-benchmark-selftest.test.ts": 453, - "test/arm-setup-smoke-workflow.test.ts": 47, - "test/artifacts-allowlist-decisions.test.ts": 14, + "test/approval-classes.test.ts": 7087, + "test/archaeology-lint.test.ts": 1758, + "test/arm-benchmark-selftest.test.ts": 415, + "test/arm-setup-smoke-workflow.test.ts": 20, + "test/artifacts-allowlist-decisions.test.ts": 11, "test/artifacts-init-migration.test.ts": 251, - "test/aside-driver.test.ts": 171, - "test/aside-probe-shell.test.ts": 9587, - "test/aside-render.test.ts": 10296, - "test/audit-compliance.test.ts": 23, - "test/auq-error-fallback-hook.test.ts": 151, - "test/auq-format-always-loaded.test.ts": 33, - "test/auq-mode-capture.test.ts": 116, - "test/auq-native-capture.test.ts": 2233, - "test/auq-parallel.test.ts": 12909, - "test/auq-substance-panel.test.ts": 84, - "test/auto-decide-fixture.test.ts": 3010, - "test/autoplan-admission.test.ts": 855, - "test/autoplan-amend-input.test.ts": 1061, - "test/autoplan-answer-invalidation.test.ts": 6231, - "test/autoplan-artifact-recorder.test.ts": 5572, - "test/autoplan-artifact-windows-argv.test.ts": 130, - "test/autoplan-bounded-journal.test.ts": 416, - "test/autoplan-capy-e2e.test.ts": 7074, - "test/autoplan-compaction-copies.test.ts": 115, - "test/autoplan-driver.test.ts": 2946, - "test/autoplan-dual-voice-evidence.test.ts": 1624, - "test/autoplan-dual-voice-fixture.test.ts": 3902, - "test/autoplan-edit-digests-al.test.ts": 377, - "test/autoplan-gate-judgment.test.ts": 8263, - "test/autoplan-guard-log.test.ts": 79, - "test/autoplan-guard-reasons.test.ts": 13, - "test/autoplan-init.test.ts": 1158, - "test/autoplan-long-session-observer.test.ts": 204, - "test/autoplan-method-read-audit.test.ts": 522, - "test/autoplan-methodology-names.test.ts": 1204, - "test/autoplan-obligations.test.ts": 2380, - "test/autoplan-owned-read.test.ts": 2354, - "test/autoplan-owned-state.test.ts": 1541, - "test/autoplan-pending-artifact.test.ts": 979, - "test/autoplan-pending-question.test.ts": 4282, - "test/autoplan-phase-handoff.test.ts": 112, - "test/autoplan-phase-observer.test.ts": 99, + "test/aside-driver.test.ts": 150, + "test/aside-probe-shell.test.ts": 9593, + "test/aside-render.test.ts": 10224, + "test/audit-compliance.test.ts": 22, + "test/auq-error-fallback-hook.test.ts": 170, + "test/auq-format-always-loaded.test.ts": 45, + "test/auq-mode-capture.test.ts": 147, + "test/auq-native-capture.test.ts": 2302, + "test/auq-parallel.test.ts": 12051, + "test/auq-substance-panel.test.ts": 102, + "test/auto-decide-fixture.test.ts": 2984, + "test/autoplan-admission.test.ts": 958, + "test/autoplan-amend-input.test.ts": 999, + "test/autoplan-answer-invalidation.test.ts": 8280, + "test/autoplan-artifact-recorder.test.ts": 5705, + "test/autoplan-artifact-windows-argv.test.ts": 80, + "test/autoplan-bounded-journal.test.ts": 376, + "test/autoplan-budget.test.ts": 9339, + "test/autoplan-capy-e2e.test.ts": 8983, + "test/autoplan-checkpoint.test.ts": 6677, + "test/autoplan-compaction-copies.test.ts": 117, + "test/autoplan-compaction-preserved-segment.test.ts": 1266, + "test/autoplan-driver.test.ts": 2085, + "test/autoplan-dual-voice-evidence.test.ts": 1255, + "test/autoplan-dual-voice-fixture.test.ts": 3240, + "test/autoplan-durability.test.ts": 1740, + "test/autoplan-edit-digests-al.test.ts": 287, + "test/autoplan-gate-artifacts.test.ts": 1959, + "test/autoplan-gate-judgment.test.ts": 17866, + "test/autoplan-guard-log.test.ts": 62, + "test/autoplan-guard-reasons.test.ts": 12, + "test/autoplan-init.test.ts": 957, + "test/autoplan-long-session-observer.test.ts": 72, + "test/autoplan-method-read-audit.test.ts": 274, + "test/autoplan-methodology-names.test.ts": 1136, + "test/autoplan-obligations.test.ts": 2439, + "test/autoplan-owned-read.test.ts": 2432, + "test/autoplan-owned-state.test.ts": 1704, + "test/autoplan-pairing.test.ts": 35, + "test/autoplan-pending-artifact.test.ts": 904, + "test/autoplan-pending-question.test.ts": 4167, + "test/autoplan-phase-handoff.test.ts": 129, + "test/autoplan-phase-observer.test.ts": 102, "test/autoplan-phase-order.test.ts": 65, - "test/autoplan-preconfigured-onboarding-ar.test.ts": 746, - "test/autoplan-public-narration.test.ts": 41, - "test/autoplan-publication-generation.test.ts": 23, - "test/autoplan-publication-guard.test.ts": 1777, - "test/autoplan-publication-hook.test.ts": 2534, - "test/autoplan-publication-payload.test.ts": 2270, - "test/autoplan-record.test.ts": 2073, - "test/autoplan-residuals.test.ts": 1917, - "test/autoplan-review-discovery.test.ts": 10592, - "test/autoplan-revise.test.ts": 6976, - "test/autoplan-run-concurrency.test.ts": 1551, - "test/autoplan-run-recovery.test.ts": 4885, - "test/autoplan-schema-canary-compare.test.ts": 20, - "test/autoplan-scope.test.ts": 664, - "test/autoplan-snapshot.test.ts": 2140, - "test/autoplan-timing.test.ts": 337, - "test/benchmark-cli.test.ts": 529, - "test/benchmark-provider-adapters.test.ts": 60, + "test/autoplan-preconfigured-onboarding-ar.test.ts": 988, + "test/autoplan-public-export.test.ts": 5753, + "test/autoplan-public-narration.test.ts": 70, + "test/autoplan-publication-generation.test.ts": 25, + "test/autoplan-publication-guard.test.ts": 1625, + "test/autoplan-publication-hook.test.ts": 2553, + "test/autoplan-publication-payload.test.ts": 2216, + "test/autoplan-record.test.ts": 2925, + "test/autoplan-residuals.test.ts": 6404, + "test/autoplan-review-discovery.test.ts": 11020, + "test/autoplan-revise.test.ts": 10146, + "test/autoplan-run-concurrency.test.ts": 3664, + "test/autoplan-run-recovery.test.ts": 8822, + "test/autoplan-schema-canary-compare.test.ts": 29, + "test/autoplan-scope.test.ts": 711, + "test/autoplan-snapshot.test.ts": 2015, + "test/autoplan-timing.test.ts": 353, + "test/benchmark-cli.test.ts": 516, + "test/benchmark-provider-adapters.test.ts": 61, "test/benchmark-runner.test.ts": 23, - "test/bin-context-windows-slug.test.ts": 2361, - "test/bin-windows-bun-import-paths.test.ts": 843, - "test/binary-version-probe.test.ts": 125, - "test/binding-template-drift.test.ts": 51, - "test/bootstrap-retention-shard.test.ts": 2455, - "test/bootstrap-retention.test.ts": 12736, - "test/bootstrap-session-lifecycle.test.ts": 5093, - "test/brain-cache-roundtrip.test.ts": 113, - "test/brain-cache-spec.test.ts": 21, - "test/brain-preflight.test.ts": 32, - "test/brain-sync-removals.test.ts": 8936, - "test/brain-sync-windows-paths.test.ts": 11, - "test/brain-sync.test.ts": 57159, - "test/branch-slug-hygiene.test.ts": 758, - "test/build-cso-nonfatal.test.ts": 46, - "test/build-cso-result-record.test.ts": 745, - "test/build-gbrain-env.test.ts": 58, - "test/build-script-shell-compat.test.ts": 13, - "test/builder-profile.test.ts": 3729, - "test/bun-subprocess-fd-lifetime.test.ts": 64, - "test/bun-version-drift.test.ts": 646, - "test/cache-concurrent-refresh.test.ts": 54, - "test/capy-skill-wrapper.test.ts": 4065, - "test/carve-guard-completeness.test.ts": 13, - "test/carve-guards-negative.test.ts": 18, - "test/carve-plan-fixture.test.ts": 380, - "test/carve-section-ordering.test.ts": 40, - "test/carve-section-sharding.test.ts": 1438, - "test/catalog-budget.test.ts": 44, - "test/catalog-mode-full.test.ts": 962, - "test/catalog-trim.test.ts": 43, - "test/census-red-docs.test.ts": 40, - "test/ceo-barless-submit.test.ts": 87, - "test/ceo-count-ad-v2.test.ts": 33, - "test/ceo-expansion-auq.test.ts": 84, - "test/ceo-expansion-pacing-native.test.ts": 81, - "test/ceo-finding-fixture.test.ts": 773, - "test/ceo-hold-posture-review.test.ts": 109, - "test/ceo-mode-expansion-disposition.test.ts": 66, - "test/ceo-mode-handoff-hook.test.ts": 53, - "test/ceo-mode-handoff.test.ts": 70, - "test/ceo-mode-labels-native.test.ts": 44, - "test/ceo-mode-option.test.ts": 1653, - "test/ceo-mode-pending-submit.test.ts": 53, + "test/bin-context-windows-slug.test.ts": 2898, + "test/bin-windows-bun-import-paths.test.ts": 935, + "test/binary-version-probe.test.ts": 132, + "test/binding-template-drift.test.ts": 39, + "test/bootstrap-retention-shard.test.ts": 3133, + "test/bootstrap-retention.test.ts": 12024, + "test/bootstrap-session-lifecycle.test.ts": 5096, + "test/brain-cache-roundtrip.test.ts": 153, + "test/brain-cache-spec.test.ts": 24, + "test/brain-preflight.test.ts": 43, + "test/brain-sync-removals.test.ts": 9851, + "test/brain-sync-windows-paths.test.ts": 32, + "test/brain-sync.test.ts": 58148, + "test/branch-slug-hygiene.test.ts": 723, + "test/build-cso-nonfatal.test.ts": 51, + "test/build-cso-result-record.test.ts": 660, + "test/build-gbrain-env.test.ts": 90, + "test/build-script-shell-compat.test.ts": 15, + "test/builder-profile.test.ts": 4068, + "test/bun-resolve.test.ts": 687, + "test/bun-subprocess-fd-lifetime.test.ts": 78, + "test/bun-version-drift.test.ts": 532, + "test/bun-version-shells.test.ts": 849, + "test/cache-concurrent-refresh.test.ts": 143, + "test/capy-review-voice.test.ts": 9959, + "test/capy-skill-wrapper.test.ts": 7846, + "test/carve-guard-completeness.test.ts": 15, + "test/carve-guards-negative.test.ts": 34, + "test/carve-plan-fixture.test.ts": 464, + "test/carve-section-ordering.test.ts": 28, + "test/carve-section-sharding.test.ts": 1499, + "test/catalog-budget.test.ts": 49, + "test/catalog-mode-full.test.ts": 1085, + "test/catalog-trim.test.ts": 55, + "test/census-red-docs.test.ts": 38, + "test/ceo-barless-submit.test.ts": 114, + "test/ceo-count-ad-v2.test.ts": 37, + "test/ceo-expansion-auq.test.ts": 89, + "test/ceo-expansion-pacing-native.test.ts": 65, + "test/ceo-finding-fixture.test.ts": 842, + "test/ceo-hold-posture-review.test.ts": 130, + "test/ceo-mode-expansion-disposition.test.ts": 64, + "test/ceo-mode-handoff-hook.test.ts": 54, + "test/ceo-mode-handoff.test.ts": 80, + "test/ceo-mode-labels-native.test.ts": 45, + "test/ceo-mode-option.test.ts": 1644, + "test/ceo-mode-pending-submit.test.ts": 48, "test/ceo-mode-posture-native.test.ts": 41, - "test/ceo-mode-preference-al.test.ts": 1850, - "test/ceo-mode-prerequisite.test.ts": 1067, - "test/ceo-mode-routing-fixture.test.ts": 788, - "test/ceo-plan-mode-fixture.test.ts": 778, - "test/ceo-posture-packet.test.ts": 299, - "test/ceo-section-loading-fixture.test.ts": 339, - "test/ceo-split-collection.test.ts": 482, - "test/ceo-split-question-policy.test.ts": 398, - "test/ceo-stale-fill-decision.test.ts": 81, - "test/ceo-workflow-clarity.test.ts": 25, - "test/changed-files-union.test.ts": 378, - "test/chromium-sandbox-ci.test.ts": 232, - "test/ci-eval-cache.test.ts": 265, - "test/ci-image-cli-pin.test.ts": 25, - "test/ci-image-tag-binding.test.ts": 50, - "test/ci-native-evidence.test.ts": 776, - "test/ci-paid-coordination.test.ts": 6577, - "test/claude-code-migration.test.ts": 174, - "test/claude-code-runner.test.ts": 3074, - "test/claude-code-skill.test.ts": 1475, - "test/claude-code-windows-job.test.ts": 36, - "test/claude-md-size.test.ts": 11, - "test/claude-overlay-models.test.ts": 25, - "test/claude-overlay-setup-default.test.ts": 34320, - "test/claude-overlay-setup-installs.test.ts": 47031, - "test/claude-overlay-setup-lifecycle.test.ts": 55022, - "test/claude-producer-stream.test.ts": 3536, - "test/claude-provider-keychain.test.ts": 170, - "test/code-intelligence-cli.test.ts": 650, - "test/code-intelligence.test.ts": 4299, - "test/codex-boundary-evidence.test.ts": 13, - "test/codex-carve-fixture.test.ts": 762, - "test/codex-ci-access.test.ts": 212, - "test/codex-effort.test.ts": 1568, - "test/codex-eval-recording.test.ts": 306, - "test/codex-generation-model.test.ts": 114, - "test/codex-hardening.test.ts": 10279, - "test/codex-invocation-sites.test.ts": 322, - "test/codex-model-probe.test.ts": 5510, - "test/codex-multiblock.test.ts": 11, - "test/codex-probe-cache.test.ts": 12496, - "test/codex-probe-subcommands.test.ts": 5105, - "test/codex-resume-flag-semantics.test.ts": 13, - "test/codex-session-lifecycle.test.ts": 12014, - "test/codex-skill-isolation.test.ts": 141, - "test/codex-under-codex-detection.test.ts": 25, - "test/codex-web-search-flag.test.ts": 445, + "test/ceo-mode-preference-al.test.ts": 2215, + "test/ceo-mode-prerequisite.test.ts": 1149, + "test/ceo-mode-routing-fixture.test.ts": 944, + "test/ceo-plan-find-cross-branch.test.ts": 163, + "test/ceo-plan-mode-fixture.test.ts": 881, + "test/ceo-posture-packet.test.ts": 322, + "test/ceo-section-loading-fixture.test.ts": 358, + "test/ceo-split-collection.test.ts": 548, + "test/ceo-split-question-policy.test.ts": 442, + "test/ceo-stale-fill-decision.test.ts": 84, + "test/ceo-workflow-clarity.test.ts": 47, + "test/changed-files-union.test.ts": 380, + "test/chromium-sandbox-ci.test.ts": 174, + "test/ci-eval-cache.test.ts": 273, + "test/ci-image-cli-pin.test.ts": 33, + "test/ci-image-tag-binding.test.ts": 18, + "test/ci-native-evidence.test.ts": 782, + "test/ci-paid-coordination.test.ts": 6665, + "test/claude-code-migration.test.ts": 190, + "test/claude-code-runner.test.ts": 3027, + "test/claude-code-skill.test.ts": 1515, + "test/claude-code-windows-job.test.ts": 49, + "test/claude-md-size.test.ts": 10, + "test/claude-overlay-models.test.ts": 30, + "test/claude-overlay-setup-default.test.ts": 34280, + "test/claude-overlay-setup-installs.test.ts": 47530, + "test/claude-overlay-setup-lifecycle.test.ts": 53306, + "test/claude-producer-stream.test.ts": 3537, + "test/claude-provider-keychain.test.ts": 77, + "test/code-intelligence-cli.test.ts": 662, + "test/code-intelligence.test.ts": 4561, + "test/codex-boundary-evidence.test.ts": 12, + "test/codex-carve-fixture.test.ts": 929, + "test/codex-ci-access.test.ts": 238, + "test/codex-effort.test.ts": 1821, + "test/codex-eval-recording.test.ts": 318, + "test/codex-generation-model.test.ts": 115, + "test/codex-hardening.test.ts": 10324, + "test/codex-invocation-sites.test.ts": 418, + "test/codex-model-probe.test.ts": 5344, + "test/codex-multiblock.test.ts": 13, + "test/codex-probe-cache.test.ts": 12745, + "test/codex-probe-subcommands.test.ts": 5118, + "test/codex-resume-flag-semantics.test.ts": 16, + "test/codex-session-lifecycle.test.ts": 12019, + "test/codex-skill-isolation.test.ts": 145, + "test/codex-under-codex-detection.test.ts": 29, + "test/codex-web-search-flag.test.ts": 374, "test/conductor-env-shim.test.ts": 9, - "test/context-bill.test.ts": 83, - "test/context-budget-ratchet.test.ts": 111, - "test/context-identity.test.ts": 25573, - "test/context-remaining-work-provenance.test.ts": 15, - "test/context-save-hardening.test.ts": 422, - "test/cookie-workflow-judge-input.test.ts": 744, - "test/cookie-workflow-manual-review.test.ts": 132, - "test/copilot-windows-bash.test.ts": 11, - "test/cost-known.test.ts": 87, - "test/coverage-audit-evidence.test.ts": 176, - "test/coverage-audit.test.ts": 1280, - "test/cso-bounded-file.test.ts": 29, - "test/cso-cache.test.ts": 314, - "test/cso-cli-lifecycle.test.ts": 5069, - "test/cso-cli-recheck.test.ts": 17629, - "test/cso-cli.test.ts": 29819, - "test/cso-contracts.test.ts": 242, - "test/cso-distribution.test.ts": 3183, - "test/cso-docker-integration.test.ts": 28, - "test/cso-docker-mounts.test.ts": 43, - "test/cso-docker-policy.test.ts": 25, - "test/cso-docker-socket-realpath.test.ts": 29, - "test/cso-eval.test.ts": 7658, - "test/cso-file-ceiling.test.ts": 31627, - "test/cso-git-global-config.test.ts": 27, - "test/cso-git-hardening.test.ts": 329, - "test/cso-history.test.ts": 13, - "test/cso-image-provisioning.test.ts": 283, - "test/cso-launcher-generation.test.ts": 1631, - "test/cso-lease-identity.test.ts": 491, - "test/cso-macos-launcher.test.ts": 21, - "test/cso-native-evidence.test.ts": 92, - "test/cso-node-lifecycle-integration.test.ts": 39, - "test/cso-ntfs-fixture.test.ts": 111, - "test/cso-postgresql-policy.test.ts": 25, - "test/cso-preparation-adversarial.test.ts": 137, - "test/cso-preparation-container.test.ts": 83, - "test/cso-preparation-executor.test.ts": 690, - "test/cso-preparation-java.test.ts": 28, - "test/cso-preparation.test.ts": 72, - "test/cso-preserved.test.ts": 15, - "test/cso-public-ghcr.test.ts": 30, - "test/cso-python-runner-shadow.test.ts": 2634, - "test/cso-rails-verification.test.ts": 31, - "test/cso-registry-socket.test.ts": 1812, - "test/cso-requalification.test.ts": 3194, - "test/cso-runtime-promotion.test.ts": 146, - "test/cso-scanner-cli.test.ts": 7588, + "test/context-bill.test.ts": 90, + "test/context-budget-ratchet.test.ts": 109, + "test/context-identity.test.ts": 25065, + "test/context-remaining-work-provenance.test.ts": 12, + "test/context-save-hardening.test.ts": 380, + "test/cookie-workflow-judge-input.test.ts": 774, + "test/cookie-workflow-manual-review.test.ts": 89, + "test/copilot-windows-bash.test.ts": 10, + "test/cost-known.test.ts": 51, + "test/coverage-audit-evidence.test.ts": 177, + "test/coverage-audit.test.ts": 1066, + "test/cso-audit-paths.test.ts": 17621, + "test/cso-bounded-file.test.ts": 21, + "test/cso-cache.test.ts": 320, + "test/cso-cli-lifecycle.test.ts": 4902, + "test/cso-cli-recheck.test.ts": 17452, + "test/cso-cli.test.ts": 29390, + "test/cso-contracts.test.ts": 241, + "test/cso-distribution.test.ts": 2968, + "test/cso-docker-argv0.test.ts": 939, + "test/cso-docker-integration.test.ts": 23, + "test/cso-docker-mounts.test.ts": 40, + "test/cso-docker-policy.test.ts": 24, + "test/cso-docker-socket-realpath.test.ts": 30, + "test/cso-eval.test.ts": 7893, + "test/cso-file-ceiling.test.ts": 30942, + "test/cso-git-global-config.test.ts": 33, + "test/cso-git-hardening.test.ts": 192, + "test/cso-history.test.ts": 11, + "test/cso-image-provisioning.test.ts": 264, + "test/cso-json-redaction.test.ts": 263, + "test/cso-launcher-generation.test.ts": 1547, + "test/cso-lease-identity.test.ts": 492, + "test/cso-macos-launcher.test.ts": 14, + "test/cso-native-evidence.test.ts": 85, + "test/cso-node-lifecycle-integration.test.ts": 35, + "test/cso-ntfs-fixture.test.ts": 159, + "test/cso-postgresql-policy.test.ts": 31, + "test/cso-preparation-adversarial.test.ts": 76, + "test/cso-preparation-container.test.ts": 59, + "test/cso-preparation-executor.test.ts": 707, + "test/cso-preparation-java.test.ts": 21, + "test/cso-preparation.test.ts": 84, + "test/cso-preserved.test.ts": 19, + "test/cso-public-ghcr.test.ts": 38, + "test/cso-python-runner-shadow.test.ts": 2567, + "test/cso-rails-verification.test.ts": 34, + "test/cso-registry-socket.test.ts": 2372, + "test/cso-requalification.test.ts": 3251, + "test/cso-runtime-promotion.test.ts": 142, + "test/cso-scanner-cli.test.ts": 7357, "test/cso-scanner-docker-integration.test.ts": 36, - "test/cso-scanner-executor.test.ts": 128, - "test/cso-scanner-release.test.ts": 131, - "test/cso-scanners.test.ts": 81, - "test/cso-snapshot-disappearance-race.test.ts": 189, - "test/cso-snapshot-identity.test.ts": 443, - "test/cso-snapshot-state.test.ts": 3612, + "test/cso-scanner-executor.test.ts": 165, + "test/cso-scanner-release.test.ts": 98, + "test/cso-scanners.test.ts": 84, + "test/cso-snapshot-disappearance-race.test.ts": 155, + "test/cso-snapshot-identity.test.ts": 491, + "test/cso-snapshot-state.test.ts": 3688, "test/cso-spec-taxonomy-alignment.test.ts": 13, "test/cso-stack-cold-integration.test.ts": 29, - "test/cso-staging-run.test.ts": 82, - "test/cso-verification-cleanup.test.ts": 1072, - "test/cso-verifier.test.ts": 108, - "test/cso-watchdog.test.ts": 8237, - "test/cso-windows-build-contract.test.ts": 16, - "test/cso-windows-docker.test.ts": 20, - "test/cso-windows-launcher.test.ts": 23, - "test/cso-witness.test.ts": 948, - "test/declared-annotation.test.ts": 16, - "test/defensive-review-framing.test.ts": 14, - "test/dependency-security.test.ts": 53, - "test/deps-smoke.test.ts": 52, - "test/design-approval-flow.test.ts": 6434, - "test/design-board-reload.test.ts": 22, - "test/design-catalog.test.ts": 29, - "test/design-checklist-sync.test.ts": 818, - "test/design-completion-handoff-scored.test.ts": 44, - "test/design-consultation-command-contract.test.ts": 305, + "test/cso-staging-run.test.ts": 79, + "test/cso-verification-cleanup.test.ts": 1086, + "test/cso-verifier.test.ts": 32, + "test/cso-watchdog.test.ts": 8268, + "test/cso-windows-build-contract.test.ts": 17, + "test/cso-windows-docker.test.ts": 19, + "test/cso-windows-launcher.test.ts": 19, + "test/cso-witness.test.ts": 1037, + "test/declared-annotation.test.ts": 18, + "test/defensive-review-framing.test.ts": 15, + "test/dependency-security.test.ts": 55, + "test/deps-smoke.test.ts": 55, + "test/design-approval-flow.test.ts": 6353, + "test/design-board-reload.test.ts": 25, + "test/design-catalog.test.ts": 25, + "test/design-checklist-sync.test.ts": 882, + "test/design-completion-handoff-scored.test.ts": 38, + "test/design-consultation-command-contract.test.ts": 314, "test/design-consultation-contract.test.ts": 27, - "test/design-daemon-windows-identity.test.ts": 42, - "test/design-detect-contract.test.ts": 141, - "test/design-detector-source-fixture.test.ts": 5985, - "test/design-doc-data-guard.test.ts": 13, + "test/design-daemon-windows-identity.test.ts": 35, + "test/design-detect-contract.test.ts": 134, + "test/design-detector-source-fixture.test.ts": 5858, + "test/design-doc-data-guard.test.ts": 14, "test/design-flag-utils.test.ts": 27, - "test/design-html-section-completion.test.ts": 2953, - "test/design-md.test.ts": 548, - "test/design-printed-paths.test.ts": 84, - "test/design-research-fixture.test.ts": 22, - "test/design-setup-probe.test.ts": 11343, - "test/detector-corpora.test.ts": 381, - "test/detector-corpus-auto-decide-preserved.test.ts": 42, - "test/detector-corpus-plan-ceo-section-loading.test.ts": 47, - "test/detector-corpus-plan-design-review-plan-mode.test.ts": 274, - "test/detector-corpus-plan-eng-multi-finding-batching.test.ts": 255, - "test/detector-corpus-shared-libs-plan-callers.test.ts": 23, - "test/detector-corpus-ship-docsync-late-result.test.ts": 48, - "test/dev-setup-render-isolation.test.ts": 159, - "test/devex-finding-fixture.test.ts": 1112, - "test/devex-peer-comparison-calibration.test.ts": 322, - "test/diagram-render-drift.test.ts": 311, - "test/diff-scope.test.ts": 1961, - "test/disabled-dated-record-at.test.ts": 129, - "test/disabled-plan-review-evidence.test.ts": 1340, - "test/discover-section-templates.test.ts": 14, - "test/dispatch-rules.test.ts": 34, - "test/distill-apply.test.ts": 1018, - "test/distill-free-text.test.ts": 1009, - "test/docs-config-keys.test.ts": 161, - "test/docsync-atomic-writes.test.ts": 1577, - "test/docsync-authority.test.ts": 546, - "test/docsync-child-marker.test.ts": 21, - "test/docsync-command-grammar.test.ts": 263, - "test/docsync-fault-interface.test.ts": 27316, - "test/docsync-lifecycle-interface.test.ts": 138, - "test/docsync-nested-writes.test.ts": 729, - "test/docsync-report-interface.test.ts": 376, - "test/doctor-components.test.ts": 20, - "test/document-skills-redaction.test.ts": 18, - "test/dom-dump-hygiene.test.ts": 759, - "test/dx-selected-navigation-ap.test.ts": 102, - "test/e2e-harness-audit.test.ts": 20, - "test/e2e-shard-reuse.test.ts": 2335, - "test/e2e-tier-alignment.test.ts": 136, - "test/egress-lib.test.ts": 302, - "test/egress-receipt-wiring.test.ts": 193, + "test/design-html-section-completion.test.ts": 3129, + "test/design-md.test.ts": 495, + "test/design-printed-paths.test.ts": 94, + "test/design-research-fixture.test.ts": 61, + "test/design-setup-probe.test.ts": 11230, + "test/detector-corpora.test.ts": 392, + "test/detector-corpus-auto-decide-preserved.test.ts": 41, + "test/detector-corpus-plan-ceo-section-loading.test.ts": 41, + "test/detector-corpus-plan-design-review-plan-mode.test.ts": 241, + "test/detector-corpus-plan-eng-multi-finding-batching.test.ts": 215, + "test/detector-corpus-shared-libs-plan-callers.test.ts": 26, + "test/detector-corpus-ship-docsync-late-result.test.ts": 37, + "test/detector-corpus-ship-docsync-launch-failure.test.ts": 38, + "test/dev-setup-render-isolation.test.ts": 136, + "test/devex-finding-fixture.test.ts": 993, + "test/devex-peer-comparison-calibration.test.ts": 297, + "test/diagram-render-drift.test.ts": 312, + "test/diff-scope.test.ts": 1772, + "test/disabled-dated-record-at.test.ts": 69, + "test/disabled-plan-review-evidence.test.ts": 1267, + "test/discover-section-templates.test.ts": 13, + "test/dispatch-rules.test.ts": 85, + "test/distill-apply.test.ts": 914, + "test/distill-free-text.test.ts": 1038, + "test/docs-config-keys.test.ts": 155, + "test/docsync-atomic-writes.test.ts": 1686, + "test/docsync-authority.test.ts": 567, + "test/docsync-child-marker.test.ts": 23, + "test/docsync-command-grammar.test.ts": 303, + "test/docsync-fault-interface.test.ts": 27471, + "test/docsync-lifecycle-interface.test.ts": 124, + "test/docsync-nested-writes.test.ts": 994, + "test/docsync-report-interface.test.ts": 547, + "test/doctor-components.test.ts": 23, + "test/document-skills-redaction.test.ts": 17, + "test/dom-dump-hygiene.test.ts": 875, + "test/dx-error-capture.test.ts": 4905, + "test/dx-error-contract-grader.test.ts": 24, + "test/dx-error-contract.test.ts": 59, + "test/dx-selected-navigation-ap.test.ts": 112, + "test/e2e-harness-audit.test.ts": 27, + "test/e2e-shard-reuse.test.ts": 2398, + "test/e2e-tier-alignment.test.ts": 133, + "test/egress-lib.test.ts": 298, + "test/egress-receipt-wiring.test.ts": 197, "test/egress-receipt.test.ts": 5416, - "test/empty-find-fallthrough.test.ts": 250, - "test/eng-batching-current-ledger.test.ts": 235, - "test/eng-batching-native-replay.test.ts": 62, - "test/eng-batching-saved-ledger.test.ts": 591, - "test/eng-count-question-policy.test.ts": 31, - "test/eng-devex-s-count.test.ts": 42, - "test/eng-finding-retry-budget.test.ts": 468, - "test/eng-first-review.test.ts": 245, - "test/eng-published-navigation.test.ts": 71, - "test/eng-resolution-block-position.test.ts": 244, - "test/eng-review-routing.test.ts": 24, - "test/eng-scope-entry-ap.test.ts": 78, - "test/eng-seeded-completion-ai.test.ts": 12134, - "test/eng-seeded-coverage.test.ts": 1388, - "test/eng-semantic-terminal.test.ts": 74, - "test/eng-test-plan-edit-approval.test.ts": 993, - "test/env-host-fence-conformance.test.ts": 7384, - "test/env-host-runtime-assets.test.ts": 1475, - "test/eval-budgets-policy.test.ts": 54, - "test/eval-cli-family.test.ts": 1519, - "test/eval-detach-timeout-floor.test.ts": 1187, - "test/eval-flake-rank.test.ts": 214, - "test/eval-history.test.ts": 1863, - "test/eval-input-cache.test.ts": 73, + "test/empty-find-fallthrough.test.ts": 254, + "test/eng-batching-current-ledger.test.ts": 226, + "test/eng-batching-native-replay.test.ts": 63, + "test/eng-batching-saved-ledger.test.ts": 655, + "test/eng-count-question-policy.test.ts": 32, + "test/eng-devex-s-count.test.ts": 40, + "test/eng-finding-retry-budget.test.ts": 505, + "test/eng-first-review.test.ts": 205, + "test/eng-published-navigation.test.ts": 57, + "test/eng-resolution-block-position.test.ts": 313, + "test/eng-review-routing.test.ts": 28, + "test/eng-scope-entry-ap.test.ts": 85, + "test/eng-seeded-completion-ai.test.ts": 12146, + "test/eng-seeded-coverage.test.ts": 1357, + "test/eng-semantic-terminal.test.ts": 73, + "test/eng-test-plan-edit-approval.test.ts": 1092, + "test/env-host-fence-conformance.test.ts": 7437, + "test/env-host-runtime-assets.test.ts": 1372, + "test/eval-budgets-policy.test.ts": 47, + "test/eval-cli-family.test.ts": 1449, + "test/eval-detach-timeout-floor.test.ts": 1045, + "test/eval-flake-rank.test.ts": 263, + "test/eval-history.test.ts": 1756, + "test/eval-input-cache.test.ts": 76, "test/eval-kinds.test.ts": 48, - "test/eval-list-cli.test.ts": 198, - "test/eval-model.test.ts": 9, - "test/eval-sweep-workflow.test.ts": 14, - "test/evals-pr-lane-workflow.test.ts": 14, - "test/evals-tracking-issue.test.ts": 225, - "test/evals-workflow-wiring.test.ts": 254, - "test/evidence-bundle-portability.test.ts": 4205, - "test/evidence.test.ts": 13605, - "test/exit-propagation.test.ts": 336, - "test/explain-level-config.test.ts": 588, - "test/extension-pty-inject-invariant.test.ts": 20, - "test/external-host-carve.test.ts": 2237, - "test/flake-ledger.test.ts": 37, - "test/founder-resources-optout.test.ts": 149, - "test/free-fixtures.test.ts": 1206, - "test/free-home-guard.test.ts": 174, - "test/free-seed-ratchet.test.ts": 63, - "test/free-tests-workflow-wiring.test.ts": 24, - "test/freeze-owned-lifecycle.test.ts": 2992, - "test/frontend-scope.test.ts": 1093, - "test/fs-atomic.test.ts": 35, - "test/fs-utils.test.ts": 250, - "test/gate-diff-cli.test.ts": 3008, - "test/gate-diff.test.ts": 48, - "test/gate-integrity-templates.test.ts": 46, - "test/gate-list.test.ts": 243, - "test/gate-secret-scan.test.ts": 549, - "test/gate-tail-lint.test.ts": 1555, - "test/gbrain-cycle-completed.test.ts": 43, - "test/gbrain-detect-install.test.ts": 634, - "test/gbrain-detect-shape.test.ts": 428, - "test/gbrain-detection-override.test.ts": 1061, - "test/gbrain-dream-stage.test.ts": 266, + "test/eval-list-cli.test.ts": 217, + "test/eval-model.test.ts": 10, + "test/eval-models.test.ts": 781, + "test/eval-plan-prereg-diagnostics.test.ts": 413, + "test/eval-sweep-workflow.test.ts": 12, + "test/evals-pr-lane-workflow.test.ts": 16, + "test/evals-tracking-issue.test.ts": 230, + "test/evals-workflow-wiring.test.ts": 255, + "test/evidence-bundle-portability.test.ts": 4311, + "test/evidence.test.ts": 13723, + "test/exit-propagation.test.ts": 338, + "test/explain-level-config.test.ts": 615, + "test/extension-pty-inject-invariant.test.ts": 13, + "test/external-host-carve.test.ts": 2109, + "test/flake-ledger.test.ts": 35, + "test/founder-resources-optout.test.ts": 204, + "test/free-fixtures.test.ts": 1247, + "test/free-home-guard.test.ts": 73, + "test/free-seed-ratchet.test.ts": 85, + "test/free-tests-workflow-wiring.test.ts": 29, + "test/freeze-owned-lifecycle.test.ts": 3130, + "test/frontend-scope.test.ts": 1249, + "test/fs-atomic.test.ts": 84, + "test/fs-utils.test.ts": 238, + "test/gate-diff-cli.test.ts": 3258, + "test/gate-diff.test.ts": 32, + "test/gate-integrity-templates.test.ts": 33, + "test/gate-list.test.ts": 258, + "test/gate-secret-scan.test.ts": 553, + "test/gate-tail-lint.test.ts": 1525, + "test/gbrain-cycle-completed.test.ts": 38, + "test/gbrain-detect-install.test.ts": 665, + "test/gbrain-detect-shape.test.ts": 489, + "test/gbrain-detection-override.test.ts": 1105, + "test/gbrain-dream-stage.test.ts": 289, "test/gbrain-exec-invariant.test.ts": 13, - "test/gbrain-guards.test.ts": 22, - "test/gbrain-init-voyage-code-3.test.ts": 167, - "test/gbrain-lib-validate-varname.test.ts": 50, - "test/gbrain-lib-verify.test.ts": 161, - "test/gbrain-local-status.test.ts": 3925, - "test/gbrain-prune-gone-worktrees.test.ts": 270, - "test/gbrain-read-capability.test.ts": 1624, - "test/gbrain-refresh-install-render.test.ts": 10, - "test/gbrain-repo-policy-client.test.ts": 881, - "test/gbrain-repo-policy.test.ts": 1487, - "test/gbrain-source-gitignore.test.ts": 26, - "test/gbrain-source-worktree-advance.test.ts": 768, - "test/gbrain-sources-parse.test.ts": 18, - "test/gbrain-sources.test.ts": 110, - "test/gbrain-spawn-windows-shell.test.ts": 19, - "test/gbrain-structured-busy.test.ts": 1751, - "test/gbrain-supabase-provision.test.ts": 134, - "test/gbrain-sync-skip.test.ts": 10695, + "test/gbrain-guards.test.ts": 26, + "test/gbrain-init-voyage-code-3.test.ts": 179, + "test/gbrain-lib-validate-varname.test.ts": 51, + "test/gbrain-lib-verify.test.ts": 166, + "test/gbrain-local-status.test.ts": 4029, + "test/gbrain-prune-gone-worktrees.test.ts": 375, + "test/gbrain-read-capability.test.ts": 1889, + "test/gbrain-refresh-install-render.test.ts": 12, + "test/gbrain-repo-policy-client.test.ts": 958, + "test/gbrain-repo-policy.test.ts": 1588, + "test/gbrain-source-gitignore.test.ts": 123, + "test/gbrain-source-worktree-advance.test.ts": 845, + "test/gbrain-sources-parse.test.ts": 21, + "test/gbrain-sources.test.ts": 102, + "test/gbrain-spawn-windows-shell.test.ts": 16, + "test/gbrain-structured-busy.test.ts": 1865, + "test/gbrain-supabase-provision.test.ts": 131, + "test/gbrain-sync-no-bash-message.test.ts": 23, + "test/gbrain-sync-skip.test.ts": 10871, "test/gbrain-sync-voyage-code-3-integration.test.ts": 14, - "test/gen-skill-docs-checks.test.ts": 11679, - "test/gen-skill-docs-idempotency.test.ts": 2729, - "test/gen-skill-docs-import-purity.test.ts": 38, - "test/gen-skill-docs-out-dir.test.ts": 2511, + "test/gen-skill-docs-checks.test.ts": 11740, + "test/gen-skill-docs-idempotency.test.ts": 2727, + "test/gen-skill-docs-import-purity.test.ts": 42, + "test/gen-skill-docs-out-dir.test.ts": 2461, "test/gen-skill-docs-prune-stale.test.ts": 713, - "test/gen-skill-docs.test.ts": 6678, - "test/generated-bash-placeholders.test.ts": 623, - "test/generated-docs-fences.test.ts": 203, - "test/generator-eexist.test.ts": 352, - "test/git-ref-fixture-tripwire.test.ts": 103, - "test/gitattributes-eol.test.ts": 874, - "test/global-discover.test.ts": 722, - "test/greptile-early-cli.test.ts": 249, - "test/greptile-early.test.ts": 25, - "test/gstack-analytics-avg-duration.test.ts": 214, - "test/gstack-artifacts-init.test.ts": 6656, - "test/gstack-artifacts-url.test.ts": 123, - "test/gstack-brain-context-load.test.ts": 899, - "test/gstack-browser-ensure.test.ts": 3315, - "test/gstack-capy-install.test.ts": 5793, + "test/gen-skill-docs.test.ts": 6685, + "test/generated-bash-placeholders.test.ts": 764, + "test/generated-docs-fences.test.ts": 197, + "test/generator-eexist.test.ts": 389, + "test/git-ref-fixture-tripwire.test.ts": 112, + "test/gitattributes-eol.test.ts": 911, + "test/global-discover.test.ts": 769, + "test/greptile-early-cli.test.ts": 241, + "test/greptile-early.test.ts": 24, + "test/gstack-analytics-avg-duration.test.ts": 204, + "test/gstack-artifacts-init.test.ts": 6640, + "test/gstack-artifacts-url.test.ts": 119, + "test/gstack-brain-context-load.test.ts": 1004, + "test/gstack-browser-ensure.test.ts": 5469, + "test/gstack-capy-install.test.ts": 30245, + "test/gstack-ceo-plan-find.test.ts": 227, "test/gstack-ci-gate.test.ts": 25, - "test/gstack-codex-session-import.test.ts": 660, - "test/gstack-config-browse-extension-id.test.ts": 362, - "test/gstack-config-cross-project.test.ts": 215, - "test/gstack-config-defaults.test.ts": 5994, - "test/gstack-config-gbrain-refresh.test.ts": 130, - "test/gstack-config-key-locale.test.ts": 138, - "test/gstack-config-memorable-key.test.ts": 401, - "test/gstack-config-redact-keys.test.ts": 295, - "test/gstack-config-transcript-scope.test.ts": 2475, - "test/gstack-context-recovery.test.ts": 105, - "test/gstack-decision-bins.test.ts": 6121, - "test/gstack-decision-semantic.test.ts": 37, - "test/gstack-decision.test.ts": 24, - "test/gstack-design-claim.test.ts": 754, - "test/gstack-design-detect-plugins.test.ts": 354, - "test/gstack-design-detect.test.ts": 16090, - "test/gstack-design-doc-find.test.ts": 404, - "test/gstack-detach.test.ts": 23805, - "test/gstack-developer-profile.test.ts": 14209, - "test/gstack-docs-candidate.test.ts": 937, - "test/gstack-doctor.test.ts": 23299, - "test/gstack-egress-cli.test.ts": 551, - "test/gstack-gbrain-detect-mcp-mode.test.ts": 938, - "test/gstack-gbrain-mcp-verify.test.ts": 1240, - "test/gstack-gbrain-source-wireup.test.ts": 2974, - "test/gstack-gbrain-sync-transcript-mode.test.ts": 2471, - "test/gstack-gbrain-sync.test.ts": 1938, - "test/gstack-home-module-scope.test.ts": 67, - "test/gstack-launch-probe.test.ts": 110, - "test/gstack-learnings-search.test.ts": 1856, - "test/gstack-lease.test.ts": 948, - "test/gstack-memorable.test.ts": 8619, - "test/gstack-memory-helpers.test.ts": 11103, - "test/gstack-memory-ingest.test.ts": 13647, - "test/gstack-next-version.test.ts": 1469, - "test/gstack-paths.test.ts": 944, - "test/gstack-post-cli.test.ts": 460, - "test/gstack-post.test.ts": 26, - "test/gstack-question-log.test.ts": 2744, - "test/gstack-question-preference.test.ts": 9361, + "test/gstack-codex-session-import.test.ts": 696, + "test/gstack-config-browse-extension-id.test.ts": 375, + "test/gstack-config-cross-project.test.ts": 284, + "test/gstack-config-defaults.test.ts": 6231, + "test/gstack-config-gbrain-refresh.test.ts": 137, + "test/gstack-config-key-locale.test.ts": 139, + "test/gstack-config-memorable-key.test.ts": 351, + "test/gstack-config-redact-keys.test.ts": 243, + "test/gstack-config-transcript-scope.test.ts": 2709, + "test/gstack-context-recovery.test.ts": 110, + "test/gstack-decision-bins.test.ts": 5874, + "test/gstack-decision-semantic.test.ts": 39, + "test/gstack-decision.test.ts": 29, + "test/gstack-design-claim.test.ts": 644, + "test/gstack-design-detect-plugins.test.ts": 407, + "test/gstack-design-detect.test.ts": 15669, + "test/gstack-design-doc-find.test.ts": 348, + "test/gstack-detach.test.ts": 23812, + "test/gstack-developer-profile.test.ts": 13090, + "test/gstack-docs-candidate.test.ts": 770, + "test/gstack-doctor.test.ts": 28549, + "test/gstack-egress-cli.test.ts": 546, + "test/gstack-ff-update.test.ts": 15528, + "test/gstack-gbrain-detect-mcp-mode.test.ts": 1044, + "test/gstack-gbrain-mcp-verify.test.ts": 1312, + "test/gstack-gbrain-source-wireup.test.ts": 3055, + "test/gstack-gbrain-sync-transcript-mode.test.ts": 2557, + "test/gstack-gbrain-sync.test.ts": 2053, + "test/gstack-home-module-scope.test.ts": 75, + "test/gstack-launch-probe.test.ts": 103, + "test/gstack-learnings-search.test.ts": 1729, + "test/gstack-lease.test.ts": 4117, + "test/gstack-memorable.test.ts": 8662, + "test/gstack-memory-helpers.test.ts": 11106, + "test/gstack-memory-ingest.test.ts": 13044, + "test/gstack-next-version.test.ts": 1435, + "test/gstack-paths.test.ts": 918, + "test/gstack-post-cli.test.ts": 447, + "test/gstack-post.test.ts": 27, + "test/gstack-question-log.test.ts": 2562, + "test/gstack-question-preference.test.ts": 8575, "test/gstack-redact-cli.test.ts": 3346, - "test/gstack-regen.test.ts": 2152, - "test/gstack-render-cli.test.ts": 412, - "test/gstack-repo-mode.test.ts": 1410, - "test/gstack-restamp-queue.test.ts": 9472, - "test/gstack-retro-metrics.test.ts": 726, - "test/gstack-safe-git.test.ts": 1131, - "test/gstack-schema-pack.test.ts": 11, - "test/gstack-session-kind.test.ts": 154, - "test/gstack-settings-hook-schema-aware.test.ts": 5276, - "test/gstack-settings-hook-symlink.test.ts": 1339, - "test/gstack-ship-policy.test.ts": 1340, - "test/gstack-ship-receipt.test.ts": 1634, - "test/gstack-skill-start.test.ts": 21654, - "test/gstack-slug-cwd-walk-up.test.ts": 904, - "test/gstack-slug-get.test.ts": 500, - "test/gstack-slug-parity.test.ts": 4728, - "test/gstack-slug-sanitize.test.ts": 171, - "test/gstack-state-root-override.test.ts": 571, - "test/gstack-team-init-hook-schema.test.ts": 163, - "test/gstack-upgrade-bin.test.ts": 6020, - "test/gstack-upgrade-fresh-shell.test.ts": 5524, - "test/gstack-upgrade-migration-v1_17_0_0.test.ts": 49, - "test/gstack-upgrade-migration-v1_37_0_0.test.ts": 117, - "test/gstack-upgrade-migration-v1_40_0_0.test.ts": 188, - "test/gstack-upgrade-migration-v1_78_0_0.test.ts": 45, - "test/gstack-upgrade-migration-v1_91_19_0.test.ts": 157, - "test/gstack-version-bump.test.ts": 1759, - "test/gstack-wtree-windows-paths.test.ts": 186, - "test/harness-version.test.ts": 115, - "test/headless-artifacts.test.ts": 751, - "test/health-capture.test.ts": 207, - "test/health-eval-fixture.test.ts": 279, - "test/helpers-unit.test.ts": 39, - "test/helpers/budget-override.test.ts": 18, - "test/helpers/capture-parity-baseline.test.ts": 166, - "test/helpers/claude-pty-runner.auq.unit.test.ts": 52, - "test/helpers/claude-pty-runner.boundaries.unit.test.ts": 70, - "test/helpers/claude-pty-runner.classify.unit.test.ts": 61, - "test/helpers/claude-pty-runner.launch.unit.test.ts": 302, - "test/helpers/claude-pty-runner.plan-native.unit.test.ts": 48, - "test/helpers/claude-pty-runner.runners.unit.test.ts": 284, + "test/gstack-regen.test.ts": 2003, + "test/gstack-render-cli.test.ts": 392, + "test/gstack-repo-mode.test.ts": 1337, + "test/gstack-restamp-queue.test.ts": 9214, + "test/gstack-retro-metrics.test.ts": 818, + "test/gstack-safe-git.test.ts": 1090, + "test/gstack-schema-pack.test.ts": 12, + "test/gstack-session-kind.test.ts": 118, + "test/gstack-settings-hook-schema-aware.test.ts": 4992, + "test/gstack-settings-hook-symlink.test.ts": 1263, + "test/gstack-ship-policy.test.ts": 1290, + "test/gstack-ship-queue.test.ts": 11840, + "test/gstack-ship-receipt.test.ts": 1833, + "test/gstack-skill-start.test.ts": 24611, + "test/gstack-slug-cwd-walk-up.test.ts": 898, + "test/gstack-slug-get.test.ts": 521, + "test/gstack-slug-parity.test.ts": 5082, + "test/gstack-slug-sanitize.test.ts": 162, + "test/gstack-state-root-override.test.ts": 552, + "test/gstack-team-init-hook-schema.test.ts": 194, + "test/gstack-upgrade-bin.test.ts": 11370, + "test/gstack-upgrade-fresh-shell.test.ts": 6111, + "test/gstack-upgrade-migration-v1_17_0_0.test.ts": 53, + "test/gstack-upgrade-migration-v1_37_0_0.test.ts": 119, + "test/gstack-upgrade-migration-v1_40_0_0.test.ts": 202, + "test/gstack-upgrade-migration-v1_78_0_0.test.ts": 39, + "test/gstack-upgrade-migration-v1_91_19_0.test.ts": 177, + "test/gstack-upgrade-path-spelling.test.ts": 530, + "test/gstack-version-bump.test.ts": 1721, + "test/gstack-wtree-windows-paths.test.ts": 162, + "test/harness-version.test.ts": 106, + "test/headless-artifacts.test.ts": 792, + "test/health-capture.test.ts": 158, + "test/health-eval-fixture.test.ts": 196, + "test/held-install-recovery.test.ts": 32501, + "test/helpers-unit.test.ts": 40, + "test/helpers/budget-override.test.ts": 71, + "test/helpers/capture-parity-baseline.test.ts": 163, + "test/helpers/claude-pty-runner.auq.unit.test.ts": 55, + "test/helpers/claude-pty-runner.boundaries.unit.test.ts": 62, + "test/helpers/claude-pty-runner.classify.unit.test.ts": 46, + "test/helpers/claude-pty-runner.launch.unit.test.ts": 313, + "test/helpers/claude-pty-runner.plan-native.unit.test.ts": 41, + "test/helpers/claude-pty-runner.runners.unit.test.ts": 277, "test/helpers/claude-pty-runner.scope-gate-floor.unit.test.ts": 45, - "test/helpers/claude-pty-runner.screen.unit.test.ts": 67, + "test/helpers/claude-pty-runner.screen.unit.test.ts": 42, "test/helpers/e2e-gate.unit.test.ts": 18, - "test/helpers/eval-store.test.ts": 316, - "test/helpers/hermetic-env.test.ts": 1223, - "test/helpers/observability.test.ts": 81, - "test/helpers/providers/gemini.test.ts": 39, - "test/helpers/resolve-repo-path.test.ts": 17, - "test/helpers/run-bin.test.ts": 24, - "test/helpers/session-runner.test.ts": 100, - "test/helpers/sync-command-capture.test.ts": 1050, - "test/heredoc-pipe-deadlock.test.ts": 128, - "test/hermetic-skill-runtime.test.ts": 2480, - "test/hermetic-skills-seeding.test.ts": 154, - "test/hermetic-wiring.test.ts": 174, - "test/honesty-kernel.test.ts": 42, - "test/hook-log.test.ts": 231, - "test/hook-scripts.test.ts": 26541, - "test/hooks-windows-paths.test.ts": 132, - "test/host-config.test.ts": 2652, - "test/host-conformance.test.ts": 88220, - "test/host-renders-prune.test.ts": 63454, - "test/host-renders.test.ts": 23899, - "test/hostile-path-writers.test.ts": 2246, - "test/impeccable-fixtures.test.ts": 15, - "test/install-fixture.test.ts": 1045, - "test/install-verdict.test.ts": 106, - "test/instruction-facts.test.ts": 58, - "test/investigate-freeze-path.test.ts": 5436, - "test/investigate-recipes.test.ts": 125, - "test/ios-debug-bridge-release-guard.test.ts": 11, - "test/ios-qa-daemon-cli.test.ts": 23, - "test/ios-qa-regen.test.ts": 278, - "test/ios-qa-stateserver-hardening.test.ts": 14, - "test/ios-qa-swift-build.test.ts": 17, - "test/ios-qa.test.ts": 205, - "test/is-conductor.test.ts": 9, + "test/helpers/eval-store.test.ts": 303, + "test/helpers/hermetic-env.test.ts": 1393, + "test/helpers/observability.test.ts": 77, + "test/helpers/providers/gemini.test.ts": 21, + "test/helpers/resolve-repo-path.test.ts": 13, + "test/helpers/run-bin.test.ts": 23, + "test/helpers/session-runner.test.ts": 98, + "test/helpers/sync-command-capture.test.ts": 1065, + "test/heredoc-pipe-deadlock.test.ts": 144, + "test/hermetic-skill-runtime.test.ts": 2605, + "test/hermetic-skills-seeding.test.ts": 204, + "test/hermetic-wiring.test.ts": 176, + "test/honesty-kernel.test.ts": 28, + "test/hook-log.test.ts": 269, + "test/hook-scripts.test.ts": 26813, + "test/hooks-windows-paths.test.ts": 164, + "test/host-config.test.ts": 2995, + "test/host-conformance.test.ts": 86601, + "test/host-renders-prune.test.ts": 63485, + "test/host-renders.test.ts": 25268, + "test/hostile-path-writers.test.ts": 2348, + "test/impeccable-fixtures.test.ts": 13, + "test/install-fixture.test.ts": 1153, + "test/install-verdict.test.ts": 1544, + "test/instruction-facts.test.ts": 54, + "test/investigate-freeze-path.test.ts": 5496, + "test/investigate-recipes.test.ts": 16, + "test/ios-debug-bridge-release-guard.test.ts": 24, + "test/ios-qa-daemon-cli.test.ts": 18, + "test/ios-qa-regen.test.ts": 327, + "test/ios-qa-stateserver-hardening.test.ts": 19, + "test/ios-qa-swift-build.test.ts": 20, + "test/ios-qa.test.ts": 201, + "test/is-conductor.test.ts": 14, "test/jargon-list.test.ts": 13, - "test/jsonl-merge.test.ts": 320, - "test/jsonl-store.test.ts": 16, - "test/judge-calibration.test.ts": 55, - "test/judge-panel-median.test.ts": 49, - "test/land-and-deploy-ci-gate.test.ts": 3185, - "test/land-and-deploy-command-trigger.test.ts": 13, - "test/land-and-deploy-flow.test.ts": 699, - "test/land-and-deploy-postfail.test.ts": 16, - "test/lane-coordination.test.ts": 1877, - "test/learnings-callers-unavailable.test.ts": 1442, - "test/learnings-injection.test.ts": 14, - "test/learnings.test.ts": 5210, - "test/llm-judge-abort.test.ts": 26, - "test/llm-judge-frontier.test.ts": 110, - "test/llm-judge-stream.test.ts": 37, - "test/llms-txt-shape.test.ts": 34, - "test/maintenance-cli-args.test.ts": 154, - "test/memorable-user-prompt-hook.test.ts": 11317, - "test/memory-cache-injection.test.ts": 300, - "test/memory-ingest-include-gitignored.test.ts": 56, - "test/memory-ingest-landing.test.ts": 1641, - "test/memory-ingest-sources.test.ts": 2647, - "test/memory-ingest-timeout.test.ts": 25, - "test/memory-pipeline.test.ts": 712, - "test/migration-checkpoint-ownership.test.ts": 132, - "test/migrations-v1.27.0.0.test.ts": 825, - "test/migrations-v1.65.0.0.test.ts": 233, - "test/mktemp-portability.test.ts": 80, - "test/model-catalog-isolation.test.ts": 65, - "test/model-overlays.test.ts": 20, - "test/model-policy-cli.test.ts": 3238, - "test/model-policy-freshness.test.ts": 176, - "test/model-policy-workflow.test.ts": 238, - "test/model-policy.test.ts": 63, - "test/model-role-invocation.test.ts": 34715, - "test/module-size-ratchet.test.ts": 183, - "test/native-auto-decide-pty.test.ts": 10065, - "test/native-auto-decide.test.ts": 323, - "test/no-quoted-tilde-assignments.test.ts": 31, - "test/no-stale-gstack-brain-refs.test.ts": 354, - "test/no-suicide-exit.test.ts": 98, - "test/office-hours-attempt.test.ts": 39337, - "test/office-hours-budget.test.ts": 35, - "test/office-hours-completion.test.ts": 140, - "test/office-hours-open-question-form.test.ts": 30, - "test/office-hours-phase4-caller.test.ts": 38, - "test/office-hours-review.test.ts": 1017, - "test/office-hours-writeback-env.test.ts": 471, - "test/office-posture-recording.test.ts": 53, - "test/onboarding-moved-literals.test.ts": 41, + "test/jsonl-merge.test.ts": 314, + "test/jsonl-store.test.ts": 14, + "test/judge-calibration.test.ts": 45, + "test/judge-panel-median.test.ts": 28, + "test/land-and-deploy-ci-gate.test.ts": 3161, + "test/land-and-deploy-command-trigger.test.ts": 11, + "test/land-and-deploy-flow.test.ts": 660, + "test/land-and-deploy-postfail.test.ts": 14, + "test/lane-coordination.test.ts": 1839, + "test/learnings-callers-unavailable.test.ts": 1418, + "test/learnings-injection.test.ts": 12, + "test/learnings.test.ts": 5358, + "test/llm-judge-abort.test.ts": 28, + "test/llm-judge-frontier.test.ts": 107, + "test/llm-judge-stream.test.ts": 35, + "test/llms-txt-shape.test.ts": 28, + "test/maintenance-cli-args.test.ts": 176, + "test/memorable-user-prompt-hook.test.ts": 11489, + "test/memory-cache-injection.test.ts": 282, + "test/memory-ingest-include-gitignored.test.ts": 59, + "test/memory-ingest-landing.test.ts": 1745, + "test/memory-ingest-sources.test.ts": 2691, + "test/memory-ingest-timeout.test.ts": 27, + "test/memory-pipeline.test.ts": 656, + "test/migration-checkpoint-ownership.test.ts": 152, + "test/migrations-v1.27.0.0.test.ts": 827, + "test/migrations-v1.65.0.0.test.ts": 242, + "test/mktemp-portability.test.ts": 81, + "test/model-catalog-isolation.test.ts": 69, + "test/model-overlays.test.ts": 19, + "test/model-policy-cli.test.ts": 3220, + "test/model-policy-freshness.test.ts": 155, + "test/model-policy-workflow.test.ts": 280, + "test/model-policy.test.ts": 70, + "test/model-role-invocation.test.ts": 35711, + "test/module-size-ratchet.test.ts": 185, + "test/native-auto-decide-pty.test.ts": 10148, + "test/native-auto-decide.test.ts": 261, + "test/no-quoted-tilde-assignments.test.ts": 29, + "test/no-stale-gstack-brain-refs.test.ts": 350, + "test/no-suicide-exit.test.ts": 115, + "test/office-hours-attempt.test.ts": 39882, + "test/office-hours-budget.test.ts": 38, + "test/office-hours-completion.test.ts": 128, + "test/office-hours-open-question-form.test.ts": 15, + "test/office-hours-phase4-caller.test.ts": 29, + "test/office-hours-review.test.ts": 997, + "test/office-hours-writeback-env.test.ts": 452, + "test/office-posture-recording.test.ts": 46, + "test/onboarding-moved-literals.test.ts": 40, "test/one-way-doors.test.ts": 11, - "test/open-gstack-browser-liveness.test.ts": 13, - "test/openclaw-native-skills.test.ts": 13, - "test/osv-config-wiring.test.ts": 32, - "test/osv-ignore-expiry.test.ts": 10, - "test/outside-consent.test.ts": 1004, - "test/outside-review-result.test.ts": 789, - "test/outside-review-severity.test.ts": 81, - "test/outside-review-unparsed-severity.test.ts": 145, - "test/outside-runner-contract.test.ts": 734, - "test/outside-send-boundary.test.ts": 349, - "test/outside-voice-evidence.test.ts": 50, - "test/outside-voice-failure-policy.test.ts": 150, - "test/outside-voice-fixture.test.ts": 205, - "test/outside-voice-invocation.test.ts": 8911, - "test/outside-voice-preflight.test.ts": 371, - "test/outside-voice-provenance.test.ts": 1109, - "test/outside-voice-receipt.test.ts": 419, - "test/outside-voice-routing.test.ts": 1202, - "test/overlay-lifecycle.test.ts": 314, - "test/overlay-measurement.test.ts": 272, - "test/overlay-recording-order.test.ts": 26, - "test/overlay-sdk-cancel-eof.test.ts": 118, - "test/owner-brief-contributor-banned.test.ts": 469, - "test/paid-free-boundary.test.ts": 2404, - "test/paid-orphan-tripwire.test.ts": 88, - "test/paid-overlay-scheduling.test.ts": 521, - "test/paid-pr-profile.test.ts": 1441, - "test/paid-report-census.test.ts": 188, - "test/paid-report-fail-open.test.ts": 1328, - "test/paid-retry-supervision.test.ts": 1123, - "test/paid-run-manifest.test.ts": 1635, - "test/paid-selection-propagation.test.ts": 61, - "test/paid-shard-settlement.test.ts": 1269, - "test/paid-shards.test.ts": 5942, - "test/paid-slice-deadline.test.ts": 1542, - "test/pair-agent-token-hygiene.test.ts": 12, - "test/parity-baseline-integrity.test.ts": 19, - "test/parity-sectioned.test.ts": 16, - "test/parity-suite.test.ts": 98, - "test/path-spelling.test.ts": 345, - "test/pending-question-completion.test.ts": 108, - "test/periodic-exclude-policy.test.ts": 86, - "test/plan-ceo-floor-interactive-boundary.test.ts": 1207, - "test/plan-count-artifacts.test.ts": 35, - "test/plan-count-checkbox.test.ts": 15261, - "test/plan-count-clipped-elision.test.ts": 54, - "test/plan-count-collection-completion.test.ts": 30092, - "test/plan-count-completion.test.ts": 13883, - "test/plan-count-cropped-wrap.test.ts": 79, - "test/plan-count-cross-cwd-ancestry.test.ts": 119, - "test/plan-count-design-ui-recovery.test.ts": 15722, + "test/open-gstack-browser-liveness.test.ts": 10, + "test/openclaw-native-skills.test.ts": 12, + "test/osv-config-wiring.test.ts": 33, + "test/osv-ignore-expiry.test.ts": 12, + "test/outside-consent.test.ts": 1038, + "test/outside-review-result.test.ts": 674, + "test/outside-review-severity.test.ts": 68, + "test/outside-review-unparsed-severity.test.ts": 139, + "test/outside-runner-contract.test.ts": 739, + "test/outside-send-boundary.test.ts": 380, + "test/outside-voice-evidence.test.ts": 44, + "test/outside-voice-failure-policy.test.ts": 121, + "test/outside-voice-fixture.test.ts": 142, + "test/outside-voice-invocation.test.ts": 9113, + "test/outside-voice-native-deadline.test.ts": 41, + "test/outside-voice-preflight.test.ts": 405, + "test/outside-voice-provenance.test.ts": 1103, + "test/outside-voice-receipt.test.ts": 358, + "test/outside-voice-routing.test.ts": 1110, + "test/overlay-lifecycle.test.ts": 341, + "test/overlay-measurement.test.ts": 283, + "test/overlay-recording-order.test.ts": 24, + "test/overlay-sdk-cancel-eof.test.ts": 137, + "test/owner-brief-contributor-banned.test.ts": 462, + "test/paid-free-boundary.test.ts": 2384, + "test/paid-orphan-tripwire.test.ts": 86, + "test/paid-overlay-scheduling.test.ts": 406, + "test/paid-pr-profile.test.ts": 1429, + "test/paid-report-census.test.ts": 139, + "test/paid-report-fail-open.test.ts": 1208, + "test/paid-retry-supervision.test.ts": 1091, + "test/paid-run-manifest.test.ts": 1630, + "test/paid-selection-propagation.test.ts": 63, + "test/paid-shard-settlement.test.ts": 1274, + "test/paid-shards.test.ts": 6029, + "test/paid-slice-deadline.test.ts": 1599, + "test/pair-agent-token-hygiene.test.ts": 11, + "test/parity-baseline-integrity.test.ts": 20, + "test/parity-sectioned.test.ts": 15, + "test/parity-suite.test.ts": 102, + "test/path-spelling.test.ts": 325, + "test/pending-question-completion.test.ts": 114, + "test/periodic-exclude-policy.test.ts": 88, + "test/plan-ceo-floor-interactive-boundary.test.ts": 1273, + "test/plan-count-artifacts.test.ts": 43, + "test/plan-count-checkbox.test.ts": 15295, + "test/plan-count-clipped-elision.test.ts": 60, + "test/plan-count-collection-completion.test.ts": 30506, + "test/plan-count-completion.test.ts": 13994, + "test/plan-count-cropped-wrap.test.ts": 123, + "test/plan-count-cross-cwd-ancestry.test.ts": 141, + "test/plan-count-design-ui-recovery.test.ts": 15966, "test/plan-count-dx-handoff.test.ts": 77, - "test/plan-count-empty-review.test.ts": 1507, - "test/plan-count-file-permission.test.ts": 44625, - "test/plan-count-fixture.test.ts": 14941, - "test/plan-count-history.test.ts": 694, - "test/plan-count-long-edit.test.ts": 37, - "test/plan-count-native-input.test.ts": 11526, - "test/plan-count-owned-permission.test.ts": 11302, - "test/plan-count-pending-exit.test.ts": 228, - "test/plan-count-prerequisite.test.ts": 42, - "test/plan-count-preview-footer.test.ts": 3451, + "test/plan-count-empty-review.test.ts": 1450, + "test/plan-count-file-permission.test.ts": 44707, + "test/plan-count-fixture.test.ts": 15071, + "test/plan-count-history.test.ts": 711, + "test/plan-count-long-edit.test.ts": 38, + "test/plan-count-native-input.test.ts": 11607, + "test/plan-count-owned-permission.test.ts": 11344, + "test/plan-count-pending-exit.test.ts": 296, + "test/plan-count-prerequisite.test.ts": 45, + "test/plan-count-preview-footer.test.ts": 3458, "test/plan-count-session-cwd.test.ts": 66, - "test/plan-count-timeout.test.ts": 9435, - "test/plan-count-transcript.test.ts": 57, - "test/plan-count-truncated-border.test.ts": 39, + "test/plan-count-timeout.test.ts": 9464, + "test/plan-count-transcript.test.ts": 58, + "test/plan-count-truncated-border.test.ts": 48, "test/plan-count-truncated-question.test.ts": 36, - "test/plan-create-combined-permission.test.ts": 92, + "test/plan-create-combined-permission.test.ts": 91, "test/plan-create-permission.test.ts": 55, - "test/plan-create-prepublication.test.ts": 91, - "test/plan-design-floor-fixture.test.ts": 227, - "test/plan-design-sdk-fixture.test.ts": 424, - "test/plan-design-with-ui-fixture.test.ts": 1433, - "test/plan-edit-cropped-permission.test.ts": 100, + "test/plan-create-prepublication.test.ts": 84, + "test/plan-design-floor-fixture.test.ts": 199, + "test/plan-design-sdk-fixture.test.ts": 470, + "test/plan-design-with-ui-fixture.test.ts": 1604, + "test/plan-edit-cropped-permission.test.ts": 113, "test/plan-eng-resume.test.ts": 13, "test/plan-floor-dx-actor.test.ts": 74, - "test/plan-floor-edit-wrap.test.ts": 50, - "test/plan-floor-permission.test.ts": 1548, - "test/plan-floor-review.test.ts": 34, - "test/plan-floor-target.test.ts": 12502, - "test/plan-format-approach-prompt.test.ts": 9, - "test/plan-format-kind-note.test.ts": 14, - "test/plan-mode-evidence.test.ts": 720, - "test/plan-pending-question-pty.test.ts": 417, - "test/plan-reality.test.ts": 325, - "test/plan-review-board-feedback.test.ts": 4268, - "test/plan-review-calibration.test.ts": 331, - "test/plan-review-cases.test.ts": 1020, - "test/plan-review-decisions.test.ts": 277, - "test/plan-review-report-recording.test.ts": 5394, - "test/plan-scope-selection.test.ts": 2729, - "test/plan-seed-submission.test.ts": 54219, - "test/plan-skill-question-events.test.ts": 2175, - "test/plan-skill-question-hook-scope.test.ts": 3003, - "test/plan-skill-questions.test.ts": 15836, - "test/plan-skill-read-permission.test.ts": 42, - "test/plan-skill-webfetch-permission.test.ts": 1164, - "test/plan-tune-cathedral.test.ts": 609, - "test/plan-tune-gates.test.ts": 1102, - "test/plan-tune.test.ts": 1274, + "test/plan-floor-edit-wrap.test.ts": 48, + "test/plan-floor-permission.test.ts": 1660, + "test/plan-floor-review.test.ts": 32, + "test/plan-floor-target.test.ts": 12508, + "test/plan-format-approach-prompt.test.ts": 18, + "test/plan-format-kind-note.test.ts": 12, + "test/plan-mode-evidence.test.ts": 798, + "test/plan-pending-question-pty.test.ts": 509, + "test/plan-reality.test.ts": 386, + "test/plan-review-board-feedback.test.ts": 4290, + "test/plan-review-calibration.test.ts": 320, + "test/plan-review-cases.test.ts": 1046, + "test/plan-review-decisions.test.ts": 272, + "test/plan-review-report-recording.test.ts": 5405, + "test/plan-scope-selection.test.ts": 2745, + "test/plan-seed-submission.test.ts": 53872, + "test/plan-skill-question-events.test.ts": 2626, + "test/plan-skill-question-hook-scope.test.ts": 3480, + "test/plan-skill-questions.test.ts": 16397, + "test/plan-skill-read-permission.test.ts": 71, + "test/plan-skill-webfetch-permission.test.ts": 1293, + "test/plan-tune-cathedral.test.ts": 672, + "test/plan-tune-gates.test.ts": 1178, + "test/plan-tune.test.ts": 1324, "test/platform-qualification-workflow.test.ts": 10, - "test/post-rename-doc-regen.test.ts": 21, - "test/pr-dependencies.test.ts": 2026, - "test/pr-direct-cases.test.ts": 2049, - "test/pr-shared-input-selection.test.ts": 737, - "test/pr-title-rewrite.test.ts": 118, + "test/post-rename-doc-regen.test.ts": 22, + "test/pr-dependencies.test.ts": 2792, + "test/pr-direct-cases.test.ts": 2038, + "test/pr-shared-input-selection.test.ts": 772, + "test/pr-title-rewrite.test.ts": 116, "test/pr-title-sync-workflow-safety.test.ts": 11, - "test/preamble-compose.test.ts": 17, - "test/preamble-first-task-scaffold.test.ts": 760, - "test/pregate-guards.test.ts": 4463, - "test/pregate-invalidation.test.ts": 3533, - "test/pregate-regate.test.ts": 9630, - "test/pregate-selection.test.ts": 6068, - "test/pricing-eval-plan.test.ts": 1121, - "test/prompt-audit-manifest.test.ts": 315, - "test/prosons-neutral-posture.test.ts": 13, - "test/provider-model-defaults.test.ts": 284, - "test/pty-askuserquestion-single-line.test.ts": 32, - "test/pty-numbered-option-indent-native.test.ts": 43, - "test/pty-option-selection.test.ts": 593, - "test/pty-output-wake.test.ts": 10731, - "test/pty-screen-session.test.ts": 8883, - "test/pty-screen-supervision.test.ts": 10487, - "test/pty-screen-unicode-ap.test.ts": 114, - "test/pty-screen.test.ts": 101, - "test/pty-skill-seeding-wiring.test.ts": 471, - "test/pty-trust-dialog.test.ts": 3058, - "test/pty-upgrade-isolation.test.ts": 765, - "test/pty-workspace-trust.test.ts": 366, - "test/published-text.test.ts": 22, - "test/qa-browser-deadline-evidence.test.ts": 3875, - "test/qa-browser-preservation.test.ts": 1496, - "test/qa-bugs-fixture.test.ts": 16, - "test/qa-caller-authority.test.ts": 75, - "test/qa-caller-freshness-order.test.ts": 42, - "test/qa-caller-report-observer.test.ts": 125, - "test/qa-checkpoint-evidence.test.ts": 75, - "test/qa-deadline-publication-observer.test.ts": 267, - "test/qa-deadline-selection.test.ts": 41, - "test/qa-deadline.test.ts": 19474, - "test/qa-evidence-producer.test.ts": 8730, - "test/qa-evidence-selection.test.ts": 63, - "test/qa-evidence.test.ts": 10210, - "test/qa-exploratory-callers.test.ts": 13918, - "test/qa-fix-loop-fixture.test.ts": 2035, - "test/qa-functional-evidence.test.ts": 4595, - "test/qa-functional-fixture.test.ts": 946, - "test/qa-functional-observer-atomic.test.ts": 450, - "test/qa-functional-observer.test.ts": 1037, - "test/qa-functional-prompt.test.ts": 901, - "test/qa-health-rubric.test.ts": 14, - "test/qa-lazy-sections.test.ts": 9380, - "test/qa-only-browser-probe.test.ts": 759, - "test/qa-only-capability.test.ts": 1581, - "test/qa-only-cleanup.test.ts": 7810, - "test/qa-only-fixture.test.ts": 11208, - "test/qa-probe-gates.test.ts": 49, - "test/qa-report-fields.test.ts": 12, - "test/qa-supervision-selection.test.ts": 32, - "test/question-log-hook.test.ts": 1479, - "test/question-preference-hook.test.ts": 2613, - "test/question-tuning-registry-path.test.ts": 13, - "test/recover-receipts.test.ts": 177, - "test/redact-audit-log.test.ts": 50, - "test/redact-context-exemptions.test.ts": 33, - "test/redact-doc-resolver.test.ts": 21, - "test/redact-dotenv-filename-false-positive.test.ts": 14, - "test/redact-engine-autoredact.test.ts": 15, - "test/redact-engine.test.ts": 86, - "test/redact-parcel-id-false-positive.test.ts": 16, - "test/redact-pattern-lint.test.ts": 20, - "test/redact-prepush-emails.test.ts": 15524, - "test/redact-prepush-hook.test.ts": 3820, - "test/redact-prepush-rebase-force-push.test.ts": 721, - "test/redact-prepush-scan-range.test.ts": 1346, - "test/redact-prepush-target.test.ts": 9300, - "test/redact-span-binding.test.ts": 38, - "test/redact-unicode-offsets.test.ts": 67, + "test/preamble-compose.test.ts": 16, + "test/preamble-first-task-scaffold.test.ts": 1822, + "test/pregate-docs-lane-review.test.ts": 2119, + "test/pregate-guards.test.ts": 6930, + "test/pregate-import-graph-paths.test.ts": 2060, + "test/pregate-invalidation.test.ts": 4593, + "test/pregate-manifest-paths.test.ts": 650, + "test/pregate-regate.test.ts": 9394, + "test/pregate-remote-gbrain.test.ts": 852, + "test/pregate-remote.test.ts": 3561, + "test/pregate-secrets-source-context.test.ts": 904, + "test/pregate-selection.test.ts": 8149, + "test/pregate-supervise.test.ts": 29119, + "test/pregate-timing.test.ts": 1574, + "test/pricing-eval-plan.test.ts": 1135, + "test/prompt-audit-manifest.test.ts": 259, + "test/prosons-neutral-posture.test.ts": 11, + "test/provider-model-defaults.test.ts": 246, + "test/pty-askuserquestion-single-line.test.ts": 31, + "test/pty-numbered-option-indent-native.test.ts": 42, + "test/pty-option-selection.test.ts": 594, + "test/pty-output-wake.test.ts": 10763, + "test/pty-screen-session.test.ts": 8855, + "test/pty-screen-supervision.test.ts": 10434, + "test/pty-screen-unicode-ap.test.ts": 115, + "test/pty-screen.test.ts": 141, + "test/pty-skill-seeding-wiring.test.ts": 463, + "test/pty-trust-dialog.test.ts": 3060, + "test/pty-upgrade-isolation.test.ts": 859, + "test/pty-workspace-trust.test.ts": 363, + "test/published-text.test.ts": 21, + "test/qa-browser-deadline-evidence.test.ts": 4066, + "test/qa-browser-preservation.test.ts": 1431, + "test/qa-bugs-fixture.test.ts": 17, + "test/qa-caller-authority.test.ts": 82, + "test/qa-caller-freshness-order.test.ts": 63, + "test/qa-caller-report-observer.test.ts": 159, + "test/qa-checkpoint-evidence.test.ts": 100, + "test/qa-deadline-publication-observer.test.ts": 258, + "test/qa-deadline-selection.test.ts": 29, + "test/qa-deadline.test.ts": 19447, + "test/qa-evidence-producer.test.ts": 9186, + "test/qa-evidence-selection.test.ts": 60, + "test/qa-evidence.test.ts": 10282, + "test/qa-exploratory-callers.test.ts": 13744, + "test/qa-fix-loop-fixture.test.ts": 2414, + "test/qa-functional-evidence.test.ts": 4831, + "test/qa-functional-fixture.test.ts": 882, + "test/qa-functional-observer-atomic.test.ts": 454, + "test/qa-functional-observer.test.ts": 1127, + "test/qa-functional-prompt.test.ts": 944, + "test/qa-health-rubric.test.ts": 13, + "test/qa-lazy-sections.test.ts": 9027, + "test/qa-only-browser-probe.test.ts": 751, + "test/qa-only-capability.test.ts": 1478, + "test/qa-only-cleanup.test.ts": 7773, + "test/qa-only-fixture.test.ts": 10410, + "test/qa-probe-gates.test.ts": 48, + "test/qa-report-fields.test.ts": 24, + "test/qa-supervision-selection.test.ts": 29, + "test/question-log-hook.test.ts": 1454, + "test/question-preference-hook.test.ts": 2748, + "test/question-tuning-registry-path.test.ts": 14, + "test/readme-skill-lists.test.ts": 18, + "test/recover-receipts.test.ts": 695, + "test/redact-audit-log.test.ts": 33, + "test/redact-context-exemptions.test.ts": 30, + "test/redact-doc-resolver.test.ts": 23, + "test/redact-dotenv-filename-false-positive.test.ts": 15, + "test/redact-engine-autoredact.test.ts": 14, + "test/redact-engine.test.ts": 82, + "test/redact-parcel-id-false-positive.test.ts": 15, + "test/redact-pattern-lint.test.ts": 19, + "test/redact-prepush-emails.test.ts": 14736, + "test/redact-prepush-hook.test.ts": 3766, + "test/redact-prepush-rebase-force-push.test.ts": 1065, + "test/redact-prepush-scan-range.test.ts": 1884, + "test/redact-prepush-target.test.ts": 8369, + "test/redact-span-binding.test.ts": 52, + "test/redact-unicode-offsets.test.ts": 65, "test/regression-1539-review-self-verify.test.ts": 14, - "test/regression-1611-gbrain-sync-resume.test.ts": 30, + "test/regression-1611-gbrain-sync-resume.test.ts": 34, "test/regression-1624-retro-stale-base.test.ts": 12, "test/regression-1834-retro-recommendations.test.ts": 10, - "test/regression-2922-memory-ingest-sources.test.ts": 605, - "test/regression-dot-leading-slug.test.ts": 99, - "test/regression-issue2091-bsd-mktemp.test.ts": 178, - "test/regression-issue3024-zsh-sourced-helpers.test.ts": 1239, - "test/regression-pr1169-build-app-sed.test.ts": 63, - "test/regression-pr1169-mktemp-fallbacks.test.ts": 37, - "test/regression-transcript-frontmatter-fence.test.ts": 28, - "test/regression-transcript-slug-collision.test.ts": 51, - "test/relink-disabled-router.test.ts": 859, - "test/relink.test.ts": 10148, - "test/remote-identity-vectors.test.ts": 671, - "test/render-sections-provenance.test.ts": 332, - "test/replay-pr-selection.test.ts": 712, + "test/regression-2922-memory-ingest-sources.test.ts": 530, + "test/regression-dot-leading-slug.test.ts": 111, + "test/regression-issue2091-bsd-mktemp.test.ts": 166, + "test/regression-issue3024-zsh-sourced-helpers.test.ts": 1143, + "test/regression-pr1169-build-app-sed.test.ts": 56, + "test/regression-pr1169-mktemp-fallbacks.test.ts": 36, + "test/regression-transcript-frontmatter-fence.test.ts": 24, + "test/regression-transcript-slug-collision.test.ts": 24, + "test/relink-disabled-router.test.ts": 846, + "test/relink.test.ts": 9618, + "test/remote-identity-vectors.test.ts": 572, + "test/render-sections-provenance.test.ts": 278, + "test/replay-pr-selection.test.ts": 754, "test/resolver-ask-user-format.test.ts": 25, - "test/resolvers-gbrain-put-rewrite.test.ts": 33, - "test/resolvers-gbrain-save-results.test.ts": 15, - "test/restamp-command-boundary.test.ts": 4040, - "test/retired-commands.test.ts": 34, - "test/review-army-budget.test.ts": 1652, - "test/review-base-refresh.test.ts": 140, - "test/review-checklists.test.ts": 21, + "test/resolvers-gbrain-put-rewrite.test.ts": 24, + "test/resolvers-gbrain-save-results.test.ts": 17, + "test/restamp-command-boundary.test.ts": 3674, + "test/restamp-gate-ahead-changelog.test.ts": 2122, + "test/retired-commands.test.ts": 22, + "test/review-army-budget.test.ts": 1879, + "test/review-base-refresh.test.ts": 116, + "test/review-checklists.test.ts": 22, "test/review-consensus-lifecycle.test.ts": 30, - "test/review-count-markdown.test.ts": 97, - "test/review-entry-and-design-clarity-au.test.ts": 90, + "test/review-count-markdown.test.ts": 95, + "test/review-entry-and-design-clarity-au.test.ts": 50, "test/review-enum-lifecycle.test.ts": 27, - "test/review-finalization-budget.test.ts": 2568, - "test/review-log-findings.test.ts": 5932, - "test/review-log.test.ts": 3338, - "test/review-n-plus-one-contract.test.ts": 689, - "test/review-quality-provenance.test.ts": 37, - "test/review-start-evidence.test.ts": 22686, - "test/review-workflow-clarity.test.ts": 58, - "test/review-workflow-fixture.test.ts": 31, - "test/router-disabled-skills.test.ts": 692, - "test/routing-probe.test.ts": 23, - "test/run-in-background-guidance.test.ts": 2088, - "test/run-shard-child.test.ts": 1252, - "test/runtime-pins.test.ts": 72, - "test/runtime-root-assets.test.ts": 1849, - "test/safety-rule-registry.test.ts": 33, - "test/salience-allowlist.test.ts": 23, - "test/sandbox-doctor-shell.test.ts": 14, - "test/schema-version-migration.test.ts": 52, - "test/sealed-guard.test.ts": 2229, - "test/secret-sink-harness.test.ts": 51, - "test/section-capture-native-tools.test.ts": 3876, - "test/section-manifest-consistency.test.ts": 20, - "test/security-dashboard-fallback.test.ts": 1473, - "test/session-runner-browse-errors.test.ts": 784, - "test/session-runner-groupkill.test.ts": 4125, - "test/session-runner-startup-grace.test.ts": 13091, - "test/session-runner-stream-lifecycle.test.ts": 265, - "test/session-runner-timeout.test.ts": 3026, - "test/session-runner-tools.test.ts": 5279, - "test/session-update-autostash.test.ts": 5169, - "test/session-update-hook-hold.test.ts": 3156, - "test/session-update-stages.test.ts": 4257, - "test/setup-alias-name-uniqueness.test.ts": 1642, - "test/setup-browser-hint.test.ts": 41, - "test/setup-bun-cmd-and-pipe-bugs.test.ts": 33, - "test/setup-bun-floor.test.ts": 196, - "test/setup-claude-code-migration.test.ts": 16522, - "test/setup-claude-skill-assets.test.ts": 1133, - "test/setup-cleanup-orphans.test.ts": 161, - "test/setup-codesign-restore.test.ts": 381, - "test/setup-codesign.test.ts": 21, - "test/setup-codex-design-pdf-runtime.test.ts": 167, - "test/setup-codex-model.test.ts": 34, - "test/setup-codex-scope-migrations.test.ts": 34163, - "test/setup-codex-scope-namespaces.test.ts": 56588, - "test/setup-codex-scope-review-boundaries.test.ts": 51854, - "test/setup-codex-scope.test.ts": 60385, - "test/setup-conductor-auq-hook.test.ts": 22213, - "test/setup-conductor-worktree.test.ts": 35, - "test/setup-crlf-repair.test.ts": 244, - "test/setup-cso-degrade.test.ts": 179, - "test/setup-cso-windows-probe.test.ts": 45, - "test/setup-deploy-key-presence.test.ts": 16, + "test/review-finalization-budget.test.ts": 2506, + "test/review-log-findings.test.ts": 4910, + "test/review-log.test.ts": 2689, + "test/review-n-plus-one-contract.test.ts": 605, + "test/review-quality-provenance.test.ts": 38, + "test/review-start-evidence.test.ts": 21394, + "test/review-workflow-clarity.test.ts": 37, + "test/review-workflow-fixture.test.ts": 23, + "test/router-disabled-skills.test.ts": 564, + "test/routing-probe.test.ts": 22, + "test/run-in-background-guidance.test.ts": 1797, + "test/run-shard-child.test.ts": 1232, + "test/runtime-pins.test.ts": 61, + "test/runtime-root-assets.test.ts": 1538, + "test/safety-rule-registry.test.ts": 30, + "test/salience-allowlist.test.ts": 25, + "test/sandbox-doctor-shell.test.ts": 16, + "test/sanitize-echo.test.ts": 319, + "test/schema-version-migration.test.ts": 59, + "test/script-invocation-tripwire.test.ts": 1271, + "test/script-invocation.test.ts": 232, + "test/sealed-guard.test.ts": 2152, + "test/secret-sink-harness.test.ts": 47, + "test/section-capture-native-tools.test.ts": 3810, + "test/section-manifest-consistency.test.ts": 18, + "test/security-dashboard-fallback.test.ts": 1320, + "test/session-runner-browse-errors.test.ts": 778, + "test/session-runner-groupkill.test.ts": 4090, + "test/session-runner-startup-grace.test.ts": 13087, + "test/session-runner-stream-lifecycle.test.ts": 262, + "test/session-runner-timeout.test.ts": 3027, + "test/session-runner-tools.test.ts": 5121, + "test/session-update-autostash.test.ts": 11251, + "test/session-update-heartbeat.test.ts": 257, + "test/session-update-held-banner.test.ts": 1639, + "test/session-update-hook-hold.test.ts": 5260, + "test/session-update-stages.test.ts": 5384, + "test/setup-alias-name-uniqueness.test.ts": 1311, + "test/setup-browser-hint.test.ts": 43, + "test/setup-bun-cmd-and-pipe-bugs.test.ts": 26, + "test/setup-bun-floor.test.ts": 182, + "test/setup-claude-code-migration.test.ts": 15950, + "test/setup-claude-skill-assets.test.ts": 954, + "test/setup-cleanup-orphans.test.ts": 168, + "test/setup-codesign-restore.test.ts": 290, + "test/setup-codesign.test.ts": 19, + "test/setup-codex-design-pdf-runtime.test.ts": 112, + "test/setup-codex-model.test.ts": 12, + "test/setup-codex-scope-migrations.test.ts": 32725, + "test/setup-codex-scope-namespaces.test.ts": 54477, + "test/setup-codex-scope-review-boundaries.test.ts": 49800, + "test/setup-codex-scope.test.ts": 58903, + "test/setup-conductor-auq-hook.test.ts": 21509, + "test/setup-conductor-worktree.test.ts": 29, + "test/setup-crlf-repair.test.ts": 241, + "test/setup-cso-degrade.test.ts": 169, + "test/setup-cso-windows-probe.test.ts": 44, + "test/setup-cursor-legacy-skills.test.ts": 4340, + "test/setup-deploy-key-presence.test.ts": 15, "test/setup-deploy-not-deployed.test.ts": 10, - "test/setup-deploy-vercel-trigger.test.ts": 11, - "test/setup-emoji-font.test.ts": 59, - "test/setup-gbrain-bin-invocation-paths.test.ts": 12, - "test/setup-gbrain-fixture.test.ts": 2363, - "test/setup-gbrain-path4-caller.test.ts": 2659, - "test/setup-gbrain-path4-structure.test.ts": 15, - "test/setup-gbrain-remote-caller.test.ts": 8779, - "test/setup-gbrain-windows-mcp.test.ts": 67, - "test/setup-help.test.ts": 62, - "test/setup-hook-canonical-paths.test.ts": 22, - "test/setup-hook-syntax-gate.test.ts": 8637, - "test/setup-install-registry.test.ts": 82095, - "test/setup-kiro-native.test.ts": 677, - "test/setup-link-ownership.test.ts": 738, - "test/setup-needs-build.test.ts": 290, - "test/setup-plan-tune-hooks-noninteractive.test.ts": 499, - "test/setup-playwright-best-effort.test.ts": 17826, - "test/setup-playwright-platform.test.ts": 5145, - "test/setup-prune-stale-generated.test.ts": 154, - "test/setup-ps1.test.ts": 86, - "test/setup-runtime-lib-command.test.ts": 13993, - "test/setup-runtime-root-guard.test.ts": 16555, - "test/setup-sections-linking.test.ts": 13, - "test/setup-skill-copies.test.ts": 390, - "test/setup-staged-copy.test.ts": 51, - "test/setup-timeline-hook-gate.test.ts": 339, - "test/setup-windows-fallback.test.ts": 52, - "test/setup-windows-launch-hint.test.ts": 255, - "test/setup-windows-rerun-refresh.test.ts": 235, - "test/shard-cli-parity.test.ts": 109, - "test/shard-engine-equivalence.test.ts": 3108, - "test/shard-engine.test.ts": 3680, - "test/shared-libs-cancellation.test.ts": 107, - "test/shared-libs-checker-interface-evidence.test.ts": 55245, - "test/shared-libs-evidence.test.ts": 21, - "test/shared-libs-fixture.test.ts": 8454, - "test/shared-libs-plan-actor.test.ts": 112, - "test/shared-libs-rendering.test.ts": 1261, - "test/shared-libs-revalidation-prompt.test.ts": 14020, - "test/shared-libs-review-start-evidence.test.ts": 3967, - "test/shared-libs-snapshot-check.test.ts": 34383, - "test/shared-libs-source-reads.test.ts": 1425, - "test/shared-libs-stage-actor.test.ts": 121031, - "test/ship-apple-gate.test.ts": 18, - "test/ship-control-flow.test.ts": 237, - "test/ship-coverage-audit-af.test.ts": 57, - "test/ship-document-release-dispatch.test.ts": 4850, - "test/ship-greptile-early.test.ts": 14, - "test/ship-greptile-pr-check.test.ts": 78, - "test/ship-hook-actor.test.ts": 2099, - "test/ship-hook-refresh.test.ts": 2830, - "test/ship-hook-windows-paths.test.ts": 370, - "test/ship-issue-intent.test.ts": 707, - "test/ship-measure-bar.test.ts": 66, + "test/setup-deploy-vercel-trigger.test.ts": 10, + "test/setup-emoji-font.test.ts": 65, + "test/setup-gbrain-bin-invocation-paths.test.ts": 14, + "test/setup-gbrain-fixture.test.ts": 2386, + "test/setup-gbrain-path4-caller.test.ts": 2564, + "test/setup-gbrain-path4-structure.test.ts": 12, + "test/setup-gbrain-remote-caller.test.ts": 8895, + "test/setup-gbrain-windows-mcp.test.ts": 155, + "test/setup-help.test.ts": 58, + "test/setup-hook-canonical-paths.test.ts": 39, + "test/setup-hook-syntax-gate.test.ts": 8335, + "test/setup-install-registry.test.ts": 86484, + "test/setup-kiro-native.test.ts": 575, + "test/setup-link-ownership.test.ts": 718, + "test/setup-needs-build.test.ts": 254, + "test/setup-plan-tune-hooks-noninteractive.test.ts": 439, + "test/setup-playwright-best-effort.test.ts": 19882, + "test/setup-playwright-platform.test.ts": 5076, + "test/setup-prune-stale-generated.test.ts": 210, + "test/setup-ps1.test.ts": 15, + "test/setup-runtime-lib-command.test.ts": 13833, + "test/setup-runtime-root-guard.test.ts": 16604, + "test/setup-sections-linking.test.ts": 14, + "test/setup-skill-copies.test.ts": 410, + "test/setup-staged-copy.test.ts": 55, + "test/setup-timeline-hook-gate.test.ts": 355, + "test/setup-windows-fallback.test.ts": 42, + "test/setup-windows-launch-hint.test.ts": 155, + "test/setup-windows-rerun-refresh.test.ts": 142, + "test/shard-cli-parity.test.ts": 87, + "test/shard-engine-equivalence.test.ts": 3137, + "test/shard-engine.test.ts": 3709, + "test/shared-libs-cancellation.test.ts": 113, + "test/shared-libs-checker-interface-evidence.test.ts": 55560, + "test/shared-libs-evidence.test.ts": 24, + "test/shared-libs-fixture.test.ts": 8339, + "test/shared-libs-plan-actor.test.ts": 61, + "test/shared-libs-rendering.test.ts": 1139, + "test/shared-libs-revalidation-prompt.test.ts": 13480, + "test/shared-libs-review-start-evidence.test.ts": 3820, + "test/shared-libs-snapshot-check.test.ts": 32403, + "test/shared-libs-source-reads.test.ts": 1347, + "test/shared-libs-stage-actor.test.ts": 127424, + "test/ship-apple-gate.test.ts": 16, + "test/ship-control-flow.test.ts": 299, + "test/ship-coverage-audit-af.test.ts": 59, + "test/ship-document-release-dispatch.test.ts": 4781, + "test/ship-greptile-early.test.ts": 13, + "test/ship-greptile-pr-check.test.ts": 81, + "test/ship-hook-actor.test.ts": 2041, + "test/ship-hook-refresh.test.ts": 2588, + "test/ship-hook-windows-paths.test.ts": 386, + "test/ship-issue-intent.test.ts": 3730, + "test/ship-measure-bar.test.ts": 47, "test/ship-measure-loop-skill.test.ts": 13, - "test/ship-measure-seeded-fixture.test.ts": 1254, - "test/ship-measure-sweep.test.ts": 621, - "test/ship-measure.test.ts": 2141, - "test/ship-plan-completion-invariants.test.ts": 1363, + "test/ship-measure-seeded-fixture.test.ts": 1314, + "test/ship-measure-sweep.test.ts": 916, + "test/ship-measure.test.ts": 2175, + "test/ship-plan-completion-invariants.test.ts": 1161, + "test/ship-policy-compat.test.ts": 462, "test/ship-pr-liveness-policy.test.ts": 14, - "test/ship-publication-gates.test.ts": 680, - "test/ship-reentry-gates.test.ts": 25, + "test/ship-publication-gates.test.ts": 550, + "test/ship-reentry-gates.test.ts": 23, "test/ship-review-loop.test.ts": 22, - "test/ship-section-fixture.test.ts": 364, - "test/ship-skip-actor.test.ts": 33403, - "test/ship-skip-requeue.test.ts": 33, - "test/ship-skip-selection.test.ts": 840, - "test/ship-template-redaction.test.ts": 18, - "test/ship-test-detection-markers.test.ts": 170, - "test/ship-triage-labels.test.ts": 13, - "test/ship-version-sync.test.ts": 650, - "test/ship-workflow-clarity.test.ts": 52, - "test/shortcut-debt-ledger.test.ts": 20, + "test/ship-section-fixture.test.ts": 360, + "test/ship-skip-actor.test.ts": 32083, + "test/ship-skip-requeue.test.ts": 31, + "test/ship-skip-selection.test.ts": 897, + "test/ship-template-redaction.test.ts": 24, + "test/ship-test-detection-markers.test.ts": 153, + "test/ship-triage-labels.test.ts": 17, + "test/ship-version-sync.test.ts": 546, + "test/ship-workflow-clarity.test.ts": 49, + "test/shortcut-debt-ledger.test.ts": 19, "test/sideways-review.test.ts": 13, - "test/skill-browse-state-extraction.test.ts": 27, - "test/skill-budget-regression.test.ts": 39, - "test/skill-census.test.ts": 27, - "test/skill-ceo-section-ordering.test.ts": 2191, - "test/skill-check-driver.test.ts": 112, - "test/skill-collision-sentinel.test.ts": 19, - "test/skill-coverage-floor.test.ts": 70, - "test/skill-cross-model-recommendation-emit.test.ts": 31, - "test/skill-fixture.test.ts": 51, - "test/skill-parser.test.ts": 33, - "test/skill-positional-literals.test.ts": 1195, + "test/skill-browse-state-extraction.test.ts": 22, + "test/skill-budget-regression.test.ts": 41, + "test/skill-census.test.ts": 24, + "test/skill-ceo-section-ordering.test.ts": 2222, + "test/skill-check-driver.test.ts": 98, + "test/skill-collision-sentinel.test.ts": 16, + "test/skill-coverage-floor.test.ts": 51, + "test/skill-cross-model-recommendation-emit.test.ts": 24, + "test/skill-end-completion-durability.test.ts": 8482, + "test/skill-fixture.test.ts": 52, + "test/skill-parser.test.ts": 26, + "test/skill-positional-literals.test.ts": 1081, "test/skill-preflight-budget.test.ts": 16, - "test/skill-size-budget.test.ts": 473, - "test/skill-validation.test.ts": 1125, - "test/skillify-host-paths.test.ts": 1013, - "test/slop-diff-cli.test.ts": 342, - "test/sol-skill-fixture.test.ts": 811, - "test/spawned-consent-rule.test.ts": 21, - "test/spawnsync-timeout-tripwire.test.ts": 183, - "test/spec-quality-gate-secret-sink.test.ts": 1706, - "test/spec-template-invariants.test.ts": 27, - "test/spend-ledger.test.ts": 118, - "test/stamp-templates.test.ts": 491, - "test/state-root-config-merge.test.ts": 937, - "test/state-root-one-variable.test.ts": 4563, - "test/state-root-parity.test.ts": 199, - "test/state-root-ratchet.test.ts": 316, - "test/state-root-resolver-failure.test.ts": 33, - "test/static-no-legacy-writes.test.ts": 1085, - "test/strict-output-capture.test.ts": 88, - "test/strict-output-formats.test.ts": 832, - "test/strict-output-settlement.test.ts": 4340, - "test/strict-output.test.ts": 19, - "test/sync-gbrain-code-scope.test.ts": 119, - "test/sync-gbrain-cycle-freshness.test.ts": 86, - "test/sync-gbrain-readiness-fixture.test.ts": 129, - "test/sync-gbrain-source-probe.test.ts": 525, - "test/takes-fence-fallback.test.ts": 17, - "test/tasks-section-jq.test.ts": 24, - "test/taste-engine.test.ts": 869, - "test/team-init-hook-shell-neutral.test.ts": 120, - "test/team-mode.test.ts": 2060, - "test/telemetry-repo-strip.test.ts": 33, - "test/telemetry.test.ts": 7450, - "test/template-context-parity.test.ts": 13, - "test/terse-build.test.ts": 18, - "test/test-free-shards-capture.test.ts": 1244, - "test/test-free-shards-git-maintenance.test.ts": 155, - "test/test-free-shards-sandbox-knobs.test.ts": 119, - "test/test-free-shards-settlement-lifecycle.test.ts": 45902, - "test/test-free-shards-settlement-ownership.test.ts": 37525, - "test/test-free-shards.test.ts": 9838, - "test/test-health-report.test.ts": 264, - "test/test-health-workflow.test.ts": 12, - "test/test-of-test-ratchet.test.ts": 172, - "test/test-pr-profile.test.ts": 40, - "test/test-value-bar.test.ts": 103, - "test/testing-internals-anchors.test.ts": 708, - "test/third-party-actions-recording.test.ts": 111, - "test/third-party-actions.test.ts": 264, - "test/timeline-stop-hook-slug.test.ts": 4374, - "test/timeline-stop-hook.test.ts": 564, - "test/timeline.test.ts": 11905, - "test/touchfiles-facade.test.ts": 21, - "test/touchfiles-map-diff.test.ts": 167, - "test/touchfiles.test.ts": 1114, - "test/tracker-guard-wiring.test.ts": 48, - "test/tracker-guard.test.ts": 160, - "test/transcript-consent.test.ts": 985, - "test/transcript-gate-values.test.ts": 1393, - "test/transcript-scope-brain-sync.test.ts": 4558, - "test/transcript-scope-ingest.test.ts": 783, - "test/tree-receipt-stamp-sensitive.test.ts": 10129, - "test/trial-cause.test.ts": 979, - "test/troubleshooting-anchors.test.ts": 1314, - "test/troubleshooting-windows-recovery.test.ts": 13, - "test/typecheck-test-ratchet.test.ts": 34, - "test/ubicloud-runner.test.ts": 2556, - "test/uninstall-windows-copies.test.ts": 1819, - "test/uninstall.test.ts": 5563, - "test/update-check-crash-sentinel.test.ts": 633, - "test/upgrade-migration-v1.test.ts": 46, - "test/upgrade-setup-recovery.test.ts": 380, - "test/upgrade-template-pins.test.ts": 10, - "test/user-render-out-dir-install.test.ts": 172, - "test/user-slug-fallback.test.ts": 677, - "test/v0-dormancy.test.ts": 32, - "test/verify-gate.test.ts": 2066, - "test/version-source.test.ts": 12, - "test/voice-directive.test.ts": 32, - "test/windows-free-selection-autoplan-guard.test.ts": 26, - "test/windows-native-workflows.test.ts": 238, - "test/workflow-action-pins.test.ts": 18, - "test/workflow-boundaries-fixture.test.ts": 2830, - "test/workflow-concurrency.test.ts": 15, - "test/workflow-excerpt.test.ts": 112, - "test/workflow-judge-cache.test.ts": 2117, - "test/workflow-judge-input.test.ts": 51, - "test/workflow-required-steps.test.ts": 24, - "test/worktree-isolated-shapes.test.ts": 30, - "test/worktree.test.ts": 608, - "test/writing-style-resolver.test.ts": 18 + "test/skill-size-budget.test.ts": 463, + "test/skill-validation.test.ts": 1085, + "test/skillify-host-paths.test.ts": 1103, + "test/slop-diff-cli.test.ts": 340, + "test/sol-skill-fixture.test.ts": 822, + "test/spawned-consent-rule.test.ts": 25, + "test/spawnsync-timeout-tripwire.test.ts": 176, + "test/spec-quality-gate-secret-sink.test.ts": 1571, + "test/spec-template-invariants.test.ts": 19, + "test/spend-ledger.test.ts": 127, + "test/stamp-templates.test.ts": 439, + "test/state-matrix.test.ts": 975, + "test/state-root-config-merge.test.ts": 1117, + "test/state-root-one-variable.test.ts": 4741, + "test/state-root-parity.test.ts": 172, + "test/state-root-ratchet.test.ts": 325, + "test/state-root-resolver-failure.test.ts": 31, + "test/static-no-legacy-writes.test.ts": 1097, + "test/strict-output-capture.test.ts": 85, + "test/strict-output-formats.test.ts": 781, + "test/strict-output-settlement.test.ts": 4273, + "test/strict-output.test.ts": 16, + "test/sync-gbrain-code-scope.test.ts": 108, + "test/sync-gbrain-cycle-freshness.test.ts": 83, + "test/sync-gbrain-readiness-fixture.test.ts": 144, + "test/sync-gbrain-source-probe.test.ts": 496, + "test/takes-fence-fallback.test.ts": 14, + "test/tasks-section-jq.test.ts": 26, + "test/taste-engine.test.ts": 775, + "test/team-init-hook-shell-neutral.test.ts": 108, + "test/team-mode.test.ts": 2001, + "test/telemetry-repo-strip.test.ts": 29, + "test/telemetry.test.ts": 7181, + "test/template-context-parity.test.ts": 16, + "test/terse-build.test.ts": 22, + "test/test-free-shards-capture.test.ts": 1242, + "test/test-free-shards-git-maintenance.test.ts": 125, + "test/test-free-shards-sandbox-knobs.test.ts": 97, + "test/test-free-shards-settlement-lifecycle.test.ts": 46203, + "test/test-free-shards-settlement-ownership.test.ts": 37739, + "test/test-free-shards.test.ts": 9725, + "test/test-health-report.test.ts": 249, + "test/test-health-workflow.test.ts": 11, + "test/test-of-test-ratchet.test.ts": 181, + "test/test-pr-profile.test.ts": 43, + "test/test-value-bar.test.ts": 93, + "test/testing-internals-anchors.test.ts": 711, + "test/third-party-actions-recording.test.ts": 108, + "test/third-party-actions.test.ts": 254, + "test/timeline-stop-hook-slug.test.ts": 4382, + "test/timeline-stop-hook.test.ts": 536, + "test/timeline.test.ts": 11030, + "test/touchfiles-facade.test.ts": 20, + "test/touchfiles-map-diff.test.ts": 152, + "test/touchfiles.test.ts": 1064, + "test/tracker-guard-wiring.test.ts": 46, + "test/tracker-guard.test.ts": 198, + "test/transcript-consent.test.ts": 967, + "test/transcript-gate-values.test.ts": 1478, + "test/transcript-scope-brain-sync.test.ts": 4537, + "test/transcript-scope-ingest.test.ts": 886, + "test/tree-receipt-gbrain-pair.test.ts": 809, + "test/tree-receipt-stamp-sensitive.test.ts": 9714, + "test/trial-cause.test.ts": 985, + "test/troubleshooting-anchors.test.ts": 1306, + "test/troubleshooting-windows-recovery.test.ts": 14, + "test/typecheck-test-ratchet.test.ts": 36, + "test/ubicloud-runner.test.ts": 2533, + "test/uninstall-windows-copies.test.ts": 1740, + "test/uninstall.test.ts": 5543, + "test/update-check-crash-sentinel.test.ts": 610, + "test/update-check-main-moved.test.ts": 3617, + "test/upgrade-migration-v1.test.ts": 38, + "test/upgrade-setup-recovery.test.ts": 444, + "test/upgrade-template-pins.test.ts": 11, + "test/user-render-out-dir-install.test.ts": 128, + "test/user-slug-fallback.test.ts": 644, + "test/v0-dormancy.test.ts": 31, + "test/verify-gate.test.ts": 1994, + "test/version-source.test.ts": 13, + "test/voice-directive.test.ts": 85, + "test/windows-free-selection-autoplan-guard.test.ts": 31, + "test/windows-native-workflows.test.ts": 243, + "test/workflow-action-pins.test.ts": 20, + "test/workflow-boundaries-fixture.test.ts": 2673, + "test/workflow-concurrency.test.ts": 13, + "test/workflow-excerpt.test.ts": 103, + "test/workflow-judge-cache.test.ts": 1780, + "test/workflow-judge-input.test.ts": 50, + "test/workflow-required-steps.test.ts": 25, + "test/worktree-isolated-shapes.test.ts": 33, + "test/worktree.test.ts": 510, + "test/writing-style-resolver.test.ts": 17, + "test/wtree-consumers.test.ts": 1013 } } diff --git a/scripts/free-test-seed-allowlist.json b/scripts/free-test-seed-allowlist.json index 1b4c032ea..4af44717a 100644 --- a/scripts/free-test-seed-allowlist.json +++ b/scripts/free-test-seed-allowlist.json @@ -3,7 +3,6 @@ {"file": "test/host-conformance.test.ts", "reason": "real ./setup per host and layout; the time is setup's own skill-linking loop, not fixture copies (shared fixture landed in W6c)"}, {"file": "test/shared-libs-stage-actor.test.ts", "reason": "re-runs the paid shared-libs runner body against git fixture repos per test; owned by the paid-harness value-bar review"}, {"file": "test/setup-install-registry.test.ts", "reason": "82s in the 2026-10-15 recording (58s on 2026-10-04): 11 cases each run the real ./setup, gstack-relink, gstack-config and gstack-uninstall against throwaway checkouts", "todo": "split by describe block so the packer can balance it, then rerun bun run test:ubicloud --record-durations (TODOS.md, fix wave 2 follow-ups)"}, - {"file": "test/host-renders-prune.test.ts", "reason": "64s in the 2026-10-15 recording (unseeded before): every case runs a real ./setup or the gstack-upgrade migration over host render dirs", "todo": "split by describe block so the packer can balance it, then rerun bun run test:ubicloud --record-durations (TODOS.md, fix wave 2 follow-ups)"}, - {"file": "test/setup-codex-scope.test.ts", "reason": "60.4s in the 2026-10-15 recording (48s on 2026-10-04): Codex install scope through the real ./setup", "todo": "split by describe block so the packer can balance it, then rerun bun run test:ubicloud --record-durations (TODOS.md, fix wave 2 follow-ups)"} + {"file": "test/host-renders-prune.test.ts", "reason": "64s in the 2026-10-15 recording (unseeded before): every case runs a real ./setup or the gstack-upgrade migration over host render dirs", "todo": "split by describe block so the packer can balance it, then rerun bun run test:ubicloud --record-durations (TODOS.md, fix wave 2 follow-ups)"} ] } From eca247e99a3b86642e907cdd11c309f8afe624e2 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 16 Oct 2026 22:35:01 -0700 Subject: [PATCH 3/8] v1.91.120.0 test: split the doctor windows bash test so each case fits the Windows per-test timeout (#3241) * test: split the doctor windows bash test so each case fits the Windows per-test timeout Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(changelog): doctor windows bash test split entry Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore(release): stamp v1.91.120.0 Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- CHANGELOG.md | 11 +++++++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- package.json | 2 +- test/gstack-doctor.test.ts | 10 +++++++++- 5 files changed, 23 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 805415a3b..c1b75a4c6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [1.91.120.0] - 2026-10-17 + +**The Windows doctor test no longer times out.** The `windows bash` test from v1.91.117.0 ran five full `gstack-doctor` passes in one test. Each pass takes up to about 6 s on a Windows runner, so the test took 20 to 30 s against the 30 s per-test limit, and it timed out on one pull request run. + +### Fixed +- **The `windows bash` doctor test is three tests, one per case,** each with its own fixture and at most two doctor passes. All 13 assertions are unchanged, and no timeout was raised. +- **The `EBUSY` cleanup error that followed the timeout** came from the timeout itself. On a timeout, Bun kills the bash child the test is waiting on, but the doctor's own `bun` and `git` subprocesses keep running and hold the fixture directory open on Windows. With every test well inside the limit, nothing is killed mid-run. + +### If you… +- **…add cases to a test that shells out to `gstack-doctor`:** give each case its own test. A full doctor pass costs seconds on Windows, and a test killed at its timeout leaves orphaned children that lock its temp directory. + ## [1.91.119.0] - 2026-10-17 **The weekly health check's seed check passes again.** 54 free test files had landed since the 2026-10-15 recording, so CEO-10 in `bun run test:health` failed and CI packed those files at the 99th-percentile guess (#3224). diff --git a/VERSION b/VERSION index 00430b049..acab04bef 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.119.0 +1.91.120.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 0b558c8a9..dd98117a9 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.119.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.120.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/package.json b/package.json index 94cdfacbe..8aecddc95 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.119", + "version": "1.91.120", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/test/gstack-doctor.test.ts b/test/gstack-doctor.test.ts index ec1d0cc83..f8852f7c4 100644 --- a/test/gstack-doctor.test.ts +++ b/test/gstack-doctor.test.ts @@ -1027,16 +1027,24 @@ describe('gstack-doctor: rescue refs, CLAUDE.md skill lists, Windows bash', () = const probe = (f: Fixture, inputs: Record) => { const file = path.join(f.base, 'bash-probe.json'); write(file, JSON.stringify(inputs)); return file; }; const GIT_BASH = 'C:/Program Files/Git/bin/bash.exe'; - test('windows bash: on Windows the row names the resolved bash and what chose it; a refusal fails with BASH_UNAVAILABLE naming GSTACK_GIT_BASH; off Windows there is no row', () => { + test('windows bash: on Windows the row names the resolved bash and what chose it', () => { const f = makeFixture(); const found = doctor(f, [], { GSTACK_DOCTOR_PLATFORM: 'windows', GSTACK_DOCTOR_BASH_PROBE: probe(f, { exists: [GIT_BASH], gitExecPath: 'C:/Program Files/Git/mingw64/libexec/git-core' }) }); expect(found.row('windows bash'), found.out).toEqual({ state: 'ok', detail: `${GIT_BASH} (chosen by git --exec-path)`, fix: '' }); const override = doctor(f, [], { GSTACK_DOCTOR_PLATFORM: 'windows', GSTACK_GIT_BASH: 'D:\\tools\\bash.exe', GSTACK_DOCTOR_BASH_PROBE: probe(f, { exists: ['D:/tools/bash.exe', GIT_BASH] }) }); expect(override.row('windows bash').detail).toBe('D:/tools/bash.exe (chosen by GSTACK_GIT_BASH)'); + }); + + test('windows bash: GSTACK_GIT_BASH and a different deprecated GSTACK_BASH warn naming both', () => { + const f = makeFixture(); const differ = doctor(f, [], { GSTACK_DOCTOR_PLATFORM: 'windows', GSTACK_GIT_BASH: 'D:/a/bash.exe', GSTACK_BASH: 'D:/b/bash.exe', GSTACK_DOCTOR_BASH_PROBE: probe(f, { exists: ['D:/a/bash.exe', 'D:/b/bash.exe'] }) }); expect(differ.row('windows bash').state).toBe('warn'); expect(differ.row('windows bash').detail).toContain('D:/a/bash.exe (chosen by GSTACK_GIT_BASH)'); expect(differ.row('windows bash').detail).toContain('GSTACK_GIT_BASH (D:/a/bash.exe) and the deprecated GSTACK_BASH (D:/b/bash.exe) differ'); + }); + + test('windows bash: a refusal fails with BASH_UNAVAILABLE naming GSTACK_GIT_BASH; off Windows there is no row', () => { + const f = makeFixture(); const refused = doctor(f, [], { GSTACK_DOCTOR_PLATFORM: 'windows', GSTACK_DOCTOR_BASH_PROBE: probe(f, { exists: [], gitExecPath: null, which: { bash: 'C:/Windows/System32/bash.exe' } }) }); const row = refused.row('windows bash'); expect(row.state, refused.out).toBe('fail'); From d258bcffb0cb7bda5f133f3e957f932d816d282f Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 16 Oct 2026 23:44:32 -0700 Subject: [PATCH 4/8] v1.91.121.0 test(windows-seed): refresh the Windows duration seed from real windows-latest timings (#3243) * fix(windows-seed): record slow Windows files in full instead of at the 6-minute deadline The first Windows recording on eca247e99 (run 39008249142) killed test/gstack-doctor.test.ts at the 360 s per-file deadline and would have seeded it at 360 s, although it takes about 484 s on Windows. --record-durations now honors an explicit --wall-timeout as its per-file deadline, and the windows-record-durations job passes --wall-timeout 1200 (inside its 30-minute job limit). The shard job's 15-minute timeout and the shard count are unchanged. The recording job also uploads its full per-file logs, so a file that fails while recording (browse/test/cookie-import-native-job.test.ts did in that run) can be diagnosed. Intentional pin change: test/windows-native-workflows.test.ts now expects the --wall-timeout 1200 recording command and the log upload step. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test(windows-seed): refresh the Windows free-suite duration seed from a windows-latest recording Recorded by the windows-record-durations job (run 39009112245, recorder exit 0, no failed or timed-out files) at 31150049, with the full per-file deadline: 638 -> 738 durations (106 added, 6 removed). test/gstack-doctor.test.ts 392 s and test/hook-scripts.test.ts 135 s were unseeded; browse/test/cookie-import-native-job.test.ts 99 s -> 118 s. With the new seed the six-shard plan isolates gstack-doctor in its own shard (392 s predicted) and puts the other two in separate shards (265 s each), where the old seed packed cookie-import-native-job into a 121-file shard. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs(changelog): Windows seed refresh entry Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore(release): stamp v1.91.121.0 Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- .github/workflows/windows-free-tests.yml | 12 +- CHANGELOG.md | 11 + VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- package.json | 2 +- scripts/free-test-durations-windows.json | 1374 ++++++++++++---------- scripts/test-free-shards.ts | 14 +- test/test-free-shards.test.ts | 7 + test/windows-native-workflows.test.ts | 5 +- 9 files changed, 784 insertions(+), 645 deletions(-) diff --git a/.github/workflows/windows-free-tests.yml b/.github/workflows/windows-free-tests.yml index 824ccfc48..5d7775a52 100644 --- a/.github/workflows/windows-free-tests.yml +++ b/.github/workflows/windows-free-tests.yml @@ -235,11 +235,21 @@ jobs: env: TEMP: ${{ runner.temp }} TMP: ${{ runner.temp }} - run: bun run test:windows --record-durations + run: bun run test:windows --record-durations --wall-timeout 1200 - name: Name the recording as the Windows seed if: always() shell: bash run: cp scripts/free-test-durations.json "$RUNNER_TEMP/free-test-durations-windows.json" + - name: Upload full recording logs + if: always() + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 + with: + name: windows-record-durations-logs + path: | + .context/free-test-logs/gstack-free-test-*.log + ${{ runner.temp }}/gstack-free-test-*.log + include-hidden-files: true + if-no-files-found: ignore - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 if: always() with: diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b75a4c6..79fc1201d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [1.91.121.0] - 2026-10-17 + +**Windows free-test shards stop running out of time on files the Windows seed didn't know.** The Windows duration seed dated from 2026-10-04 and had no entry for `test/gstack-doctor.test.ts` (about 6.5 minutes on Windows) or `test/hook-scripts.test.ts`. The packer guessed, put `cookie-import-native-job` into a 121-file shard, and that shard hit the 15-minute job limit. + +### Fixed +- **Windows duration seed refreshed from a real `windows-latest` recording.** `scripts/free-test-durations-windows.json` goes from 638 to 738 entries. The six-shard plan now gives `gstack-doctor` a shard of its own and puts the other slow files in separate shards. The shard job's timeout and shard count are unchanged. +- **`--record-durations` honors `--wall-timeout`.** The recorder used to kill any file at 360 s and record that deadline as its duration. The Windows recording job now passes `--wall-timeout 1200` and uploads its full per-file logs. + +### If you… +- **…refresh the Windows seed:** run `gh workflow run windows-free-tests.yml --ref -f record_durations=true`, check that the job exited 0, then commit the `free-test-durations-windows` artifact. A file that fails while recording now leaves its log in `windows-record-durations-logs`. + ## [1.91.120.0] - 2026-10-17 **The Windows doctor test no longer times out.** The `windows bash` test from v1.91.117.0 ran five full `gstack-doctor` passes in one test. Each pass takes up to about 6 s on a Windows runner, so the test took 20 to 30 s against the 30 s per-test limit, and it timed out on one pull request run. diff --git a/VERSION b/VERSION index acab04bef..f3edfab61 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.120.0 +1.91.121.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index dd98117a9..f39a93c46 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.120.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.121.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/package.json b/package.json index 8aecddc95..aa46790a8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.120", + "version": "1.91.121", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/scripts/free-test-durations-windows.json b/scripts/free-test-durations-windows.json index 6f8db34ec..8f2bc3798 100644 --- a/scripts/free-test-durations-windows.json +++ b/scripts/free-test-durations-windows.json @@ -1,644 +1,744 @@ { "version": 1, - "recordedAt": "2026-10-04T19:14:06.352Z", + "recordedAt": "2026-10-17T06:23:07.787Z", "durations": { - "browse/test/activity.test.ts": 128, - "browse/test/adversarial-security.test.ts": 85, - "browse/test/batch.test.ts": 6404, - "browse/test/bridge-chromium-e2e.test.ts": 3673, - "browse/test/browse-client.test.ts": 189, - "browse/test/browse-eval-wrapping.test.ts": 89, - "browse/test/browser-manager-custom-chromium.test.ts": 1005, - "browse/test/browser-skills-storage.test.ts": 179, - "browse/test/build-command-response.test.ts": 981, - "browse/test/build.test.ts": 160, - "browse/test/bun-polyfill.test.ts": 2455, - "browse/test/busy-daemon-iron-rule.test.ts": 7811, - "browse/test/busy-daemon-recovery.test.ts": 779, - "browse/test/cdp-allowlist.test.ts": 40, - "browse/test/cdp-e2e.test.ts": 1134, - "browse/test/cdp-inspector-history-cap.test.ts": 109, - "browse/test/cdp-mutex.test.ts": 841, - "browse/test/cdp-session-cleanup.test.ts": 62, - "browse/test/claude-bin.test.ts": 51, - "browse/test/cli-lock.test.ts": 81, - "browse/test/cli-loopback-no-proxy.test.ts": 66, - "browse/test/cli-setsid-daemonize.test.ts": 61, - "browse/test/cli-start-final-healthcheck.test.ts": 49, - "browse/test/cli-supervisor.test.ts": 91, - "browse/test/content-security.test.ts": 1659, - "browse/test/cookie-auth-verification.test.ts": 19136, - "browse/test/cookie-credential-deadline.test.ts": 371, - "browse/test/cookie-database.test.ts": 675, - "browse/test/cookie-fixture-delete-lease.test.ts": 1305, - "browse/test/cookie-import-browser.test.ts": 105, - "browse/test/cookie-import-native-job.test.ts": 99288, - "browse/test/cookie-import-native.test.ts": 7321, - "browse/test/cookie-import-node.test.ts": 4376, - "browse/test/cookie-import-operation.test.ts": 1784, - "browse/test/cookie-import-reliability.test.ts": 1231, - "browse/test/cookie-import-transport.test.ts": 55, - "browse/test/cookie-picker-binding-browser.test.ts": 3233, - "browse/test/cookie-picker-binding.test.ts": 725, - "browse/test/cookie-picker-csrf-browser.test.ts": 1163, - "browse/test/cookie-picker-routes.test.ts": 601, - "browse/test/cookie-picker-ui.test.ts": 40992, - "browse/test/daemon-log-hygiene.test.ts": 113, - "browse/test/daemon-mismatch-refuse.test.ts": 325, - "browse/test/data-platform.test.ts": 158, - "browse/test/domain-skills-e2e.test.ts": 1063, - "browse/test/domain-skills-storage.test.ts": 140, - "browse/test/dotenv-isolation.test.ts": 498, - "browse/test/dual-listener.test.ts": 1057, - "browse/test/dx-polish.test.ts": 54, - "browse/test/error-handling.test.ts": 46, - "browse/test/extension-sender-auth.test.ts": 76, - "browse/test/extension-token.test.ts": 1710, - "browse/test/file-drop.test.ts": 53, - "browse/test/file-permissions.test.ts": 512, - "browse/test/fill-change-event.test.ts": 2056, - "browse/test/find-browse.test.ts": 126, - "browse/test/from-file-path-validation.test.ts": 68, - "browse/test/handoff.test.ts": 7769, - "browse/test/headless-gpu-and-reap.test.ts": 639, - "browse/test/headless-launch-options.test.ts": 1235, - "browse/test/launch-signal-flags.test.ts": 57, - "browse/test/learnings-injection.test.ts": 2308, - "browse/test/media-extract-unit.test.ts": 135, - "browse/test/memory-command.test.ts": 1273, - "browse/test/memory-leak-reproducer.test.ts": 490, - "browse/test/navigation-guard.test.ts": 9998, - "browse/test/output-path-symlinks.test.ts": 106, - "browse/test/pair-agent-optin-gate.test.ts": 868, - "browse/test/pdf-flags.test.ts": 63, - "browse/test/playwright-core-patch.test.ts": 53, - "browse/test/poisoned-bundle-probe.test.ts": 524, - "browse/test/process-liveness-windows.test.ts": 189, - "browse/test/proxy-config.test.ts": 63, - "browse/test/proxy-redact.test.ts": 39, - "browse/test/pty-inject-scan.test.ts": 1455, - "browse/test/pty-session-lease.test.ts": 78, - "browse/test/rebrand-signed-bundle.test.ts": 59, - "browse/test/regression-pr1169-pdf-from-file-invalid-json.test.ts": 79, - "browse/test/restart-env.test.ts": 62, - "browse/test/sanitize.test.ts": 40, - "browse/test/screenshot-size-guard.test.ts": 382, - "browse/test/security-adversarial-fixes.test.ts": 78, - "browse/test/security-adversarial.test.ts": 62, + "browse/test/activity.test.ts": 78, + "browse/test/adversarial-security.test.ts": 41, + "browse/test/batch.test.ts": 5919, + "browse/test/bridge-chromium-e2e.test.ts": 4106, + "browse/test/browse-client.test.ts": 291, + "browse/test/browse-eval-wrapping.test.ts": 150, + "browse/test/browser-manager-custom-chromium.test.ts": 620, + "browse/test/browser-skills-storage.test.ts": 115, + "browse/test/build-command-response.test.ts": 704, + "browse/test/build.test.ts": 111, + "browse/test/bun-child-config.test.ts": 67, + "browse/test/bun-polyfill.test.ts": 1473, + "browse/test/busy-daemon-iron-rule.test.ts": 7808, + "browse/test/busy-daemon-recovery.test.ts": 600, + "browse/test/cdp-allowlist.test.ts": 50, + "browse/test/cdp-e2e.test.ts": 1315, + "browse/test/cdp-inspector-history-cap.test.ts": 34, + "browse/test/cdp-mutex.test.ts": 817, + "browse/test/cdp-session-cleanup.test.ts": 52, + "browse/test/claude-bin.test.ts": 31, + "browse/test/cli-chain-stdin.test.ts": 153, + "browse/test/cli-config-mismatch-message.test.ts": 86, + "browse/test/cli-lock.test.ts": 49, + "browse/test/cli-loopback-no-proxy.test.ts": 39, + "browse/test/cli-setsid-daemonize.test.ts": 25, + "browse/test/cli-start-final-healthcheck.test.ts": 37, + "browse/test/cli-supervisor.test.ts": 52, + "browse/test/content-security.test.ts": 1229, + "browse/test/cookie-auth-verification.test.ts": 14212, + "browse/test/cookie-credential-deadline.test.ts": 230, + "browse/test/cookie-database.test.ts": 451, + "browse/test/cookie-fixture-delete-lease.test.ts": 1124, + "browse/test/cookie-import-browser.test.ts": 74, + "browse/test/cookie-import-native-job.test.ts": 118070, + "browse/test/cookie-import-native.test.ts": 4727, + "browse/test/cookie-import-node.test.ts": 4003, + "browse/test/cookie-import-operation.test.ts": 441, + "browse/test/cookie-import-reliability.test.ts": 1230, + "browse/test/cookie-import-transport.test.ts": 38, + "browse/test/cookie-picker-binding-browser.test.ts": 2699, + "browse/test/cookie-picker-binding.test.ts": 359, + "browse/test/cookie-picker-csrf-browser.test.ts": 695, + "browse/test/cookie-picker-routes.test.ts": 369, + "browse/test/cookie-picker-ui.test.ts": 33245, + "browse/test/daemon-log-hygiene.test.ts": 208, + "browse/test/daemon-mismatch-refuse.test.ts": 228, + "browse/test/data-platform.test.ts": 56, + "browse/test/domain-skills-e2e.test.ts": 546, + "browse/test/domain-skills-storage.test.ts": 84, + "browse/test/dotenv-isolation.test.ts": 555, + "browse/test/dual-listener.test.ts": 615, + "browse/test/dx-polish.test.ts": 51, + "browse/test/error-handling.test.ts": 35, + "browse/test/extension-sender-auth.test.ts": 69, + "browse/test/extension-token.test.ts": 1570, + "browse/test/file-drop.test.ts": 59, + "browse/test/file-permissions.test.ts": 896, + "browse/test/fill-change-event.test.ts": 2053, + "browse/test/find-browse.test.ts": 205, + "browse/test/from-file-path-validation.test.ts": 75, + "browse/test/handoff.test.ts": 5180, + "browse/test/headless-gpu-and-reap.test.ts": 558, + "browse/test/headless-launch-options.test.ts": 326, + "browse/test/launch-signal-flags.test.ts": 85, + "browse/test/learnings-injection.test.ts": 1372, + "browse/test/media-extract-unit.test.ts": 82, + "browse/test/memory-command.test.ts": 502, + "browse/test/memory-leak-reproducer.test.ts": 500, + "browse/test/navigation-guard.test.ts": 3054, + "browse/test/output-path-symlinks.test.ts": 32, + "browse/test/pair-agent-optin-gate.test.ts": 387, + "browse/test/path-security-realpath.test.ts": 437, + "browse/test/pdf-flags.test.ts": 32, + "browse/test/playwright-core-patch.test.ts": 27, + "browse/test/poisoned-bundle-probe.test.ts": 250, + "browse/test/process-liveness-windows.test.ts": 182, + "browse/test/proxy-config.test.ts": 56, + "browse/test/proxy-env-daemon.test.ts": 64, + "browse/test/proxy-env.test.ts": 48, + "browse/test/proxy-redact.test.ts": 34, + "browse/test/pty-inject-scan.test.ts": 773, + "browse/test/pty-session-lease.test.ts": 36, + "browse/test/rebrand-signed-bundle.test.ts": 31, + "browse/test/regression-pr1169-pdf-from-file-invalid-json.test.ts": 56, + "browse/test/restart-env.test.ts": 35, + "browse/test/runtime-root-server-bundle.test.ts": 48, + "browse/test/sanitize.test.ts": 30, + "browse/test/screenshot-size-guard.test.ts": 260, + "browse/test/security-adversarial-fixes.test.ts": 41, + "browse/test/security-adversarial.test.ts": 54, "browse/test/security-bench.test.ts": 52, - "browse/test/security-classifier-download-cleanup.test.ts": 59, - "browse/test/security-classifier.test.ts": 42, - "browse/test/security-integration.test.ts": 44, - "browse/test/security-live-playwright.test.ts": 1037, - "browse/test/security-sidecar-client.test.ts": 85, - "browse/test/security.test.ts": 73, - "browse/test/server-auth.test.ts": 725, - "browse/test/server-factory.test.ts": 2959, - "browse/test/server-flush-trackers.test.ts": 62, - "browse/test/server-launch-resolution.test.ts": 97, - "browse/test/server-lock-errors.test.ts": 110, - "browse/test/server-no-import-side-effects.test.ts": 679, - "browse/test/server-pty-lease-routes.test.ts": 636, - "browse/test/server-route-auth-blackbox.test.ts": 2355, - "browse/test/server-route-dispatch-ratchet.test.ts": 574, - "browse/test/server-sanitize-surrogates.test.ts": 675, - "browse/test/server-tmp-state-path.test.ts": 56, - "browse/test/session-cookie-store.test.ts": 81, - "browse/test/sidebar-tabs.test.ts": 749, - "browse/test/sidebar-ux.test.ts": 693, - "browse/test/sidepanel-patient-autoconnect.test.ts": 59, - "browse/test/sidepanel-reattach.test.ts": 89, - "browse/test/sidepanel-restart-dispose.test.ts": 63, - "browse/test/skill-token.test.ts": 61, - "browse/test/socks-bridge.test.ts": 604, - "browse/test/sse-helpers.test.ts": 201, - "browse/test/sse-session-cookie.test.ts": 58, - "browse/test/state-ttl.test.ts": 49, - "browse/test/stealth-extended.test.ts": 47, - "browse/test/stealth-layer-c.test.ts": 56, - "browse/test/stealth-webdriver.test.ts": 9862, - "browse/test/stop-ack-before-shutdown.test.ts": 184, - "browse/test/stop-dead-daemon.test.ts": 484, - "browse/test/tab-each.test.ts": 111, - "browse/test/tab-guardrail.test.ts": 681, - "browse/test/tab-isolation.test.ts": 718, - "browse/test/tab-session-frame-detach.test.ts": 63, - "browse/test/telemetry-optout.test.ts": 198, - "browse/test/telemetry.test.ts": 287, - "browse/test/temp-dirs.test.ts": 144, - "browse/test/terminal-agent-detach-reattach.test.ts": 71, - "browse/test/terminal-agent-import.test.ts": 4581, - "browse/test/terminal-agent-keepalive.test.ts": 59, - "browse/test/terminal-agent-native-observation.test.ts": 82, - "browse/test/terminal-agent-owner-watchdog.test.ts": 3255, - "browse/test/terminal-agent-pid-identity.test.ts": 167, - "browse/test/terminal-agent-port-range.test.ts": 79, - "browse/test/terminal-agent-ring-buffer-runtime.test.ts": 77, - "browse/test/terminal-agent-session-routing.test.ts": 49, - "browse/test/terminal-agent-watchdog.test.ts": 49, - "browse/test/terminal-agent.test.ts": 728, - "browse/test/terminal-pty-lifecycle.test.ts": 43, - "browse/test/token-registry.test.ts": 59, - "browse/test/tunnel-gate-unit.test.ts": 650, - "browse/test/watch.test.ts": 590, - "browse/test/welcome-page.test.ts": 95, - "browse/test/windows-spawn-hide.test.ts": 116, - "browse/test/xprotect-heal.test.ts": 452, - "browser-skills/hackernews-frontpage/script.test.ts": 63, - "design/test/brief.test.ts": 46, - "design/test/cli-persistence.test.ts": 7156, - "design/test/cli-version.test.ts": 90, - "design/test/feedback-roundtrip-daemon.test.ts": 447, - "design/test/feedback-roundtrip.test.ts": 3442, - "design/test/image-args.test.ts": 104, - "design/test/image-gen-pairing.test.ts": 45, - "design/test/receipted-fetch.test.ts": 62, - "ios-qa/daemon/test/allowlist.test.ts": 53, - "ios-qa/daemon/test/audit.test.ts": 49, - "ios-qa/daemon/test/auth-mint.test.ts": 58, - "ios-qa/daemon/test/daemon-integration.test.ts": 445, - "ios-qa/daemon/test/proxy-classify.test.ts": 63, - "ios-qa/daemon/test/proxy-transport.test.ts": 1876, - "ios-qa/daemon/test/session-tokens.test.ts": 52, - "ios-qa/daemon/test/single-instance.test.ts": 56, - "ios-qa/daemon/test/tailscale-localapi.test.ts": 75, - "ios-qa/scripts/gen-accessors.test.ts": 173, - "make-pdf/test/asideClient.test.ts": 62, - "make-pdf/test/cli-args.test.ts": 48, - "make-pdf/test/cli-exit-codes.test.ts": 487, - "make-pdf/test/diagram-prepass.test.ts": 162, - "make-pdf/test/e2e/ci-prereqs.test.ts": 47, - "make-pdf/test/e2e/combined-gate.test.ts": 58, - "make-pdf/test/e2e/diagram-gate.test.ts": 59, - "make-pdf/test/e2e/emoji-gate.test.ts": 54, - "make-pdf/test/e2e/format-gate.test.ts": 53, - "make-pdf/test/e2e/landscape-gate.test.ts": 54, - "make-pdf/test/e2e/toc-gate.test.ts": 60, - "make-pdf/test/image-policy.test.ts": 43, - "make-pdf/test/render-offline-sanitize.test.ts": 77, - "make-pdf/test/render.test.ts": 101, - "make-pdf/test/setup-smoke.test.ts": 86, - "make-pdf/test/toc-anchors.test.ts": 71, - "make-pdf/test/toc-pages.test.ts": 91, - "test/agents-digest.test.ts": 57, - "test/analytics.test.ts": 68, - "test/anthropic-preflight.test.ts": 43, - "test/archaeology-lint.test.ts": 2835, - "test/arm-benchmark-selftest.test.ts": 2846, - "test/arm-setup-smoke-workflow.test.ts": 189, - "test/auq-format-always-loaded.test.ts": 111, - "test/auq-native-capture.test.ts": 425, - "test/auq-parallel.test.ts": 30247, - "test/autoplan-artifact-windows-argv.test.ts": 298, - "test/autoplan-init.test.ts": 2142, - "test/autoplan-method-read-audit.test.ts": 686, - "test/autoplan-owned-state.test.ts": 838, - "test/autoplan-pending-artifact.test.ts": 53, - "test/autoplan-pending-question.test.ts": 4731, - "test/autoplan-phase-handoff.test.ts": 252, - "test/autoplan-phase-observer.test.ts": 83, - "test/autoplan-phase-order.test.ts": 155, - "test/autoplan-public-narration.test.ts": 116, - "test/autoplan-publication-generation.test.ts": 198, - "test/autoplan-publication-guard.test.ts": 6926, - "test/autoplan-publication-hook.test.ts": 7511, - "test/benchmark-runner.test.ts": 66, - "test/binding-template-drift.test.ts": 286, - "test/bootstrap-retention-shard.test.ts": 49, - "test/bootstrap-session-lifecycle.test.ts": 45, - "test/brain-cache-roundtrip.test.ts": 415, - "test/brain-cache-spec.test.ts": 61, - "test/brain-preflight.test.ts": 65, - "test/build-script-shell-compat.test.ts": 43, - "test/bun-subprocess-fd-lifetime.test.ts": 37, - "test/bun-version-drift.test.ts": 55, - "test/cache-concurrent-refresh.test.ts": 95, - "test/carve-guard-completeness.test.ts": 52, - "test/carve-guards-negative.test.ts": 57, - "test/carve-plan-fixture.test.ts": 528, - "test/carve-section-ordering.test.ts": 70, - "test/carve-section-sharding.test.ts": 4092, - "test/catalog-budget.test.ts": 83, - "test/catalog-mode-full.test.ts": 2266, - "test/catalog-trim.test.ts": 187, - "test/ceo-barless-submit.test.ts": 188, - "test/ceo-count-ad-v2.test.ts": 66, - "test/ceo-expansion-auq.test.ts": 175, - "test/ceo-expansion-pacing-native.test.ts": 160, - "test/ceo-hold-posture-review.test.ts": 267, - "test/ceo-mode-expansion-disposition.test.ts": 159, - "test/ceo-mode-labels-native.test.ts": 98, - "test/ceo-mode-option.test.ts": 675, - "test/ceo-mode-pending-submit.test.ts": 103, - "test/ceo-mode-posture-native.test.ts": 116, - "test/ceo-mode-prerequisite.test.ts": 101, - "test/ceo-mode-routing-fixture.test.ts": 5434, - "test/ceo-plan-mode-fixture.test.ts": 3870, - "test/ceo-posture-packet.test.ts": 130, - "test/ceo-section-loading-fixture.test.ts": 636, - "test/ceo-split-collection.test.ts": 761, - "test/ceo-split-question-policy.test.ts": 640, - "test/ceo-stale-fill-decision.test.ts": 142, - "test/ceo-workflow-clarity.test.ts": 69, - "test/changed-files-union.test.ts": 2654, - "test/ci-image-cli-pin.test.ts": 86, - "test/ci-image-tag-binding.test.ts": 55, - "test/ci-paid-coordination.test.ts": 19997, - "test/claude-code-runner.test.ts": 5039, - "test/claude-code-windows-job.test.ts": 3266, - "test/claude-md-size.test.ts": 182, - "test/claude-overlay-models.test.ts": 222, - "test/claude-provider-keychain.test.ts": 383, - "test/codex-carve-fixture.test.ts": 2277, - "test/codex-generation-model.test.ts": 310, - "test/codex-invocation-sites.test.ts": 629, - "test/codex-resume-flag-semantics.test.ts": 79, - "test/conductor-env-shim.test.ts": 51, - "test/context-budget-ratchet.test.ts": 293, - "test/context-remaining-work-provenance.test.ts": 52, - "test/cookie-workflow-judge-input.test.ts": 1403, - "test/cookie-workflow-manual-review.test.ts": 184, - "test/coverage-audit.test.ts": 6141, - "test/cso-bounded-file.test.ts": 69, - "test/cso-docker-policy.test.ts": 86, - "test/cso-git-hardening.test.ts": 87, - "test/cso-history.test.ts": 52, - "test/cso-image-provisioning.test.ts": 287, - "test/cso-lease-identity.test.ts": 369, - "test/cso-node-lifecycle-integration.test.ts": 91, - "test/cso-ntfs-fixture.test.ts": 586, - "test/cso-postgresql-policy.test.ts": 72, - "test/cso-preparation.test.ts": 180, - "test/cso-preserved.test.ts": 66, - "test/cso-public-ghcr.test.ts": 128, - "test/cso-runtime-promotion.test.ts": 90, - "test/cso-scanner-docker-integration.test.ts": 90, - "test/cso-scanners.test.ts": 173, - "test/cso-snapshot-disappearance-race.test.ts": 62, - "test/cso-spec-taxonomy-alignment.test.ts": 54, - "test/cso-stack-cold-integration.test.ts": 90, - "test/cso-verifier.test.ts": 69, - "test/cso-windows-build-contract.test.ts": 70, - "test/declared-annotation.test.ts": 70, - "test/dependency-security.test.ts": 167, - "test/deps-smoke.test.ts": 150, - "test/design-board-reload.test.ts": 328, - "test/design-catalog.test.ts": 118, - "test/design-checklist-sync.test.ts": 1858, - "test/design-completion-handoff-scored.test.ts": 211, - "test/design-consultation-contract.test.ts": 115, - "test/design-daemon-windows-identity.test.ts": 167, - "test/design-detect-contract.test.ts": 280, - "test/design-doc-data-guard.test.ts": 80, - "test/design-flag-utils.test.ts": 179, - "test/design-html-section-completion.test.ts": 8849, - "test/design-md.test.ts": 1644, - "test/design-printed-paths.test.ts": 249, - "test/design-research-fixture.test.ts": 68, - "test/devex-finding-fixture.test.ts": 2226, - "test/devex-peer-comparison-calibration.test.ts": 974, - "test/diagram-render-drift.test.ts": 166, - "test/disabled-dated-record-at.test.ts": 200, - "test/discover-section-templates.test.ts": 67, - "test/docsync-authority.test.ts": 4021, - "test/docsync-child-marker.test.ts": 104, - "test/docsync-lifecycle-interface.test.ts": 730, - "test/document-skills-redaction.test.ts": 108, - "test/dom-dump-hygiene.test.ts": 688, - "test/dx-selected-navigation-ap.test.ts": 220, - "test/e2e-harness-audit.test.ts": 108, - "test/e2e-tier-alignment.test.ts": 393, - "test/eng-batching-current-ledger.test.ts": 534, - "test/eng-batching-native-replay.test.ts": 199, - "test/eng-batching-saved-ledger.test.ts": 1316, - "test/eng-count-question-policy.test.ts": 108, - "test/eng-devex-s-count.test.ts": 134, - "test/eng-finding-retry-budget.test.ts": 2220, - "test/eng-first-review.test.ts": 550, - "test/eng-published-navigation.test.ts": 195, - "test/eng-resolution-block-position.test.ts": 578, - "test/eng-review-routing.test.ts": 95, - "test/eng-seeded-completion-ai.test.ts": 15320, - "test/eng-seeded-coverage.test.ts": 4093, - "test/eng-semantic-terminal.test.ts": 216, - "test/eval-budgets-policy.test.ts": 177, - "test/eval-flake-rank.test.ts": 1456, - "test/eval-kinds.test.ts": 345, - "test/eval-model.test.ts": 74, - "test/evals-workflow-wiring.test.ts": 1679, - "test/exit-propagation.test.ts": 643, - "test/extension-pty-inject-invariant.test.ts": 152, - "test/external-host-carve.test.ts": 5073, - "test/flake-ledger.test.ts": 156, - "test/free-home-guard.test.ts": 107, - "test/free-seed-ratchet.test.ts": 459, - "test/free-tests-workflow-wiring.test.ts": 170, - "test/gbrain-detection-override.test.ts": 1989, - "test/gbrain-exec-invariant.test.ts": 58, - "test/gbrain-guards.test.ts": 96, - "test/gbrain-source-gitignore.test.ts": 83, - "test/gbrain-sources-parse.test.ts": 67, - "test/gbrain-spawn-windows-shell.test.ts": 61, - "test/gbrain-sync-voyage-code-3-integration.test.ts": 86, - "test/gen-skill-docs-checks.test.ts": 27558, - "test/gen-skill-docs-idempotency.test.ts": 4950, - "test/gen-skill-docs-import-purity.test.ts": 257, - "test/gen-skill-docs-prune-stale.test.ts": 1203, - "test/generated-docs-fences.test.ts": 1349, - "test/generator-eexist.test.ts": 667, - "test/git-ref-fixture-tripwire.test.ts": 234, - "test/global-discover.test.ts": 806, - "test/gstack-ci-gate.test.ts": 77, - "test/gstack-config-gbrain-refresh.test.ts": 1528, - "test/gstack-design-detect-plugins.test.ts": 915, - "test/gstack-home-module-scope.test.ts": 194, - "test/gstack-render-cli.test.ts": 852, - "test/gstack-schema-pack.test.ts": 59, - "test/gstack-upgrade-migration-v1_78_0_0.test.ts": 432, - "test/harness-version.test.ts": 318, - "test/helpers-unit.test.ts": 110, - "test/helpers/budget-override.test.ts": 68, - "test/helpers/capture-parity-baseline.test.ts": 397, - "test/helpers/claude-pty-runner.auq.unit.test.ts": 111, - "test/helpers/claude-pty-runner.boundaries.unit.test.ts": 138, - "test/helpers/claude-pty-runner.classify.unit.test.ts": 127, - "test/helpers/claude-pty-runner.launch.unit.test.ts": 62, - "test/helpers/claude-pty-runner.plan-native.unit.test.ts": 101, - "test/helpers/claude-pty-runner.runners.unit.test.ts": 1696, - "test/helpers/claude-pty-runner.scope-gate-floor.unit.test.ts": 105, - "test/helpers/claude-pty-runner.screen.unit.test.ts": 109, - "test/helpers/e2e-gate.unit.test.ts": 62, - "test/helpers/eval-store.test.ts": 2499, - "test/helpers/hermetic-env.test.ts": 15841, - "test/helpers/observability.test.ts": 449, - "test/helpers/providers/gemini.test.ts": 79, - "test/helpers/run-bin.test.ts": 199, - "test/heredoc-pipe-deadlock.test.ts": 629, - "test/instruction-facts.test.ts": 145, - "test/investigate-freeze-path.test.ts": 21734, - "test/ios-debug-bridge-release-guard.test.ts": 80, - "test/ios-qa-daemon-cli.test.ts": 184, - "test/ios-qa-stateserver-hardening.test.ts": 61, - "test/ios-qa-swift-build.test.ts": 75, - "test/ios-qa.test.ts": 357, - "test/is-conductor.test.ts": 57, - "test/jargon-list.test.ts": 79, - "test/judge-calibration.test.ts": 150, - "test/land-and-deploy-flow.test.ts": 15166, - "test/land-and-deploy-postfail.test.ts": 85, - "test/llm-judge-abort.test.ts": 90, - "test/llm-judge-frontier.test.ts": 300, - "test/llm-judge-stream.test.ts": 115, - "test/llms-txt-shape.test.ts": 115, - "test/maintenance-cli-args.test.ts": 538, - "test/memory-ingest-timeout.test.ts": 94, - "test/migration-checkpoint-ownership.test.ts": 2143, - "test/mktemp-portability.test.ts": 806, - "test/model-overlays.test.ts": 95, - "test/module-size-ratchet.test.ts": 278, - "test/native-auto-decide-pty.test.ts": 13309, - "test/native-auto-decide.test.ts": 789, - "test/no-quoted-tilde-assignments.test.ts": 107, - "test/no-suicide-exit.test.ts": 335, - "test/office-hours-budget.test.ts": 145, - "test/office-hours-open-question-form.test.ts": 69, - "test/office-hours-phase4-caller.test.ts": 104, - "test/office-hours-review.test.ts": 1134, - "test/office-posture-recording.test.ts": 124, - "test/one-way-doors.test.ts": 51, - "test/open-gstack-browser-liveness.test.ts": 55, - "test/openclaw-native-skills.test.ts": 51, - "test/osv-config-wiring.test.ts": 52, + "browse/test/security-classifier-download-cleanup.test.ts": 50, + "browse/test/security-classifier.test.ts": 30, + "browse/test/security-integration.test.ts": 36, + "browse/test/security-live-playwright.test.ts": 951, + "browse/test/security-sidecar-client.test.ts": 59, + "browse/test/security.test.ts": 43, + "browse/test/server-auth.test.ts": 508, + "browse/test/server-factory.test.ts": 2024, + "browse/test/server-flush-trackers.test.ts": 27, + "browse/test/server-launch-resolution.test.ts": 38, + "browse/test/server-lock-errors.test.ts": 81, + "browse/test/server-no-import-side-effects.test.ts": 520, + "browse/test/server-pty-lease-routes.test.ts": 403, + "browse/test/server-route-auth-blackbox.test.ts": 1573, + "browse/test/server-route-dispatch-ratchet.test.ts": 317, + "browse/test/server-sanitize-surrogates.test.ts": 354, + "browse/test/server-tmp-state-path.test.ts": 34, + "browse/test/session-cookie-store.test.ts": 86, + "browse/test/sidebar-tabs.test.ts": 471, + "browse/test/sidebar-ux.test.ts": 412, + "browse/test/sidepanel-patient-autoconnect.test.ts": 30, + "browse/test/sidepanel-reattach.test.ts": 32, + "browse/test/sidepanel-restart-dispose.test.ts": 32, + "browse/test/skill-token.test.ts": 34, + "browse/test/socks-bridge.test.ts": 506, + "browse/test/sse-helpers.test.ts": 175, + "browse/test/sse-session-cookie.test.ts": 34, + "browse/test/state-ttl.test.ts": 25, + "browse/test/stealth-extended.test.ts": 32, + "browse/test/stealth-layer-c.test.ts": 34, + "browse/test/stealth-webdriver.test.ts": 8809, + "browse/test/stop-ack-before-shutdown.test.ts": 177, + "browse/test/stop-dead-daemon.test.ts": 305, + "browse/test/tab-each.test.ts": 50, + "browse/test/tab-external-close-dispatch.test.ts": 816, + "browse/test/tab-external-close.test.ts": 508, + "browse/test/tab-guardrail.test.ts": 565, + "browse/test/tab-isolation.test.ts": 763, + "browse/test/tab-session-frame-detach.test.ts": 35, + "browse/test/telemetry-optout.test.ts": 67, + "browse/test/telemetry.test.ts": 39, + "browse/test/temp-dirs.test.ts": 45, + "browse/test/terminal-agent-detach-reattach.test.ts": 28, + "browse/test/terminal-agent-import.test.ts": 4415, + "browse/test/terminal-agent-keepalive.test.ts": 31, + "browse/test/terminal-agent-native-observation.test.ts": 38, + "browse/test/terminal-agent-owner-watchdog.test.ts": 2297, + "browse/test/terminal-agent-pid-identity.test.ts": 91, + "browse/test/terminal-agent-port-range.test.ts": 41, + "browse/test/terminal-agent-ring-buffer-runtime.test.ts": 50, + "browse/test/terminal-agent-session-routing.test.ts": 33, + "browse/test/terminal-agent-signal-cleanup.test.ts": 39, + "browse/test/terminal-agent-watchdog.test.ts": 34, + "browse/test/terminal-agent.test.ts": 380, + "browse/test/terminal-pty-lifecycle.test.ts": 37, + "browse/test/token-registry.test.ts": 44, + "browse/test/tunnel-gate-unit.test.ts": 345, + "browse/test/watch.test.ts": 365, + "browse/test/welcome-page.test.ts": 37, + "browse/test/windows-spawn-hide.test.ts": 52, + "browse/test/xprotect-heal.test.ts": 301, + "browser-skills/hackernews-frontpage/script.test.ts": 34, + "design/test/brief.test.ts": 28, + "design/test/cli-persistence.test.ts": 6766, + "design/test/cli-version.test.ts": 57, + "design/test/feedback-roundtrip-daemon.test.ts": 171, + "design/test/feedback-roundtrip.test.ts": 3395, + "design/test/image-args.test.ts": 118, + "design/test/image-gen-pairing.test.ts": 133, + "design/test/receipted-fetch.test.ts": 45, + "ios-qa/daemon/test/allowlist.test.ts": 47, + "ios-qa/daemon/test/audit.test.ts": 53, + "ios-qa/daemon/test/auth-mint.test.ts": 41, + "ios-qa/daemon/test/daemon-integration.test.ts": 3980, + "ios-qa/daemon/test/proxy-classify.test.ts": 90, + "ios-qa/daemon/test/proxy-transport.test.ts": 1756, + "ios-qa/daemon/test/session-tokens.test.ts": 31, + "ios-qa/daemon/test/single-instance.test.ts": 30, + "ios-qa/daemon/test/tailscale-localapi.test.ts": 42, + "ios-qa/scripts/gen-accessors.test.ts": 87, + "make-pdf/test/asideClient.test.ts": 47, + "make-pdf/test/cli-args.test.ts": 51, + "make-pdf/test/cli-exit-codes.test.ts": 297, + "make-pdf/test/diagram-prepass.test.ts": 112, + "make-pdf/test/e2e/ci-prereqs.test.ts": 28, + "make-pdf/test/e2e/combined-gate.test.ts": 32, + "make-pdf/test/e2e/diagram-gate.test.ts": 37, + "make-pdf/test/e2e/emoji-gate.test.ts": 37, + "make-pdf/test/e2e/format-gate.test.ts": 40, + "make-pdf/test/e2e/landscape-gate.test.ts": 38, + "make-pdf/test/e2e/toc-gate.test.ts": 37, + "make-pdf/test/image-policy.test.ts": 29, + "make-pdf/test/render-offline-sanitize.test.ts": 47, + "make-pdf/test/render.test.ts": 58, + "make-pdf/test/setup-smoke.test.ts": 54, + "make-pdf/test/toc-anchors.test.ts": 46, + "make-pdf/test/toc-pages.test.ts": 49, + "test/agents-digest.test.ts": 37, + "test/analytics.test.ts": 55, + "test/anthropic-preflight.test.ts": 25, + "test/archaeology-lint.test.ts": 2035, + "test/arm-benchmark-selftest.test.ts": 2788, + "test/arm-setup-smoke-workflow.test.ts": 135, + "test/auq-format-always-loaded.test.ts": 76, + "test/auq-native-capture.test.ts": 323, + "test/auq-parallel.test.ts": 27784, + "test/auq-substance-panel.test.ts": 109, + "test/autoplan-admission.test.ts": 1629, + "test/autoplan-artifact-windows-argv.test.ts": 240, + "test/autoplan-bounded-journal.test.ts": 566, + "test/autoplan-budget.test.ts": 10875, + "test/autoplan-capy-e2e.test.ts": 10262, + "test/autoplan-compaction-copies.test.ts": 282, + "test/autoplan-compaction-preserved-segment.test.ts": 1283, + "test/autoplan-guard-log.test.ts": 72, + "test/autoplan-guard-reasons.test.ts": 28, + "test/autoplan-init.test.ts": 1486, + "test/autoplan-long-session-observer.test.ts": 105, + "test/autoplan-method-read-audit.test.ts": 332, + "test/autoplan-owned-read.test.ts": 4598, + "test/autoplan-owned-state.test.ts": 535, + "test/autoplan-pairing.test.ts": 49, + "test/autoplan-pending-artifact.test.ts": 42, + "test/autoplan-pending-question.test.ts": 4439, + "test/autoplan-phase-handoff.test.ts": 137, + "test/autoplan-phase-observer.test.ts": 46, + "test/autoplan-phase-order.test.ts": 100, + "test/autoplan-public-narration.test.ts": 70, + "test/autoplan-publication-generation.test.ts": 117, + "test/autoplan-publication-guard.test.ts": 5524, + "test/autoplan-publication-hook.test.ts": 3401, + "test/autoplan-publication-payload.test.ts": 2730, + "test/autoplan-record.test.ts": 3410, + "test/autoplan-revise.test.ts": 10957, + "test/autoplan-schema-canary-compare.test.ts": 44, + "test/benchmark-runner.test.ts": 60, + "test/binary-version-probe.test.ts": 260, + "test/binding-template-drift.test.ts": 225, + "test/bootstrap-retention-shard.test.ts": 34, + "test/bootstrap-session-lifecycle.test.ts": 34, + "test/brain-cache-roundtrip.test.ts": 310, + "test/brain-cache-spec.test.ts": 47, + "test/brain-preflight.test.ts": 64, + "test/build-script-shell-compat.test.ts": 36, + "test/bun-subprocess-fd-lifetime.test.ts": 32, + "test/cache-concurrent-refresh.test.ts": 80, + "test/carve-guard-completeness.test.ts": 39, + "test/carve-guards-negative.test.ts": 41, + "test/carve-plan-fixture.test.ts": 510, + "test/carve-section-ordering.test.ts": 52, + "test/carve-section-sharding.test.ts": 2218, + "test/catalog-budget.test.ts": 71, + "test/catalog-mode-full.test.ts": 1095, + "test/catalog-trim.test.ts": 62, + "test/census-red-docs.test.ts": 59, + "test/ceo-barless-submit.test.ts": 114, + "test/ceo-count-ad-v2.test.ts": 62, + "test/ceo-expansion-auq.test.ts": 105, + "test/ceo-expansion-pacing-native.test.ts": 98, + "test/ceo-hold-posture-review.test.ts": 144, + "test/ceo-mode-expansion-disposition.test.ts": 89, + "test/ceo-mode-handoff-hook.test.ts": 204, + "test/ceo-mode-labels-native.test.ts": 68, + "test/ceo-mode-option.test.ts": 444, + "test/ceo-mode-pending-submit.test.ts": 75, + "test/ceo-mode-posture-native.test.ts": 73, + "test/ceo-mode-prerequisite.test.ts": 85, + "test/ceo-mode-routing-fixture.test.ts": 4832, + "test/ceo-plan-mode-fixture.test.ts": 3740, + "test/ceo-posture-packet.test.ts": 88, + "test/ceo-section-loading-fixture.test.ts": 386, + "test/ceo-split-collection.test.ts": 514, + "test/ceo-split-question-policy.test.ts": 417, + "test/ceo-stale-fill-decision.test.ts": 102, + "test/ceo-workflow-clarity.test.ts": 48, + "test/changed-files-union.test.ts": 2889, + "test/ci-image-cli-pin.test.ts": 52, + "test/ci-image-tag-binding.test.ts": 32, + "test/ci-paid-coordination.test.ts": 12119, + "test/claude-code-runner.test.ts": 3912, + "test/claude-code-windows-job.test.ts": 2926, + "test/claude-md-size.test.ts": 28, + "test/claude-overlay-models.test.ts": 61, + "test/claude-producer-stream.test.ts": 34, + "test/claude-provider-keychain.test.ts": 141, + "test/codex-carve-fixture.test.ts": 2111, + "test/codex-generation-model.test.ts": 210, + "test/codex-invocation-sites.test.ts": 438, + "test/codex-resume-flag-semantics.test.ts": 81, + "test/conductor-env-shim.test.ts": 35, + "test/context-budget-ratchet.test.ts": 194, + "test/context-remaining-work-provenance.test.ts": 32, + "test/cookie-workflow-judge-input.test.ts": 1009, + "test/cookie-workflow-manual-review.test.ts": 139, + "test/copilot-windows-bash.test.ts": 40, + "test/cost-known.test.ts": 102, + "test/coverage-audit.test.ts": 6956, + "test/cso-bounded-file.test.ts": 46, + "test/cso-docker-policy.test.ts": 58, + "test/cso-docker-socket-realpath.test.ts": 49, + "test/cso-git-global-config.test.ts": 86, + "test/cso-git-hardening.test.ts": 60, + "test/cso-history.test.ts": 35, + "test/cso-image-provisioning.test.ts": 249, + "test/cso-lease-identity.test.ts": 209, + "test/cso-native-evidence.test.ts": 59, + "test/cso-node-lifecycle-integration.test.ts": 60, + "test/cso-ntfs-fixture.test.ts": 340, + "test/cso-postgresql-policy.test.ts": 50, + "test/cso-preparation-java.test.ts": 47, + "test/cso-preparation.test.ts": 116, + "test/cso-preserved.test.ts": 42, + "test/cso-public-ghcr.test.ts": 43, + "test/cso-requalification.test.ts": 223, + "test/cso-runtime-promotion.test.ts": 270, + "test/cso-scanner-docker-integration.test.ts": 81, + "test/cso-scanners.test.ts": 101, + "test/cso-snapshot-disappearance-race.test.ts": 49, + "test/cso-spec-taxonomy-alignment.test.ts": 46, + "test/cso-staging-run.test.ts": 165, + "test/cso-verifier.test.ts": 63, + "test/cso-windows-build-contract.test.ts": 45, + "test/cso-windows-docker.test.ts": 52, + "test/declared-annotation.test.ts": 61, + "test/defensive-review-framing.test.ts": 35, + "test/dependency-security.test.ts": 137, + "test/deps-smoke.test.ts": 113, + "test/design-board-reload.test.ts": 349, + "test/design-catalog.test.ts": 99, + "test/design-checklist-sync.test.ts": 1801, + "test/design-completion-handoff-scored.test.ts": 61, + "test/design-consultation-contract.test.ts": 54, + "test/design-daemon-windows-identity.test.ts": 93, + "test/design-detect-contract.test.ts": 218, + "test/design-doc-data-guard.test.ts": 59, + "test/design-flag-utils.test.ts": 76, + "test/design-html-section-completion.test.ts": 5695, + "test/design-md.test.ts": 793, + "test/design-printed-paths.test.ts": 109, + "test/design-research-fixture.test.ts": 37, + "test/detector-corpora.test.ts": 423, + "test/detector-corpus-auto-decide-preserved.test.ts": 80, + "test/detector-corpus-plan-ceo-section-loading.test.ts": 75, + "test/detector-corpus-plan-design-review-plan-mode.test.ts": 1420, + "test/detector-corpus-plan-eng-multi-finding-batching.test.ts": 211, + "test/detector-corpus-shared-libs-plan-callers.test.ts": 46, + "test/detector-corpus-ship-docsync-late-result.test.ts": 83, + "test/detector-corpus-ship-docsync-launch-failure.test.ts": 62, + "test/devex-finding-fixture.test.ts": 1778, + "test/devex-peer-comparison-calibration.test.ts": 596, + "test/diagram-render-drift.test.ts": 129, + "test/disabled-dated-record-at.test.ts": 116, + "test/discover-section-templates.test.ts": 36, + "test/dispatch-rules.test.ts": 63, + "test/docsync-authority.test.ts": 3365, + "test/docsync-child-marker.test.ts": 51, + "test/docsync-lifecycle-interface.test.ts": 594, + "test/doctor-components.test.ts": 71, + "test/document-skills-redaction.test.ts": 65, + "test/dom-dump-hygiene.test.ts": 315, + "test/dx-error-contract-grader.test.ts": 64, + "test/dx-error-contract.test.ts": 57, + "test/dx-selected-navigation-ap.test.ts": 131, + "test/e2e-harness-audit.test.ts": 49, + "test/e2e-tier-alignment.test.ts": 172, + "test/eng-batching-current-ledger.test.ts": 248, + "test/eng-batching-native-replay.test.ts": 97, + "test/eng-batching-saved-ledger.test.ts": 684, + "test/eng-count-question-policy.test.ts": 79, + "test/eng-devex-s-count.test.ts": 70, + "test/eng-finding-retry-budget.test.ts": 1506, + "test/eng-first-review.test.ts": 290, + "test/eng-published-navigation.test.ts": 85, + "test/eng-resolution-block-position.test.ts": 265, + "test/eng-review-routing.test.ts": 52, + "test/eng-seeded-completion-ai.test.ts": 16200, + "test/eng-seeded-coverage.test.ts": 1338, + "test/eng-semantic-terminal.test.ts": 110, + "test/env-host-runtime-assets.test.ts": 2602, + "test/eval-budgets-policy.test.ts": 97, + "test/eval-flake-rank.test.ts": 663, + "test/eval-history.test.ts": 2055, + "test/eval-kinds.test.ts": 136, + "test/eval-model.test.ts": 39, + "test/eval-sweep-workflow.test.ts": 105, + "test/evals-workflow-wiring.test.ts": 848, + "test/exit-propagation.test.ts": 413, + "test/extension-pty-inject-invariant.test.ts": 34, + "test/external-host-carve.test.ts": 3163, + "test/flake-ledger.test.ts": 74, + "test/free-home-guard.test.ts": 59, + "test/free-seed-ratchet.test.ts": 305, + "test/free-tests-workflow-wiring.test.ts": 101, + "test/gate-integrity-templates.test.ts": 81, + "test/gbrain-detection-override.test.ts": 1436, + "test/gbrain-exec-invariant.test.ts": 35, + "test/gbrain-guards.test.ts": 56, + "test/gbrain-source-gitignore.test.ts": 582, + "test/gbrain-sources-parse.test.ts": 50, + "test/gbrain-spawn-windows-shell.test.ts": 141, + "test/gbrain-sync-voyage-code-3-integration.test.ts": 55, + "test/gen-skill-docs-checks.test.ts": 18267, + "test/gen-skill-docs-idempotency.test.ts": 3568, + "test/gen-skill-docs-import-purity.test.ts": 76, + "test/gen-skill-docs-prune-stale.test.ts": 688, + "test/generated-docs-fences.test.ts": 1228, + "test/generator-eexist.test.ts": 443, + "test/git-ref-fixture-tripwire.test.ts": 151, + "test/gitattributes-eol.test.ts": 1232, + "test/global-discover.test.ts": 3257, + "test/greptile-early.test.ts": 77, + "test/gstack-ci-gate.test.ts": 65, + "test/gstack-config-gbrain-refresh.test.ts": 1474, + "test/gstack-design-detect-plugins.test.ts": 674, + "test/gstack-doctor.test.ts": 392261, + "test/gstack-home-module-scope.test.ts": 162, + "test/gstack-launch-probe.test.ts": 42, + "test/gstack-post.test.ts": 79, + "test/gstack-regen.test.ts": 16822, + "test/gstack-render-cli.test.ts": 680, + "test/gstack-schema-pack.test.ts": 47, + "test/gstack-upgrade-migration-v1_78_0_0.test.ts": 411, + "test/gstack-wtree-windows-paths.test.ts": 716, + "test/harness-version.test.ts": 292, + "test/helpers-unit.test.ts": 89, + "test/helpers/budget-override.test.ts": 66, + "test/helpers/capture-parity-baseline.test.ts": 333, + "test/helpers/claude-pty-runner.auq.unit.test.ts": 94, + "test/helpers/claude-pty-runner.boundaries.unit.test.ts": 99, + "test/helpers/claude-pty-runner.classify.unit.test.ts": 101, + "test/helpers/claude-pty-runner.launch.unit.test.ts": 48, + "test/helpers/claude-pty-runner.plan-native.unit.test.ts": 85, + "test/helpers/claude-pty-runner.runners.unit.test.ts": 1612, + "test/helpers/claude-pty-runner.scope-gate-floor.unit.test.ts": 81, + "test/helpers/claude-pty-runner.screen.unit.test.ts": 78, + "test/helpers/e2e-gate.unit.test.ts": 46, + "test/helpers/eval-store.test.ts": 2538, + "test/helpers/hermetic-env.test.ts": 12214, + "test/helpers/observability.test.ts": 403, + "test/helpers/providers/gemini.test.ts": 46, + "test/helpers/run-bin.test.ts": 147, + "test/heredoc-pipe-deadlock.test.ts": 526, + "test/honesty-kernel.test.ts": 63, + "test/hook-scripts.test.ts": 135136, + "test/instruction-facts.test.ts": 134, + "test/investigate-freeze-path.test.ts": 20245, + "test/investigate-recipes.test.ts": 51, + "test/ios-debug-bridge-release-guard.test.ts": 43, + "test/ios-qa-daemon-cli.test.ts": 128, + "test/ios-qa-stateserver-hardening.test.ts": 43, + "test/ios-qa-swift-build.test.ts": 49, + "test/ios-qa.test.ts": 411, + "test/is-conductor.test.ts": 39, + "test/jargon-list.test.ts": 46, + "test/judge-calibration.test.ts": 92, + "test/judge-panel-median.test.ts": 89, + "test/land-and-deploy-command-trigger.test.ts": 40, + "test/land-and-deploy-flow.test.ts": 10910, + "test/land-and-deploy-postfail.test.ts": 46, + "test/llm-judge-abort.test.ts": 57, + "test/llm-judge-frontier.test.ts": 158, + "test/llm-judge-stream.test.ts": 75, + "test/llms-txt-shape.test.ts": 73, + "test/maintenance-cli-args.test.ts": 316, + "test/memory-ingest-timeout.test.ts": 62, + "test/migration-checkpoint-ownership.test.ts": 1518, + "test/mktemp-portability.test.ts": 593, + "test/model-catalog-isolation.test.ts": 158, + "test/model-overlays.test.ts": 49, + "test/model-policy-freshness.test.ts": 250, + "test/model-policy.test.ts": 134, + "test/module-size-ratchet.test.ts": 280, + "test/native-auto-decide-pty.test.ts": 12802, + "test/native-auto-decide.test.ts": 356, + "test/no-quoted-tilde-assignments.test.ts": 55, + "test/no-suicide-exit.test.ts": 181, + "test/office-hours-budget.test.ts": 75, + "test/office-hours-open-question-form.test.ts": 37, + "test/office-hours-phase4-caller.test.ts": 81, + "test/office-hours-review.test.ts": 1891, + "test/office-posture-recording.test.ts": 85, + "test/one-way-doors.test.ts": 47, + "test/open-gstack-browser-liveness.test.ts": 34, + "test/openclaw-native-skills.test.ts": 30, + "test/osv-config-wiring.test.ts": 48, "test/osv-ignore-expiry.test.ts": 61, - "test/outside-review-result.test.ts": 610, - "test/outside-voice-evidence.test.ts": 215, - "test/outside-voice-failure-policy.test.ts": 328, - "test/outside-voice-fixture.test.ts": 1705, - "test/outside-voice-routing.test.ts": 1944, - "test/overlay-lifecycle.test.ts": 468, - "test/overlay-measurement.test.ts": 821, - "test/overlay-recording-order.test.ts": 85, - "test/overlay-sdk-cancel-eof.test.ts": 177, - "test/paid-free-boundary.test.ts": 8707, - "test/paid-orphan-tripwire.test.ts": 266, - "test/paid-overlay-scheduling.test.ts": 1805, - "test/paid-pr-profile.test.ts": 4294, - "test/paid-report-census.test.ts": 135, - "test/paid-report-fail-open.test.ts": 2256, - "test/paid-retry-supervision.test.ts": 3444, - "test/paid-run-manifest.test.ts": 5261, - "test/paid-selection-propagation.test.ts": 142, - "test/paid-shard-settlement.test.ts": 1775, - "test/paid-shards.test.ts": 4911, - "test/paid-slice-deadline.test.ts": 1645, - "test/pair-agent-token-hygiene.test.ts": 57, - "test/parity-baseline-integrity.test.ts": 69, - "test/parity-sectioned.test.ts": 65, - "test/parity-suite.test.ts": 291, - "test/pending-question-completion.test.ts": 413, - "test/periodic-exclude-policy.test.ts": 365, - "test/plan-count-checkbox.test.ts": 122, - "test/plan-count-completion.test.ts": 685, - "test/plan-count-cropped-wrap.test.ts": 242, - "test/plan-count-cross-cwd-ancestry.test.ts": 394, - "test/plan-count-design-ui-recovery.test.ts": 191, - "test/plan-count-dx-handoff.test.ts": 262, - "test/plan-count-empty-review.test.ts": 129, - "test/plan-count-history.test.ts": 74, - "test/plan-count-long-edit.test.ts": 128, - "test/plan-count-native-input.test.ts": 146, - "test/plan-count-owned-permission.test.ts": 125, - "test/plan-count-pending-exit.test.ts": 299, - "test/plan-count-prerequisite.test.ts": 167, - "test/plan-count-preview-footer.test.ts": 158, - "test/plan-count-session-cwd.test.ts": 257, - "test/plan-count-timeout.test.ts": 70, - "test/plan-count-transcript.test.ts": 220, - "test/plan-count-truncated-border.test.ts": 127, - "test/plan-count-truncated-question.test.ts": 122, - "test/plan-create-combined-permission.test.ts": 375, - "test/plan-create-permission.test.ts": 229, - "test/plan-design-floor-fixture.test.ts": 1636, - "test/plan-design-sdk-fixture.test.ts": 3179, - "test/plan-design-with-ui-fixture.test.ts": 7398, - "test/plan-edit-cropped-permission.test.ts": 425, - "test/plan-eng-resume.test.ts": 67, - "test/plan-floor-dx-actor.test.ts": 267, - "test/plan-floor-review.test.ts": 118, - "test/plan-floor-target.test.ts": 14872, - "test/plan-format-kind-note.test.ts": 77, - "test/plan-pending-question-pty.test.ts": 137, - "test/plan-review-board-feedback.test.ts": 12699, - "test/plan-review-calibration.test.ts": 1199, - "test/plan-review-decisions.test.ts": 410, - "test/plan-review-report-recording.test.ts": 8160, - "test/plan-scope-selection.test.ts": 3556, - "test/plan-skill-question-hook-scope.test.ts": 9517, - "test/plan-skill-read-permission.test.ts": 134, - "test/plan-skill-webfetch-permission.test.ts": 4989, - "test/platform-qualification-workflow.test.ts": 52, - "test/post-rename-doc-regen.test.ts": 68, - "test/pr-direct-cases.test.ts": 5659, - "test/pr-shared-input-selection.test.ts": 1716, - "test/pr-title-sync-workflow-safety.test.ts": 78, - "test/prompt-audit-manifest.test.ts": 695, - "test/provider-model-defaults.test.ts": 89, - "test/pty-askuserquestion-single-line.test.ts": 105, - "test/pty-numbered-option-indent-native.test.ts": 137, - "test/pty-option-selection.test.ts": 65, - "test/pty-output-wake.test.ts": 3152, - "test/pty-screen-session.test.ts": 57, - "test/pty-screen-supervision.test.ts": 10111, - "test/pty-screen-unicode-ap.test.ts": 192, - "test/pty-screen.test.ts": 192, - "test/pty-skill-seeding-wiring.test.ts": 426, - "test/pty-trust-dialog.test.ts": 54, - "test/qa-browser-preservation.test.ts": 11468, - "test/qa-bugs-fixture.test.ts": 73, - "test/qa-caller-authority.test.ts": 185, - "test/qa-caller-freshness-order.test.ts": 114, - "test/qa-caller-report-observer.test.ts": 77, - "test/qa-checkpoint-evidence.test.ts": 258, - "test/qa-deadline-publication-observer.test.ts": 80, - "test/qa-deadline-selection.test.ts": 91, - "test/qa-deadline.test.ts": 23157, - "test/qa-evidence-selection.test.ts": 193, - "test/qa-evidence.test.ts": 17401, - "test/qa-fix-loop-fixture.test.ts": 5504, - "test/qa-health-rubric.test.ts": 42, - "test/qa-only-browser-probe.test.ts": 1441, - "test/qa-probe-gates.test.ts": 119, - "test/qa-supervision-selection.test.ts": 75, - "test/question-tuning-registry-path.test.ts": 48, - "test/redact-context-exemptions.test.ts": 96, - "test/redact-doc-resolver.test.ts": 42, - "test/redact-dotenv-filename-false-positive.test.ts": 46, - "test/redact-engine-autoredact.test.ts": 44, - "test/redact-engine.test.ts": 77, - "test/redact-parcel-id-false-positive.test.ts": 46, - "test/redact-pattern-lint.test.ts": 56, - "test/redact-prepush-target.test.ts": 46225, - "test/redact-span-binding.test.ts": 107, - "test/redact-unicode-offsets.test.ts": 187, - "test/regression-1539-review-self-verify.test.ts": 59, - "test/regression-issue2091-bsd-mktemp.test.ts": 603, - "test/regression-pr1169-mktemp-fallbacks.test.ts": 166, - "test/regression-transcript-frontmatter-fence.test.ts": 103, - "test/remote-identity-vectors.test.ts": 223, - "test/replay-pr-selection.test.ts": 1498, - "test/resolvers-gbrain-put-rewrite.test.ts": 85, - "test/resolvers-gbrain-save-results.test.ts": 48, - "test/retired-commands.test.ts": 100, - "test/review-army-budget.test.ts": 2958, - "test/review-consensus-lifecycle.test.ts": 72, - "test/review-count-markdown.test.ts": 180, - "test/review-entry-and-design-clarity-au.test.ts": 130, - "test/review-enum-lifecycle.test.ts": 96, - "test/review-finalization-budget.test.ts": 5927, - "test/review-n-plus-one-contract.test.ts": 3174, - "test/review-quality-provenance.test.ts": 77, - "test/review-workflow-clarity.test.ts": 93, - "test/router-disabled-skills.test.ts": 1302, - "test/run-shard-child.test.ts": 1404, - "test/safety-rule-registry.test.ts": 90, - "test/salience-allowlist.test.ts": 82, - "test/schema-version-migration.test.ts": 346, - "test/section-manifest-consistency.test.ts": 74, - "test/session-runner-browse-errors.test.ts": 1939, - "test/session-runner-stream-lifecycle.test.ts": 378, - "test/session-runner-timeout.test.ts": 76, - "test/session-runner-tools.test.ts": 243, - "test/setup-alias-name-uniqueness.test.ts": 20718, - "test/setup-browser-hint.test.ts": 608, - "test/setup-bun-cmd-and-pipe-bugs.test.ts": 361, - "test/setup-cleanup-orphans.test.ts": 81, - "test/setup-codex-design-pdf-runtime.test.ts": 79, - "test/setup-codex-model.test.ts": 79, - "test/setup-codex-scope-review-boundaries.test.ts": 157, - "test/setup-cso-windows-probe.test.ts": 79, - "test/setup-deploy-key-presence.test.ts": 139, - "test/setup-gbrain-bin-invocation-paths.test.ts": 72, - "test/setup-gbrain-path4-caller.test.ts": 5288, - "test/setup-gbrain-path4-structure.test.ts": 67, - "test/setup-gbrain-remote-caller.test.ts": 10158, - "test/setup-help.test.ts": 451, - "test/setup-playwright-platform.test.ts": 7531, - "test/setup-prune-stale-generated.test.ts": 2139, - "test/setup-sections-linking.test.ts": 57, - "test/setup-skill-copies.test.ts": 77, - "test/setup-staged-copy.test.ts": 377, - "test/setup-windows-fallback.test.ts": 69, - "test/setup-windows-rerun-refresh.test.ts": 1511, - "test/shard-cli-parity.test.ts": 314, - "test/shared-libs-cancellation.test.ts": 328, - "test/shared-libs-evidence.test.ts": 91, - "test/shared-libs-plan-actor.test.ts": 208, - "test/shared-libs-rendering.test.ts": 2639, - "test/shared-libs-source-reads.test.ts": 12864, - "test/ship-apple-gate.test.ts": 76, - "test/ship-control-flow.test.ts": 3719, - "test/ship-coverage-audit-af.test.ts": 153, - "test/ship-hook-windows-paths.test.ts": 2096, - "test/ship-pr-liveness-policy.test.ts": 72, - "test/ship-publication-gates.test.ts": 1628, - "test/ship-reentry-gates.test.ts": 78, - "test/ship-review-loop.test.ts": 79, - "test/ship-section-fixture.test.ts": 1645, - "test/ship-skip-requeue.test.ts": 129, - "test/ship-template-redaction.test.ts": 76, - "test/ship-test-detection-markers.test.ts": 1628, - "test/ship-triage-labels.test.ts": 69, - "test/ship-workflow-clarity.test.ts": 126, - "test/shortcut-debt-ledger.test.ts": 69, - "test/skill-browse-state-extraction.test.ts": 278, - "test/skill-budget-regression.test.ts": 329, - "test/skill-check-driver.test.ts": 397, - "test/skill-collision-sentinel.test.ts": 78, - "test/skill-coverage-floor.test.ts": 151, - "test/skill-cross-model-recommendation-emit.test.ts": 77, - "test/skill-parser.test.ts": 99, - "test/skill-positional-literals.test.ts": 7526, - "test/skill-preflight-budget.test.ts": 67, - "test/skillify-host-paths.test.ts": 2351, - "test/sol-skill-fixture.test.ts": 3379, - "test/spawnsync-timeout-tripwire.test.ts": 549, - "test/spec-template-invariants.test.ts": 112, - "test/state-root-parity.test.ts": 2452, - "test/strict-output-capture.test.ts": 225, - "test/strict-output-formats.test.ts": 2977, - "test/strict-output-settlement.test.ts": 4288, - "test/strict-output.test.ts": 63, - "test/sync-gbrain-readiness-fixture.test.ts": 597, - "test/takes-fence-fallback.test.ts": 48, - "test/tasks-section-jq.test.ts": 236, - "test/template-context-parity.test.ts": 57, - "test/terse-build.test.ts": 62, - "test/test-free-shards-sandbox-knobs.test.ts": 428, - "test/test-free-shards-settlement-lifecycle.test.ts": 80, - "test/test-free-shards-settlement-ownership.test.ts": 75, - "test/test-health-report.test.ts": 643, - "test/test-health-workflow.test.ts": 52, - "test/test-of-test-ratchet.test.ts": 405, - "test/test-pr-profile.test.ts": 90, - "test/test-value-bar.test.ts": 428, - "test/third-party-actions-recording.test.ts": 542, - "test/third-party-actions.test.ts": 478, - "test/touchfiles-facade.test.ts": 99, - "test/touchfiles-map-diff.test.ts": 1770, - "test/tracker-guard-wiring.test.ts": 142, - "test/troubleshooting-anchors.test.ts": 53, - "test/typecheck-test-ratchet.test.ts": 98, - "test/uninstall-windows-copies.test.ts": 9656, - "test/v0-dormancy.test.ts": 85, - "test/version-source.test.ts": 75, - "test/windows-free-selection-autoplan-guard.test.ts": 80, - "test/windows-native-workflows.test.ts": 534, - "test/workflow-action-pins.test.ts": 88, - "test/workflow-boundaries-fixture.test.ts": 15849, - "test/workflow-concurrency.test.ts": 81, - "test/workflow-excerpt.test.ts": 307, - "test/workflow-judge-cache.test.ts": 13496, - "test/worktree-isolated-shapes.test.ts": 122, - "test/worktree.test.ts": 5426 + "test/outside-review-severity.test.ts": 168, + "test/outside-review-unparsed-severity.test.ts": 292, + "test/outside-send-boundary.test.ts": 499, + "test/outside-voice-evidence.test.ts": 200, + "test/outside-voice-failure-policy.test.ts": 233, + "test/outside-voice-fixture.test.ts": 1585, + "test/outside-voice-native-deadline.test.ts": 69, + "test/outside-voice-routing.test.ts": 1710, + "test/overlay-lifecycle.test.ts": 402, + "test/overlay-measurement.test.ts": 631, + "test/overlay-recording-order.test.ts": 53, + "test/overlay-sdk-cancel-eof.test.ts": 115, + "test/paid-free-boundary.test.ts": 9506, + "test/paid-orphan-tripwire.test.ts": 174, + "test/paid-overlay-scheduling.test.ts": 1395, + "test/paid-pr-profile.test.ts": 3674, + "test/paid-report-census.test.ts": 237, + "test/paid-report-fail-open.test.ts": 2098, + "test/paid-retry-supervision.test.ts": 2530, + "test/paid-run-manifest.test.ts": 5052, + "test/paid-selection-propagation.test.ts": 88, + "test/paid-shard-settlement.test.ts": 1565, + "test/paid-shards.test.ts": 9945, + "test/paid-slice-deadline.test.ts": 1594, + "test/pair-agent-token-hygiene.test.ts": 44, + "test/parity-baseline-integrity.test.ts": 53, + "test/parity-sectioned.test.ts": 54, + "test/parity-suite.test.ts": 233, + "test/path-spelling.test.ts": 1422, + "test/pending-question-completion.test.ts": 276, + "test/periodic-exclude-policy.test.ts": 278, + "test/plan-count-checkbox.test.ts": 74, + "test/plan-count-completion.test.ts": 440, + "test/plan-count-cropped-wrap.test.ts": 140, + "test/plan-count-cross-cwd-ancestry.test.ts": 249, + "test/plan-count-design-ui-recovery.test.ts": 93, + "test/plan-count-dx-handoff.test.ts": 201, + "test/plan-count-empty-review.test.ts": 74, + "test/plan-count-history.test.ts": 46, + "test/plan-count-long-edit.test.ts": 87, + "test/plan-count-native-input.test.ts": 95, + "test/plan-count-owned-permission.test.ts": 88, + "test/plan-count-pending-exit.test.ts": 166, + "test/plan-count-prerequisite.test.ts": 102, + "test/plan-count-preview-footer.test.ts": 82, + "test/plan-count-session-cwd.test.ts": 162, + "test/plan-count-timeout.test.ts": 47, + "test/plan-count-transcript.test.ts": 145, + "test/plan-count-truncated-border.test.ts": 77, + "test/plan-count-truncated-question.test.ts": 76, + "test/plan-create-combined-permission.test.ts": 242, + "test/plan-create-permission.test.ts": 153, + "test/plan-design-floor-fixture.test.ts": 1393, + "test/plan-design-sdk-fixture.test.ts": 2646, + "test/plan-design-with-ui-fixture.test.ts": 6444, + "test/plan-edit-cropped-permission.test.ts": 270, + "test/plan-eng-resume.test.ts": 44, + "test/plan-floor-dx-actor.test.ts": 144, + "test/plan-floor-edit-wrap.test.ts": 113, + "test/plan-floor-review.test.ts": 80, + "test/plan-floor-target.test.ts": 14476, + "test/plan-format-approach-prompt.test.ts": 34, + "test/plan-format-kind-note.test.ts": 37, + "test/plan-pending-question-pty.test.ts": 76, + "test/plan-review-board-feedback.test.ts": 10440, + "test/plan-review-calibration.test.ts": 688, + "test/plan-review-decisions.test.ts": 335, + "test/plan-review-report-recording.test.ts": 8758, + "test/plan-scope-selection.test.ts": 3675, + "test/plan-skill-question-hook-scope.test.ts": 6962, + "test/plan-skill-read-permission.test.ts": 110, + "test/plan-skill-webfetch-permission.test.ts": 3898, + "test/platform-qualification-workflow.test.ts": 40, + "test/post-rename-doc-regen.test.ts": 59, + "test/pr-direct-cases.test.ts": 5718, + "test/pr-shared-input-selection.test.ts": 1298, + "test/pr-title-sync-workflow-safety.test.ts": 47, + "test/pregate-import-graph-paths.test.ts": 8100, + "test/pregate-manifest-paths.test.ts": 6068, + "test/pregate-wtree-refusal.test.ts": 6553, + "test/prompt-audit-manifest.test.ts": 536, + "test/prosons-neutral-posture.test.ts": 40, + "test/provider-model-defaults.test.ts": 64, + "test/pty-askuserquestion-single-line.test.ts": 79, + "test/pty-numbered-option-indent-native.test.ts": 86, + "test/pty-option-selection.test.ts": 47, + "test/pty-output-wake.test.ts": 3285, + "test/pty-screen-session.test.ts": 42, + "test/pty-screen-supervision.test.ts": 10134, + "test/pty-screen-unicode-ap.test.ts": 174, + "test/pty-screen.test.ts": 144, + "test/pty-skill-seeding-wiring.test.ts": 391, + "test/pty-trust-dialog.test.ts": 44, + "test/published-text.test.ts": 58, + "test/qa-browser-preservation.test.ts": 10434, + "test/qa-bugs-fixture.test.ts": 62, + "test/qa-caller-authority.test.ts": 176, + "test/qa-caller-freshness-order.test.ts": 103, + "test/qa-caller-report-observer.test.ts": 57, + "test/qa-checkpoint-evidence.test.ts": 239, + "test/qa-deadline-publication-observer.test.ts": 63, + "test/qa-deadline-selection.test.ts": 81, + "test/qa-deadline.test.ts": 21660, + "test/qa-evidence-selection.test.ts": 125, + "test/qa-evidence.test.ts": 13989, + "test/qa-fix-loop-fixture.test.ts": 5560, + "test/qa-health-rubric.test.ts": 36, + "test/qa-only-browser-probe.test.ts": 1977, + "test/qa-probe-gates.test.ts": 106, + "test/qa-report-fields.test.ts": 43, + "test/qa-supervision-selection.test.ts": 69, + "test/question-tuning-registry-path.test.ts": 49, + "test/readme-skill-lists.test.ts": 43, + "test/redact-context-exemptions.test.ts": 77, + "test/redact-doc-resolver.test.ts": 94, + "test/redact-dotenv-filename-false-positive.test.ts": 77, + "test/redact-engine-autoredact.test.ts": 93, + "test/redact-parcel-id-false-positive.test.ts": 58, + "test/redact-pattern-lint.test.ts": 52, + "test/redact-prepush-emails.test.ts": 37019, + "test/redact-prepush-target.test.ts": 42318, + "test/redact-span-binding.test.ts": 81, + "test/redact-unicode-offsets.test.ts": 162, + "test/regression-1539-review-self-verify.test.ts": 41, + "test/regression-1834-retro-recommendations.test.ts": 31, + "test/regression-issue2091-bsd-mktemp.test.ts": 513, + "test/regression-pr1169-mktemp-fallbacks.test.ts": 130, + "test/regression-transcript-frontmatter-fence.test.ts": 74, + "test/remote-identity-vectors.test.ts": 212, + "test/replay-pr-selection.test.ts": 1401, + "test/resolvers-gbrain-put-rewrite.test.ts": 75, + "test/resolvers-gbrain-save-results.test.ts": 73, + "test/retired-commands.test.ts": 88, + "test/review-army-budget.test.ts": 4143, + "test/review-base-refresh.test.ts": 1423, + "test/review-consensus-lifecycle.test.ts": 78, + "test/review-count-markdown.test.ts": 163, + "test/review-entry-and-design-clarity-au.test.ts": 106, + "test/review-enum-lifecycle.test.ts": 73, + "test/review-finalization-budget.test.ts": 5566, + "test/review-n-plus-one-contract.test.ts": 3812, + "test/review-quality-provenance.test.ts": 76, + "test/router-disabled-skills.test.ts": 1094, + "test/run-shard-child.test.ts": 1345, + "test/runtime-pins.test.ts": 172, + "test/safety-rule-registry.test.ts": 74, + "test/salience-allowlist.test.ts": 61, + "test/schema-version-migration.test.ts": 290, + "test/section-manifest-consistency.test.ts": 58, + "test/session-runner-browse-errors.test.ts": 1498, + "test/session-runner-stream-lifecycle.test.ts": 338, + "test/session-runner-timeout.test.ts": 54, + "test/session-runner-tools.test.ts": 161, + "test/setup-alias-name-uniqueness.test.ts": 17731, + "test/setup-browser-hint.test.ts": 567, + "test/setup-bun-cmd-and-pipe-bugs.test.ts": 499, + "test/setup-cleanup-orphans.test.ts": 306, + "test/setup-codex-design-pdf-runtime.test.ts": 81, + "test/setup-codex-model.test.ts": 93, + "test/setup-codex-scope-review-boundaries.test.ts": 473, + "test/setup-cso-windows-probe.test.ts": 357, + "test/setup-cursor-legacy-skills.test.ts": 474, + "test/setup-deploy-key-presence.test.ts": 148, + "test/setup-deploy-not-deployed.test.ts": 41, + "test/setup-deploy-vercel-trigger.test.ts": 57, + "test/setup-gbrain-bin-invocation-paths.test.ts": 79, + "test/setup-gbrain-path4-caller.test.ts": 3645, + "test/setup-gbrain-path4-structure.test.ts": 75, + "test/setup-gbrain-remote-caller.test.ts": 9128, + "test/setup-help.test.ts": 515, + "test/setup-hook-syntax-gate.test.ts": 98800, + "test/setup-playwright-platform.test.ts": 6847, + "test/setup-prune-stale-generated.test.ts": 2751, + "test/setup-sections-linking.test.ts": 46, + "test/setup-skill-copies.test.ts": 129, + "test/setup-staged-copy.test.ts": 456, + "test/setup-windows-fallback.test.ts": 141, + "test/setup-windows-rerun-refresh.test.ts": 1408, + "test/shard-cli-parity.test.ts": 220, + "test/shared-libs-cancellation.test.ts": 257, + "test/shared-libs-evidence.test.ts": 89, + "test/shared-libs-plan-actor.test.ts": 139, + "test/shared-libs-rendering.test.ts": 2425, + "test/shared-libs-source-reads.test.ts": 15268, + "test/ship-apple-gate.test.ts": 64, + "test/ship-control-flow.test.ts": 3997, + "test/ship-coverage-audit-af.test.ts": 115, + "test/ship-greptile-early.test.ts": 314, + "test/ship-greptile-pr-check.test.ts": 1145, + "test/ship-hook-windows-paths.test.ts": 2185, + "test/ship-measure-bar.test.ts": 222, + "test/ship-measure-loop-skill.test.ts": 70, + "test/ship-pr-liveness-policy.test.ts": 50, + "test/ship-publication-gates.test.ts": 18722, + "test/ship-reentry-gates.test.ts": 65, + "test/ship-review-loop.test.ts": 59, + "test/ship-section-fixture.test.ts": 1638, + "test/ship-skip-requeue.test.ts": 318, + "test/ship-template-redaction.test.ts": 42, + "test/ship-test-detection-markers.test.ts": 1429, + "test/ship-triage-labels.test.ts": 40, + "test/ship-workflow-clarity.test.ts": 92, + "test/shortcut-debt-ledger.test.ts": 180, + "test/sideways-review.test.ts": 72, + "test/skill-browse-state-extraction.test.ts": 215, + "test/skill-budget-regression.test.ts": 407, + "test/skill-check-driver.test.ts": 403, + "test/skill-collision-sentinel.test.ts": 79, + "test/skill-coverage-floor.test.ts": 115, + "test/skill-cross-model-recommendation-emit.test.ts": 52, + "test/skill-md-size-guard.test.ts": 2496, + "test/skill-parser.test.ts": 86, + "test/skill-positional-literals.test.ts": 5711, + "test/skill-preflight-budget.test.ts": 53, + "test/skillify-host-paths.test.ts": 2098, + "test/sol-skill-fixture.test.ts": 3451, + "test/spawnsync-timeout-tripwire.test.ts": 381, + "test/spec-template-invariants.test.ts": 80, + "test/spend-ledger.test.ts": 365, + "test/state-root-parity.test.ts": 1999, + "test/strict-output-capture.test.ts": 212, + "test/strict-output-formats.test.ts": 2337, + "test/strict-output-settlement.test.ts": 4253, + "test/strict-output.test.ts": 51, + "test/sync-gbrain-readiness-fixture.test.ts": 475, + "test/takes-fence-fallback.test.ts": 39, + "test/tasks-section-jq.test.ts": 173, + "test/team-init-hook-shell-neutral.test.ts": 1055, + "test/template-context-parity.test.ts": 36, + "test/terse-build.test.ts": 48, + "test/test-free-shards-git-maintenance.test.ts": 708, + "test/test-free-shards-sandbox-knobs.test.ts": 407, + "test/test-free-shards-settlement-lifecycle.test.ts": 62, + "test/test-free-shards-settlement-ownership.test.ts": 71, + "test/test-health-report.test.ts": 949, + "test/test-health-workflow.test.ts": 43, + "test/test-of-test-ratchet.test.ts": 389, + "test/test-pr-profile.test.ts": 84, + "test/test-value-bar.test.ts": 562, + "test/third-party-actions-recording.test.ts": 639, + "test/third-party-actions.test.ts": 441, + "test/timeline-stop-hook-slug.test.ts": 4770, + "test/touchfiles-facade.test.ts": 67, + "test/touchfiles-map-diff.test.ts": 1611, + "test/tracker-guard-wiring.test.ts": 122, + "test/trial-cause.test.ts": 1074, + "test/typecheck-test-ratchet.test.ts": 76, + "test/uninstall-windows-copies.test.ts": 7745, + "test/v0-dormancy.test.ts": 73, + "test/version-source.test.ts": 60, + "test/voice-directive.test.ts": 110, + "test/windows-free-selection-autoplan-guard.test.ts": 81, + "test/windows-native-workflows.test.ts": 450, + "test/workflow-action-pins.test.ts": 71, + "test/workflow-boundaries-fixture.test.ts": 15322, + "test/workflow-concurrency.test.ts": 48, + "test/workflow-excerpt.test.ts": 170, + "test/workflow-judge-cache.test.ts": 15259, + "test/workflow-required-steps.test.ts": 76, + "test/worktree-isolated-shapes.test.ts": 69, + "test/worktree.test.ts": 5238 } } diff --git a/scripts/test-free-shards.ts b/scripts/test-free-shards.ts index 8b53a9f20..7e73c048a 100755 --- a/scripts/test-free-shards.ts +++ b/scripts/test-free-shards.ts @@ -1707,13 +1707,21 @@ export function exitCodeFor(status: FreeShardStatus): number { return status === 'timed-out' ? 124 : 1; } +/** Per-file deadline for `--record-durations`: an explicit --wall-timeout, else the one-file default. */ +export function recordingWallTimeoutMs(options: Pick): number { + return options.wallTimeoutExplicit ? options.wallTimeoutMs : wallTimeoutForShard(1); +} + /** * `--record-durations`: time every file in its own child (exact per-file wall, * immune to bun's stream buffering) and write the committed seed atomically. * Uses the same isolated, strictly classified children as a normal run. * Run against an immutable checkout; never time while editing its inputs. + * An explicit --wall-timeout sets the per-file deadline, so a file slower than + * the default deadline is timed in full instead of being killed and recorded + * at the deadline. */ -async function recordFreeTestDurations(files: string[], jobs: number): Promise { +async function recordFreeTestDurations(files: string[], jobs: number, wallTimeoutMs: number): Promise { const durations: Record = {}; const failed: string[] = []; const expectedCount = files.length; @@ -1722,7 +1730,7 @@ async function recordFreeTestDurations(files: string[], jobs: number): Promise !(file in TREE_MUTATING)), files.filter(file => file in TREE_MUTATING), jobs, async (file, index) => { const outcome = await runFreeShard([file], index + 1, files.length, { - wallTimeoutMs: wallTimeoutForShard(1), quiet: true, homeGuard: sharedFreeHome, + wallTimeoutMs, quiet: true, homeGuard: sharedFreeHome, }); durations[normalizeRelativePath(file)] = outcome.elapsedMs; if (outcome.status !== 'passed') failed.push(file); @@ -1907,7 +1915,7 @@ async function main(): Promise { } if (options.recordDurations) { - return recordFreeTestDurations(files, fullSuiteJobs()); + return recordFreeTestDurations(files, fullSuiteJobs(), recordingWallTimeoutMs(options)); } if (options.attributeHome) return attributeFreeHomeWriters(files.filter(file => !(file in TREE_MUTATING)), files.filter(file => file in TREE_MUTATING), fullSuiteJobs(), (file, index, homeGuard) => runFreeShard([file], index + 1, files.length, { wallTimeoutMs: wallTimeoutForShard(1), quiet: true, log: () => {}, homeGuard })); diff --git a/test/test-free-shards.test.ts b/test/test-free-shards.test.ts index 2ef9d8fbc..16272b9f8 100644 --- a/test/test-free-shards.test.ts +++ b/test/test-free-shards.test.ts @@ -18,6 +18,8 @@ import { DEFAULT_WALL_TIMEOUT_MS, PER_FILE_WALL_MS, wallTimeoutForShard, + recordingWallTimeoutMs, + parseCliOptions, KNOWN_WINDOWS_INCOMPATIBLE, TEST_ROOTS, TREE_MUTATING, @@ -940,6 +942,11 @@ describe('test-free-shards: wall-timeout scaling', () => { test('an explicit base above the scaled value wins', () => { expect(wallTimeoutForShard(10, 10 * 60_000)).toBe(10 * 60_000); }); + + test('--record-durations times each file under the one-file default unless --wall-timeout is explicit', () => { + expect(recordingWallTimeoutMs(parseCliOptions(['--record-durations']))).toBe(wallTimeoutForShard(1)); + expect(recordingWallTimeoutMs(parseCliOptions(['--record-durations', '--wall-timeout', '1200']))).toBe(1_200_000); + }); }); diff --git a/test/windows-native-workflows.test.ts b/test/windows-native-workflows.test.ts index 0023e3228..838d7c528 100644 --- a/test/windows-native-workflows.test.ts +++ b/test/windows-native-workflows.test.ts @@ -62,11 +62,14 @@ test('a record_durations dispatch times each Windows-safe file alone and uploads expect(job.if).toBe('${{ inputs.record_durations }}'); expect(job['runs-on']).toBe('windows-latest'); const record = job.steps.find((step: any) => step.name === 'Time every Windows-safe file alone'); - expect(record.run).toBe('bun run test:windows --record-durations'); + expect(record.run).toBe('bun run test:windows --record-durations --wall-timeout 1200'); expect(record.env.GSTACK_FREE_TEST_DURATIONS).toBeUndefined(); const rename = job.steps.find((step: any) => step.name === 'Name the recording as the Windows seed'); expect(rename.if).toBe('always()'); expect(rename.run).toBe('cp scripts/free-test-durations.json "$RUNNER_TEMP/free-test-durations-windows.json"'); + const logs = job.steps.find((step: any) => step.name === 'Upload full recording logs'); + expect(logs.if).toBe('always()'); + expect(logs.with['include-hidden-files']).toBe(true); expect(job.steps.at(-1).with.name).toBe('free-test-durations-windows'); }); From 9dea818e34d6964229bca83eed112eaedaeef507 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 17 Oct 2026 09:47:50 -0700 Subject: [PATCH 5/8] v1.91.122.0 fix(deps): clear the 2026-11-30 OSV suppressions, replace #3228, exempt dependabot from Version Gate rule 1 (#3239) * fix(deps): clear the OSV suppressions that expire on 2026-11-30 Delete the hono, @anthropic-ai/sdk (#2754) and sprintf-js ignores, which the lockfiles no longer match. Override image-size to 2.0.4 (#2753) and chokidar to 4.0.3 in lib/diagram-render (drops braces), and delete those ignores. Re-date katex to 2027-01-31: its fix is outside mermaid 11's range (mermaid-js/mermaid#8388). html-to-docx 1.8.0 bundles its own image-size 1.x, which the override cannot reach and whose ICNS parser loops forever. make-pdf --to docx now hands it only PNG, JPEG, GIF, WebP or SVG bytes. A golden docx test proves the Word output is unchanged. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * build(deps-dev): @types/bun 1.4.3, prettier 3.9.10; hold the Anthropic SDKs to patches Replaces dependabot #3228 without its agent-sdk 0.3 and sdk 0.133 bumps, which break typecheck:test and overlay-sdk-cancel-eof. Their 0.x breaking releases are semver-minor to dependabot, so the ignore covers minor and major. @types/bun 1.4.3 retires 18 test type diagnostics; the baseline locks that in. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(ci): exempt dependabot dependency-manifest PRs from Version Gate rule 1 Dependabot never edits VERSION, so hard rule 1 failed every package.json PR it opened. The workflow now passes the PR author and changed-file list; the gate skips rule 1 only for dependabot[bot] when every file is a package.json, bun.lock(b) or .github/dependabot.yml. A failed file lookup keeps the rule. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(make-pdf): guard every html-to-docx sizing path, keep non-ICNS formats Review found three spellings that got past the regex guard and still hung --to docx: a data-src decoy, a percent-encoded separator, and an unquoted encoded colon. html-to-docx sizes images on three paths, and buildImage URI-decodes the whole src first. The guard now mirrors all three, drops ICNS (the only input its bundled image-size routes to the looping parser) instead of allowlisting formats, so BMP and TIFF embed as before, and re-parses the result with html-to-docx's own html-to-vdom to fail closed on anything the regex misreads. The golden test tolerates CRLF checkouts on Windows. Version Gate treats a failed file lookup as an empty list, so a partial paginated result cannot decide the exemption. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore(release): stamp v1.91.121.0 Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore(release): restamp v1.91.122.0 Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --------- Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> --- .github/dependabot.yml | 8 + .github/workflows/version-gate.yml | 4 + .osv-scanner.toml | 75 +------- CHANGELOG.md | 17 ++ TODOS.md | 11 +- VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- bun.lock | 16 +- lib/diagram-render/bun.lock | 31 +--- lib/diagram-render/package.json | 1 + make-pdf/src/docx-images.ts | 78 +++++++++ make-pdf/src/html-to-vdom.d.ts | 3 + make-pdf/src/orchestrator.ts | 2 + make-pdf/test/docx-image-size.test.ts | 113 ++++++++++++ make-pdf/test/fixtures/docx-images/doc.md | 11 ++ .../fixtures/docx-images/document.golden.xml | 163 ++++++++++++++++++ make-pdf/test/fixtures/docx-images/square.gif | Bin 0 -> 110 bytes make-pdf/test/fixtures/docx-images/tall.jpg | Bin 0 -> 287 bytes make-pdf/test/fixtures/docx-images/wide.png | Bin 0 -> 328 bytes package.json | 8 +- scripts/compare-pr-version.ts | 14 ++ scripts/typecheck-test-baseline.json | 18 -- test/ceo-finding-fixture.test.ts | 2 +- test/compare-pr-version.test.ts | 80 +++++++++ test/osv-config-wiring.test.ts | 8 + test/osv-ignore-expiry.test.ts | 19 +- test/workflow-action-pins.test.ts | 9 + tsconfig.test.json | 3 +- 28 files changed, 554 insertions(+), 144 deletions(-) create mode 100644 make-pdf/src/docx-images.ts create mode 100644 make-pdf/src/html-to-vdom.d.ts create mode 100644 make-pdf/test/docx-image-size.test.ts create mode 100644 make-pdf/test/fixtures/docx-images/doc.md create mode 100644 make-pdf/test/fixtures/docx-images/document.golden.xml create mode 100644 make-pdf/test/fixtures/docx-images/square.gif create mode 100644 make-pdf/test/fixtures/docx-images/tall.jpg create mode 100644 make-pdf/test/fixtures/docx-images/wide.png create mode 100644 test/compare-pr-version.test.ts diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3fdfdc9f2..7392520e5 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -21,6 +21,14 @@ updates: update-types: ["version-update:semver-minor", "version-update:semver-major"] - dependency-name: "playwright-core" update-types: ["version-update:semver-minor", "version-update:semver-major"] + # The eval harness pins the agent SDK exactly. Its 0.x breaking releases + # are semver-minor to dependabot: agent-sdk 0.2 -> 0.3 and sdk 0.78 -> + # 0.133 (#3228) break typecheck:test and overlay-sdk-cancel-eof. Patch + # updates still flow; the SDK migration lands as its own maintainer PR. + - dependency-name: "@anthropic-ai/claude-agent-sdk" + update-types: ["version-update:semver-minor", "version-update:semver-major"] + - dependency-name: "@anthropic-ai/sdk" + update-types: ["version-update:semver-minor", "version-update:semver-major"] open-pull-requests-limit: 5 - package-ecosystem: "github-actions" diff --git a/.github/workflows/version-gate.yml b/.github/workflows/version-gate.yml index e034aaa3e..4943a1f6e 100644 --- a/.github/workflows/version-gate.yml +++ b/.github/workflows/version-gate.yml @@ -73,6 +73,10 @@ jobs: - name: Compare PR VERSION to next free slot env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PR_VERSION: ${{ steps.versions.outputs.pr_version }} + PR_AUTHOR: ${{ github.event.pull_request.user.login }} run: | + if ! PR_CHANGED_FILES=$(gh api --paginate "repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" --jq '.[].filename'); then PR_CHANGED_FILES=""; fi + export PR_CHANGED_FILES bun run scripts/compare-pr-version.ts next.json "${{ github.event.pull_request.number }}" diff --git a/.osv-scanner.toml b/.osv-scanner.toml index cac5e40a6..7062905f8 100644 --- a/.osv-scanner.toml +++ b/.osv-scanner.toml @@ -16,73 +16,16 @@ # forces a fresh decision. Tracking issues are filed at ship time and named in # each reason. -[[IgnoredVulns]] -id = "GHSA-frvp-7c67-39w9" -# @hono/node-server 1.19.x. Reachable only through @modelcontextprotocol/sdk, -# which is an unused transitive dependency (no source file imports it) and never -# starts a Hono HTTP server, so the advisory's request path is not exercised. -# The only fix is @hono/node-server 2.0.5, a major bump the MCP SDK pins against -# (^1.19.9); forcing it via override risks breaking the SDK at runtime for a -# vulnerability we do not expose. Re-evaluate if the MCP SDK becomes a direct, -# server-hosting dependency. -reason = "Unreachable transitive (unused @modelcontextprotocol/sdk); fix requires a risky major override on a pinned peer dep." -ignoreUntil = 2026-11-30T00:00:00Z - -[[IgnoredVulns]] -id = "GHSA-5p2g-fcmc-qvqq" -# image-size 1.2.1 via html-to-docx@1.8.0. image-size 2.0.3 (2026-09-14) -# fixes both advisories, but html-to-docx pins image-size ^1.0.0 and no fixed -# 1.x exists, so taking the fix is a cross-major override. Exposure: -# image-size only parses images the user themselves embeds into their own -# generated .docx; no untrusted input path. Upgrade trigger: html-to-docx -# moving off image-size 1.x, or a deliberate override to 2.x after checking -# html-to-docx's call site against 2.x's API with a docx-export smoke test. -# Tracking: #2753. -reason = "Fixed in image-size 2.0.3, but html-to-docx pins image-size ^1.0.0 (no fixed 1.x); local-only input path (user's own docx images). Re-evaluate on expiry." -ignoreUntil = 2026-11-30T00:00:00Z - -[[IgnoredVulns]] -id = "GHSA-w3rx-r6r6-pgpr" -# Same package/node as GHSA-5p2g-fcmc-qvqq above; same rationale. -reason = "Fixed in image-size 2.0.3, but html-to-docx pins image-size ^1.0.0 (no fixed 1.x); local-only input path (user's own docx images). Re-evaluate on expiry." -ignoreUntil = 2026-11-30T00:00:00Z - -[[IgnoredVulns]] -id = "GHSA-p7fg-763f-g4gf" -# @anthropic-ai/sdk 0.81.0 nested under @anthropic-ai/claude-agent-sdk@0.2.117, -# which is deliberately exact-pinned (eval-harness stability; the v1.77 wave -# pinned the whole harness after repeated CLI-drift breakage) and declares -# ^0.81.0 (0.x caret = 0.81.x only), so the 0.91.1 fix cannot be reached -# without violating the harness pin. 4.8 MEDIUM. Upgrade trigger: the next -# deliberate claude-agent-sdk bump. Tracking: #2754. -reason = "Fix requires breaking the deliberate eval-harness agent-sdk pin; MEDIUM severity accepted until the next harness bump." -ignoreUntil = 2026-11-30T00:00:00Z - -[[IgnoredVulns]] -id = "GHSA-vfj7-8cjw-p6xm" -# braces 3.0.3 in lib/diagram-render only: @excalidraw/excalidraw -> sass -> -# chokidar -> braces. chokidar is sass's Node file watcher; the diagram-render -# bundle is built for the browser and contains no chokidar/braces code -# (test/osv-config-wiring.test.ts checks the built page for chokidar). No fixed -# braces release exists. Re-evaluate on expiry or when excalidraw drops sass. -reason = "Build-time only (excalidraw -> sass -> chokidar); not in the shipped browser bundle; no fixed release." -ignoreUntil = 2026-11-30T00:00:00Z - -[[IgnoredVulns]] -id = "GHSA-hp3w-g68c-fv3c" -# sprintf-js 1.1.3 (DoS through an unbounded precision specifier in the FORMAT -# string). Reachable only as roarr's logger dependency (global-agent -> roarr), -# which formats its own constant messages; no caller passes user-controlled -# format strings. No fixed release exists. -reason = "No fixed release; only roarr's constant-format logging reaches it." -ignoreUntil = 2026-11-30T00:00:00Z - [[IgnoredVulns]] id = "GHSA-238p-pmpm-9mq7" # katex 0.16.47 in lib/diagram-render (mermaid's math renderer). The advisory # needs prototype pollution to already exist in the page; the render page is -# offline, loads only gstack's own bundle and the user's diagram source. The -# only fix is 0.18.x, outside mermaid 11.16's ^0.16 range. Low severity (2.1). -# Re-evaluate when mermaid accepts katex 0.18. -reason = "Requires pre-existing prototype pollution in an offline single-bundle page; fix is outside mermaid's katex range; low severity." -ignoreUntil = 2026-11-30T00:00:00Z +# offline, loads only gstack's own bundle and the user's diagram source. Low +# severity (2.1). The fix is katex 0.18.2, outside mermaid 11's ^0.16.47 range. +# Mermaid 12 accepts ^0.18, but @excalidraw/mermaid-to-excalidraw 2.2.2 (the +# latest) requires mermaid ^11.12.1, and katex 0.18 renames KaTeX's CSS +# classes, so forcing it means a bundle requalification, not a lockfile bump. +# Upgrade trigger: a mermaid 11.x release that allows katex 0.18 +# (https://github.com/mermaid-js/mermaid/issues/8388), then rebuild the bundle. +reason = "Fix (katex 0.18.2) is outside mermaid 11's ^0.16 range; waiting on mermaid-js/mermaid#8388. Needs pre-existing prototype pollution in an offline single-bundle page; low severity." +ignoreUntil = 2027-01-31T00:00:00Z diff --git a/CHANGELOG.md b/CHANGELOG.md index 79fc1201d..7dfa0a6e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [1.91.122.0] - 2026-10-17 + +**Main no longer goes red on 2026-11-16.** All seven `.osv-scanner.toml` suppressions expired on 2026-11-30, and `test/osv-ignore-expiry.test.ts` fails 14 days early. Six are gone and the seventh is re-dated with an upstream link. Dependabot's grouped dev bump (#3228) is replaced by hand, and Version Gate stops failing every dependabot package.json PR. + +### Fixed +- **Six OSV suppressions removed (#2754, #2753).** The hono, @anthropic-ai/sdk and sprintf-js ignores no longer matched either lockfile. image-size is overridden to 2.0.4. braces leaves `lib/diagram-render` because chokidar is overridden to 4.0.3; that bundle's sha256 is unchanged. katex (low) is re-dated to 2027-01-31: its fix needs a mermaid 11 release that allows katex 0.18 (mermaid-js/mermaid#8388). osv-scanner reports no issues and no unused ignores. +- **`make-pdf --to docx` no longer hangs on an ICNS image.** html-to-docx 1.8.0 sizes images with its own bundled image-size 1.x, which the override cannot reach and which loops forever on GHSA-w3rx-r6r6-pgpr's input. ICNS images are dropped with a warning before conversion. The result is re-parsed with html-to-docx's own html-to-vdom, so a tag the guard misreads fails the conversion instead of hanging it. Every other image format embeds as before; a golden test pins the Word output. +- **Version Gate passes dependabot dependency PRs.** Hard rule 1 (VERSION above base) is skipped only when the author is `dependabot[bot]` and every changed file is a `package.json`, a `bun.lock` or `.github/dependabot.yml`. A failed file lookup keeps the rule. + +### Changed +- **@types/bun 1.4.3 and prettier 3.9.10.** The test type baseline drops 18 diagnostics. +- **Dependabot holds both Anthropic SDKs to patch updates.** Their breaking 0.x releases (agent-sdk 0.2 to 0.3, sdk 0.78 to 0.133) count as minor bumps to dependabot and break `typecheck:test` and `overlay-sdk-cancel-eof`. + +### If you… +- **…delete an OSV ignore after adding an override:** check that the vulnerable code loads from node_modules. A dependency that bundles its own copy keeps the old code even though the lockfile looks fixed. +- **…convert untrusted markdown with `--to docx --allow-network`:** html-to-docx still downloads remote images and sizes them with its bundled copy (#2753 stays open for this). + ## [1.91.121.0] - 2026-10-17 **Windows free-test shards stop running out of time on files the Windows seed didn't know.** The Windows duration seed dated from 2026-10-04 and had no entry for `test/gstack-doctor.test.ts` (about 6.5 minutes on Windows) or `test/hook-scripts.test.ts`. The packer guessed, put `cookie-import-native-job` into a 121-file shard, and that shard hit the 15-minute job limit. diff --git a/TODOS.md b/TODOS.md index e8ab35a1b..aa26453fa 100644 --- a/TODOS.md +++ b/TODOS.md @@ -41,8 +41,8 @@ The 158 older open issues were re-checked against main 5cb5e1c (v1.91.83.0). Of - **/cso** - #2993: tracked under the /cso capacity follow-ups above. **Priority:** P2. - **Dependency security ledgers** (not code defects; keep open until the trigger) - - #2753: `.osv-scanner.toml` ignores image-size (via html-to-docx) until 2026-11-30. Bump it once a fixed release exists, or re-justify at expiry. **Effort:** S. **Priority:** P3. - - #2754: `.osv-scanner.toml` ignores `@anthropic-ai/sdk` 0.81.0 under the pinned claude-agent-sdk until 2026-11-30. Drop it with the next harness bump. **Effort:** S. **Priority:** P3. + - `.osv-scanner.toml` ignores katex 0.16.47 in lib/diagram-render (GHSA-238p-pmpm-9mq7, low) until 2027-01-31. The fix (0.18.2) is outside mermaid 11's range; when mermaid-js/mermaid#8388 ships, override katex, rebuild the bundle and drop the ignore. **Effort:** S. **Priority:** P3. + - #2753 residual: html-to-docx 1.8.0 bundles its own image-size 1.x, which the package.json override cannot reach. `make-pdf --to docx` never hands it ICNS bytes (make-pdf/src/docx-images.ts), but with `--allow-network` html-to-docx downloads remote images and sizes them itself. Inline remote images before the guard for docx, or replace html-to-docx. Revisit 2026-12-15. **Effort:** M. **Priority:** P2. - **Tests and CI** - #2756: the periodic lane. Tracked under "Periodic-lane stabilization (#2756)". **Priority:** P2. - #2967: `test/redact-prepush-scan-range.test.ts` (and its rebase twin) run fixture pushes with the inherited global config, so a developer's `core.hooksPath` pre-push runs inside the fixture. Set `GIT_CONFIG_GLOBAL=/dev/null` and `GIT_CONFIG_NOSYSTEM=1` in the helper. **Effort:** S. **Priority:** P3. @@ -965,10 +965,9 @@ wave"). Each was explicitly deferred with rationale, not dropped: - **mermaid 10→11-class major bumps in lib/diagram-render** — the wave's dependency pass cleared 102 of 105 OSV advisories via in-range bumps + - overrides; the residual ignores (image-size no-fix, @anthropic-ai/sdk under - the harness-pinned agent-sdk) carry `ignoreUntil` expiries (~2026-11-30) and - re-justify themselves on expiry. When the agent-sdk pin next moves, drop the - GHSA-p7fg ignore. Effort S. **Priority:** P3. + overrides; the residual ignores carry `ignoreUntil` expiries and + re-justify themselves on expiry. Only the katex ignore remains (see the + dependency security ledgers above). Effort S. **Priority:** P3. - **#2750 split absorption** — the record-scanning Codex JSONL parser (real fix; current Codex streams interleave envelopes so sessions vanish from /retro global) should be absorbed once the author splits it from the diff --git a/VERSION b/VERSION index f3edfab61..e0b7c3105 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.121.0 +1.91.122.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index f39a93c46..47072b96d 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.121.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.122.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/bun.lock b/bun.lock index db2f7ae8d..f96507bb4 100644 --- a/bun.lock +++ b/bun.lock @@ -10,6 +10,7 @@ "cross-spawn": "^7.0.6", "diff": "^9.0.0", "html-to-docx": "1.8.0", + "html-to-vdom": "0.7.0", "marked": "^18.0.11", "playwright": "^1.62.1", "sharp": "^0.35.4", @@ -18,8 +19,8 @@ "devDependencies": { "@anthropic-ai/claude-agent-sdk": "0.2.141", "@anthropic-ai/sdk": "^0.78.0", - "@types/bun": "1.4.2", - "prettier": "3.9.9", + "@types/bun": "1.4.3", + "prettier": "3.9.10", "typescript": "7.0.2", "xterm": "^5.3.0", "xterm-addon-fit": "^0.8.0", @@ -34,6 +35,7 @@ "adm-zip": "^0.6.1", "fast-uri": "3.1.8", "hono": "4.13.13", + "image-size": "2.0.4", "ip-address": "10.7.3", "proxy-addr": "2.0.8", "sharp": "0.35.5", @@ -181,7 +183,7 @@ "@protobufjs/utf8": ["@protobufjs/utf8@1.1.2", "", {}, "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug=="], - "@types/bun": ["@types/bun@1.4.2", "", { "dependencies": { "bun-types": "1.4.2" } }, "sha512-GimotNn7+ZV0uVArItBbriZsR1oNf0+WTzPkdcFrzShI7k2norL0uzEaJT8T33dWr7O/c9ZDuAFQrctKCi72oQ=="], + "@types/bun": ["@types/bun@1.4.3", "", { "dependencies": { "bun-types": "1.4.3" } }, "sha512-N67Pqy8JXbAY/j0tNraS3V5mubGvc6rrrNDmDCtZLlFzccbUJPDb0tvgUBC5q4m8ybkP93Jcn1QB+RYQ6PvBhw=="], "@types/node": ["@types/node@26.4.0", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-faiGnoIrLH/V8cibOMEAZ8pMw6oXqSukl29ra4mN8GdaB2ZewzeaLj+INpV5N+Z1eKWzY+IzaIZH2EIR6YZRNQ=="], @@ -237,7 +239,7 @@ "browser-split": ["browser-split@0.0.1", "", {}, "sha512-JhvgRb2ihQhsljNda3BI8/UcRHVzrVwo3Q+P8vDtSiyobXuFpuZ9mq+MbRGMnC22CjW3RrfXdg6j6ITX8M+7Ow=="], - "bun-types": ["bun-types@1.4.2", "", { "dependencies": { "@types/node": "*" } }, "sha512-bxV1FgK7yBIzjRe5zBozIM4Bem11ZJcCXSrjWRG3YWLt8yFDePu4cLjpebO8OvPeIE9trbyPF4fuj3Cia4Fj3w=="], + "bun-types": ["bun-types@1.4.3", "", { "dependencies": { "@types/node": "*", "undici-types": "*" } }, "sha512-tinRJNGOmUN+tEAsn2y2e942n9JHRHR42iUYzDH75NmhJqVBokGSQkkfSFdNWwsANIdrK6ACH9t01M452YyTwg=="], "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], @@ -371,7 +373,7 @@ "iconv-lite": ["iconv-lite@0.7.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ=="], - "image-size": ["image-size@1.2.1", "", { "dependencies": { "queue": "6.0.2" }, "bin": { "image-size": "bin/image-size.js" } }, "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw=="], + "image-size": ["image-size@2.0.4", "", { "bin": { "image-size": "bin/image-size.js" } }, "sha512-QRUkFFsRV/6fuESxb9Vkq+a0LkSrgKXuc2NEqfikiXxxN/G3tjWt5EVUlMaImRBZRZK/jRBEbYvpPYZL8t08Zw=="], "image-to-base64": ["image-to-base64@2.2.0", "", { "dependencies": { "node-fetch": "^2.6.0" } }, "sha512-Z+aMwm/91UOQqHhrz7Upre2ytKhWejZlWV/JxUTD1sT7GWWKFDJUEV5scVQKnkzSgPHFuQBUEWcanO+ma0PSVw=="], @@ -469,7 +471,7 @@ "playwright-core": ["playwright-core@1.62.1", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-wPYSwEBJY9GHraISXqyqtx0na0LpO3XEX7jNDhntbex7tzUS7kLnZsOlFruFJB4Hi/rhDMjXGqHewDZ68nYZVw=="], - "prettier": ["prettier@3.9.9", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-Z/CJHIkdujO/OtN7nXUii0Rf3VT5SRuhjBA82Xvu2XhBUgX3nhP67T0LHceBdQLex7OOFGTox+Q5Yg8Jk2Qivg=="], + "prettier": ["prettier@3.9.10", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-skGHTH1Yb9QvaTC4hWnRTzEYtCpApF0UMBPz+t/0ZPzP8ihefo/btKd+QA7pUE0fEwA1SbS/NmhyEcstdXOIdA=="], "process": ["process@0.11.10", "", {}, "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A=="], @@ -483,8 +485,6 @@ "qs": ["qs@6.16.0", "", { "dependencies": { "es-define-property": "^1.0.1", "side-channel": "^1.1.1" } }, "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA=="], - "queue": ["queue@6.0.2", "", { "dependencies": { "inherits": "~2.0.3" } }, "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA=="], - "range-parser": ["range-parser@1.3.0", "", {}, "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw=="], "raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="], diff --git a/lib/diagram-render/bun.lock b/lib/diagram-render/bun.lock index fa55c8ade..ccf979184 100644 --- a/lib/diagram-render/bun.lock +++ b/lib/diagram-render/bun.lock @@ -14,6 +14,7 @@ }, }, "overrides": { + "chokidar": "4.0.3", "dompurify": "3.4.16", "lodash-es": "4.18.1", "nanoid": "5.1.16", @@ -178,14 +179,8 @@ "@upsetjs/venn.js": ["@upsetjs/venn.js@2.0.0", "", { "optionalDependencies": { "d3-selection": "^3.0.0", "d3-transition": "^3.0.1" } }, "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw=="], - "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], - "aria-hidden": ["aria-hidden@1.2.6", "", { "dependencies": { "tslib": "^2.0.0" } }, "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA=="], - "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - - "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], - "browser-fs-access": ["browser-fs-access@0.29.1", "", {}, "sha512-LSvVX5e21LRrXqVMhqtAwj5xPgDb+fXAIH80NsnCQ9xuZPs2xWsOREi24RKgZa1XOiQRbcmVrv87+ulOKsgjxw=="], "canvas-roundrect-polyfill": ["canvas-roundrect-polyfill@0.0.1", "", {}, "sha512-yWq+R3U3jE+coOeEb3a3GgE2j/0MMiDKM/QpLb6h9ihf5fGY9UXtvK9o4vNqjWXoZz7/3EaSVU3IX53TvFFUOw=="], @@ -194,7 +189,7 @@ "chevrotain-allstar": ["chevrotain-allstar@0.3.1", "", { "dependencies": { "lodash-es": "^4.17.21" }, "peerDependencies": { "chevrotain": "^11.0.0" } }, "sha512-b7g+y9A0v4mxCW1qUhf3BSVPg+/NvGErk/dOkrDaHA0nQIQGAtrOjlX//9OQtRlSCy+x9rfB5N8yC71lH1nvMw=="], - "chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "clsx": ["clsx@1.1.1", "", {}, "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="], @@ -292,18 +287,12 @@ "es6-promise-pool": ["es6-promise-pool@2.5.0", "", {}, "sha512-VHErXfzR/6r/+yyzPKeBvO0lgjfC5cbDCQWjWwMZWSb6YU39TGIl51OUmCfWCq4ylMdJSB8zkz2vIuIeIxXApA=="], - "fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="], - "fractional-indexing": ["fractional-indexing@3.2.0", "", {}, "sha512-PcOxmqwYCW7O2ovKRU8OoQQj2yqTfEB/yeTYk4gPid6dN5ODRfU1hXd9tTVZzax/0NkO7AxpHykvZnT1aYp/BQ=="], - "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], - "fuzzy": ["fuzzy@0.1.3", "", {}, "sha512-/gZffu4ykarLrCiP3Ygsa86UAo1E5vEVlvTrpkKywXSbP9Xhln3oSp9QSV57gEq3JFFpGJ4GZ+5zdEp3FcUh4w=="], "get-nonce": ["get-nonce@1.0.1", "", {}, "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q=="], - "glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], - "glur": ["glur@1.1.2", "", {}, "sha512-l+8esYHTKOx2G/Aao4lEQ0bnHWg4fWtJbVoZZT9Knxi01pB8C80BR85nONLFwkkQoFRCmXY+BUcGZN3yZ2QsRA=="], "hachure-fill": ["hachure-fill@0.5.2", "", {}, "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg=="], @@ -320,14 +309,6 @@ "internmap": ["internmap@2.0.3", "", {}, "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg=="], - "is-binary-path": ["is-binary-path@2.1.0", "", { "dependencies": { "binary-extensions": "^2.0.0" } }, "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="], - - "is-extglob": ["is-extglob@2.1.1", "", {}, "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ=="], - - "is-glob": ["is-glob@4.0.3", "", { "dependencies": { "is-extglob": "^2.1.1" } }, "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="], - - "is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="], - "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], "jotai": ["jotai@2.11.0", "", { "peerDependencies": { "@types/react": ">=17.0.0", "react": ">=17.0.0" }, "optionalPeers": ["@types/react", "react"] }, "sha512-zKfoBBD1uDw3rljwHkt0fWuja1B76R7CjznuBO+mSX6jpsO1EBeWNRKpeaQho9yPI/pvCv4recGfgOXGxwPZvQ=="], @@ -360,8 +341,6 @@ "nanoid": ["nanoid@5.1.16", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-kVrnsrJqMR8+oLJnGEmSWw9BivK5mt7H3FZatVRjrc5wGqFYuBxX1yG7+A7Gi5AefkX6t/oCkizcQgpu0cY1dQ=="], - "normalize-path": ["normalize-path@3.0.0", "", {}, "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="], - "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], "open-color": ["open-color@1.9.1", "", {}, "sha512-vCseG/EQ6/RcvxhUcGJiHViOgrtz4x0XbZepXvKik66TMGkvbmjeJrKFyBEx6daG5rNyyd14zYXhz0hZVwQFOw=="], @@ -378,8 +357,6 @@ "pica": ["pica@7.1.1", "", { "dependencies": { "glur": "^1.1.2", "inherits": "^2.0.3", "multimath": "^2.0.0", "object-assign": "^4.1.1", "webworkify": "^1.5.0" } }, "sha512-WY73tMvNzXWEld2LicT9Y260L43isrZ85tPuqRyvtkljSDLmnNFQmZICt4xUJMVulmcc6L9O7jbBrtx3DOz/YQ=="], - "picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], - "png-chunk-text": ["png-chunk-text@1.0.0", "", {}, "sha512-DEROKU3SkkLGWNMzru3xPVgxyd48UGuMSZvioErCure6yhOc/pRH2ZV+SEn7nmaf7WNf3NdIpH+UTrRdKyq9Lw=="], "png-chunks-encode": ["png-chunks-encode@1.0.0", "", { "dependencies": { "crc-32": "^0.3.0", "sliced": "^1.0.1" } }, "sha512-J1jcHgbQRsIIgx5wxW9UmCymV3wwn4qCCJl6KYgEU/yHCh/L2Mwq/nMOkRPtmV79TLxRZj5w3tH69pvygFkDqA=="], @@ -402,7 +379,7 @@ "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], - "readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "robust-predicates": ["robust-predicates@3.0.3", "", {}, "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA=="], @@ -428,8 +405,6 @@ "tinyexec": ["tinyexec@1.3.0", "", {}, "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ=="], - "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], - "ts-dedent": ["ts-dedent@2.3.0", "", {}, "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], diff --git a/lib/diagram-render/package.json b/lib/diagram-render/package.json index 6c4bc4ef6..8a41abd38 100644 --- a/lib/diagram-render/package.json +++ b/lib/diagram-render/package.json @@ -14,6 +14,7 @@ "react-dom": "18.3.1" }, "overrides": { + "chokidar": "4.0.3", "dompurify": "3.4.16", "nanoid": "5.1.16", "source-map-js": "1.2.2", diff --git a/make-pdf/src/docx-images.ts b/make-pdf/src/docx-images.ts new file mode 100644 index 000000000..1df00b6d6 --- /dev/null +++ b/make-pdf/src/docx-images.ts @@ -0,0 +1,78 @@ +/** + * DOCX image guard. html-to-docx 1.8.0 sizes every data-URI with its + * own bundled copy of image-size 1.x, which the package.json override cannot + * reach. That copy's detector sends a buffer to its ICNS parser exactly when + * the bytes start with "icns", and the parser loops forever on a zero-length + * entry (GHSA-w3rx-r6r6-pgpr). No other parser in the copy has a known flaw. + * + * guardDocxImages drops the tags it can see that would size unsafe + * bytes, then re-parses the result with the same html-to-vdom html-to-docx + * uses and refuses the document if any it would size is still unsafe, + * so a tag the regex misreads fails closed instead of hanging. + */ +import HTMLToVDOM from "html-to-vdom"; + +/** html-to-docx's data-URI pattern, shared by all three of its sizeOf call sites. */ +const DATA_URI = /^data:([A-Za-z-+\/]+);base64,(.+)$/; +const IMG_TAG = /]*>/gi; +const SRC_ATTR = /(?:^|\s)src\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i; + +interface ImgNode { tagName?: string; properties?: { src?: unknown }; children?: ImgNode[] } + +const toVdom = HTMLToVDOM({ + VNode: function (this: ImgNode, tagName: string, properties: ImgNode["properties"], children: ImgNode[]) { + Object.assign(this, { tagName, properties, children }); + }, + VText: function () {}, +}); + +function tryDecode(text: string): string | null { + try { + return decodeURIComponent(text); + } catch { + return null; + } +} + +function isIcns(base64: string | null | undefined): boolean { + return base64 != null && Buffer.from(base64, "base64").toString("ascii", 0, 4) === "icns"; +} + +/** + * False when html-to-docx would hand ICNS bytes to its bundled sizer. Its two + * paragraph paths match the raw src and URI-decode the payload; buildImage + * URI-decodes the whole src, matches that, and sizes the payload as is. + */ +function sizesSafely(src: unknown): boolean { + if (typeof src !== "string") return true; + const raw = src.match(DATA_URI); + if (raw && isIcns(tryDecode(raw[2]))) return false; + return !isIcns(tryDecode(src)?.match(DATA_URI)?.[2]); +} + +/** html-to-docx's minifyHTMLString, so the re-parse sees the string it parses. */ +function minify(html: string): string { + return html.replace(/\n/g, " ").replace(/\r/g, " ").replace(/[\t]+[\t ]+<").replace(/>[\t ]+$/g, ">"); +} + +function* imgSources(nodes: ImgNode | ImgNode[]): Generator { + for (const node of Array.isArray(nodes) ? nodes : [nodes]) { + if (node.tagName === "img") yield node.properties?.src; + if (node.children) yield* imgSources(node.children); + } +} + +export function guardDocxImages(html: string, warn: (msg: string) => void): string { + const guarded = html.replace(IMG_TAG, (tag) => { + const src = tag.match(SRC_ATTR); + if (sizesSafely(src?.[1] ?? src?.[2] ?? src?.[3])) return tag; + warn("docx: dropped an ICNS image (html-to-docx's bundled image-size hangs on it)"); + return ""; + }); + for (const src of imgSources(toVdom(minify(guarded)))) { + if (!sizesSafely(src)) { + throw new Error("docx: an tag hides an ICNS image, which html-to-docx's bundled image-size hangs on; convert or remove it"); + } + } + return guarded; +} diff --git a/make-pdf/src/html-to-vdom.d.ts b/make-pdf/src/html-to-vdom.d.ts new file mode 100644 index 000000000..4224f4fdf --- /dev/null +++ b/make-pdf/src/html-to-vdom.d.ts @@ -0,0 +1,3 @@ +declare module 'html-to-vdom' { + export default function HTMLToVDOM(dependencies: { VNode: Function; VText: Function }): (html: string) => any; +} diff --git a/make-pdf/src/orchestrator.ts b/make-pdf/src/orchestrator.ts index b392e6393..4fe440546 100644 --- a/make-pdf/src/orchestrator.ts +++ b/make-pdf/src/orchestrator.ts @@ -41,6 +41,7 @@ import { substituteSlots, } from "./diagram-prepass"; import { applyImagePolicy } from "./image-policy"; +import { guardDocxImages } from "./docx-images"; /** Default output location (`$P generate letter.md` → /tmp/letter.pdf). */ export const OUTPUT_TMP_DIR = process.platform === "win32" ? os.tmpdir() : "/tmp"; @@ -174,6 +175,7 @@ export async function generate(opts: GenerateOptions): Promise { progress.end("Rasterizing diagrams for DOCX"); } finalHtml = convertDiagnosticsForDocx(finalHtml); + finalHtml = guardDocxImages(finalHtml, warn); } // ─── --to html: write the self-contained document, no print round-trip ── diff --git a/make-pdf/test/docx-image-size.test.ts b/make-pdf/test/docx-image-size.test.ts new file mode 100644 index 000000000..8301303c9 --- /dev/null +++ b/make-pdf/test/docx-image-size.test.ts @@ -0,0 +1,113 @@ +/** + * DOCX image sizing (#2753). package.json overrides image-size to 2.x, which + * fixes GHSA-5p2g-fcmc-qvqq and GHSA-w3rx-r6r6-pgpr in the lockfile, but + * html-to-docx 1.8.0 never loads it: it runs its own bundled image-size 1.x. + * The golden document.xml pins the Word output the change must not move. The + * guard tests prove ICNS bytes, which hang that bundled copy, never reach it, + * however the tag is spelled. + */ +import { describe, expect, test } from "bun:test"; +import { execFileSync } from "node:child_process"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; + +import { guardDocxImages } from "../src/docx-images"; +import { generate } from "../src/orchestrator"; + +const FIXTURES = path.join(import.meta.dir, "fixtures", "docx-images"); +const EMU_PER_PX = 9525; +const IMAGES = [ + { file: "wide.png", ext: "png", width: 120, height: 48 }, + { file: "tall.jpg", ext: "jpeg", width: 30, height: 90 }, + { file: "square.gif", ext: "gif", width: 64, height: 64 }, +]; + +/** GHSA-w3rx-r6r6-pgpr: valid ICNS magic and a zero-length entry. */ +function icnsLoop(): Buffer { + const buf = Buffer.alloc(24); + buf.write("icns", 0); + buf.writeUInt32BE(24, 4); + buf.write("ic08", 8); + return buf; +} + +function unzip(args: string[]): Buffer { + return execFileSync("unzip", args, { timeout: 30_000, maxBuffer: 16 * 1024 * 1024 }); +} + +describe("make-pdf --to docx image sizing", () => { + test("embeds every image at its pixel size, matching the image-size 1.x output", async () => { + const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "make-pdf-docx-images-")); + try { + const out = path.join(workDir, "out.docx"); + await generate({ input: path.join(FIXTURES, "doc.md"), output: out, to: "docx", quiet: true }); + + const xml = unzip(["-p", out, "word/document.xml"]).toString("utf8"); + const extents = [...xml.matchAll(//g)].map(m => [Number(m[1]), Number(m[2])]); + expect(extents).toEqual(IMAGES.map(img => [img.width * EMU_PER_PX, img.height * EMU_PER_PX])); + + const media = unzip(["-Z1", out]).toString("utf8").split("\n").filter(name => /^word\/media\/.+/.test(name)); + expect(media).toHaveLength(IMAGES.length); + for (const [i, img] of IMAGES.entries()) { + expect(media[i].endsWith(`.${img.ext}`)).toBe(true); + expect(unzip(["-p", out, media[i]]).equals(fs.readFileSync(path.join(FIXTURES, img.file)))).toBe(true); + } + + const normalized = xml.replace(/image-[A-Za-z0-9_-]{21}\.(png|jpeg|gif)/g, "image-ID.$1"); + const golden = fs.readFileSync(path.join(FIXTURES, "document.golden.xml"), "utf8").replace(/\r\n/g, "\n"); + expect(normalized.trimEnd()).toBe(golden.trimEnd()); + } finally { + fs.rmSync(workDir, { recursive: true, force: true }); + } + }); + + test("the guard drops ICNS images however the tag is spelled and keeps every other format", () => { + const icns = "data:image/png;base64," + icnsLoop().toString("base64"); + const png = "data:image/png;base64," + fs.readFileSync(path.join(FIXTURES, "wide.png")).toString("base64"); + const bmp = "data:image/bmp;base64," + Buffer.from("BM" + "\0".repeat(52)).toString("base64"); + const warnings: string[] = []; + const guard = (html: string) => guardDocxImages(html, msg => warnings.push(msg)); + expect(guard(`

`)).toBe(`

`); + expect(warnings).toEqual([]); + for (const tag of [ + ``, + `x`, + ``, + ``, + ``, + ``, + ``, + ``, + ]) expect(guard(`

${tag}

`)).toBe("

"); + expect(warnings).toHaveLength(8); + }); + + test("a tag the regex misreads fails closed through html-to-docx's own parser", () => { + const icns = "data:image/png;base64," + icnsLoop().toString("base64"); + expect(() => guardDocxImages(`

>

`, () => {})).toThrow("hides an ICNS image"); + }); + + test("the re-parse uses the html-to-vdom copy html-to-docx loads", () => { + const fromDocx = require.resolve("html-to-vdom/package.json", { paths: [path.dirname(require.resolve("html-to-docx/package.json"))] }); + expect(fromDocx).toBe(require.resolve("html-to-vdom/package.json")); + }); + + test("an ICNS file named .png is dropped with a warning instead of hanging the conversion", () => { + const workDir = fs.mkdtempSync(path.join(os.tmpdir(), "make-pdf-docx-icns-")); + try { + fs.writeFileSync(path.join(workDir, "evil.png"), icnsLoop()); + fs.writeFileSync(path.join(workDir, "doc.md"), "# ICNS\n\n![evil](evil.png)\n\n![inline](data:image/png;base64," + icnsLoop().toString("base64") + ")\n"); + const out = path.join(workDir, "out.docx"); + const script = `import { generate } from ${JSON.stringify(path.join(import.meta.dir, "..", "src", "orchestrator.ts"))}; +await generate({ input: ${JSON.stringify(path.join(workDir, "doc.md"))}, output: ${JSON.stringify(out)}, to: "docx" });`; + const run = Bun.spawnSync([process.execPath, "-e", script], { timeout: 30_000, stdout: "pipe", stderr: "pipe" }); + const stderr = run.stderr.toString(); + expect(run.exitCode).toBe(0); + expect(stderr.match(/docx: dropped an ICNS image/g)).toHaveLength(2); + expect(unzip(["-p", out, "word/document.xml"]).toString("utf8")).not.toContain(""); + } finally { + fs.rmSync(workDir, { recursive: true, force: true }); + } + }); +}); diff --git a/make-pdf/test/fixtures/docx-images/doc.md b/make-pdf/test/fixtures/docx-images/doc.md new file mode 100644 index 000000000..fd1fdec1a --- /dev/null +++ b/make-pdf/test/fixtures/docx-images/doc.md @@ -0,0 +1,11 @@ +# Image sizing smoke + +A wide PNG: + +![wide](wide.png) + +A tall JPEG and a square GIF: + +![tall](tall.jpg) + +![square](square.gif) diff --git a/make-pdf/test/fixtures/docx-images/document.golden.xml b/make-pdf/test/fixtures/docx-images/document.golden.xml new file mode 100644 index 000000000..e9e4c4c04 --- /dev/null +++ b/make-pdf/test/fixtures/docx-images/document.golden.xml @@ -0,0 +1,163 @@ + + + + + + + + + + + + + + + + + + + + + + + + Image sizing smoke + + + + + + + + + A wide PNG: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A tall JPEG and a square GIF: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/make-pdf/test/fixtures/docx-images/square.gif b/make-pdf/test/fixtures/docx-images/square.gif new file mode 100644 index 0000000000000000000000000000000000000000..3fcc4a7c726df05cb9e8aeb6bcb57c4669478915 GIT binary patch literal 110 zcmZ?wbhEHbbYO5`XkcLQ$t)B(5vBN(g_QvabU*}1hJneor+?+?xBQFeY`N9F`QD!2 z{B4gsrakLi_UhEOcihK6`CR|j`~26r@BjFDxY~~_`q<&4HT}%8&z!wp%df2Z+I2Q- M`<->>0SpY*00poy(EtDd literal 0 HcmV?d00001 diff --git a/make-pdf/test/fixtures/docx-images/tall.jpg b/make-pdf/test/fixtures/docx-images/tall.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7bdd8c0a98ce53a72a4981bd72b2632e582ee6ca GIT binary patch literal 287 zcmb7-OAdlC6h+^&(83E*8n9sfU?gZUlCT3!+=a_=D<-bPfs637m|BJ~^9)b!$G+?r z&cHpN`yS^$7lH>A6NMqA<4F`}X`W}PQhHexdR{J+S|8Tsc31D~S<$qOX)9BkZUlu8 z6i`Bx7_GGV8~Xqmzy($eH!zaOB-$rT0TKFer_*?7!C8flL0EKYIj{is0}(^_!z3Kx Miuc>8Uj(%8A3CWd^8f$< literal 0 HcmV?d00001 diff --git a/make-pdf/test/fixtures/docx-images/wide.png b/make-pdf/test/fixtures/docx-images/wide.png new file mode 100644 index 0000000000000000000000000000000000000000..f388b4ab726a390f111f63b50f3c572b2ea394f1 GIT binary patch literal 328 zcmeAS@N?(olHy`uVBq!ia0vp^6+mpj!3HF6o?j*RC03YNt{|7u;G)CK#ai@_k{^hRTXw5X!JWBJmu|Ba4( literal 0 HcmV?d00001 diff --git a/package.json b/package.json index aa46790a8..41bab4c69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.121", + "version": "1.91.122", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", @@ -73,6 +73,7 @@ "cross-spawn": "^7.0.6", "diff": "^9.0.0", "html-to-docx": "1.8.0", + "html-to-vdom": "0.7.0", "marked": "^18.0.11", "playwright": "^1.62.1", "sharp": "^0.35.4", @@ -94,8 +95,8 @@ "devDependencies": { "@anthropic-ai/claude-agent-sdk": "0.2.141", "@anthropic-ai/sdk": "^0.78.0", - "@types/bun": "1.4.2", - "prettier": "3.9.9", + "@types/bun": "1.4.3", + "prettier": "3.9.10", "typescript": "7.0.2", "xterm": "^5.3.0", "xterm-addon-fit": "^0.8.0" @@ -105,6 +106,7 @@ "adm-zip": "^0.6.1", "fast-uri": "3.1.8", "hono": "4.13.13", + "image-size": "2.0.4", "ip-address": "10.7.3", "proxy-addr": "2.0.8", "sharp": "0.35.5" diff --git a/scripts/compare-pr-version.ts b/scripts/compare-pr-version.ts index 27f746aaa..c2c813bf3 100644 --- a/scripts/compare-pr-version.ts +++ b/scripts/compare-pr-version.ts @@ -77,10 +77,24 @@ console.log(` Queue (${claimed.length} open PRs claiming versions):`); if (claimedList) console.log(claimedList); console.log("::endgroup::"); +// Dependabot never edits VERSION, so hard rule 1 would fail every dependency +// PR it opens. Exempt it only when the author is dependabot and every changed +// file is a dependency manifest, a lockfile or the dependabot config. The +// workflow passes the author and the file list; an empty list (the lookup +// failed) keeps the rule. +const DEPENDENCY_FILE = /(?:^|\/)(?:package\.json|bun\.lockb?)$|^\.github\/dependabot\.yml$/; +const changedFiles = (process.env.PR_CHANGED_FILES ?? "").split("\n").map((f) => f.trim()).filter(Boolean); +const dependabotManifestOnly = + process.env.PR_AUTHOR === "dependabot[bot]" && changedFiles.length > 0 && changedFiles.every((f) => DEPENDENCY_FILE.test(f)); + // Hard rule 1: this PR's VERSION must be strictly greater than the base // version, otherwise we're not actually bumping. const pBase = parseV((parsed.base_version ?? "").trim()); if (pBase && cmp(pPR, pBase) <= 0) { + if (dependabotManifestOnly) { + console.log(`::notice::${tag} is a dependabot dependency update (${changedFiles.join(", ")}); VERSION bump not required.`); + process.exit(0); + } console.log(`::error::VERSION not bumped: ${tag} claims v${prVersion} but base is v${parsed.base_version}.`); process.exit(1); } diff --git a/scripts/typecheck-test-baseline.json b/scripts/typecheck-test-baseline.json index 5a97c3cc2..215ee7eb1 100644 --- a/scripts/typecheck-test-baseline.json +++ b/scripts/typecheck-test-baseline.json @@ -90,13 +90,7 @@ "test/ceo-count-ad-v2.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type '({ answered: boolean; answeredAt: string; answers: { ...; }; failed: boolean; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; sessionId: string; toolUseId: string; unansweredQuestionIndices: never[]; } | { ...; } | { ...; } | { ...; } | { ...' is not assignable to parameter of type 'NativePlanQuestionCall[]'. Type '({ answered: boolean; answeredAt: string; answers: { ...; }; failed: boolean; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; sessionId: string; toolUseId: string; unansweredQuestionIndices: never[]; } | { ...; } | { ...; } | { ...; } | { ...' is not assignable to type 'NativePlanQuestionCall[]'. Type '{ answered: boolean; answeredAt: string; answers: { ...; }; failed: boolean; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; sessionId: string; toolUseId: string; unansweredQuestionIndices: never[]; } | { ...; } | { ...; } | { ...; } | { ....' is not assignable to type 'NativePlanQuestionCall'. Type '{ sessionId: string; toolUseId: string; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; answered: boolean; failed: boolean; answers: { \"D0 \\u2014 Add gstack skill routing rules to this project's CLAUDE.md?\\nProject/branch/task: plan-count ...' is not assignable to type 'NativePlanQuestionCall'. Types of property 'answers' are incompatible. Type '{ \"D0 \\u2014 Add gstack skill routing rules to this project's CLAUDE.md?\\nProject/branch/task: plan-count fixture on main, reviewing PLAN.md (Stripe payment webhook handler) in HOLD SCOPE mode.\\nELI10: gstack works best when your project's CLAUDE.md includes skill routing rules, so future requests like \\\"review this...' is not assignable to type 'Record'. Property '\"D1 \\u2014 Enable cross-project learnings search?\\nProject/branch/task: plan-count fixture on main, reviewing the Stripe payment webhook plan in HOLD SCOPE mode.\\nELI10: gstack can search learnings saved from your other projects on this machine to find patterns that might apply here. Everything stays local; no data leaves the machine. It helps solo developers most. Skip it if you work on multiple client codebases where mixing lessons between them would be a concern.\\nStakes if we pick wrong: Enabling on a multi-client machine could surface one client's quirks in another's review; disabling loses reusable patterns.\\nRecommendation: A because this is a local-only lookup and more prior context makes the review sharper.\\nNote: options differ in kind, not coverage \\u2014 no completeness score.\\nNet: broader recall versus strict per-project isolation.\"' is incompatible with index signature. Type 'undefined' is not assignable to type 'string'.": 1, "test/ceo-expansion-auq.test.ts\tTS2339\tProperty 'is_error' does not exist on type '{ text: string; type: string; } | { caller: { ...; }; id: string; input: { questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; }; name: string; type: string; } | { ...; } | { ...; }'. Property 'is_error' does not exist on type '{ text: string; type: string; }'.": 1, "test/ceo-expansion-auq.test.ts\tTS7053\tElement implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ toolu_014Q5SA47BqSvstMA1QpQzds: { reply: string; request: string; }; toolu_01GSNy9VjrqLscsjp6sceiV2: { reply: string; request: string; }; }'. No index signature with a parameter of type 'string' was found on type '{ toolu_014Q5SA47BqSvstMA1QpQzds: { reply: string; request: string; }; toolu_01GSNy9VjrqLscsjp6sceiV2: { reply: string; request: string; }; }'.": 5, - "test/ceo-finding-fixture.test.ts\tTS2322\tType 'string | number | string[]' is not assignable to type 'string'. Type 'number' is not assignable to type 'string'.": 1, - "test/ceo-finding-fixture.test.ts\tTS2339\tProperty 'map' does not exist on type 'string | number | string[] | readonly [\"Run /office-hours first\", \"\\\"Skip — standard review\\\"\"] | readonly [\"Run /office-hours first\", \"Skip\"] | readonly [\"Run /office-hours first\", \"Skip security review\"] | ... 4 more ... | readonly [...]'. Property 'map' does not exist on type 'string'.": 1, - "test/ceo-finding-fixture.test.ts\tTS2345\tArgument of type '(question: string | number | string[], labels: string | number | string[] | readonly [\"Run /office-hours first\", \"\\\"Skip — standard review\\\"\"] | readonly [\"Run /office-hours first\", \"Skip\"] | readonly [\"Run /office-hours first\", \"Skip security review\"] | ... 4 more ... | readonly [...], expected: string | ... 1 mo...' is not assignable to parameter of type '(...args: (string | number | string[])[] | [\"D1 — Discuss /office-hours in our documentation?\", string[], 1] | [\"D1 — No design doc found: run /office-hours before the review?\", readonly [...], 2] | ... 8 more ... | [...]) => void | Promise<...>'. Types of parameters 'question' and 'args' are incompatible. Type '(string | number | string[])[] | [\"D1 — Discuss /office-hours in our documentation?\", string[], 1] | [\"D1 — No design doc found: run /office-hours before the review?\", readonly [...], 2] | ... 8 more ... | [...]' is not assignable to type '[question: string | number | string[], labels: string | number | string[] | readonly [\"Run /office-hours first\", \"\\\"Skip — standard review\\\"\"] | readonly [\"Run /office-hours first\", \"Skip\"] | readonly [\"Run /office-hours first\", \"Skip security review\"] | ... 4 more ... | readonly [...], expected: string | ... 1 mo...'. Type '(string | number | string[])[]' is not assignable to type '[question: string | number | string[], labels: string | number | string[] | readonly [\"Run /office-hours first\", \"\\\"Skip — standard review\\\"\"] | readonly [\"Run /office-hours first\", \"Skip\"] | readonly [\"Run /office-hours first\", \"Skip security review\"] | ... 4 more ... | readonly [...], expected: string | ... 1 mo...'. Target requires 3 element(s) but source may have fewer.": 1, - "test/ceo-finding-fixture.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type 'string | number | string[]' is not assignable to parameter of type 'number'. Type 'string' is not assignable to type 'number'.": 1, "test/ceo-finding-fixture.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type '{ kind: \"committed\" | \"failed\" | \"forbidden\" | \"unregistered-event\"; status: 200 | 403 | 503; }' is not assignable to parameter of type 'RequestOutcome'. Type '{ kind: \"committed\" | \"failed\" | \"forbidden\" | \"unregistered-event\"; status: 200 | 403 | 503; }' is not assignable to type '{ kind: \"failed\" | \"unregistered-event\"; status: 503; }'. Types of property 'status' are incompatible. Type '200 | 403 | 503' is not assignable to type '503'. Type '200' is not assignable to type '503'.": 1, - "test/ceo-finding-fixture.test.ts\tTS7006\tParameter 'i' implicitly has an 'any' type.": 1, - "test/ceo-finding-fixture.test.ts\tTS7006\tParameter 'label' implicitly has an 'any' type.": 1, "test/ceo-hold-posture-review.test.ts\tTS2339\tProperty 'filePath' does not exist on type '{}'.": 4, "test/ceo-hold-posture-review.test.ts\tTS2339\tProperty 'questions' does not exist on type 'AskUserQuestionFingerprint'.": 4, "test/ceo-hold-posture-review.test.ts\tTS2339\tProperty 'selectedOptions' does not exist on type 'AskUserQuestionFingerprint'.": 1, @@ -140,8 +134,6 @@ "test/cso-ntfs-fixture.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type 'bigint | undefined' is not assignable to parameter of type 'bigint'. Type 'undefined' is not assignable to type 'bigint'.": 1, "test/cso-preparation-executor.test.ts\tTS2339\tProperty 'sidecar' does not exist on type 'PreparedDatabaseContract'. Property 'sidecar' does not exist on type '{ adapter: \"sqlite\"; connections: string[]; }'.": 1, "test/cso-public-ghcr.test.ts\tTS2352\tConversion of type '() => Promise' to type 'typeof fetch' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Property 'preconnect' is missing in type '() => Promise' but required in type 'typeof fetch'.": 1, - "test/cso-scanner-executor.test.ts\tTS2345\tArgument of type 'unknown' is not assignable to parameter of type '\"gitleaks\" | \"osv\" | \"schemathesis\" | \"semgrep\" | \"trivy\" | \"zizmor\"'.": 9, - "test/cso-scanner-executor.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. The type 'readonly [\"gitleaks\", \"osv\", \"semgrep\", \"zizmor\", \"trivy\", \"schemathesis\"]' is 'readonly' and cannot be assigned to the mutable type 'unknown[]'.": 2, "test/design-catalog.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type 'string' is not assignable to parameter of type '\"quality\" | \"slop\"'.": 1, "test/design-completion-handoff-scored.test.ts\tTS2352\tConversion of type '({ answered: boolean; answeredAt: string; answers: { ...; }; failed: boolean; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; sessionId: string; toolUseId: string; unansweredQuestionIndices: never[]; } | ... 10 more ... | { ...; })[]' to type 'NativePlanQuestionCall[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Type '{ answered: boolean; answeredAt: string; answers: { ...; }; failed: boolean; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; sessionId: string; toolUseId: string; unansweredQuestionIndices: never[]; } | ... 10 more ... | { ...; }' is not comparable to type 'NativePlanQuestionCall'. Type '{ sessionId: string; toolUseId: string; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; answered: boolean; failed: boolean; answers: { \"Pass 1 (Info Architecture) \\u2014 7/10. The plan has DOM order and heading structure, but no scan path ...' is not comparable to type 'NativePlanQuestionCall'. Types of property 'answers' are incompatible. Type '{ \"Pass 1 (Info Architecture) \\u2014 7/10. The plan has DOM order and heading structure, but no scan path specification: what does the user's eye land on first, second, third? The Visual Hierarchy gap identifies that Save is indistinguishable from other buttons, but names it as a styling problem rather than an IA pr...' is not comparable to type 'Record'. Property '\"Pass 1 (Info Architecture) \\u2014 7/10. The plan has DOM order and heading structure, but no scan path specification: what does the user's eye land on first, second, third? The Visual Hierarchy gap identifies that Save is indistinguishable from other buttons, but names it as a styling problem rather than an IA problem \\u2014 the primary action is missing from the visual hierarchy. Should I add a scan path description to the plan? \"' is incompatible with index signature. Type 'undefined' is not comparable to type 'string'.": 1, "test/design-completion-handoff-scored.test.ts\tTS2352\tConversion of type '({ answered: boolean; answeredAt: string; answers: { ...; }; failed: boolean; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; sessionId: string; toolUseId: string; unansweredQuestionIndices: never[]; } | ... 4 more ... | { ...; })[]' to type 'NativePlanQuestionCall[]' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Type '{ answered: boolean; answeredAt: string; answers: { ...; }; failed: boolean; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; sessionId: string; toolUseId: string; unansweredQuestionIndices: never[]; } | ... 4 more ... | { ...; }' is not comparable to type 'NativePlanQuestionCall'. Type '{ sessionId: string; toolUseId: string; questions: { header: string; multiSelect: boolean; options: { description: string; label: string; }[]; question: string; }[]; answered: boolean; failed: boolean; answers: { \"Pass 1 \\u2014 Visual Hierarchy: The plan lists this gap but has no fix. The Save button renders with th...' is not comparable to type 'NativePlanQuestionCall'. Types of property 'answers' are incompatible. Type '{ \"Pass 1 \\u2014 Visual Hierarchy: The plan lists this gap but has no fix. The Save button renders with the same size, weight, and color as Reset, Cancel, and Export. DESIGN.md already specifies the remedy: Save gets #1d4ed8 fill with white text; the other three are ghost neutral buttons. Should I add this fix speci...' is not comparable to type 'Record'. Property '\"Pass 1 \\u2014 Visual Hierarchy: The plan lists this gap but has no fix. The Save button renders with the same size, weight, and color as Reset, Cancel, and Export. DESIGN.md already specifies the remedy: Save gets #1d4ed8 fill with white text; the other three are ghost neutral buttons. Should I add this fix specification to the plan? \"' is incompatible with index signature. Type 'undefined' is not comparable to type 'string'.": 1, @@ -258,10 +250,6 @@ "test/helpers/shared-libs-path-fixture.ts\tTS2352\tConversion of type '{ env: { GSTACK_HOME: string; }; repo: string; root: string; state: string; }' to type 'SharedLibsFixture' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first. Type '{ env: { GSTACK_HOME: string; }; repo: string; root: string; state: string; }' is missing the following properties from type 'SharedLibsFixture': bin, trace, hookTrace, tip": 1, "test/helpers/shared-libs-plan-actor.ts\tTS18046\t'questions' is of type 'unknown'.": 1, "test/impeccable-fixtures.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'.": 1, - "test/llm-judge-abort.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type '{ passed: boolean; }' is not assignable to parameter of type 'undefined'.": 3, - "test/llm-judge-frontier.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type '{ reason: string; score: number; }' is not assignable to parameter of type 'undefined'.": 1, - "test/llm-judge-frontier.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type '{ score: number; }' is not assignable to parameter of type 'undefined'.": 3, - "test/llm-judge-stream.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type '{ actionability: number; clarity: number; completeness: number; reasoning: string; }' is not assignable to parameter of type 'undefined'.": 1, "test/model-overlays.test.ts\tTS2322\tType 'string' is not assignable to type '\"claude\" | \"fable-5\" | \"gemini\" | \"gpt\" | \"gpt-5.4\" | \"gpt-5.6-sol\" | \"gpt-6-astra\" | \"o-series\" | \"opus-4-7\" | \"opus-4-8\" | \"sonnet-5\" | undefined'.": 4, "test/native-auto-decide-pty.test.ts\tTS2345\tArgument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'.": 1, "test/native-auto-decide.test.ts\tTS2345\tArgument of type '{ assistantMessages: { sessionId: string; text: string; timestamp: string; }[]; calls: never[]; status: string; }' is not assignable to parameter of type 'PlanCountTranscript'. Types of property 'status' are incompatible. Type 'string' is not assignable to type '\"error\" | \"missing\" | \"ready\"'.": 1, @@ -423,8 +411,6 @@ "test/pty-workspace-trust.test.ts\tTS2345\tArgument of type '(_command: any, options: any) => any' is not assignable to parameter of type '{ (options: SpawnOptions & { cmd: string[]; }): Subprocess<...>; '. Property '\"D1 \\u2014 Add gstack skill routing rules to this project's CLAUDE.md?\\nProject/branch/task: plan-count fixture on main, running /plan-design-review on PLAN.md.\\nELI10: gstack skills work best when the project's CLAUDE.md tells the assistant which slash command to reach for (bugs \\u2192 /investigate, design plan \\u2192 /plan-design-review, and so on). Without it you invoke skills by hand each time. This is a one-time prompt per project.\\nStakes if we pick wrong: pick A and CLAUDE.md gains a short section you may not want in a fixture repo; pick B and skills are never suggested automatically here.\\nRecommendation: A because routing rules cost one short section and save repeated manual invocations.\\nNote: options differ in kind, not coverage \\u2014 no completeness score.\\nNet: convenience of auto-routing vs keeping the fixture CLAUDE.md untouched. Note: plan mode is active, so if you pick A the CLAUDE.md edit and commit happen after we leave plan mode.\"' is incompatible with index signature. Type 'undefined' is not comparable to type 'string'.": 1, "test/salience-allowlist.test.ts\tTS2307\tCannot find module '../bin/gstack-brain-cache' or its corresponding type declarations.": 3, "test/schema-version-migration.test.ts\tTS2307\tCannot find module '../bin/gstack-brain-cache' or its corresponding type declarations.": 3, - "test/schema-version-migration.test.ts\tTS2353\tObject literal may only specify known properties, and 'timeout' does not exist in type '(done: (err?: unknown) => void) => void | Promise'.": 3, "test/section-capture-native-tools.test.ts\tTS2339\tProperty 'CI' does not exist on type '{ NODE_ENV?: string | undefined; PATH: string; TZ?: string | undefined; }'.": 1, - "test/session-runner-browse-errors.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type 'never[]' is not assignable to parameter of type 'undefined'.": 1, "test/session-runner-browse-errors.test.ts\tTS7006\tParameter 'row' implicitly has an 'any' type.": 6, "test/setup-gbrain-path4-caller.test.ts\tTS2339\tProperty 'diagnostic-secret' does not exist on type '{ 'no-init': number; 'no-install': number; 'no-registration': number; 'no-verifier': number; }'.": 1, "test/setup-gbrain-path4-caller.test.ts\tTS2339\tProperty 'exit' does not exist on type '{ 'no-init': number; 'no-install': number; 'no-registration': number; 'no-verifier': number; }'.": 1, @@ -453,12 +437,10 @@ "test/setup-gbrain-path4-caller.test.ts\tTS2339\tProperty 'wrong-engine' does not exist on type '{ 'no-init': number; 'no-install': number; 'no-registration': number; 'no-verifier': number; }'.": 1, "test/setup-gbrain-remote-caller.test.ts\tTS18048\t'lateDecision' is possibly 'undefined'.": 1, "test/shared-libs-checker-interface-evidence.test.ts\tTS18048\t'current' is possibly 'undefined'.": 1, - "test/shared-libs-checker-interface-evidence.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. The type 'readonly [\"symlinks\", \"submodule\", \"ignored\", \"legacy\", \"assume-unchanged\", \"skip-worktree\", \"removed-filter\"]' is 'readonly' and cannot be assigned to the mutable type 'unknown[]'.": 2, "test/shared-libs-fixture.test.ts\tTS18046\t'packet' is of type 'unknown'.": 4, "test/shared-libs-fixture.test.ts\tTS2345\tArgument of type '(options: { label: string; } | { description: string; label: string; } | { description: string; label: string; }) => Promise' is not assignable to parameter of type '(...args: [{ label: string; } | { description: string; label: string; } | { description: string; label: string; }, done: (err?: unknown) => void] | [{ label: string; } | { description: string; label: string; } | { ...; }, { ...; } | undefined, done: (err?: unknown) => void]) => void | Promise<...>'. Types of parameters 'options' and 'args' are incompatible. Type '[{ label: string; } | { description: string; label: string; } | { description: string; label: string; }, done: (err?: unknown) => void] | [{ label: string; } | { description: string; label: string; } | { description: string; label: string; }, { ...; } | undefined, done: (err?: unknown) => void]' is not assignable to type '[options: { label: string; } | { description: string; label: string; } | { description: string; label: string; }]'. Type '[{ label: string; } | { description: string; label: string; } | { description: string; label: string; }, done: (err?: unknown) => void]' is not assignable to type '[options: { label: string; } | { description: string; label: string; } | { description: string; label: string; }]'. Source has 2 element(s) but target allows only 1.": 1, "test/shared-libs-fixture.test.ts\tTS2345\tArgument of type '(options: { label: string; } | { description: string; label: string; } | { label: string; preview: string; } | { description: string; label: string; preview: string; } | { label: string; } | { description: string; label: string; } | { ...; }) => Promise<...>' is not assignable to parameter of type '(...args: [{ label: string; } | { description: string; label: string; } | { label: string; preview: string; } | { description: string; label: string; preview: string; } | { label: string; } | { description: string; label: string; } | { ...; }, done: (err?: unknown) => void] | [...]) => void | Promise<...>'. Types of parameters 'options' and 'args' are incompatible. Type '[{ label: string; } | { description: string; label: string; } | { label: string; preview: string; } | { description: string; label: string; preview: string; } | { label: string; } | { description: string; label: string; } | { ...; }, done: (err?: unknown) => void] | [...]' is not assignable to type '[options: { label: string; } | { description: string; label: string; } | { label: string; preview: string; } | { description: string; label: string; preview: string; } | { label: string; } | { description: string; label: string; } | { ...; }]'. Type '[{ label: string; } | { description: string; label: string; } | { label: string; preview: string; } | { description: string; label: string; preview: string; } | { label: string; } | { description: string; label: string; } | { ...; }, done: (err?: unknown) => void]' is not assignable to type '[options: { label: string; } | { description: string; label: string; } | { label: string; preview: string; } | { description: string; label: string; preview: string; } | { label: string; } | { description: string; label: string; } | { ...; }]'. Source has 2 element(s) but target allows only 1.": 1, "test/shared-libs-fixture.test.ts\tTS2345\tArgument of type '({ input }: { input: any; }) => Promise' is not assignable to parameter of type '(args_0: unknown, ...args: unknown[]) => void | Promise'. Types of parameters '__0' and 'args_0' are incompatible. Type 'unknown' is not assignable to type '{ input: any; }'.": 1, - "test/shared-libs-fixture.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type 'readonly [\"Skip\", \"Keep current\", \"Decline\", \"Do not change\", \"Leave as-is\"] | readonly [\"Fix it\", \"Apply remedy\", \"Approve\", \"Extract helper\", \"Reuse library\", \"Choice (recommended)\"]' is not assignable to parameter of type 'unknown[]'. The type 'readonly [\"Skip\", \"Keep current\", \"Decline\", \"Do not change\", \"Leave as-is\"]' is 'readonly' and cannot be assigned to the mutable type 'unknown[]'.": 1, "test/shared-libs-fixture.test.ts\tTS7053\tElement implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ \"Pre-Landing Review: 0 issues (0 critical, 0 informational). 1 [ADVISORY] needs your input:\\n\\n1. [ADVISORY] src/retry-worker.ts:2 \\u2014 Duplicated `retrySeconds` parser (shared-libs, confidence 9/10, maintainability + core)\\n Both src/retry-worker.ts:2-15 (this diff) and src/retry-route.ts:2-15 are verbatim co...'. No index signature with a parameter of type 'string' was found on type '{ \"Pre-Landing Review: 0 issues (0 critical, 0 informational). 1 [ADVISORY] needs your input:\\n\\n1. [ADVISORY] src/retry-worker.ts:2 \\u2014 Duplicated `retrySeconds` parser (shared-libs, confidence 9/10, maintainability + core)\\n Both src/retry-worker.ts:2-15 (this diff) and src/retry-route.ts:2-15 are verbatim co...'.": 1, "test/shared-libs-review-start-evidence.test.ts\tTS2345\tArgument of type 'unknown' is not assignable to parameter of type 'number | undefined'.": 1, "test/shared-libs-stage-actor.test.ts\tTS2769\tNo overload matches this call. The last overload gave the following error. Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'.": 1, diff --git a/test/ceo-finding-fixture.test.ts b/test/ceo-finding-fixture.test.ts index db0da204b..3c7d1b700 100644 --- a/test/ceo-finding-fixture.test.ts +++ b/test/ceo-finding-fixture.test.ts @@ -262,7 +262,7 @@ test.each([ [reviewStartLead, reviewStartLabels, 2], ['D1 — No design doc found: run /office-hours before the review?', ['Run /office-hours now', 'Skip — proceed with review (Recommended)'], 2], [reviewStartLead, ['Skip — standard review', 'Run /office-hours first'], 1], - ...['Example: ', 'If approved: ', 'Do not ', '> ', ' ', '"', '`'].map(prefix => [prefix + reviewStartLead, reviewStartLabels, 1]), + ...['Example: ', 'If approved: ', 'Do not ', '> ', ' ', '"', '`'].map(prefix => [prefix + reviewStartLead, reviewStartLabels, 1] as const), ['D1 — Discuss /office-hours in our documentation?', reviewStartLabels, 1], ['D1 — Run /office-hours instead of this review?', reviewStartLabels, 1], [reviewStartLead, ['Run /office-hours first', 'Skip'], 1], diff --git a/test/compare-pr-version.test.ts b/test/compare-pr-version.test.ts new file mode 100644 index 000000000..e4a4d3890 --- /dev/null +++ b/test/compare-pr-version.test.ts @@ -0,0 +1,80 @@ +/** + * Version Gate (scripts/compare-pr-version.ts). Hard rule 1 requires VERSION + * above the base, which dependabot can never satisfy, so a dependabot PR that + * touches only dependency manifests, lockfiles and dependabot config is exempt. + * Every other author or file keeps the rule. + */ +import { describe, expect, test } from 'bun:test'; +import * as fs from 'node:fs'; +import * as os from 'node:os'; +import * as path from 'node:path'; + +const ROOT = path.resolve(import.meta.dir, '..'); +const SCRIPT = path.join(ROOT, 'scripts', 'compare-pr-version.ts'); + +function gate(env: { PR_VERSION: string; PR_AUTHOR?: string; PR_CHANGED_FILES?: string }) { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'version-gate-')); + try { + const next = path.join(dir, 'next.json'); + fs.writeFileSync(next, JSON.stringify({ version: '1.91.117.0', base_version: '1.91.116.0', claimed: [{ pr: 3236, branch: 'fix-wave-5', version: '1.91.117.0' }] })); + const run = Bun.spawnSync([process.execPath, 'run', SCRIPT, next, '3227'], { + env: { PATH: process.env.PATH ?? '', ...env }, + timeout: 30_000, + stdout: 'pipe', + stderr: 'pipe', + }); + return { code: run.exitCode, out: run.stdout.toString() + run.stderr.toString() }; + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } +} + +const DEPENDABOT = 'dependabot[bot]'; + +describe('version gate: dependabot dependency-manifest exemption', () => { + test('an unbumped VERSION still fails for a human author', () => { + const result = gate({ PR_VERSION: '1.91.116.0', PR_AUTHOR: 'garrytan', PR_CHANGED_FILES: 'package.json\nbun.lock' }); + expect(result.code).toBe(1); + expect(result.out).toContain('::error::VERSION not bumped'); + }); + + test('a dependabot PR behind main that touches only manifests, lockfiles and dependabot config passes', () => { + const files = ['package.json', 'bun.lock', 'lib/diagram-render/package.json', 'lib/diagram-render/bun.lock', '.github/dependabot.yml'].join('\n'); + const result = gate({ PR_VERSION: '1.91.106.0', PR_AUTHOR: DEPENDABOT, PR_CHANGED_FILES: files + '\n' }); + expect(result.code).toBe(0); + expect(result.out).toContain('::notice::PR #3227 is a dependabot dependency update'); + expect(result.out).not.toContain('::error::'); + }); + + test('a dependabot PR with any other file keeps hard rule 1', () => { + for (const other of ['scripts/compare-pr-version.ts', 'VERSION', '.github/workflows/version-gate.yml', 'evil-package.json', 'package.json.bak']) { + const result = gate({ PR_VERSION: '1.91.116.0', PR_AUTHOR: DEPENDABOT, PR_CHANGED_FILES: `package.json\nbun.lock\n${other}` }); + expect(result.code).toBe(1); + expect(result.out).toContain('::error::VERSION not bumped'); + } + }); + + test('a missing file list or author keeps hard rule 1', () => { + expect(gate({ PR_VERSION: '1.91.116.0', PR_AUTHOR: DEPENDABOT, PR_CHANGED_FILES: '' }).code).toBe(1); + expect(gate({ PR_VERSION: '1.91.116.0', PR_AUTHOR: DEPENDABOT }).code).toBe(1); + expect(gate({ PR_VERSION: '1.91.116.0', PR_CHANGED_FILES: 'package.json' }).code).toBe(1); + }); + + test('a bumped dependabot VERSION goes through the collision rule as before', () => { + const result = gate({ PR_VERSION: '1.91.117.0', PR_AUTHOR: DEPENDABOT, PR_CHANGED_FILES: 'package.json' }); + expect(result.code).toBe(1); + expect(result.out).toContain('::error::VERSION collision'); + }); + + test('the workflow passes the PR author and its changed-file list to the gate', () => { + const workflow = Bun.YAML.parse(fs.readFileSync(path.join(ROOT, '.github', 'workflows', 'version-gate.yml'), 'utf8')) as any; + const step = workflow.jobs.check.steps.find((s: any) => s.name === 'Compare PR VERSION to next free slot'); + expect(step.env.PR_AUTHOR).toBe('${{ github.event.pull_request.user.login }}'); + expect(step.env.GH_TOKEN).toBe('${{ secrets.GITHUB_TOKEN }}'); + expect(step.run).toContain('pulls/${{ github.event.pull_request.number }}/files'); + expect(step.run).toContain('--paginate'); + expect(step.run).toContain('then PR_CHANGED_FILES=""; fi'); + expect(step.run).toContain('export PR_CHANGED_FILES'); + expect(workflow.jobs.check.permissions).toEqual({ contents: 'read', 'pull-requests': 'read' }); + }); +}); diff --git a/test/osv-config-wiring.test.ts b/test/osv-config-wiring.test.ts index 69cab8835..442924b45 100644 --- a/test/osv-config-wiring.test.ts +++ b/test/osv-config-wiring.test.ts @@ -50,4 +50,12 @@ describe("osv-scanner config wiring", () => { const page = fs.readFileSync(path.join(ROOT, "lib", "diagram-render", "dist", "diagram-render.html"), "utf8"); expect(page).not.toMatch(/chokidar|FSWatcher/); }); + + test("the chokidar override keeps braces (GHSA-vfj7-8cjw-p6xm, no fixed release) out of lib/diagram-render", () => { + const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, "lib", "diagram-render", "package.json"), "utf8")); + expect(pkg.overrides.chokidar).toMatch(/^4\./); + const lock = fs.readFileSync(path.join(ROOT, "lib", "diagram-render", "bun.lock"), "utf8"); + expect(lock).toMatch(/"chokidar": \["chokidar@4\.\d+\.\d+"/); + expect(lock).not.toMatch(/"braces": \["braces@/); + }); }); diff --git a/test/osv-ignore-expiry.test.ts b/test/osv-ignore-expiry.test.ts index c185d3ec3..d88b9fdb5 100644 --- a/test/osv-ignore-expiry.test.ts +++ b/test/osv-ignore-expiry.test.ts @@ -58,18 +58,15 @@ describe('OSV suppression expiry', () => { for (const text of ['"$SCAN_RESULT" = "failure"', 'gh issue create', 'gh issue comment', 'gh issue close']) expect(run).toContain(text); }); - test('the image-size entries name the fixed release and the pin that blocks it (#2753)', () => { - const toml = fs.readFileSync(path.join(import.meta.dir, '..', '.osv-scanner.toml'), 'utf8'); - const entries = toml.split('[[IgnoredVulns]]').slice(1).filter(e => /^id = "GHSA-(?:5p2g-fcmc-qvqq|w3rx-r6r6-pgpr)"/m.test(e)); - expect(entries).toHaveLength(2); - for (const entry of entries) { - expect(entry).not.toContain('No fixed version exists'); - expect(entry).toMatch(/^reason = ".*image-size 2\.0\.3.*\^1\.0\.0.*"$/m); - expect(entry).toContain('ignoreUntil = 2026-11-30T00:00:00Z'); - } - // The stated blocker is the lockfile's: html-to-docx asks for image-size ^1.0.0 and resolves a 1.x. + test('image-size is overridden to a fixed 2.x and its suppressions are gone (#2753)', () => { + const toml = fs.readFileSync(path.join(ROOT, CONFIG), 'utf8'); + expect(toml).not.toMatch(/GHSA-(?:5p2g-fcmc-qvqq|w3rx-r6r6-pgpr)/); + const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); + expect(pkg.overrides['image-size']).toBe('2.0.4'); + // html-to-docx still asks for ^1.0.0; the override is what moves the lockfile off the affected 1.x. const lock = fs.readFileSync(path.join(ROOT, 'bun.lock'), 'utf8'); expect(lock).toMatch(/"html-to-docx": \["html-to-docx@[^"]+", "", \{ "dependencies": \{[^}]*"image-size": "\^1\.0\.0"/); - expect(lock).toMatch(/"image-size": \["image-size@1\.\d+\.\d+"/); + expect(lock).toMatch(/"image-size": \["image-size@2\.0\.4"/); + expect(lock).not.toMatch(/"image-size": \["image-size@1\./); }); }); diff --git a/test/workflow-action-pins.test.ts b/test/workflow-action-pins.test.ts index a86ab0d3a..6293412ef 100644 --- a/test/workflow-action-pins.test.ts +++ b/test/workflow-action-pins.test.ts @@ -113,4 +113,13 @@ describe('workflow action pins', () => { expect(ignored[name]).toEqual({ 'dependency-name': name, 'update-types': ['version-update:semver-minor', 'version-update:semver-major'] }); } }); + + test('Dependabot holds the Anthropic SDKs to patch updates; their 0.x breaking releases arrive as semver-minor', () => { + const config = Bun.YAML.parse(fs.readFileSync(path.join(GITHUB_DIR, 'dependabot.yml'), 'utf-8')) as any; + const bun = (config.updates ?? []).find((update: any) => update['package-ecosystem'] === 'bun'); + const ignored = Object.fromEntries((bun?.ignore ?? []).map((rule: any) => [rule['dependency-name'], rule])); + for (const name of ['@anthropic-ai/claude-agent-sdk', '@anthropic-ai/sdk']) { + expect(ignored[name]).toEqual({ 'dependency-name': name, 'update-types': ['version-update:semver-minor', 'version-update:semver-major'] }); + } + }); }); diff --git a/tsconfig.test.json b/tsconfig.test.json index 6276a3d73..da9480913 100644 --- a/tsconfig.test.json +++ b/tsconfig.test.json @@ -8,7 +8,8 @@ "design/test/**/*.ts", "ios-qa/**/*.test.ts", "ios-qa/daemon/test/**/*.ts", - "make-pdf/src/html-to-docx.d.ts" + "make-pdf/src/html-to-docx.d.ts", + "make-pdf/src/html-to-vdom.d.ts" ], "exclude": [ "lib/diagram-render/**", From 521fd424896ed1e64bc48da0a41847ad002ae591 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 17 Oct 2026 16:48:32 +0000 Subject: [PATCH 6/8] build(deps): bump the github-actions group across 1 directory with 2 updates (#3229) Bumps the github-actions group with 2 updates in the / directory: [actions/upload-artifact](https://github.com/actions/upload-artifact) and [actions/download-artifact](https://github.com/actions/download-artifact). Updates `actions/upload-artifact` from 7.0.1 to 7.0.2 - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v7.0.1...cf430e030ddbb5b0abf93d22962f4752f3646cd9) Updates `actions/download-artifact` from 8.0.1 to 8.0.2 - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v8.0.1...9000827ccba6bdab643e8b6fd33ac0654aef8333) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-version: 8.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/upload-artifact dependency-version: 7.0.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/free-tests.yml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/free-tests.yml b/.github/workflows/free-tests.yml index 5a51c9a68..aff850978 100644 --- a/.github/workflows/free-tests.yml +++ b/.github/workflows/free-tests.yml @@ -62,7 +62,7 @@ jobs: - name: Seed growth ratchet (60 s ceiling, shrink-only allowlist) run: | GSTACK_FREE_SEED_BASE="$(git merge-base HEAD origin/main)" bun test test/free-seed-ratchet.test.ts - - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: free-plan path: ${{ runner.temp }}/free-plan.json @@ -171,7 +171,7 @@ jobs: GSTACK_CSO_WINDOWS_TESTS: "1" - name: Upload #2894 lease diagnostics if: failure() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: cso-lease-diagnostics-a${{ github.run_attempt }} path: ${{ runner.temp }}/cso-lease-diagnostics @@ -298,7 +298,7 @@ jobs: with: bun-version: 1.4.2 - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: name: free-plan path: ${{ runner.temp }} @@ -409,7 +409,7 @@ jobs: - name: Upload strict shard result if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: free-result-${{ matrix.shard }} path: ${{ runner.temp }}/free-results/*.json @@ -419,7 +419,7 @@ jobs: # GREEN — that's the point — so its evidence must survive green runs. - name: Upload flake ledger if: always() - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: flake-ledger-${{ matrix.shard }} path: ${{ runner.temp }}/flake-ledger.jsonl @@ -438,7 +438,7 @@ jobs: # after a recovered retry too, so a green job retains its first failure. - name: Upload shard logs on failure or recovered retry if: failure() || steps.flake_spool.outputs.present == 'true' - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7 with: name: free-test-shard-logs-${{ matrix.shard }} path: .context/free-test-logs/gstack-free-test-*.log @@ -478,11 +478,11 @@ jobs: - uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 with: bun-version: 1.4.2 - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: name: free-plan path: ${{ runner.temp }} - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: pattern: free-result-* merge-multiple: true @@ -490,7 +490,7 @@ jobs: # Per-shard ledgers land in their own subdirectories (all are named # flake-ledger.jsonl). A green run is where a retried flake hides, so the # summary runs before strict verification. - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 + - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8 with: pattern: flake-ledger-* path: ${{ runner.temp }}/flake-ledgers From 56f25ef82bb7cb5cb2b0efaeec4e8843eb2a3594 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 17 Oct 2026 10:03:41 -0700 Subject: [PATCH 7/8] v1.91.123.0 fix(cso): comprehensive verify can patch read-only snapshots and accepts runtime-plan's profile (#3240) * fix(cso): comprehensive verify can patch read-only snapshots and accepts runtime-plan's profile * docs(changelog): unreleased entry for the /cso verify repair path * v1.91.123.0 stamp --- CHANGELOG.md | 11 +++++++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- lib/cso/cli.ts | 15 ++++++++++++--- lib/cso/verification.ts | 2 ++ package.json | 2 +- test/cso-contracts.test.ts | 1 + test/cso-node-lifecycle-integration.test.ts | 3 ++- 8 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7dfa0a6e9..679805e64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## [1.91.123.0] - 2026-10-17 + +**/cso comprehensive repairs run again.** In the first paid runtime qualification, the agent recorded 148 repair reviews across 42 comprehensive runs, but not one verification attempt started. Every runtime scored 0/24 on held-out repairs. Two helper bugs stacked: the patch write failed on the snapshot's read-only files, and `runtime-plan` handed the agent a profile name that `verify` refused. + +### Fixed +- **`verify` can patch read-only snapshot files.** Snapshot copies keep their 0444 modes, so writing the patched file failed with EACCES for any non-root user, which is how real users and the evaluator run. The error surfaced as a generic "unexpected or unsafe input". The helper now makes the file owner-writable for the write and restores its mode afterwards. +- **`runtime-plan` returns the qualified runtime ID** (for example `node-24.4.0-amd64`) instead of the stack alias, and the skill copies that value into the verification request. `verify` rejects any other profile with an `INVALID_ARGUMENT` that names the expected ID, before an attempt is counted. + +### If you… +- **…build a verification request by hand:** use the `runtimeProfile` that `runtime-plan` printed. The stack alias is refused. + ## [1.91.122.0] - 2026-10-17 **Main no longer goes red on 2026-11-16.** All seven `.osv-scanner.toml` suppressions expired on 2026-11-30, and `test/osv-ignore-expiry.test.ts` fails 14 days early. Six are gone and the seventh is re-dated with an upstream link. Dependabot's grouped dev bump (#3228) is replaced by hand, and Version Gate stops failing every dependabot package.json PR. diff --git a/VERSION b/VERSION index e0b7c3105..48617770e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.122.0 +1.91.123.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 47072b96d..957e4470a 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.122.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.123.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/lib/cso/cli.ts b/lib/cso/cli.ts index 6061afbd0..672272742 100644 --- a/lib/cso/cli.ts +++ b/lib/cso/cli.ts @@ -2056,7 +2056,7 @@ function testPlan(args: string[]) { ...publicTestPlan(manifest, canonicalTestPlan(join(dir, 'snapshot'), stack)), }; } -function runtimePlan(args: string[]) { +function runtimePlan(args: string[], dependencies: CsoCliDependencies) { const { dir } = run(args); if (!args.length || !['node', 'bun', 'python', 'rails'].includes(args[0])) throw new CsoError('INVALID_ARGUMENT', 'runtime-plan requires one supported stack and --port PORT'); @@ -2075,9 +2075,13 @@ function runtimePlan(args: string[]) { preparation.prerequisites.map((item) => item.message).join('; ') || `${stack} preparation metadata is incomplete`, ); + let runtimeProfile = preparation.runtimeProfile; + try { + runtimeProfile = selectRuntime(runtimeProfile, platform(), dependencies.runtimeCatalog).id; + } catch {} return { stack, - runtimeProfile: preparation.runtimeProfile, + runtimeProfile, start: publicStartPlan(manifest, canonicalStartPlan(join(dir, 'snapshot'), stack, port)), tests: publicTestPlan(manifest, canonicalTestPlan(join(dir, 'snapshot'), stack)), }; @@ -2339,6 +2343,11 @@ async function verify(args: string[], dependencies: CsoCliDependencies) { } catch (error: any) { throw new CsoError('PREREQUISITE', error?.message || 'Qualified runtime is unavailable'); } + if (request.runtimeProfile !== runtime.id) + throw new CsoError( + 'INVALID_ARGUMENT', + `runtimeProfile must be the qualified runtime ID ${runtime.id} returned by runtime-plan`, + ); const verifier = runtime; if (!['node', 'bun', 'python', 'rails'].includes(runtime.stack)) throw new CsoError( @@ -2848,7 +2857,7 @@ export async function dispatchCsoCommand( result = testPlan(args); break; case 'runtime-plan': - result = runtimePlan(args); + result = runtimePlan(args, dependencies); break; case 'recheck': result = await recheck(args, dependencies); diff --git a/lib/cso/verification.ts b/lib/cso/verification.ts index 5b0eda27b..6ccf9ef83 100644 --- a/lib/cso/verification.ts +++ b/lib/cso/verification.ts @@ -1035,7 +1035,9 @@ export function preparePatchedSource(snapshot: string, target: string, request: ); const mode = exists ? fs.statSync(file).mode & 0o777 : 0o600; secureDirectory(dirname(file)); + if (exists) fs.chmodSync(file, mode | 0o200); fs.writeFileSync(file, change.after, { mode }); + fs.chmodSync(file, mode); } } export function certify(params: { diff --git a/package.json b/package.json index 41bab4c69..a130d5382 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.122", + "version": "1.91.123", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/test/cso-contracts.test.ts b/test/cso-contracts.test.ts index e9513eddd..a3434a54f 100644 --- a/test/cso-contracts.test.ts +++ b/test/cso-contracts.test.ts @@ -189,6 +189,7 @@ describe('tested repair certificate gate',()=>{ test('review is a separate content-bound but explicitly self-attested artifact',()=>{const raw:any=request('vulnerable\n','fixed\n');raw.review.reviewedPatchHash=patchHash(raw);const req=validateVerificationRequest(raw),artifact=makeReviewArtifact('run',req,'producer-session');raw.review.artifactId=artifact.id;const bound=validateVerificationRequest(raw);expect(validateReviewArtifact(artifact,'run',bound)).toMatchObject({producer:'producer-session',assurance:'self_attested'});expect(()=>makeReviewArtifact('run',req,req.review.reviewer)).toThrow('distinct');expect(()=>validateReviewArtifact({...artifact,rationale:'changed'},'run',bound)).toThrow('does not bind');}); test('executor observations have a strict helper-owned shape',()=>{expect(()=>validateVerificationObservation({booted:true,legitimate:true,security:'pass',existingTests:true,output:'ok',inputHash:'',tested:true})).toThrow('Unexpected');expect(()=>validateVerificationObservation({booted:'yes',legitimate:true,security:'pass',existingTests:true,output:'ok',inputHash:''})).toThrow('booleans');}); test('secret-bearing fixtures cannot enter a replayable verification bundle',async()=>{const runDir=tmp(),snapshot=path.join(runDir,'snapshot');fs.mkdirSync(snapshot);fs.writeFileSync(path.join(snapshot,'app.js'),'vulnerable\n');const raw:any=request('vulnerable\n','fixed\n');raw.review.reviewedPatchHash=patchHash(raw);raw.fixtures={'secret.txt':CREDENTIAL_CANARY};const manifest:any={entries:[{path:'app.js',transformation:undefined}]};const runtime:any={id:'node',image:'runtime@sha256:'+'a'.repeat(64),platform:'linux/amd64'};expect(verifyRepair({runId:'run',runDir,manifest,rawRequest:raw,runtime,verifier:runtime,policyHash:'c'.repeat(64),archives:[],executor:{observe:async()=>{throw new Error('must not execute');}},persist:false})).rejects.toMatchObject({code:'REDACTION_FAILED'});}); + test('a non-root producer patches a read-only snapshot file and keeps its mode',()=>{const root=tmp(),before=path.join(root,'before'),after=path.join(root,'after');fs.mkdirSync(before);fs.writeFileSync(path.join(before,'app.js'),'vulnerable\n');fs.chmodSync(path.join(before,'app.js'),0o444);const raw:any=request('vulnerable\n','fixed\n');raw.review.reviewedPatchHash=patchHash(raw);preparePatchedSource(before,after,validateVerificationRequest(raw));expect(fs.readFileSync(path.join(after,'app.js'),'utf8')).toBe('fixed\n');expect(fs.statSync(path.join(after,'app.js')).mode&0o777).toBe(0o444);}); test('declared patches require exact pristine preimages',()=>{const root=tmp(),before=path.join(root,'before'),after=path.join(root,'after');fs.mkdirSync(before);fs.writeFileSync(path.join(before,'app.js'),'changed\n');const raw:any=request('vulnerable\n','fixed\n');raw.review.reviewedPatchHash=patchHash(raw);expect(()=>preparePatchedSource(before,after,validateVerificationRequest(raw))).toThrow('preimage');}); test('helper derives dependency and configuration patch effects',()=>{expect(fileEffect('package.json')).toBe('dependency');expect(fileEffect('apps/x/pyproject.toml')).toBe('dependency');expect(fileEffect('config/environments/test.rb')).toBe('configuration');const root=tmp(),before=path.join(root,'before'),after=path.join(root,'after');fs.mkdirSync(before);fs.writeFileSync(path.join(before,'package.json'),'{}');const raw:any=request('vulnerable\n','fixed\n');raw.changes=[{path:'package.json',beforeSha256:sha256('{}'),after:'{"dependencies":{}}',effect:'configuration'}];raw.boundaryFiles=['package.json'];raw.review.reviewedPatchHash=patchHash(raw);expect(()=>preparePatchedSource(before,after,validateVerificationRequest(raw))).toThrow('must be declared as dependency');}); test('verification evidence stays outside both source trees and temporary copies are deleted on errors',async()=>{const runDir=tmp(),snapshot=path.join(runDir,'snapshot');fs.mkdirSync(snapshot);fs.writeFileSync(path.join(snapshot,'app.js'),'vulnerable\n',{mode:0o755});const testBody='test("ok",()=>{})\n';fs.writeFileSync(path.join(snapshot,'app.test.js'),testBody);const packageJson='{"scripts":{"test":"node --test"}}';fs.writeFileSync(path.join(snapshot,'package.json'),packageJson);const raw:any=request('vulnerable\n','fixed\n');raw.findingId='1abcdefabcdefabcdefabcdefabcdefa';raw.existingTests=[{executable:'/usr/local/bin/node',args:['--test','--test-reporter=tap','./app.test.js']}];raw.testFiles=['app.test.js'];raw.changes.push({path:'security/policy.js',beforeSha256:null,after:'export const enforced = true\n',effect:'source'});raw.review.reviewedPatchHash=patchHash(raw);const manifest:any={version:3,createdAt:'2026-01-01T00:00:00Z',expiresAt:'2026-01-08T00:00:00Z',root:'/repo',headCommit:'a'.repeat(40),originalHash:'b'.repeat(64),executionHash:treeHash(snapshot),entries:[{path:'app.js',originalHash:sha256('vulnerable\n'),executionHash:sha256('vulnerable\n'),bytes:11,mode:0o755},{path:'app.test.js',originalHash:sha256(testBody),executionHash:sha256(testBody),bytes:Buffer.byteLength(testBody),mode:0o600},{path:'package.json',originalHash:sha256(packageJson),executionHash:sha256(packageJson),bytes:packageJson.length,mode:0o600}]};const runtime:any={id:'node',stack:'node',image:'runtime@sha256:'+'a'.repeat(64),platform:'linux/amd64'};const executor:any={observe:async(source:string,phase:string,_request:any,_runtime:any,_verifier:any,work:string)=>{expect(work.startsWith(source+path.sep)).toBe(false);fs.mkdirSync(path.join(work,phase),{recursive:true});fs.writeFileSync(path.join(work,phase,'policy.json'),'evidence');return{booted:true,legitimate:true,security:phase==='before'?'intended_failure':'pass',existingTests:true,output:'ok',inputHash:''};}};let unattested:any;try{await verifyRepair({runId:'run',runDir,manifest,rawRequest:raw,runtime,verifier:runtime,policyHash:'c'.repeat(64),archives:[],executor,persist:false});}catch(error){unattested=error;}expect(unattested).toMatchObject({code:'PREREQUISITE',attempt:{artifactKind:'repair_candidate',findingId:raw.findingId,reproduction:'reproduced',repair:'proposed',bundleIssued:false,testCompletionAssurance:'self_reported'}});expect(unattested.message).toContain('out-of-process external assertion witness');expect(fs.existsSync(path.join(runDir,'bundles'))).toBe(false);expect(fs.readdirSync(path.join(runDir,'verification'))).toEqual([]);expect(fs.statSync(path.join(snapshot,'app.js')).mode&0o777).toBe(0o755);const failing:any={observe:async()=>{throw new Error('stop');}};expect(verifyRepair({runId:'run',runDir,manifest,rawRequest:raw,runtime,verifier:runtime,policyHash:'c'.repeat(64),archives:[],executor:failing,persist:false})).rejects.toThrow('stop');expect(fs.readdirSync(path.join(runDir,'verification'))).toEqual([]);const afterFailure:any={observe:async(_source:string,phase:string)=>{if(phase==='after')throw new CsoError('TOOL_FAILED','after setup failed');return{booted:true,legitimate:true,security:'intended_failure',existingTests:true,output:'reproduced safely',inputHash:''};}};let failed:any;try{await verifyRepair({runId:'run',runDir,manifest,rawRequest:raw,runtime,verifier:runtime,policyHash:'c'.repeat(64),archives:[],executor:afterFailure});}catch(error){failed=error;}expect(failed).toMatchObject({code:'TOOL_FAILED',attempt:{findingId:raw.findingId,reproduction:'reproduced',repair:'failed',bundleIssued:false}});const attempt=failed.attempt,artifact=JSON.parse(fs.readFileSync(path.join(runDir,'verification-attempts',`${attempt.id}.json`),'utf8'));expect(artifact).toMatchObject({id:attempt.id,findingId:raw.findingId,reproduction:'reproduced',repair:'failed',bundleIssued:false});expect(fs.existsSync(path.join(runDir,'bundles'))).toBe(false);expect(fs.readdirSync(path.join(runDir,'verification'))).toEqual([]);const assertionFailure:any={observe:async(_source:string,phase:string)=>({booted:true,legitimate:true,security:'intended_failure',existingTests:true,output:phase==='before'?'reproduced safely':'repair remained vulnerable',inputHash:''})};let notRepaired:any;try{await verifyRepair({runId:'run',runDir,manifest,rawRequest:raw,runtime,verifier:runtime,policyHash:'c'.repeat(64),archives:[],executor:assertionFailure});}catch(error){notRepaired=error;}expect(notRepaired).toMatchObject({code:'ASSERTION_FAILED',attempt:{reproduction:'reproduced',repair:'failed',bundleIssued:false,after:{security:'intended_failure'}}});expect(fs.existsSync(path.join(runDir,'bundles'))).toBe(false);expect(fs.readdirSync(path.join(runDir,'verification-attempts'))).toHaveLength(2);const brokenStartup:any={observe:async()=>({booted:false,legitimate:false,security:'pass',existingTests:false,output:'application never started',inputHash:''})};let blocked:any;try{await verifyRepair({runId:'run',runDir,manifest,rawRequest:raw,runtime,verifier:runtime,policyHash:'c'.repeat(64),archives:[],executor:brokenStartup});}catch(error){blocked=error;}expect(blocked).toMatchObject({attempt:{reproduction:'blocked',repair:'failed',bundleIssued:false}});expect(fs.readdirSync(path.join(runDir,'verification-attempts'))).toHaveLength(3);fs.writeFileSync(path.join(snapshot,'unmanifested.txt'),'changed after snapshot identity\n');let executed=false;const mustNotExecute:any={observe:async()=>{executed=true;return{booted:true,legitimate:true,security:'pass',existingTests:true,output:'',inputHash:''};}};await expect(verifyRepair({runId:'run',runDir,manifest,rawRequest:raw,runtime,verifier:runtime,policyHash:'c'.repeat(64),archives:[],executor:mustNotExecute,persist:false})).rejects.toMatchObject({code:'INCOMPATIBLE_INPUT'});expect(executed).toBe(false);}); diff --git a/test/cso-node-lifecycle-integration.test.ts b/test/cso-node-lifecycle-integration.test.ts index 69c616526..9f73c26fa 100644 --- a/test/cso-node-lifecycle-integration.test.ts +++ b/test/cso-node-lifecycle-integration.test.ts @@ -191,11 +191,12 @@ suite('CSO Node producer-visible repair lifecycle fixture', () => { const submittedFinding = submitted.findings[0]; expect(submittedFinding).toMatchObject({ reproduction: 'not_attempted', repair: 'not_attempted', closure: 'open' }); const plan = await cli.command(['runtime-plan', original.runId, 'node', '--port', '34569']); + expect(plan.runtimeProfile).toBe(cli.runtime.id); const vulnerable = fs.readFileSync(path.join(originalRunDirectory, 'snapshot', 'policy.js'), 'utf8'); const repaired = "module.exports={status:403,body:'DENIED'};\n"; const request: VerificationRequest = { findingId: submittedFinding.id, - runtimeProfile: cli.runtime.id, + runtimeProfile: plan.runtimeProfile, port: 34569, start: plan.start.command, legitimate: [{ name: 'legitimate control', path: '/control', method: 'GET', expected: { status: 200, includes: 'CONTROL_OK' } }], From 501ff8310a1e13e6bf7f7804907d58b5cd37ef2e Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Sat, 17 Oct 2026 10:19:52 -0700 Subject: [PATCH 8/8] v1.91.124.0 feat(cso): helper run clock (remainingSeconds), /cso time discipline, content-free producer tool timeline (#3242) * fix(cso): comprehensive verify can patch read-only snapshots and accepts runtime-plan's profile * feat(cso): helper replies carry remainingSeconds; producer receipts record a content-free tool timeline * fix(cso): count remainingSeconds to the investigation deadline; bound and validate the tool timeline remainingSeconds now measures to deadline - 60s, the point where scan, verify and record-review refuse with DEADLINE, and inspect carries it. The post-command clock lookup can only omit the field, never fail a command whose state change is already saved. The stream timeline records end times from tool_result, indexes only recorded calls so it stays at the 4096 cap, and receipts reject malformed timeline entries. * docs(changelog): unreleased entry for the /cso run clock * v1.91.124.0 stamp --- CHANGELOG.md | 12 ++++++++ VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- cso/SKILL.md | 2 +- cso/SKILL.md.tmpl | 2 +- lib/cso/cli.ts | 34 ++++++++++++++++++++++- lib/cso/state.ts | 2 +- package.json | 2 +- scripts/cso-eval-producer.ts | 1 + scripts/cso-eval-protocol.ts | 4 ++- scripts/cso-eval.ts | 4 ++- test/claude-producer-stream.test.ts | 28 +++++++++++++++++-- test/cso-cli.test.ts | 11 ++++++++ test/cso-eval.test.ts | 5 ++++ test/helpers/providers/claude-stream.ts | 37 +++++++++++++++++++++++-- test/helpers/providers/types.ts | 10 +++++++ 16 files changed, 144 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 679805e64..f8d22287c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog +## [1.91.124.0] - 2026-10-17 + +**/cso runs finish on time.** In the first paid runtime qualification, one comprehensive run submitted its findings ten minutes in, kept working for another 25 minutes without calling the helper, and was killed before it called `finish`. Its report was never finished, so the cold-start gate scored 63/64. The agent had no clock to follow. + +### Added +- **Helper replies carry `remainingSeconds`.** `start`, `resume`, `submit`, `scan`, `scanner-outcome`, `import-sarif`, `record-review`, `test-plan`, `runtime-plan`, `verify` and `inspect` report the whole seconds of investigation time left. The count stops where `scan`, `verify` and `record-review` start refusing with DEADLINE, so the final reporting minute stays free for `submit` and `finish`. The field is added after the command and only omitted if the deadline can't be read, so it never turns a saved change into an error. +- **The /cso skill follows the clock.** It now says to start only work that fits and, below 120 seconds, to stop waiting and `finish`. +- **Producer receipts record a content-free tool timeline.** For each tool call the eval producer records the name, its start and end offsets, and whether a subagent made it. It never records inputs or outputs. The timeline is capped at 4096 entries, validated on read, and left out of the batch index. Scoring is unchanged. + +### If you… +- **…drive `gstack-cso` from your own agent:** read `remainingSeconds` from each reply and stop starting work below two minutes. `inspect` refreshes it without side effects. + ## [1.91.123.0] - 2026-10-17 **/cso comprehensive repairs run again.** In the first paid runtime qualification, the agent recorded 148 repair reviews across 42 comprehensive runs, but not one verification attempt started. Every runtime scored 0/24 on held-out repairs. Two helper bugs stacked: the patch write failed on the snapshot's read-only files, and `runtime-plan` handed the agent a profile name that `verify` refused. diff --git a/VERSION b/VERSION index 48617770e..114fc58b8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.123.0 +1.91.124.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index 957e4470a..9a47949cd 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.123.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.124.0 — regenerate/re-copy after upgrading gstack Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed for agent hosts without a full skill install. The full skills add workflows, diff --git a/cso/SKILL.md b/cso/SKILL.md index 46e19240b..47293f45f 100644 --- a/cso/SKILL.md +++ b/cso/SKILL.md @@ -99,7 +99,7 @@ Start first; inspect snapshot, readiness, deadline, transformations, and coverag When updating coverage, copy every record's `domain` and `scope` exactly from `inspect`; a new scope leaves the planned scope unassessed. Only helper commands may update helper-owned records. -Budgets are ten minutes daily and thirty comprehensive, including one minute for reporting. Use at most three investigation workers and two reproduction groups per Docker endpoint. Attempts get five minutes and three harness repairs per finding, within the run deadline. Prioritize unresolved high impact. Report model usage only when exposed. +Budgets: ten minutes daily, thirty comprehensive. Use at most three investigation workers and two reproduction groups per Docker endpoint. Attempts get five minutes and three harness repairs per finding. Prioritize unresolved high impact. Report model usage only when exposed. Helper replies carry investigation `remainingSeconds`: start only what fits; below 120, stop and `finish`. --- ## Section index — Read each section when its situation applies diff --git a/cso/SKILL.md.tmpl b/cso/SKILL.md.tmpl index 9f936311a..765027bc5 100644 --- a/cso/SKILL.md.tmpl +++ b/cso/SKILL.md.tmpl @@ -99,7 +99,7 @@ Start first; inspect snapshot, readiness, deadline, transformations, and coverag When updating coverage, copy every record's `domain` and `scope` exactly from `inspect`; a new scope leaves the planned scope unassessed. Only helper commands may update helper-owned records. -Budgets are ten minutes daily and thirty comprehensive, including one minute for reporting. Use at most three investigation workers and two reproduction groups per Docker endpoint. Attempts get five minutes and three harness repairs per finding, within the run deadline. Prioritize unresolved high impact. Report model usage only when exposed. +Budgets: ten minutes daily, thirty comprehensive. Use at most three investigation workers and two reproduction groups per Docker endpoint. Attempts get five minutes and three harness repairs per finding. Prioritize unresolved high impact. Report model usage only when exposed. Helper replies carry investigation `remainingSeconds`: start only what fits; below 120, stop and `finish`. --- {{SECTION_INDEX:cso}} diff --git a/lib/cso/cli.ts b/lib/cso/cli.ts index 672272742..4cac4e3f8 100644 --- a/lib/cso/cli.ts +++ b/lib/cso/cli.ts @@ -57,6 +57,7 @@ import { readJson, reclaimDeadAttemptScratch, repoId, + executionDeadline, requireTime, retention, runDirectory, @@ -1609,6 +1610,7 @@ async function inspect(args: string[]) { ? readJson(join(dir, 'preparation.json')) : undefined, recovery: recoveryEvents(dir), + remainingSeconds: remainingSeconds(report.deadline), }); } async function read(args: string[]) { @@ -2796,12 +2798,31 @@ async function replay(args: string[], dependencies: CsoCliDependencies) { }); } +/** In-run replies that report the investigation time left; every one but `start` takes the run ID first. */ +const RUN_CLOCK_COMMANDS = new Set([ + 'start', + 'resume', + 'submit', + 'scan', + 'scanner-outcome', + 'import-sarif', + 'record-review', + 'test-plan', + 'runtime-plan', + 'verify', +]); +/** Whole seconds until the investigation deadline (the final reporting minute excluded), or undefined if unknown. */ +function remainingSeconds(deadline: string): number | undefined { + const ends = executionDeadline({ deadline }); + return Number.isFinite(ends) ? Math.max(0, Math.floor((ends - Date.now()) / 1000)) : undefined; +} export async function dispatchCsoCommand( command: string, args: string[], dependencies: CsoCliDependencies, ): Promise { args = [...args]; + const runId = args[0]; if (!['start', 'recheck', 'replay', 'doctor', 'provision-images'].includes(command)) { const started = Date.now(); retention(started, { deadlineMs: started + RETENTION_MAINTENANCE_MS, maxEntries: RETENTION_MAX_ENTRIES }); @@ -2876,7 +2897,18 @@ export async function dispatchCsoCommand( default: throw new CsoError('INVALID_ARGUMENT', `Unknown command: ${command}`); } - return result; + if (!RUN_CLOCK_COMMANDS.has(command) || !result || typeof result !== 'object' || Array.isArray(result)) + return result; + const deadline = (result as { deadline?: unknown }).deadline; + let seconds: number | undefined; + try { + seconds = remainingSeconds( + typeof deadline === 'string' ? deadline : loadReport(runDirectory(runId)).deadline, + ); + } catch { + seconds = undefined; + } + return seconds === undefined ? result : { ...result, remainingSeconds: seconds }; } const PRODUCTION_CLI_DEPENDENCIES: CsoCliDependencies = Object.freeze({ runtimeCatalog: RUNTIME_CATALOG, diff --git a/lib/cso/state.ts b/lib/cso/state.ts index 66ac7f6eb..aaaca9f79 100644 --- a/lib/cso/state.ts +++ b/lib/cso/state.ts @@ -944,7 +944,7 @@ export function loadReport(dir: string): RunReportV3 { export function event(report: RunReportV3, kind: string, message: string): void { report.events.push({ at: new Date().toISOString(), kind, message: redact(message) }); } -export function executionDeadline(report: RunReportV3): number { +export function executionDeadline(report: Pick): number { return Date.parse(report.deadline) - 60_000; } export function requireTime(report: RunReportV3): void { diff --git a/package.json b/package.json index a130d5382..1b48d7977 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.123", + "version": "1.91.124", "description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.", "license": "MIT", "type": "module", diff --git a/scripts/cso-eval-producer.ts b/scripts/cso-eval-producer.ts index 333e71268..a2995473b 100644 --- a/scripts/cso-eval-producer.ts +++ b/scripts/cso-eval-producer.ts @@ -686,6 +686,7 @@ export async function runProducerCell(inputPath: string, receiptPath: string, op durationMs: run.durationMs, firstUsefulResultMs: null, toolCalls: run.toolCalls, + ...(run.toolTimeline ? { toolTimeline: run.toolTimeline } : {}), output, outputHash: sha256(output), usage: { diff --git a/scripts/cso-eval-protocol.ts b/scripts/cso-eval-protocol.ts index 88174ecff..58e76d50c 100644 --- a/scripts/cso-eval-protocol.ts +++ b/scripts/cso-eval-protocol.ts @@ -130,6 +130,8 @@ export interface ProducerReceipt { durationMs: number; firstUsefulResultMs: null; toolCalls: number; + /** Content-free tool timeline (name, offset, thread) for diagnosing overruns; absent when the adapter has none. */ + toolTimeline?: Array<{ atMs: number; endMs?: number; tool: string; agent: 'main' | 'subagent' }>; output: string; outputHash: string; usage: { @@ -148,7 +150,7 @@ export interface ProducerReceipt { * Compact trusted index; raw output remains in the separately retained receipt. * Collection adds the matrix cell that the receipt's cellRef names. */ -export type ProducerReceiptIndex = Omit & { +export type ProducerReceiptIndex = Omit & { cell: ProducerCell; error?: { code: string }; }; diff --git a/scripts/cso-eval.ts b/scripts/cso-eval.ts index ad02a9d2f..eef53751d 100644 --- a/scripts/cso-eval.ts +++ b/scripts/cso-eval.ts @@ -400,6 +400,8 @@ function validateReceipt(receipt: ProducerReceipt, cell: EvalCell, inputHash: st validateInstallationIdentity(receipt.installationIdentity, 'INVALID_PRODUCER_RECEIPT'); validateProviderIdentity(receipt.providerIdentity, cell.host === 'codex' ? 'gpt' : cell.host, 'INVALID_PRODUCER_RECEIPT'); validateArtifactInventory(receipt.artifacts, 'INVALID_PRODUCER_RECEIPT'); + const timeline = receipt.toolTimeline; + if (timeline !== undefined && (!Array.isArray(timeline) || timeline.length > 4096 || timeline.some(entry => !entry || !Number.isSafeInteger(entry.atMs) || entry.atMs < 0 || (entry.endMs !== undefined && (!Number.isSafeInteger(entry.endMs) || entry.endMs < entry.atMs)) || typeof entry.tool !== 'string' || !/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(entry.tool) || !['main', 'subagent'].includes(entry.agent) || Object.keys(entry).some(key => !['atMs', 'endMs', 'tool', 'agent'].includes(key))))) throw new Error('INVALID_PRODUCER_RECEIPT'); } function validateInstallationIdentity(identity: ProducerInstallationIdentity, error: string): void { @@ -530,7 +532,7 @@ export function collectProducerReceipts(matrix: EvalMatrix, schedule: PreparedEv estimatedCost: { measured: costs.length, denominator: expected.length, totalUSD: costs.length ? costs.reduce((sum, value) => sum + value, 0) : null, source: 'pricing-table-estimate' }, }); } - const indexes: ProducerReceiptIndex[] = bound.map(({ output: _output, error, ...receipt }) => ({ ...receipt, ...(error ? { error: { code: error.code } } : {}) })); + const indexes: ProducerReceiptIndex[] = bound.map(({ output: _output, toolTimeline: _toolTimeline, error, ...receipt }) => ({ ...receipt, ...(error ? { error: { code: error.code } } : {}) })); const base = { schemaVersion: 1 as const, matrixHash: matrixHash(matrix), scheduleHash: digest(JSON.stringify(schedule)), receipts: indexes.sort((left, right) => left.cell.id.localeCompare(right.cell.id)), summary: { scheduled: matrix.cells.length, prepared: schedule.preparedCells, submitted: bound.length, missing: matrix.cells.length - bound.length, matchedPairsExpected: expectedMatchedPairs(matrix), matchedPairsSubmitted: completePairs.length, modelMismatches, groups, diff --git a/test/claude-producer-stream.test.ts b/test/claude-producer-stream.test.ts index badfbe836..014801c12 100644 --- a/test/claude-producer-stream.test.ts +++ b/test/claude-producer-stream.test.ts @@ -33,7 +33,7 @@ describe('Claude producer stream accounting', () => { test('takes usage and turns from the final result and keeps the paid result contract', () => { const state = claudeStreamState(); for (const line of lines(start('a', 1000), delta(100), stop, result({}))) consumeClaudeStreamLine(state, line); - expect(resultFromClaudeStream(state, { model: 'claude-test', durationMs: 5 })).toEqual({ output: 'REPORT', tokens: { input: 2001, output: 201, cached: 14 }, durationMs: 5, toolCalls: 2, modelUsed: 'claude-test' }); + expect(resultFromClaudeStream(state, { model: 'claude-test', durationMs: 5 })).toEqual({ output: 'REPORT', tokens: { input: 2001, output: 201, cached: 14 }, durationMs: 5, toolCalls: 2, toolTimeline: [], modelUsed: 'claude-test' }); for (const ending of [[], [result({ result: ' ' })], [result({ result: 7 })], [result({ is_error: true })], [result({ subtype: 'error_max_turns' })]]) { const partial = claudeStreamState(); for (const line of lines(start('a', 10), delta(3), stop, ...ending)) consumeClaudeStreamLine(partial, line); @@ -52,7 +52,31 @@ describe('Claude producer stream accounting', () => { for (const line of lines(start('a', 1000), delta(100), stop, subagent('s1', 50000), subagent('s1', 50000), subagent('s2', 50001), result({ result: 'MAIN ENDED TURN', modelUsage: sessionUsage }), start('b', 1002), delta(102), stop, result({ num_turns: 1, result: 'REPORT', usage: { input_tokens: 1002, output_tokens: 102, cache_read_input_tokens: 7 }, modelUsage: sessionUsage }))) consumeClaudeStreamLine(state, line); - expect(resultFromClaudeStream(state, { model: 'claude-test', durationMs: 5 })).toEqual({ output: 'REPORT', tokens: { input: 153009, output: 15308, cached: 49 }, durationMs: 5, toolCalls: 3, modelUsed: 'claude-test' }); + expect(resultFromClaudeStream(state, { model: 'claude-test', durationMs: 5 })).toEqual({ output: 'REPORT', tokens: { input: 153009, output: 15308, cached: 49 }, durationMs: 5, toolCalls: 3, toolTimeline: [], modelUsed: 'claude-test' }); + }); + + test('records a content-free tool timeline: main and subagent calls once each, never their inputs', () => { + const toolStart = (id: string, name: string) => ({ type: 'stream_event', parent_tool_use_id: null, event: { type: 'content_block_start', index: 1, content_block: { type: 'tool_use', id, name, input: {} } } }); + const mainCall = { type: 'assistant', message: { id: 'a', content: [{ type: 'tool_use', id: 'toolu_bash', name: 'Bash', input: { command: 'gstack-cso inspect SECRET_PATH' } }] } }; + const subCall = { type: 'assistant', parent_tool_use_id: 'toolu_agent', message: { id: 's1', content: [{ type: 'tool_use', id: 'toolu_sub', name: 'Bash', input: { command: 'cat SECRET_PATH' } }], usage: { input_tokens: 1, output_tokens: 1 } } }; + const state = claudeStreamState(); + for (const line of lines(start('a', 10), toolStart('toolu_bash', 'Bash'), toolStart('toolu_agent', 'Agent'), mainCall, subCall, subCall, toolStart('toolu_odd', 'mcp__x/../y'))) consumeClaudeStreamLine(state, line); + const timeline = resultFromClaudeStream(state, { model: 'claude-test', durationMs: 5, error: { code: 'timeout', reason: 'exceeded 5ms' } }).toolTimeline!; + expect(timeline.map(({ tool, agent }) => [tool, agent])).toEqual([['Bash', 'main'], ['Agent', 'main'], ['Bash', 'subagent'], ['other', 'main']]); + expect(timeline.every(entry => Number.isSafeInteger(entry.atMs) && entry.atMs >= 0 && Object.keys(entry).length === 3)).toBe(true); + expect(JSON.stringify(timeline)).not.toContain('SECRET_PATH'); + }); + + test('stamps a tool call end once from its tool_result and keeps the timeline and its id index at the cap', () => { + const state = claudeStreamState(); + const toolResult = (id: string) => ({ type: 'user', message: { content: [{ type: 'tool_result', tool_use_id: id, content: 'SECRET_OUTPUT' }] } }); + const call = (id: string) => ({ type: 'assistant', message: { id: `m${id}`, content: [{ type: 'tool_use', id, name: 'Bash', input: {} }] } }); + for (const line of lines(call('t0'), toolResult('t0'), toolResult('t0'), toolResult('unknown'), call('t1'))) consumeClaudeStreamLine(state, line); + expect(state.toolTimeline.map(entry => entry.endMs === undefined)).toEqual([false, true]); + expect(JSON.stringify(state.toolTimeline)).not.toContain('SECRET_OUTPUT'); + for (let i = 2; i < 5000; i++) consumeClaudeStreamLine(state, JSON.stringify(call(`t${i}`))); + expect(state.toolTimeline).toHaveLength(4096); + expect(state.toolUseIndex.size).toBe(4096); }); test('a killed run counts each subagent message once and never reports subagent text as the producer output', () => { diff --git a/test/cso-cli.test.ts b/test/cso-cli.test.ts index 4a14016df..b3b10735b 100644 --- a/test/cso-cli.test.ts +++ b/test/cso-cli.test.ts @@ -69,6 +69,17 @@ describe('compiled CSO command workflow',()=>{ runGit('init','-q');runGit('config','user.email','fixture@example.test');runGit('config','user.name','Fixture');fs.writeFileSync(path.join(planRepo,'package.json'),JSON.stringify({name:'sensitive-plan',version:'1.0.0',scripts:{start:'node app.js',test:'node --test'}}));fs.writeFileSync(path.join(planRepo,'package-lock.json'),JSON.stringify({name:'sensitive-plan',version:'1.0.0',lockfileVersion:3,packages:{'':{name:'sensitive-plan',version:'1.0.0'}}}));fs.writeFileSync(path.join(planRepo,'app.js'),'export const app = true\n');fs.writeFileSync(path.join(planRepo,testPath),'const test=require("node:test");test("control",()=>{})\n');runGit('add','.');runGit('commit','-qm','sensitive test path'); const started=command(['start','--repo',planRepo,'--comprehensive','--offline']);expect(started.status).toBe(0);const run=JSON.parse(started.stdout),planned=command(['runtime-plan',run.runId,'node','--port','3456']);expect(planned.status).toBe(0);const plan=JSON.parse(planned.stdout),serialized=JSON.stringify(plan); expect(serialized).not.toContain(wallet);const testHandle=plan.tests.files.find((value:string)=>value.startsWith('@cso-path//'));expect(testHandle).toMatch(/^@cso-path\/\/[a-f0-9]{32}$/);expect(plan.tests.commands[0].args).toContain(`./${testHandle}`);expect(plan.start.command).toEqual({executable:'/usr/local/bin/node',args:['app.js']}); + const budget=(Date.parse(run.deadline)-Date.parse(run.createdAt))/1000;for(const remaining of [run.remainingSeconds,plan.remainingSeconds]){expect(Number.isSafeInteger(remaining)).toBe(true);expect(remaining).toBeGreaterThan(budget-120);expect(remaining).toBeLessThanOrEqual(budget-60);}expect(plan.remainingSeconds).toBeLessThanOrEqual(run.remainingSeconds); + }); + test('run clock counts to the investigation deadline: zero in the reporting minute, which still accepts submit until the audit deadline',()=>{ + const started=command(['start','--repo',repo,'--scope','auth','--offline']);expect(started.status).toBe(0);const run=JSON.parse(started.stdout),reportPath=path.join(state,'security','cso',run.repoId,run.runId,'report.json'),input=path.join(root,`clock-${run.runId}.json`);fs.writeFileSync(input,'{}'); + const submitted=command(['submit',run.runId,input]);expect(submitted.status).toBe(0);const inspected=command(['inspect',run.runId]);expect(inspected.status).toBe(0); + for(const remaining of [JSON.parse(submitted.stdout).remainingSeconds,JSON.parse(inspected.stdout).remainingSeconds]){expect(Number.isSafeInteger(remaining)).toBe(true);expect(remaining).toBeGreaterThan(0);expect(remaining).toBeLessThanOrEqual(run.remainingSeconds);} + const report=JSON.parse(fs.readFileSync(reportPath,'utf8'));report.deadline=new Date(Date.now()+30_000).toISOString();fs.writeFileSync(reportPath,JSON.stringify(report,null,2)+'\n'); + const late=command(['inspect',run.runId]);expect(late.status).toBe(0);expect(JSON.parse(late.stdout).remainingSeconds).toBe(0); + const reporting=command(['submit',run.runId,input]);expect(reporting.status).toBe(0);expect(JSON.parse(reporting.stdout).remainingSeconds).toBe(0); + report.deadline=new Date(Date.now()-1_000).toISOString();fs.writeFileSync(reportPath,JSON.stringify({...JSON.parse(fs.readFileSync(reportPath,'utf8')),deadline:report.deadline},null,2)+'\n'); + const refused=command(['submit',run.runId,input]);expect(refused.status).not.toBe(0);expect(refused.stderr).toContain('DEADLINE');expect(refused.stdout).toBe(''); }); test('wallet-shaped helper finding IDs survive submit, review, and verification admission',()=>{const started=command(['start','--repo',repo,'--comprehensive','--offline']);expect(started.status).toBe(0);const run=JSON.parse(started.stdout),base:any={title:'Wallet-shaped helper ID',rootCause:'Tenant query omits caller tenant predicate 0',location:{path:'src/users.ts',line:1,symbol:'tenantQuery'},advisoryIds:[],severity:'high',confidence:'high',confidenceRationale:'Caller-to-sink trace directly establishes the missing predicate',evidence:'supported',attackerControl:'Tenant chooses the record ID',impact:'Cross-tenant record disclosure',scenario:'A tenant requests another tenant record by ID',trace:['route','tenantQuery','database'],references:['src/users.ts:1'],recommendation:'Bind the query to the authenticated tenant',challenge:{reviewer:'reviewer-session',independent:true,mode:'independent_agent',callers:'route caller checked',controls:'authentication lacks authorization',counterevidence:'none found',conclusion:'tenant predicate is absent'}};let helperId='';for(let i=0;i<10_000;i++){base.rootCause=`Tenant query omits caller tenant predicate ${i}`;helperId=fingerprint(base);if(redact(helperId)!==helperId)break;}expect(redact(helperId)).not.toBe(helperId);const input=path.join(root,`wallet-id-${run.runId}.json`);fs.writeFileSync(input,JSON.stringify({findings:[base]}));expect(command(['submit',run.runId,input]).status).toBe(0);const reportPath=path.join(state,'security','cso',run.repoId,run.runId,'report.json'),stored=JSON.parse(fs.readFileSync(reportPath,'utf8'));expect(stored.findings[0].id).toBe(helperId);const before=fs.readFileSync(path.join(repo,'src','users.ts'),'utf8'),request:any={findingId:helperId,runtimeProfile:'node-v1',port:3456,start:{executable:'/usr/local/bin/node',args:['src/users.ts']},legitimate:[{name:'control',path:'/health',method:'GET',expected:{status:200}}],security:{name:'tenant boundary',path:'/users/other',method:'GET',expected:{status:403},vulnerable:{status:200}},existingTests:[{executable:'/usr/local/bin/node',args:['--test']}],testFiles:['src/control.test.ts'],fixtures:{},boundaryFiles:['src/users.ts'],changes:[{path:'src/users.ts',beforeSha256:sha256(before),after:before+'// tenant predicate\n',effect:'source'}],review:{reviewer:'reviewer-session',independent:true,rootCauseRepaired:true,featurePreserved:true,boundaryMocks:false,rationale:'The tenant predicate is added while the control remains intact',reviewedPatchHash:''}};request.review.reviewedPatchHash=patchHash(request);fs.writeFileSync(input,JSON.stringify(request));const reviewed=command(['record-review',run.runId,input,'--producer','producer-session']);expect(reviewed.status).toBe(0);request.review.artifactId=JSON.parse(reviewed.stdout).reviewArtifactId;fs.writeFileSync(input,JSON.stringify(request));const verified=command(['verify',run.runId,input]);expect(verified.status).not.toBe(0);expect(verified.stderr).toContain('PREREQUISITE');expect(verified.stderr).not.toContain('REDACTION_FAILED');const review=JSON.parse(fs.readFileSync(path.join(path.dirname(reportPath),'reviews',`${request.review.artifactId}.json`),'utf8'));expect(review.findingId).toBe(helperId);}); test('daily find, early submit, and finish persist a truthful report without changing source',()=>{const before=git('status','--porcelain=v1','-z'),started=command(['start','--repo',repo,'--scope','auth','--offline']);expect(started.status).toBe(0);const run=JSON.parse(started.stdout),runId=run.runId;expect(run.completeness).toBe('not assessed');const reportPath=path.join(state,'security','cso',run.repoId,runId,'report.json');expect(fs.existsSync(reportPath)).toBe(true);const current=JSON.parse(fs.readFileSync(reportPath,'utf8')); diff --git a/test/cso-eval.test.ts b/test/cso-eval.test.ts index 6d6559576..34b773c84 100644 --- a/test/cso-eval.test.ts +++ b/test/cso-eval.test.ts @@ -268,6 +268,11 @@ describe('CSO matched evaluation accounting', () => { artifactTamper.artifacts.totalBytes = 1; expect(() => collectProducerReceipts(matrix, syntheticSchedule(), [rehashReceipt(artifactTamper)])).toThrow('INVALID_PRODUCER_RECEIPT'); + const timed = rehashReceipt({ ...structuredClone(first), toolTimeline: [{ atMs: 5, endMs: 9, tool: 'Bash', agent: 'main' }, { atMs: 7, tool: 'Agent', agent: 'subagent' }] }); + expect(collectProducerReceipts(matrix, syntheticSchedule(), [timed]).receipts[0]).not.toHaveProperty('toolTimeline'); + for (const entry of [{ atMs: 9, endMs: 5, tool: 'Bash', agent: 'main' }, { atMs: 1, tool: 'cat /secret', agent: 'main' }, { atMs: 1, tool: 'Bash', agent: 'main', input: 'x' }]) + expect(() => collectProducerReceipts(matrix, syntheticSchedule(), [rehashReceipt({ ...structuredClone(first), toolTimeline: [entry] } as ProducerReceipt)])).toThrow('INVALID_PRODUCER_RECEIPT'); + const mixedInstallation = syntheticReceipt(cells[1]); mixedInstallation.installationIdentity = syntheticInstallationIdentity('different-installation'); expect(() => collectProducerReceipts(matrix, syntheticSchedule(), [first, rehashReceipt(mixedInstallation)])).toThrow('UNMATCHED_PRODUCER_INSTALLATIONS'); diff --git a/test/helpers/providers/claude-stream.ts b/test/helpers/providers/claude-stream.ts index 18374b592..5cdb1da6e 100644 --- a/test/helpers/providers/claude-stream.ts +++ b/test/helpers/providers/claude-stream.ts @@ -1,5 +1,5 @@ import { spawn } from 'child_process'; -import type { RunResult } from './types'; +import type { RunResult, ToolTimelineEntry } from './types'; /** Usage, turns and the latest text from `claude -p --output-format stream-json --verbose --include-partial-messages`. */ export interface ClaudeStreamState { @@ -14,14 +14,36 @@ export interface ClaudeStreamState { lastText: string; result?: Record; invalidLines: number; + startedAt: number; + /** Content-free: each tool call's name, start and end offsets and thread, never its input or output. */ + toolTimeline: ToolTimelineEntry[]; + /** Timeline index by tool-use id, for recorded calls only, so it stays within the timeline cap. */ + toolUseIndex: Map; } export function claudeStreamState(): ClaudeStreamState { - return { totals: { input: 0, output: 0, cached: 0 }, open: new Map(), subagents: new Map(), turns: 0, resultTurns: 0, lastText: '', invalidLines: 0 }; + return { totals: { input: 0, output: 0, cached: 0 }, open: new Map(), subagents: new Map(), turns: 0, resultTurns: 0, lastText: '', invalidLines: 0, startedAt: Date.now(), toolTimeline: [], toolUseIndex: new Map() }; } +const TOOL_TIMELINE_LIMIT = 4096; + const count = (value: unknown): number => typeof value === 'number' && Number.isSafeInteger(value) && value >= 0 ? value : 0; +function recordToolUse(state: ClaudeStreamState, block: { id?: unknown; name?: unknown }, agent: 'main' | 'subagent'): void { + if (typeof block.id !== 'string' || state.toolUseIndex.has(block.id) || state.toolTimeline.length >= TOOL_TIMELINE_LIMIT) return; + state.toolUseIndex.set(block.id, state.toolTimeline.length); + state.toolTimeline.push({ + atMs: Date.now() - state.startedAt, + tool: typeof block.name === 'string' && /^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(block.name) ? block.name : 'other', + agent, + }); +} + +function recordToolResult(state: ClaudeStreamState, block: { tool_use_id?: unknown }): void { + const index = typeof block.tool_use_id === 'string' ? state.toolUseIndex.get(block.tool_use_id) : undefined; + if (index !== undefined && state.toolTimeline[index].endMs === undefined) state.toolTimeline[index].endMs = Date.now() - state.startedAt; +} + function close(state: ClaudeStreamState, key: string): void { const message = state.open.get(key); if (!message) return; @@ -39,6 +61,13 @@ export function consumeClaudeStreamLine(state: ClaudeStreamState, line: string): if (Number.isSafeInteger(event.num_turns) && event.num_turns >= 0) state.resultTurns += event.num_turns; return; } + if (event.type === 'assistant' && Array.isArray(event.message?.content)) { + for (const block of event.message.content) if (block?.type === 'tool_use') recordToolUse(state, block, typeof event.parent_tool_use_id === 'string' ? 'subagent' : 'main'); + } + if (event.type === 'user' && Array.isArray(event.message?.content)) { + for (const block of event.message.content) if (block?.type === 'tool_result') recordToolResult(state, block); + return; + } if (event.type === 'assistant' && typeof event.parent_tool_use_id === 'string') { const usage = event.message?.usage; if (typeof event.message?.id === 'string' && usage) state.subagents.set(event.message.id, { input: count(usage.input_tokens), output: count(usage.output_tokens), cached: count(usage.cache_read_input_tokens) }); @@ -56,6 +85,8 @@ export function consumeClaudeStreamLine(state: ClaudeStreamState, line: string): const usage = stream.message?.usage ?? {}; state.open.set(key, { input: count(usage.input_tokens), output: count(usage.output_tokens), cached: count(usage.cache_read_input_tokens) }); if (key === 'main') state.turns++; + } else if (stream.type === 'content_block_start' && stream.content_block?.type === 'tool_use') { + recordToolUse(state, stream.content_block, key === 'main' ? 'main' : 'subagent'); } else if (stream.type === 'message_delta' && stream.usage) { const message = state.open.get(key); if (!message) return; @@ -99,7 +130,7 @@ export function resultFromClaudeStream(state: ClaudeStreamState, opts: { model: const tokens = (result && resultTokens(result)) ?? claudeStreamUsage(state); const toolCalls = result ? state.resultTurns : state.turns; const modelUsed = typeof result?.model === 'string' && result.model ? result.model : opts.model; - const base = { tokens, durationMs: opts.durationMs, toolCalls, modelUsed }; + const base = { tokens, durationMs: opts.durationMs, toolCalls, toolTimeline: state.toolTimeline, modelUsed }; if (opts.error) return { ...base, output: typeof result?.result === 'string' ? result.result : state.lastText, error: opts.error }; const explicitError = result?.is_error === true || (typeof result?.subtype === 'string' && result.subtype !== 'success'); if (!result || explicitError || typeof result.result !== 'string' || !result.result.trim()) { diff --git a/test/helpers/providers/types.ts b/test/helpers/providers/types.ts index 59063e7b2..e9b51527e 100644 --- a/test/helpers/providers/types.ts +++ b/test/helpers/providers/types.ts @@ -49,6 +49,14 @@ export type RunError = | 'binary_missing' // CLI not found on PATH. | 'unknown'; // Catch-all with reason populated. +export interface ToolTimelineEntry { + atMs: number; + /** Set when the call's tool_result arrived; absent for a call still running when the stream ended. */ + endMs?: number; + tool: string; + agent: 'main' | 'subagent'; +} + export interface RunResult { /** Provider's textual output for the prompt. */ output: string; @@ -58,6 +66,8 @@ export interface RunResult { durationMs: number; /** Count of tool/function calls made during the run (0 if unsupported). */ toolCalls: number; + /** Tool calls in start order: name, start and end offsets from run start, and thread; no inputs or outputs. Unset if unsupported. */ + toolTimeline?: ToolTimelineEntry[]; /** Actual model ID the provider reports using (may be a variant of the family). */ modelUsed: string; /** If the run failed, error code + human reason. output/tokens may be partial. */