From a889ef9393c8e486f8a6c7ae504fc7aa03d3986e Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Fri, 16 Oct 2026 13:29:38 -0700 Subject: [PATCH] v1.91.105.0 fix(tests): the free suite stops needing its retry pass; test:health tells the truth (#3154) (#3212) * test: turn git auto-maintenance off in free fixtures, with a runner backstop git 2.29+ starts a detached `git maintenance run --auto` after every commit; it creates and deletes .git/objects/maintenance.lock after the commit returns. Diagnosed on 47d639a (git 2.55.0): - gstack-docs-candidate (ledger 37742176952/16): 4/150 replicated snapshots saw the .git listing change, every one `-objects/maintenance.lock`; 0/150 with the keys. repo() now sets maintenance.auto=false and gc.auto=0. - plan-design-sdk-fixture (ledger 37807608021/6): under commit load 18/150 runs failed the collector check; in every one Bun's rmSync(recursive, force) returned without throwing and left the scratch repo behind. 0/100 with the keys in the fixture's replacement git env, which never sees the runner's. - qa-functional-observer (ledger 37800857251/4): under load 6/200 observer setups threw ENOENT lstat .git/objects/maintenance.lock; 0/400 with the keys in the inherited env. The observer and its fixture (22 paid cases) are not edited; the runner backstop covers them. runFreeShard appends the two keys after any inherited GIT_CONFIG_* pairs of each shard child (a malformed inherited count is left for git to reject). A GIT_TRACE commit shows 3 maintenance lines with defaults and 0 in the runner child env; the new test pins that and the env merge cases. Failure messages now name the changed .git entries and surviving fixture directories; no assertion changed. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: synchronize the zombie publication-lock test on a framed PID line Ledger 38153371796/3 and 38161906980/3: line 69 `existsSync(ready)` failed. The test polled 300 x 10 ms for the Python parent's readiness file, then another 300 x 10 ms of /proc for state Z; under shard load the fixed count expired. existsSync also raced the write (an empty file read as pid 0). The parent now waits for its child with os.waitid(P_PID, WEXITED|WNOWAIT), which leaves it unreaped in state Z, and prints the PID with flush=True. The test reads exactly one newline-framed line from the parent's stdout under the test's own (unchanged) 10 s timeout, rejects a malformed or non-positive PID, and makes one /proc read that must show Z. Early exit, a malformed line or a timeout reports the parent's exit status and stderr tail; the owned parent is always killed in cleanup. Intentional assertion replacement: the readiness-file existence check and the polling loop are replaced by the framed-line requirement (a positive PID) and one /proc read; `expect(state).toBe('Z')` and every lock-recovery assertion are unchanged. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: stop the next-version smoke test from calling live GitHub Ledger 37804770972/9: "CLI runs against real repo and emits parseable JSON" failed with `JSON Parse error: Unexpected EOF` after 30032 ms. The smoke test ran the real CLI against live `gh`; bin/gstack-next-version's per-PR `gh api` calls run one after another (spawnSync inside its async workers), so 27 open PRs passed the 30 s spawn timeout and stdout was empty. Measured with a delayed fake gh: 8 PRs x 0.5 s = 4108 ms; 27 PRs x 1.2 s = 32637 ms. The CLI defect is filed as a P1 follow-up, not fixed here. The test keeps the real repository and the real CLI and puts a named fake gh first on PATH. It logs every argv, answers exactly the calls the CLI makes (auth status only when origin is not github.com, pr view exit 1, canned pr list, repo view and contents with one same-owner PR claiming 1.6.4.0) and exits 2 with a FAKE_GH_UNHANDLED marker for anything else; glab exits 1. The test now checks the exit code with stderr before JSON.parse, the exact call set, no marker, no glab call, host github, offline false, no fallback, no warnings, the canned claim, and version 1.6.5.0. Every existing assertion is kept; the spawn timeout is unchanged. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(test-health): report the Windows wall over PR runs and name the seed's real prerequisite free-wall read windows-free-tests.yml with `branch: 'main'`, but that workflow runs only on pull requests and workflow_dispatch, so the "main" runs it averaged were dispatch duration recordings. It now uses listWorkflowRuns' existing `event: 'pull_request'` filter and prints the population inline: `windows-free-tests (successful PR runs) 7.1 min (23 runs)`, or `no successful PR runs in window`. The free-tests half is byte-identical. The CEO-10 fix text stops offering a "CI recording" (none exists for the Linux seed) and names UBICLOUD_API_KEY; test:ubicloud --record-durations copies the seed back into the checkout, and contributors without the key leave the refresh to a maintainer. docs/TESTING_INTERNALS.md drops "or a CI recording" in the same change. Intentional pin change: test/test-health-report.test.ts free-wall value `windows-free-tests 0.0 min (1 runs)` -> `windows-free-tests (successful PR runs) 0.0 min (1 runs)`; the fixture now carries a PR run and an excluded dispatch run, plus a new case for the empty and mixed populations. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(timeline-read): reject missing and unparseable --since/--branch values `--since` and `--branch` read an unbound $2 under `set -u` and crashed with exit 1 when given no value, and an unparseable --since ("yesterday", "2 weeks") silently returned unfiltered history because the Bun regex was unanchored and fell through. Unknown arguments were silently ignored. --since is now parsed once in bash (no `date -d`, no bash-4 features) into a cutoff in epoch ms, and the Bun regex is deleted. Accepted forms: " minute|hour|day|week|month[s] ago" (case-insensitive, as before), "h|d|w" (the form gstack-global-discover documents) and ISO dates YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ (UTC). In #1723's shape, before any read: --since must be a relative time like "7 days ago" (got no value); accepted: ... --since must be a relative time like "7 days ago" (got 'yesterday'); accepted: ... --branch must be a branch name (got flag '--limit') with "got an empty value" for ''. Unknown arguments exit 2 with the usage line; --help/-h prints it and exits 0. Tests extend the --limit table in test/timeline.test.ts and run every case on empty and populated history, plus each accepted --since form filtering old events; the quoted-branch and no-filter tests are unchanged. Behavior change: unrecognized arguments (previously ignored) now exit 2. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: record the due audit follow-ups with verdicts, and file wave-2 follow-ups docs/test-audit-2026-10.md gains a dated 2026-10-15 section from a no-spend `bun run test:health --since-days 7`, with the 2026-10-12 figures from #3154 kept as history and a verdict per target: full-fallback 45.9% (open; the audit's next step is touchfile mappings for bin/, lib/, hosts/, make-pdf/), spend per merged PR $73.52 (verdict unavailable: the pre-change baseline, recomputed with collectHealth at now=2026-10-04 behind an upper-bound client, holds no trial-outcomes artifacts because the recorder shipped with the audit), cancelled slice-minutes 1,545/week, push-to-verdict p50 11.4 min (missed against 3-5 min), flaky-pass 6.1% (missed; this wave repairs it). Census reliability is not due until 2026-10-26; the interim figure is recorded and the repair stays with #3153/#3200. TODOS.md: one appended dated section (P1 gstack-next-version serial fetch with the 4160 ms measurement, P1 standing seed recorder, P1 full-fallback/spend, P1 dated flake follow-ups, P2 createQAFunctionalFixture maintenance keys, P2 diagnostic-mode HOME/state-root artifacts). The timeline-read bullet was deleted with its fix. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * chore(release): tentative stamp v1.91.105.0 with its CHANGELOG entry Stamp-at-merge policy (.gstack/ship-policy.json): the branch carries a tentative PATCH stamp and its CHANGELOG section directly under `# Changelog`; the queue restamps at merge time. Base 47d639a is 1.91.101.0, but the live slot scan shows 1.91.102.0 (#3190), 1.91.103.0 (#3200) and 1.91.104.0 (#3209) claimed, so this branch takes 1.91.105.0. Written with `gstack-restamp --version 1.91.105.0 --base main --expect-base 47d639a --allow-repo-commands` (VERSION, package.json's npm translation, the agents digest via the policy's release tool, and the CHANGELOG header). * test(seed): refresh the free-suite duration seed from a Ubicloud recording (#3154) Recorded with `bun run test:ubicloud --record-durations` (standard-16, eu-central-h1) on this branch, which equals origin/main 47d639a plus this wave; the recorder exited 0 and wrote 1219 durations (1055 before, 164 new, none removed; serial 2439 s -> 3202 s). `test:health` CEO-10 now reports 0 unseeded files. Two earlier recordings did not count: one failed on an unrelated fixed-sleep race in test/plan-seed-submission.test.ts (filed P2, not edited here), the other failed free-seed-ratchet because it ran against the first attempt's pulled seed. No file was excluded. free-seed-ratchet: three files are over the 60 s ceiling in this recording and are allowlisted with a split todo (setup-install-registry 82 s, host-renders-prune 64 s, setup-codex-scope 60.4 s); the split follow-up and the plan-seed-submission race are filed in the appended TODOS section. The ratchet test now names scripts/free-test-seed-allowlist.json literally (a pin on SEED_ALLOWLIST_FILE): pregate's lanes check maps data files to tests through string literals, and the allowlist had no lane (PREGATE_NO_LANE). Additive assertion; nothing weakened. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: give the git-maintenance backstop test a Windows-safe empty global config windows-free-shard (2) on #3212 (run 38832498861) failed two cases in test/test-free-shards-git-maintenance.test.ts, both serially reproduced by the retry pass: Git for Windows rejects GIT_CONFIG_GLOBAL=os.devNull (`fatal: unable to access '\\.\nul': Invalid argument`), so the malformed-count case saw that error instead of git's GIT_CONFIG_COUNT rejection, and the traced commit's `git init` exited nonzero. Point GIT_CONFIG_GLOBAL at a file that does not exist in the scratch HOME, as test/ceo-plan-mode-fixture.test.ts does; git reads a missing global config as empty on every platform. No assertion changed. 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 | 45 + TODOS.md | 65 +- VERSION | 2 +- agents-digest/gstack-AGENTS.md | 2 +- bin/gstack-timeline-read | 89 +- .../terminal-agent-publication-lock.test.ts | 38 +- docs/TESTING_INTERNALS.md | 37 +- docs/test-audit-2026-10.md | 31 + package.json | 2 +- scripts/free-test-durations.json | 2222 +++++++++-------- scripts/free-test-seed-allowlist.json | 5 +- scripts/test-free-shards.ts | 19 + scripts/test-health-report.ts | 15 +- test/free-seed-ratchet.test.ts | 1 + test/gstack-docs-candidate.test.ts | 7 +- test/gstack-next-version.test.ts | 111 +- test/plan-design-sdk-fixture.test.ts | 13 +- test/test-free-shards-git-maintenance.test.ts | 106 + test/test-health-report.test.ts | 23 +- test/timeline.test.ts | 60 + 20 files changed, 1778 insertions(+), 1115 deletions(-) create mode 100644 test/test-free-shards-git-maintenance.test.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index db5a7758b..487e88439 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,50 @@ # Changelog +## [1.91.105.0] - 2026-10-16 + +**The free suite stops needing its retry pass. +The health report tells the truth.** + +Six of 46 main runs last week needed the free suite's serial retry pass to go green. Five test files caused it, and three shared one cause: since git 2.29, every `git commit` starts a background `git maintenance run` that creates and deletes `.git/objects/maintenance.lock` after the commit has returned, so a test that lists, watches or deletes `.git` right afterwards sees a file that is there one moment and gone the next. Those fixtures now turn auto-maintenance off, and the free runner does it for every test child as a backstop. The other two flakes were a fixed-count poll and a smoke test that called live GitHub. `gstack-timeline-read` now refuses filters it cannot apply instead of returning everything. + +### The numbers that matter + +Measured with the repo's own reproducer (`scripts/ship-measure.ts free`, flaky retry off), before on 47d639a and after on this branch. Commands and per-file counts are in the PR body. + +| Measurement | Before | After | +|---|---|---| +| The five ledger files, 16-vCPU Ubicloud VM (`bun run test:ubicloud --diagnostic`) | 197/200 reruns clean | 600/600 | +| The three git fixtures under commit load, local runner env | 37/200 clean | 200/200 | +| Next-version smoke test, live GitHub calls | one `gh api` per open PR, one after another (27 PRs at 1.2 s: 32.6 s, past its 30 s limit) | none (runs in about 60 ms) | +| Weekly health: unseeded free test files | 164 (enforced check failing) | 0 | +| Weekly health: Windows wall population | dispatch recordings on main ("n/a (0 runs)" on Oct 12) | 78 successful PR runs, 9.2 min p50 (7 days to 2026-10-15) | + +The headline number is the first row: three of 200 clean-tree reruns failed before, none of 600 after. + +### What this means for you + +When the free suite goes red now, it is far more likely to be your change. Read the failure, not the retry ledger. + +### Itemized changes + +#### Fixed + +- **If you run `gstack-timeline-read --since` or `--branch` without a value,** you get exit 2 and `--since must be a relative time like "7 days ago" (got no value); accepted: ...` (or `--branch must be a branch name (got flag '--limit')`) instead of a crash. +- **If you pass `--since yesterday` or `--since "2 weeks"`,** you get exit 2 naming what it got, instead of your whole unfiltered history. Accepted forms: `7 days ago` (minute, hour, day, week, month), `7d` / `24h` / `2w`, and ISO dates `2026-10-01` or `2026-10-01T10:00:00Z`. +- **If you pass an argument `gstack-timeline-read` does not know,** it exits 2 with the usage line instead of ignoring it. `--help` prints the usage line. + +#### Changed + +- **If you read the weekly test-health report,** "Free-suite and Windows wall" now measures successful Windows runs on pull requests, says so (`windows-free-tests (successful PR runs) 9.2 min (78 runs)`), and prints `no successful PR runs in window` when there are none. It used to average the dispatch-only duration recordings on main. +- **If the health report says the duration seed is stale,** its fix line now names what the refresh needs (`UBICLOUD_API_KEY`, then `bun run test:ubicloud --record-durations`, which copies the seed back into your checkout) and tells contributors without the key to leave it to a maintainer. It no longer offers a CI recording, which does not exist. + +#### For contributors + +- The free runner appends `maintenance.auto=false` and `gc.auto=0` to every shard child's `GIT_CONFIG_*` pairs (`test/test-free-shards-git-maintenance.test.ts`). Fixtures that build their own git environment set the keys themselves; `docs/TESTING_INTERNALS.md#flake-ledger` has the rule and a recipe for reproducing a ledger entry from a CI run's `free-plan` artifact. +- The zombie publication-lock test synchronizes on a PID line its Python parent prints after `os.waitid(..., WNOWAIT)`, and the next-version smoke test runs the real CLI against a fake `gh` that logs and checks every call. +- `scripts/free-test-durations.json` is refreshed from a Ubicloud recording of this tree. +- No community contributions in this release. + ## [1.91.101.0] - 2026-10-13 **The field wave's residual gaps are closed.** v1.91.96.0 through v1.91.100.0 shipped the install-honesty and unattended-`/autoplan` wave (`docs/designs/GSTACK_FIELD_WAVE_2026_10_12.md`); running that release on a Capy machine left six gaps, each reproduced here with a test that failed first. diff --git a/TODOS.md b/TODOS.md index 9c7c45583..e8ab35a1b 100644 --- a/TODOS.md +++ b/TODOS.md @@ -88,9 +88,6 @@ Left open by the office-hours tier fix (#2801, #879, #1049, #1958, #1723, #1651 follows the carried `SESSION_TIER` through Phase 6 (first run gets the introduction, second run asks about the earlier assignment). No office-hours quality judge exists either. **Effort:** M. **Priority:** P2. -- **`gstack-timeline-read --since`/`--branch` without a value** — both still - read an unbound `$2` under `set -u` and crash with exit 1, the class #1723 - fixed for `--limit`. **Effort:** S. **Priority:** P3. ### P3: Oct 8 fix wave, safety hooks follow-ups (filed 2026-10-08) @@ -5394,3 +5391,65 @@ skills were told is fenced. Guard both writes. Effort S. **Priority:** P3. **Depends on:** none. + +### P1–P2: fix wave 2 follow-ups (filed 2026-10-15) + +From the free-suite health wave (flaky-pass fixes, #3154 seed refresh). Owner +Garry for each; revisit 2026-10-29 unless a date says otherwise. + +- **`gstack-next-version` fetches claimed slots one PR at a time** — + `GH_API_CONCURRENCY = 10` (bin/gstack-next-version:90), but its async workers + call `spawnSync`, so the per-PR `gh api` calls run serially: 8 stubbed PRs at + 0.5 s each took 4160 ms instead of about 500 ms (4108 ms on a rerun), and 27 + open PRs at about 1.2 s each pass the 30 s that callers allow, which is how the + old live smoke test failed. Every `/ship` slot allocation pays this. Fix: + async spawn with bounded overlap, verified by a delayed fake `gh`. Changing the + CLI selects 108 paid cases and 24 judges, so it ships as its own priced PR on + Garry's call. **Effort:** S. **Priority:** P1. +- **Standing Linux duration-seed recorder** — the seed refresh in this wave + keeps CEO-10 green for days, not weeks: main gains about 15 free test files a + day against a limit of 5 unseeded, so the weekly health run goes red again + until a recorder lands. Design: a scheduled `free-durations-record.yml` that + records on the standard runner and updates one seed PR before the Monday + health run, or the `free-plan` job consuming the latest recording artifact once + #3190 (owner of `free-tests.yml`) lands. Agree the design with the owner of + `free-tests.yml` before 2026-10-29. **Effort:** M. **Priority:** P1. +- **PR full-fallback and recorded spend (audit next step)** — 2026-10-15: + full-fallback 45.9% of PR runs, $73.52 recorded PR-lane spend per merged PR, + push-to-verdict p50 11.4 min (target 3–5 min). The pre-change spend baseline + was never recorded, so the 50% reduction verdict is unavailable + (docs/test-audit-2026-10.md, "Post-merge follow-up"). Next step, from the + audit's selection replay: touchfile mappings for `bin/`, `lib/`, `hosts/` and + `make-pdf/`, so a branch touching them stops selecting every case. Candidate + headline for the next wave. **Effort:** M. **Priority:** P1. +- **Free flaky-pass target follow-ups (2026-10-22 and 2026-10-29)** — read + main's `flake-ledger-*` artifacts (`bun run test:health --since-days 7`) and + check the free-suite flaky-pass rate is under 5% of main runs; a file still in + the ledger gets a named cause or a new entry here. **Effort:** S. **Priority:** P1. +- **`createQAFunctionalFixture` sets git auto-maintenance off itself** — its + repos inherit the free runner's backstop keys in CI, but a direct `bun test` + run still races `.git/objects/maintenance.lock` during observer setup. + The helper selects 22 paid cases, so this is a priced follow-up. + **Effort:** S. **Priority:** P2. +- **`test:ubicloud --diagnostic` cannot give clean counts for two ledger + shards** — `ship-measure free` reruns set a private `HOME` under `/tmp` and + `GSTACK_STATE_ROOT`, so `browse/test/path-validation.test.ts` (its upload + fixture builds an "outside" directory under `os.userInfo().homedir`, which + Bun takes from `HOME`) and `browse/test/pair-agent-tunnel-eval.test.ts` (its + denial log follows the inherited state root, not its fake `HOME`) fail 30/30 + in diagnostic mode while passing in the normal suite. Ledger shards that hold + them can never report `passed = n`. **Effort:** S. **Priority:** P2. +- **`test/plan-seed-submission.test.ts` reads its fake CLI's events after a + fixed 50 ms sleep** — "actual PTY launcher carries placeholder styling into + owned seed submission: xterm-256color" sends `/plan-eng-review\r`, sleeps + 50 ms and expects the `slash` event already in `events.jsonl`; under the + 16-worker duration recording on 2026-10-15 the event had not landed + (`['paste', 'enter', 'end_turn']`). Wait for the CLI's own write instead of a + timer (docs/TESTING_INTERNALS.md#flake-ledger). **Effort:** S. **Priority:** P2. +- **Split the free files the 2026-10-15 seed put over 60 s** — + `test/setup-install-registry.test.ts` (82 s), `test/host-renders-prune.test.ts` + (64 s) and `test/setup-codex-scope.test.ts` (60.4 s) are allowlisted with this + todo in `scripts/free-test-seed-allowlist.json`; `test/brain-sync.test.ts` + (57 s) and `test/setup-codex-scope-namespaces.test.ts` (57 s) are next. Split + each by describe block, rerun `bun run test:ubicloud --record-durations` and + delete the entries. **Effort:** S each. **Priority:** P2. diff --git a/VERSION b/VERSION index c658a42e6..852dfdc70 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.91.101.0 +1.91.105.0 diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md index e4c2e7105..2e819d448 100644 --- a/agents-digest/gstack-AGENTS.md +++ b/agents-digest/gstack-AGENTS.md @@ -1,4 +1,4 @@ -# gstack digest v1.91.101.0 — regenerate/re-copy after upgrading gstack +# gstack digest v1.91.105.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/bin/gstack-timeline-read b/bin/gstack-timeline-read index e1edb9179..9a3133136 100755 --- a/bin/gstack-timeline-read +++ b/bin/gstack-timeline-read @@ -1,26 +1,78 @@ #!/usr/bin/env bash # gstack-timeline-read — read and format project timeline -# Usage: gstack-timeline-read [--since "7 days ago"] [--limit N] [--branch NAME] +# Usage: gstack-timeline-read [--since "7 days ago"|7d|YYYY-MM-DD] [--limit N] [--branch NAME] # # Session timeline: local-only, never sent anywhere. # Reads ~/.gstack/projects/$SLUG/timeline.jsonl, filters, formats. # Exit 0 silently if no timeline file exists or nothing matches. Missing bun # exits 127 and a failed read exits non-zero with its stderr (#2790). A missing -# or non-positive-integer --limit exits 2 before any read (#1723). +# or non-positive-integer --limit, a missing or unparseable --since, a missing +# --branch, or an unknown argument exits 2 before any read (#1723); --help +# prints the usage line and exits 0. set -euo pipefail +USAGE='Usage: gstack-timeline-read [--since "7 days ago"|7d|YYYY-MM-DD] [--limit N] [--branch NAME]' +SINCE_FORMS='accepted: " minute|hour|day|week|month[s] ago", "h|d|w", or an ISO date YYYY-MM-DD or YYYY-MM-DDTHH:MM:SSZ' SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" eval "$("$SCRIPT_DIR/gstack-slug" 2>/dev/null)" . "$(dirname "$0")/gstack-state-root.sh" 2>/dev/null || { echo "$0: cannot resolve the gstack state root: $(dirname "$0")/gstack-state-root.sh is missing. fix: reinstall with ./setup or /gstack-upgrade (docs/state-root.md)" >&2; exit 1; } gstack_state_root_select GSTACK_HOME="$_gstack_sr_root" -SINCE="" +SINCE_MS=0 LIMIT=20 BRANCH="" +missing_value() { # remaining-arg-count next-arg -> why the flag has no usable value, or nothing + if [[ $1 -lt 2 ]]; then echo "got no value" + elif [[ -z "$2" ]]; then echo "got an empty value" + elif [[ "$2" == --* ]]; then echo "got flag '$2'" + fi + return 0 +} + +days_from_civil() { # year month day (UTC) -> days since 1970-01-01 + local y=$((10#$1)) m=$((10#$2)) d=$((10#$3)) + [[ $m -le 2 ]] && y=$((y - 1)) + local era=$((y / 400)) yoe doy mp + yoe=$((y - era * 400)); mp=$(((m + 9) % 12)); doy=$(((153 * mp + 2) / 5 + d - 1)) + echo $((era * 146097 + yoe * 365 + yoe / 4 - yoe / 100 + doy - 719468)) +} + +since_cutoff_ms() { # one --since value -> cutoff epoch ms, or nothing when unparseable + local now n unit seconds lower + now=$(date -u +%s) + lower=$(printf '%s' "$1" | tr '[:upper:]' '[:lower:]') + if [[ "$lower" =~ ^([1-9][0-9]{0,5})[[:space:]]*(minute|hour|day|week|month)s?[[:space:]]+ago$ ]]; then + n=${BASH_REMATCH[1]}; unit=${BASH_REMATCH[2]} + elif [[ "$lower" =~ ^([1-9][0-9]{0,5})([hdw])$ ]]; then + n=${BASH_REMATCH[1]} + case ${BASH_REMATCH[2]} in h) unit=hour ;; d) unit=day ;; w) unit=week ;; esac + elif [[ "$1" =~ ^([0-9]{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])Z)?$ ]]; then + seconds=$(( $(days_from_civil "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}") * 86400 )) + [[ -n "${BASH_REMATCH[4]}" ]] && seconds=$((seconds + 10#${BASH_REMATCH[5]} * 3600 + 10#${BASH_REMATCH[6]} * 60 + 10#${BASH_REMATCH[7]})) + echo $((seconds * 1000)); return 0 + else + return 0 + fi + case $unit in minute) seconds=60 ;; hour) seconds=3600 ;; day) seconds=86400 ;; week) seconds=604800 ;; month) seconds=2592000 ;; esac + echo $(((now - n * seconds) * 1000)) +} + while [[ $# -gt 0 ]]; do case "$1" in - --since) SINCE="$2"; shift 2 ;; + --help|-h) echo "$USAGE"; exit 0 ;; + --since) + problem=$(missing_value $# "${2-}") + if [[ -n "$problem" ]]; then + echo "gstack-timeline-read: --since must be a relative time like \"7 days ago\" ($problem); $SINCE_FORMS" >&2 + exit 2 + fi + SINCE_MS=$(since_cutoff_ms "$2") + if [[ -z "$SINCE_MS" ]]; then + echo "gstack-timeline-read: --since must be a relative time like \"7 days ago\" (got '$2'); $SINCE_FORMS" >&2 + exit 2 + fi + shift 2 ;; --limit) if [[ $# -lt 2 ]]; then echo "gstack-timeline-read: --limit must be a positive integer (got no value); example: --limit 20" >&2 @@ -31,8 +83,17 @@ while [[ $# -gt 0 ]]; do exit 2 fi LIMIT="$2"; shift 2 ;; - --branch) BRANCH="$2"; shift 2 ;; - *) shift ;; + --branch) + problem=$(missing_value $# "${2-}") + if [[ -n "$problem" ]]; then + echo "gstack-timeline-read: --branch must be a branch name ($problem)" >&2 + exit 2 + fi + BRANCH="$2"; shift 2 ;; + *) + echo "gstack-timeline-read: unknown argument '$1'" >&2 + echo "$USAGE" >&2 + exit 2 ;; esac done @@ -47,23 +108,11 @@ command -v bun >/dev/null 2>&1 || { exit 127 } -cat "$TIMELINE_FILE" | GSTACK_TIMELINE_SINCE="$SINCE" GSTACK_TIMELINE_BRANCH="$BRANCH" GSTACK_TIMELINE_LIMIT="$LIMIT" bun -e " +cat "$TIMELINE_FILE" | GSTACK_TIMELINE_SINCE_MS="$SINCE_MS" GSTACK_TIMELINE_BRANCH="$BRANCH" GSTACK_TIMELINE_LIMIT="$LIMIT" bun -e " const lines = (await Bun.stdin.text()).trim().split('\n').filter(Boolean); -const since = process.env.GSTACK_TIMELINE_SINCE || ''; const branch = process.env.GSTACK_TIMELINE_BRANCH || ''; const limit = Number(process.env.GSTACK_TIMELINE_LIMIT); - -let sinceMs = 0; -if (since) { - // Parse relative time like '7 days ago' - const match = since.match(/(\d+)\s*(day|hour|minute|week|month)s?\s*ago/i); - if (match) { - const n = parseInt(match[1]); - const unit = match[2].toLowerCase(); - const ms = { minute: 60000, hour: 3600000, day: 86400000, week: 604800000, month: 2592000000 }; - sinceMs = Date.now() - n * (ms[unit] || 86400000); - } -} +const sinceMs = Number(process.env.GSTACK_TIMELINE_SINCE_MS); const entries = []; for (const line of lines) { diff --git a/browse/test/terminal-agent-publication-lock.test.ts b/browse/test/terminal-agent-publication-lock.test.ts index a745cf25d..0bbf5d801 100644 --- a/browse/test/terminal-agent-publication-lock.test.ts +++ b/browse/test/terminal-agent-publication-lock.test.ts @@ -6,7 +6,8 @@ import { spawnSync } from 'node:child_process'; import { acquireAgentStateLock, agentRecordPath, readAgentStartTime, writeAgentRecord, type AgentRecord } from '../src/terminal-agent-control'; const roots: string[] = []; -const children: ReturnType[] = []; +const children: Bun.Subprocess[] = []; +let unfinished: (() => Promise) | undefined; const directory = () => { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'publication-lock-')); roots.push(root); @@ -31,6 +32,8 @@ async function fixture(dead = true) { } afterEach(async () => { + if (unfinished) console.error((await unfinished()).message); + unfinished = undefined; for (const child of children.splice(0)) { if (child.exitCode === null) try { child.kill('SIGKILL'); } catch {} await child.exited; @@ -51,25 +54,36 @@ describe('owned terminal-agent publication lock recovery', () => { test.skipIf(process.platform !== 'linux')('a dead zombie with the exact recorded birth cannot retain its publication lock', async () => { const root = directory(); - const ready = path.join(root, 'zombie-pid'); const python = [ 'import os,time', 'pid=os.fork()', 'if pid==0: os._exit(0)', - `with open(${JSON.stringify(ready)},'w') as f: f.write(str(pid))`, + 'os.waitid(os.P_PID,pid,os.WEXITED|os.WNOWAIT)', + 'print(pid,flush=True)', 'time.sleep(30)', ].join('\n'); - const parent = Bun.spawn(['python3', '-c', python], { stdio: ['ignore', 'ignore', 'ignore'] }); + const parent = Bun.spawn(['python3', '-c', python], { stdio: ['ignore', 'pipe', 'pipe'] }); children.push(parent); - for (let n = 0; n < 300 && !fs.existsSync(ready); n++) await Bun.sleep(10); - expect(fs.existsSync(ready)).toBe(true); - const pid = Number(fs.readFileSync(ready, 'utf8')); - let state = ''; - for (let n = 0; n < 300; n++) { - state = fs.readFileSync(`/proc/${pid}/stat`, 'utf8').match(/^\d+ \(.*\) ([A-Z])/u)?.[1] || ''; - if (state === 'Z') break; - await Bun.sleep(10); + const failure = async (reason: string) => { + if (parent.exitCode === null) parent.kill('SIGKILL'); + const status = await parent.exited; + const stderr = await new Response(parent.stderr).text(); + return new Error(`${reason}; zombie parent exit status ${status}; stderr tail: ${stderr.slice(-500) || '(empty)'}`); + }; + unfinished = () => failure('zombie parent never reported its exited child'); + const reader = parent.stdout.getReader(); + let line = ''; + while (!line.includes('\n')) { + const chunk = await reader.read(); + if (chunk.done) throw await failure(`zombie parent closed stdout before a full PID line (got ${JSON.stringify(line)})`); + line += new TextDecoder().decode(chunk.value); } + reader.releaseLock(); + unfinished = undefined; + const reported = line.slice(0, line.indexOf('\n')); + if (!/^[1-9]\d*$/.test(reported)) throw await failure(`zombie parent reported a malformed PID ${JSON.stringify(reported)}`); + const pid = Number(reported); + const state = fs.readFileSync(`/proc/${pid}/stat`, 'utf8').match(/^\d+ \(.*\) ([A-Z])/u)?.[1] || ''; expect(state).toBe('Z'); expect(() => process.kill(pid, 0)).not.toThrow(); const record: AgentRecord = { pid, gen: 'zombie-generation', startedAt: Date.now(), diff --git a/docs/TESTING_INTERNALS.md b/docs/TESTING_INTERNALS.md index ea4f9e105..6bf03294b 100644 --- a/docs/TESTING_INTERNALS.md +++ b/docs/TESTING_INTERNALS.md @@ -1133,15 +1133,44 @@ Free-suite flake rules: daemon without `CI=true` launches Chromium sandboxed. - Handshakes with a runner wait for the runner's own observable effect (its progress line, a coalesced read count), not for a fixture side file or a timer. +- Fixtures that commit and then list, watch or remove a repository's `.git` + turn git auto-maintenance off themselves (`maintenance.auto=false` and + `gc.auto=0` in the repo config, or in the explicit git env they build). Since + git 2.29, `git commit` starts a detached `git maintenance run --auto` that + creates and deletes `.git/objects/maintenance.lock` after the commit has + returned; a listing counts it, a watcher's `lstat` misses it, and Bun's + `rmSync(..., { recursive: true, force: true })` returns without an error while + leaving the directory behind. `runFreeShard` appends the same two keys to + every shard child's `GIT_CONFIG_*` pairs as a backstop, so it covers fixtures + that inherit the environment, and `bun run scripts/ship-measure.ts free + --backend local` measures with that environment; a fixture with its own + replacement env never sees the backstop. + +To reproduce a ledger entry, take the shard's exact file list from the CI run's +`free-plan` artifact, then rerun it with the flaky retry off on a CI-mirrored VM: + +```bash +gh run download -R garrytan/gstack -n free-plan -D /tmp/free-plan +files=$(jq -r --argjson s '.shards[] | select(.shard == $s) | .files | join(",")' /tmp/free-plan/free-plan.json) +bun run test:ubicloud --diagnostic --files "$files" --reruns 30 +``` + +The ledger entry names the shard (`flake-ledger-`). Read the counts from +the run's `free-measurement.json` (`completed`, `passed`, `capHit`): with a +before-fix failure rate p, a fix needs at least 3/p clean completed reruns of +the same command, so zero failures would have under a 5% chance if nothing had +changed. Cut or unstarted reruns are incomplete, not passes. ### Free suite duration seed `scripts/free-test-durations.json` drives shard packing; files missing from it -pack at the seed's 99th percentile. Acceptable seeds come from +pack at the seed's 99th percentile. Acceptable seeds come only from `bun run test:ubicloud --record-durations` (each file timed in its own child on a -VM with the CI lane's environment) or a CI recording. A 4-core laptop or -small-sandbox recording is not acceptable: browser and display tests skip or slow -down there, so the seed misstates them. +VM with the CI lane's environment; it needs `UBICLOUD_API_KEY` and copies the +refreshed seed back into the checkout). A 4-core laptop or small-sandbox +recording is not acceptable: browser and display tests skip or slow down there, +so the seed misstates them. Contributors without `UBICLOUD_API_KEY` leave the +refresh to a maintainer. - `--ci-plan` warns in the job summary, with the refresh command, when more than 5 files are unseeded; it never fails a PR. `--ci-verify` lists shards that ran diff --git a/docs/test-audit-2026-10.md b/docs/test-audit-2026-10.md index 80e0d3445..f1a4ba51e 100644 --- a/docs/test-audit-2026-10.md +++ b/docs/test-audit-2026-10.md @@ -274,3 +274,34 @@ The 4 remaining shouting pins are enum or marker tokens (`PLAN MODE EXCEPTION ALWAYS RUN`, `[CRITICAL]`, `ALWAYS-ON` CLI output), not emphasis. Most remaining sentence pins sit in QA caller, detector-helper and workflow files that other work in flight owns. + +## Post-merge follow-up (2026-10-15) + +The "post-merge audit metrics" TODO, from a no-spend run of +`bun run test:health --since-days 7` (window 2026-10-08T22:14Z to +2026-10-15T22:14Z). The 2026-10-12 figures are the weekly health run in issue +#3154 (run 38234556073), kept as dated history. + +| Metric | 2026-10-12 | 2026-10-15 | Target | Verdict | +|---|---:|---:|---|---| +| PR full-fallback rate | 45.0% (58/129 runs) | 45.9% (39/85 runs) | none numeric; the replay above names the cause | open: branches touching `bin/`, `lib/`, `hosts/` or `make-pdf/` still select every case | +| Recorded PR-lane spend per merged PR | $75.09 (46 merged) | $73.52 (33 merged) | down at least 50% from the pre-change baseline | unavailable: baseline not recorded (below) | +| Cancelled slice-minutes per week | 1,939 (44 runs) | 1,545 (33 runs) | none numeric | reported | +| PR push-to-verdict | p50 12.0 min, p95 1,160.7 min (122 runs) | p50 11.4 min, p95 107.9 min (80 runs) | 3–5 minutes for typical PR checks (CONTRIBUTING.md) | missed | +| Free-suite flaky-pass rate | 13.0% (6/46 main runs) | 6.1% (2/33 main runs; `terminal-agent-publication-lock` 2/33, over the 5% per-file check) | under 5% of main runs | missed; fix wave 2 repairs the five ledger files | + +**Spend baseline.** The pre-change window was recomputed with the exported +`collectHealth` at `now = 2026-10-04T00:00Z`, seven days, through a client that +drops runs created and PRs merged after that instant (`listWorkflowRuns` has no +upper bound of its own). The window holds 12 merged PRs but no +`trial-outcomes-pr-*` artifacts and no paid-plan manifest with `prCoverage`: +the recorder that feeds this metric shipped with the audit, so the PR lanes +before it wrote nothing it can read (their other artifacts are retained until +2026-11-02 and later). Baseline not recorded; verdict unavailable. The P1 in +TODOS.md is opened on the absolute figures. + +**Census reliability (not yet due).** Due after the fourth scheduled census +after the audit merge (2026-10-26). Interim: periodic 2.00 expected failed +trials per run (6/538 over 3 runs; target at most 1.0), gate census 0.33 (1/308 +over 3 runs; target at most 0.5). The TODO keeps its due date; the census +repair stays with #3153 and #3200. diff --git a/package.json b/package.json index 25d95c6d1..440c2a6c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gstack", - "version": "1.91.101", + "version": "1.91.105", "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 8f9c6cd90..5be4284f9 100644 --- a/scripts/free-test-durations.json +++ b/scripts/free-test-durations.json @@ -1,1061 +1,1225 @@ { "version": 1, - "recordedAt": "2026-10-04T19:16:06.359Z", + "recordedAt": "2026-10-15T23:37:39.698Z", "durations": { - "browse/test/activity.test.ts": 79, - "browse/test/adversarial-security.test.ts": 37, - "browse/test/batch.test.ts": 1702, - "browse/test/bridge-chromium-e2e.test.ts": 772, - "browse/test/browse-client.test.ts": 87, - "browse/test/browse-eval-wrapping.test.ts": 76, - "browse/test/browser-manager-custom-chromium.test.ts": 306, - "browse/test/browser-manager-unit.test.ts": 477, - "browse/test/browser-skill-commands.test.ts": 1200, - "browse/test/browser-skill-write.test.ts": 68, - "browse/test/browser-skills-e2e.test.ts": 86, - "browse/test/browser-skills-storage.test.ts": 44, - "browse/test/build-command-response.test.ts": 392, - "browse/test/build.test.ts": 109, + "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": 15828, - "browse/test/busy-daemon-recovery.test.ts": 626, - "browse/test/cdp-allowlist.test.ts": 32, - "browse/test/cdp-e2e.test.ts": 567, - "browse/test/cdp-inspector-history-cap.test.ts": 29, - "browse/test/cdp-mutex.test.ts": 689, - "browse/test/cdp-session-cleanup.test.ts": 41, - "browse/test/chromium-profile-isolation.test.ts": 12612, - "browse/test/claude-bin.test.ts": 25, + "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/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": 101, - "browse/test/cli-setsid-daemonize.test.ts": 19, - "browse/test/cli-start-final-healthcheck.test.ts": 25, - "browse/test/cli-supervisor.test.ts": 34, - "browse/test/commands.test.ts": 31223, - "browse/test/compare-board.test.ts": 1013, - "browse/test/config.test.ts": 152, - "browse/test/content-security.test.ts": 777, - "browse/test/cookie-auth-verification.test.ts": 7544, - "browse/test/cookie-credential-deadline.test.ts": 350, - "browse/test/cookie-database.test.ts": 376, - "browse/test/cookie-fixture-delete-lease.test.ts": 58, - "browse/test/cookie-import-browser.test.ts": 115, - "browse/test/cookie-import-native-job.test.ts": 658, - "browse/test/cookie-import-native.test.ts": 3952, - "browse/test/cookie-import-node.test.ts": 337, - "browse/test/cookie-import-operation.test.ts": 1254, - "browse/test/cookie-import-reliability.test.ts": 1842, - "browse/test/cookie-import-transport.test.ts": 24, - "browse/test/cookie-picker-binding-browser.test.ts": 2309, - "browse/test/cookie-picker-binding.test.ts": 299, - "browse/test/cookie-picker-csrf-browser.test.ts": 569, - "browse/test/cookie-picker-routes.test.ts": 352, - "browse/test/cookie-picker-ui.test.ts": 10753, - "browse/test/daemon-log-hygiene.test.ts": 68, - "browse/test/daemon-mismatch-refuse.test.ts": 159, - "browse/test/data-platform.test.ts": 29, - "browse/test/dia-gui-readiness.test.ts": 650, - "browse/test/dia-launch-comparison.test.ts": 2802, - "browse/test/dia-macos-qualification.test.ts": 2944, - "browse/test/domain-skills-e2e.test.ts": 540, - "browse/test/domain-skills-storage.test.ts": 206, - "browse/test/dotenv-isolation.test.ts": 406, - "browse/test/dual-listener.test.ts": 397, + "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": 16, - "browse/test/extension-sender-auth.test.ts": 48, - "browse/test/extension-token.test.ts": 380, - "browse/test/file-drop.test.ts": 32, - "browse/test/file-permissions.test.ts": 38, - "browse/test/fill-change-event.test.ts": 1647, - "browse/test/find-browse.test.ts": 28, - "browse/test/findport.test.ts": 422, - "browse/test/from-file-path-validation.test.ts": 21, - "browse/test/gstack-config.test.ts": 1077, - "browse/test/gstack-update-check.test.ts": 3418, - "browse/test/handoff.test.ts": 8614, - "browse/test/headless-gpu-and-reap.test.ts": 785, - "browse/test/headless-launch-options.test.ts": 1836, - "browse/test/launch-signal-flags.test.ts": 15, - "browse/test/learnings-injection.test.ts": 86, - "browse/test/media-extract-unit.test.ts": 18, - "browse/test/memory-command.test.ts": 298, - "browse/test/memory-leak-reproducer.test.ts": 365, - "browse/test/navigation-guard.test.ts": 14581, - "browse/test/output-path-symlinks.test.ts": 68, - "browse/test/pair-agent-e2e.test.ts": 1923, - "browse/test/pair-agent-optin-gate.test.ts": 358, - "browse/test/pair-agent-tunnel-eval.test.ts": 7757, - "browse/test/path-validation.test.ts": 2020, - "browse/test/pdf-flags.test.ts": 51, - "browse/test/platform.test.ts": 28, - "browse/test/playwright-core-patch.test.ts": 34, - "browse/test/poisoned-bundle-probe.test.ts": 308, - "browse/test/process-liveness-windows.test.ts": 115, - "browse/test/proxy-config.test.ts": 28, - "browse/test/proxy-redact.test.ts": 14, - "browse/test/pty-inject-scan.test.ts": 642, - "browse/test/pty-session-lease.test.ts": 39, + "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/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": 38, - "browse/test/restart-env.test.ts": 22, - "browse/test/sanitize.test.ts": 16, - "browse/test/screenshot-size-guard.test.ts": 261, - "browse/test/security-adversarial-fixes.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/security-adversarial-fixes.test.ts": 16, "browse/test/security-adversarial.test.ts": 18, - "browse/test/security-audit-r2.test.ts": 328, - "browse/test/security-bench.test.ts": 14, - "browse/test/security-classifier-download-cleanup.test.ts": 27, - "browse/test/security-classifier.test.ts": 26, - "browse/test/security-integration.test.ts": 23, - "browse/test/security-live-playwright.test.ts": 665, - "browse/test/security-sidecar-client.test.ts": 25, - "browse/test/security.test.ts": 23, - "browse/test/server-auth.test.ts": 394, - "browse/test/server-embedder-terminal-port.test.ts": 4056, - "browse/test/server-factory.test.ts": 1016, - "browse/test/server-flush-trackers.test.ts": 32, + "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-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": 23, - "browse/test/server-no-import-side-effects.test.ts": 566, - "browse/test/server-proxy-fail-fast.test.ts": 1378, - "browse/test/server-pty-lease-routes.test.ts": 297, - "browse/test/server-route-auth-blackbox.test.ts": 353, - "browse/test/server-route-dispatch-ratchet.test.ts": 309, - "browse/test/server-route-table.test.ts": 366, - "browse/test/server-sanitize-surrogates.test.ts": 335, - "browse/test/server-tmp-state-path.test.ts": 24, - "browse/test/session-cookie-store.test.ts": 44, - "browse/test/session-persist.test.ts": 680, - "browse/test/sidebar-tabs.test.ts": 347, - "browse/test/sidebar-ux.test.ts": 307, - "browse/test/sidepanel-patient-autoconnect.test.ts": 26, - "browse/test/sidepanel-reattach.test.ts": 19, - "browse/test/sidepanel-restart-dispose.test.ts": 20, - "browse/test/skill-token.test.ts": 29, - "browse/test/snapshot.test.ts": 7930, - "browse/test/socks-bridge.test.ts": 542, - "browse/test/sse-helpers.test.ts": 155, - "browse/test/sse-session-cookie.test.ts": 19, - "browse/test/state-ttl.test.ts": 17, - "browse/test/stealth-extended.test.ts": 10, - "browse/test/stealth-layer-c.test.ts": 15, - "browse/test/stealth-webdriver.test.ts": 1674, - "browse/test/stop-ack-before-shutdown.test.ts": 142, - "browse/test/stop-dead-daemon.test.ts": 225, - "browse/test/tab-each.test.ts": 38, - "browse/test/tab-guardrail.test.ts": 316, - "browse/test/tab-isolation.test.ts": 265, - "browse/test/tab-session-frame-detach.test.ts": 15, - "browse/test/telemetry-optout.test.ts": 89, - "browse/test/telemetry.test.ts": 34, - "browse/test/temp-dirs.test.ts": 60, - "browse/test/terminal-agent-detach-reattach.test.ts": 24, - "browse/test/terminal-agent-import.test.ts": 4388, - "browse/test/terminal-agent-integration.test.ts": 812, - "browse/test/terminal-agent-keepalive.test.ts": 17, - "browse/test/terminal-agent-lifecycle.test.ts": 4633, - "browse/test/terminal-agent-native-observation.test.ts": 21, - "browse/test/terminal-agent-owner-watchdog.test.ts": 119, - "browse/test/terminal-agent-pid-identity.test.ts": 32, - "browse/test/terminal-agent-port-range.test.ts": 33, - "browse/test/terminal-agent-publication-lock.test.ts": 1571, - "browse/test/terminal-agent-ring-buffer-runtime.test.ts": 39, - "browse/test/terminal-agent-session-routing.test.ts": 18, - "browse/test/terminal-agent-watchdog.test.ts": 17, - "browse/test/terminal-agent.test.ts": 283, - "browse/test/terminal-pty-lifecycle.test.ts": 12, - "browse/test/token-registry.test.ts": 31, - "browse/test/tunnel-gate-unit.test.ts": 275, - "browse/test/tunnel-revoke-cli.test.ts": 1086, - "browse/test/url-validation.test.ts": 114, - "browse/test/watch.test.ts": 320, - "browse/test/watchdog.test.ts": 2372, - "browse/test/welcome-page.test.ts": 20, - "browse/test/windows-spawn-hide.test.ts": 31, - "browse/test/xprotect-heal.test.ts": 763, - "browse/test/xvfb.test.ts": 16850, - "browser-skills/hackernews-frontpage/script.test.ts": 19, - "design/test/approval.test.ts": 51, - "design/test/auth.test.ts": 17, + "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/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/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/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": 6855, - "design/test/cli-version.test.ts": 38, - "design/test/daemon-discovery.test.ts": 11745, - "design/test/daemon.test.ts": 157, - "design/test/feedback-roundtrip-daemon.test.ts": 404, - "design/test/feedback-roundtrip.test.ts": 2871, - "design/test/gallery.test.ts": 19, - "design/test/image-args.test.ts": 40, - "design/test/image-gen-pairing.test.ts": 14, - "design/test/models.test.ts": 51, - "design/test/persist.test.ts": 53, + "design/test/cli-persistence.test.ts": 6612, + "design/test/cli-version.test.ts": 31, + "design/test/daemon-discovery.test.ts": 11317, + "design/test/daemon.test.ts": 154, + "design/test/feedback-roundtrip-daemon.test.ts": 339, + "design/test/feedback-roundtrip.test.ts": 3020, + "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": 178, - "design/test/variants-briefs.test.ts": 3675, - "design/test/variants-retry-after.test.ts": 8224, - "ios-qa/daemon/test/allowlist.test.ts": 19, - "ios-qa/daemon/test/audit.test.ts": 20, - "ios-qa/daemon/test/auth-mint.test.ts": 25, - "ios-qa/daemon/test/cli-mint.test.ts": 212, - "ios-qa/daemon/test/daemon-integration.test.ts": 388, - "ios-qa/daemon/test/proxy-classify.test.ts": 29, - "ios-qa/daemon/test/proxy-transport.test.ts": 1817, - "ios-qa/daemon/test/session-tokens.test.ts": 16, - "ios-qa/daemon/test/single-instance.test.ts": 18, - "ios-qa/daemon/test/tailscale-localapi.test.ts": 30, - "ios-qa/daemon/test/tunnel-bootstrap.test.ts": 405, - "ios-qa/scripts/gen-accessors.test.ts": 54, - "make-pdf/test/asideClient.test.ts": 20, - "make-pdf/test/cli-args.test.ts": 14, - "make-pdf/test/cli-exit-codes.test.ts": 353, - "make-pdf/test/diagram-prepass.test.ts": 69, - "make-pdf/test/e2e/ci-prereqs.test.ts": 24, - "make-pdf/test/e2e/combined-gate.test.ts": 869, - "make-pdf/test/e2e/diagram-gate.test.ts": 2774, - "make-pdf/test/e2e/emoji-gate.test.ts": 975, - "make-pdf/test/e2e/format-gate.test.ts": 5010, - "make-pdf/test/e2e/landscape-gate.test.ts": 3557, - "make-pdf/test/e2e/toc-gate.test.ts": 6090, - "make-pdf/test/image-policy.test.ts": 11, + "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, + "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": 42, - "make-pdf/test/setup-smoke.test.ts": 144, - "make-pdf/test/toc-anchors.test.ts": 29, - "make-pdf/test/toc-pages.test.ts": 39, - "test/agent-sdk-runner.test.ts": 8240, - "test/agents-digest.test.ts": 23, - "test/analytics.test.ts": 20, - "test/anthropic-preflight.test.ts": 12, - "test/archaeology-lint.test.ts": 1549, - "test/arm-benchmark-selftest.test.ts": 346, - "test/arm-setup-smoke-workflow.test.ts": 24, - "test/artifacts-allowlist-decisions.test.ts": 16, - "test/artifacts-init-migration.test.ts": 301, - "test/aside-driver.test.ts": 212, - "test/aside-probe-shell.test.ts": 9611, - "test/aside-render.test.ts": 10146, - "test/audit-compliance.test.ts": 25, - "test/auq-error-fallback-hook.test.ts": 165, - "test/auq-format-always-loaded.test.ts": 38, - "test/auq-mode-capture.test.ts": 123, - "test/auq-native-capture.test.ts": 2618, - "test/auq-parallel.test.ts": 12753, - "test/auto-decide-fixture.test.ts": 3039, - "test/autoplan-amend-input.test.ts": 1241, - "test/autoplan-artifact-recorder.test.ts": 5811, - "test/autoplan-artifact-windows-argv.test.ts": 88, - "test/autoplan-dual-voice-evidence.test.ts": 1237, - "test/autoplan-dual-voice-fixture.test.ts": 2799, - "test/autoplan-edit-digests-al.test.ts": 234, - "test/autoplan-init.test.ts": 802, - "test/autoplan-method-read-audit.test.ts": 245, - "test/autoplan-methodology-names.test.ts": 871, - "test/autoplan-obligations.test.ts": 2547, - "test/autoplan-owned-state.test.ts": 1551, - "test/autoplan-pending-artifact.test.ts": 911, - "test/autoplan-pending-question.test.ts": 4243, - "test/autoplan-phase-handoff.test.ts": 184, - "test/autoplan-phase-observer.test.ts": 112, - "test/autoplan-phase-order.test.ts": 67, - "test/autoplan-preconfigured-onboarding-ar.test.ts": 765, - "test/autoplan-public-narration.test.ts": 46, - "test/autoplan-publication-generation.test.ts": 32, - "test/autoplan-publication-guard.test.ts": 2028, - "test/autoplan-publication-hook.test.ts": 6492, - "test/autoplan-review-discovery.test.ts": 10172, - "test/autoplan-snapshot.test.ts": 1850, - "test/benchmark-cli.test.ts": 544, - "test/benchmark-runner.test.ts": 31, - "test/bin-context-windows-slug.test.ts": 1639, - "test/bin-windows-bun-import-paths.test.ts": 820, - "test/binding-template-drift.test.ts": 44, - "test/bootstrap-retention-shard.test.ts": 2379, - "test/bootstrap-retention.test.ts": 12525, - "test/bootstrap-session-lifecycle.test.ts": 5099, - "test/brain-cache-roundtrip.test.ts": 68, - "test/brain-cache-spec.test.ts": 22, - "test/brain-preflight.test.ts": 29, - "test/brain-sync-windows-paths.test.ts": 14, - "test/brain-sync.test.ts": 26459, - "test/branch-slug-hygiene.test.ts": 466, - "test/build-gbrain-env.test.ts": 76, - "test/build-script-shell-compat.test.ts": 15, - "test/builder-profile.test.ts": 3493, - "test/bun-subprocess-fd-lifetime.test.ts": 57, - "test/bun-version-drift.test.ts": 19, - "test/cache-concurrent-refresh.test.ts": 80, - "test/carve-guard-completeness.test.ts": 26, - "test/carve-guards-negative.test.ts": 27, - "test/carve-plan-fixture.test.ts": 572, - "test/carve-section-ordering.test.ts": 54, - "test/carve-section-sharding.test.ts": 1521, - "test/catalog-budget.test.ts": 40, - "test/catalog-mode-full.test.ts": 1152, - "test/catalog-trim.test.ts": 44, - "test/ceo-barless-submit.test.ts": 111, - "test/ceo-count-ad-v2.test.ts": 113, - "test/ceo-expansion-auq.test.ts": 106, - "test/ceo-expansion-pacing-native.test.ts": 58, - "test/ceo-finding-fixture.test.ts": 890, - "test/ceo-hold-posture-review.test.ts": 138, - "test/ceo-mode-expansion-disposition.test.ts": 73, - "test/ceo-mode-handoff.test.ts": 109, - "test/ceo-mode-labels-native.test.ts": 71, - "test/ceo-mode-option.test.ts": 1633, + "make-pdf/test/render.test.ts": 38, + "make-pdf/test/setup-smoke.test.ts": 91, + "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, + "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/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/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/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/ceo-mode-posture-native.test.ts": 52, - "test/ceo-mode-preference-al.test.ts": 1809, - "test/ceo-mode-prerequisite.test.ts": 1092, - "test/ceo-mode-routing-fixture.test.ts": 863, - "test/ceo-plan-mode-fixture.test.ts": 833, - "test/ceo-posture-packet.test.ts": 305, - "test/ceo-section-loading-fixture.test.ts": 329, - "test/ceo-split-collection.test.ts": 551, - "test/ceo-split-question-policy.test.ts": 487, - "test/ceo-stale-fill-decision.test.ts": 88, - "test/ceo-workflow-clarity.test.ts": 43, - "test/changed-files-union.test.ts": 377, - "test/chromium-sandbox-ci.test.ts": 159, - "test/ci-eval-cache.test.ts": 26, - "test/ci-image-cli-pin.test.ts": 39, - "test/ci-image-tag-binding.test.ts": 18, - "test/ci-native-evidence.test.ts": 653, - "test/ci-paid-coordination.test.ts": 5397, - "test/claude-code-migration.test.ts": 82, - "test/claude-code-runner.test.ts": 3023, - "test/claude-code-skill.test.ts": 1395, - "test/claude-code-windows-job.test.ts": 49, - "test/claude-md-size.test.ts": 18, - "test/claude-overlay-models.test.ts": 37, - "test/claude-overlay-setup-default.test.ts": 28091, - "test/claude-overlay-setup-installs.test.ts": 40548, - "test/claude-overlay-setup-lifecycle.test.ts": 44959, - "test/claude-provider-keychain.test.ts": 88, - "test/code-intelligence-cli.test.ts": 719, - "test/code-intelligence.test.ts": 4382, - "test/codex-boundary-evidence.test.ts": 12, - "test/codex-carve-fixture.test.ts": 781, - "test/codex-ci-access.test.ts": 239, - "test/codex-eval-recording.test.ts": 311, - "test/codex-generation-model.test.ts": 129, - "test/codex-hardening.test.ts": 10053, - "test/codex-invocation-sites.test.ts": 320, - "test/codex-model-probe.test.ts": 2328, - "test/codex-resume-flag-semantics.test.ts": 14, - "test/codex-session-lifecycle.test.ts": 12051, - "test/codex-skill-isolation.test.ts": 144, - "test/codex-under-codex-detection.test.ts": 36, - "test/codex-web-search-flag.test.ts": 252, - "test/conductor-env-shim.test.ts": 13, - "test/context-bill.test.ts": 93, - "test/context-budget-ratchet.test.ts": 103, - "test/context-identity.test.ts": 6836, - "test/context-remaining-work-provenance.test.ts": 14, - "test/context-save-hardening.test.ts": 377, - "test/cookie-workflow-judge-input.test.ts": 631, - "test/cookie-workflow-manual-review.test.ts": 75, - "test/coverage-audit-evidence.test.ts": 184, - "test/coverage-audit.test.ts": 1000, - "test/cso-bounded-file.test.ts": 26, - "test/cso-cache.test.ts": 279, - "test/cso-cli-lifecycle.test.ts": 5236, - "test/cso-cli-recheck.test.ts": 18369, - "test/cso-cli.test.ts": 30585, - "test/cso-contracts.test.ts": 261, - "test/cso-distribution.test.ts": 2283, - "test/cso-docker-integration.test.ts": 55, - "test/cso-docker-mounts.test.ts": 36, - "test/cso-docker-policy.test.ts": 28, - "test/cso-eval.test.ts": 2551, - "test/cso-git-hardening.test.ts": 595, - "test/cso-history.test.ts": 14, - "test/cso-image-provisioning.test.ts": 303, - "test/cso-launcher-generation.test.ts": 1741, - "test/cso-lease-identity.test.ts": 499, - "test/cso-macos-launcher.test.ts": 18, - "test/cso-node-lifecycle-integration.test.ts": 38, - "test/cso-ntfs-fixture.test.ts": 114, - "test/cso-postgresql-policy.test.ts": 26, - "test/cso-preparation-adversarial.test.ts": 108, - "test/cso-preparation-container.test.ts": 177, - "test/cso-preparation-executor.test.ts": 831, - "test/cso-preparation.test.ts": 138, - "test/cso-preserved.test.ts": 21, - "test/cso-public-ghcr.test.ts": 65, - "test/cso-python-runner-shadow.test.ts": 2469, - "test/cso-rails-verification.test.ts": 38, - "test/cso-registry-socket.test.ts": 2017, - "test/cso-runtime-promotion.test.ts": 34, - "test/cso-scanner-cli.test.ts": 7513, - "test/cso-scanner-docker-integration.test.ts": 37, - "test/cso-scanner-executor.test.ts": 140, - "test/cso-scanner-release.test.ts": 59, - "test/cso-scanners.test.ts": 63, - "test/cso-snapshot-disappearance-race.test.ts": 145, - "test/cso-snapshot-identity.test.ts": 460, - "test/cso-snapshot-state.test.ts": 3425, - "test/cso-spec-taxonomy-alignment.test.ts": 15, - "test/cso-stack-cold-integration.test.ts": 33, - "test/cso-verification-cleanup.test.ts": 1081, - "test/cso-verifier.test.ts": 22, - "test/cso-watchdog.test.ts": 7564, - "test/cso-windows-build-contract.test.ts": 22, - "test/cso-windows-launcher.test.ts": 22, - "test/cso-witness.test.ts": 1000, - "test/declared-annotation.test.ts": 20, - "test/dependency-security.test.ts": 59, - "test/deps-smoke.test.ts": 60, - "test/design-approval-flow.test.ts": 6295, - "test/design-board-reload.test.ts": 23, - "test/design-catalog.test.ts": 30, - "test/design-checklist-sync.test.ts": 717, - "test/design-completion-handoff-scored.test.ts": 38, - "test/design-consultation-command-contract.test.ts": 297, - "test/design-consultation-contract.test.ts": 28, - "test/design-daemon-windows-identity.test.ts": 51, - "test/design-detect-contract.test.ts": 108, - "test/design-detector-source-fixture.test.ts": 6955, - "test/design-doc-data-guard.test.ts": 16, - "test/design-flag-utils.test.ts": 31, - "test/design-html-section-completion.test.ts": 2867, - "test/design-md.test.ts": 543, - "test/design-printed-paths.test.ts": 91, - "test/design-research-fixture.test.ts": 18, - "test/design-setup-probe.test.ts": 11049, - "test/dev-setup-render-isolation.test.ts": 109, - "test/devex-finding-fixture.test.ts": 865, - "test/devex-peer-comparison-calibration.test.ts": 383, - "test/diagram-render-drift.test.ts": 313, - "test/diff-scope.test.ts": 2220, - "test/disabled-dated-record-at.test.ts": 76, - "test/disabled-plan-review-evidence.test.ts": 1172, - "test/discover-section-templates.test.ts": 21, - "test/distill-apply.test.ts": 1309, - "test/distill-free-text.test.ts": 1382, - "test/docs-config-keys.test.ts": 109, - "test/docsync-atomic-writes.test.ts": 1892, - "test/docsync-authority.test.ts": 413, - "test/docsync-child-marker.test.ts": 25, - "test/docsync-command-grammar.test.ts": 274, - "test/docsync-fault-interface.test.ts": 29390, - "test/docsync-lifecycle-interface.test.ts": 117, - "test/docsync-nested-writes.test.ts": 435, - "test/docsync-report-interface.test.ts": 395, - "test/document-skills-redaction.test.ts": 35, - "test/dom-dump-hygiene.test.ts": 718, - "test/dx-selected-navigation-ap.test.ts": 74, - "test/e2e-harness-audit.test.ts": 23, - "test/e2e-shard-reuse.test.ts": 2106, - "test/e2e-tier-alignment.test.ts": 121, - "test/egress-lib.test.ts": 376, - "test/egress-receipt-wiring.test.ts": 187, - "test/egress-receipt.test.ts": 5398, - "test/empty-find-fallthrough.test.ts": 267, - "test/eng-batching-current-ledger.test.ts": 241, + "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/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/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-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/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-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/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": 594, - "test/eng-count-question-policy.test.ts": 39, - "test/eng-devex-s-count.test.ts": 52, - "test/eng-finding-retry-budget.test.ts": 558, - "test/eng-first-review.test.ts": 231, - "test/eng-published-navigation.test.ts": 66, - "test/eng-resolution-block-position.test.ts": 250, - "test/eng-review-routing.test.ts": 27, - "test/eng-scope-entry-ap.test.ts": 76, - "test/eng-seeded-completion-ai.test.ts": 12154, - "test/eng-seeded-coverage.test.ts": 1489, - "test/eng-semantic-terminal.test.ts": 127, - "test/eng-test-plan-edit-approval.test.ts": 1021, - "test/env-host-fence-conformance.test.ts": 5625, - "test/eval-budgets-policy.test.ts": 45, - "test/eval-cli-family.test.ts": 1325, - "test/eval-detach-timeout-floor.test.ts": 1040, - "test/eval-flake-rank.test.ts": 211, - "test/eval-input-cache.test.ts": 67, - "test/eval-kinds.test.ts": 43, - "test/eval-list-cli.test.ts": 202, - "test/eval-model.test.ts": 11, - "test/evals-pr-lane-workflow.test.ts": 16, - "test/evals-workflow-wiring.test.ts": 216, - "test/evidence.test.ts": 7519, - "test/exit-propagation.test.ts": 350, - "test/explain-level-config.test.ts": 356, - "test/extension-pty-inject-invariant.test.ts": 17, - "test/external-host-carve.test.ts": 2013, - "test/flake-ledger.test.ts": 36, - "test/founder-resources-optout.test.ts": 123, - "test/free-fixtures.test.ts": 982, - "test/free-home-guard.test.ts": 82, - "test/free-seed-ratchet.test.ts": 87, - "test/free-tests-workflow-wiring.test.ts": 27, - "test/freeze-owned-lifecycle.test.ts": 3045, - "test/frontend-scope.test.ts": 1198, - "test/fs-atomic.test.ts": 26, - "test/fs-utils.test.ts": 227, - "test/gate-secret-scan.test.ts": 588, - "test/gate-tail-lint.test.ts": 1573, - "test/gbrain-cycle-completed.test.ts": 39, - "test/gbrain-detect-install.test.ts": 691, - "test/gbrain-detect-shape.test.ts": 443, - "test/gbrain-detection-override.test.ts": 928, - "test/gbrain-dream-stage.test.ts": 255, - "test/gbrain-exec-invariant.test.ts": 18, - "test/gbrain-guards.test.ts": 28, - "test/gbrain-init-voyage-code-3.test.ts": 164, - "test/gbrain-lib-validate-varname.test.ts": 59, - "test/gbrain-lib-verify.test.ts": 143, - "test/gbrain-local-status.test.ts": 3852, - "test/gbrain-prune-gone-worktrees.test.ts": 291, - "test/gbrain-read-capability.test.ts": 2074, - "test/gbrain-refresh-install-render.test.ts": 15, - "test/gbrain-repo-policy-client.test.ts": 822, - "test/gbrain-repo-policy.test.ts": 1369, - "test/gbrain-source-gitignore.test.ts": 25, - "test/gbrain-source-worktree-advance.test.ts": 664, - "test/gbrain-sources-parse.test.ts": 21, - "test/gbrain-sources.test.ts": 120, - "test/gbrain-spawn-windows-shell.test.ts": 22, - "test/gbrain-structured-busy.test.ts": 2231, - "test/gbrain-supabase-provision.test.ts": 142, - "test/gbrain-sync-skip.test.ts": 10653, - "test/gbrain-sync-voyage-code-3-integration.test.ts": 19, - "test/gen-skill-docs-checks.test.ts": 10271, - "test/gen-skill-docs-idempotency.test.ts": 2368, - "test/gen-skill-docs-import-purity.test.ts": 39, - "test/gen-skill-docs-out-dir.test.ts": 2089, - "test/gen-skill-docs-prune-stale.test.ts": 648, - "test/gen-skill-docs.test.ts": 5322, - "test/generated-docs-fences.test.ts": 199, - "test/generator-eexist.test.ts": 304, - "test/git-ref-fixture-tripwire.test.ts": 104, - "test/global-discover.test.ts": 267, + "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/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/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-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-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": 6071, - "test/gstack-artifacts-url.test.ts": 120, - "test/gstack-brain-context-load.test.ts": 1067, + "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/gstack-ci-gate.test.ts": 25, - "test/gstack-codex-session-import.test.ts": 651, - "test/gstack-config-browse-extension-id.test.ts": 299, - "test/gstack-config-cross-project.test.ts": 197, - "test/gstack-config-defaults.test.ts": 4668, - "test/gstack-config-gbrain-refresh.test.ts": 167, - "test/gstack-config-key-locale.test.ts": 136, - "test/gstack-config-memorable-key.test.ts": 388, - "test/gstack-config-redact-keys.test.ts": 187, - "test/gstack-config-transcript-scope.test.ts": 2581, - "test/gstack-context-recovery.test.ts": 113, - "test/gstack-decision-bins.test.ts": 5622, - "test/gstack-decision-semantic.test.ts": 39, - "test/gstack-decision.test.ts": 86, - "test/gstack-design-claim.test.ts": 673, - "test/gstack-design-detect-plugins.test.ts": 375, - "test/gstack-design-detect.test.ts": 16142, - "test/gstack-design-doc-find.test.ts": 346, - "test/gstack-detach.test.ts": 23780, - "test/gstack-developer-profile.test.ts": 11773, - "test/gstack-docs-candidate.test.ts": 526, - "test/gstack-egress-cli.test.ts": 585, - "test/gstack-gbrain-detect-mcp-mode.test.ts": 926, - "test/gstack-gbrain-mcp-verify.test.ts": 1242, - "test/gstack-gbrain-source-wireup.test.ts": 2711, - "test/gstack-gbrain-sync-transcript-mode.test.ts": 2500, - "test/gstack-gbrain-sync.test.ts": 1905, - "test/gstack-home-module-scope.test.ts": 71, - "test/gstack-learnings-search.test.ts": 1661, - "test/gstack-memorable.test.ts": 8823, - "test/gstack-memory-helpers.test.ts": 11132, - "test/gstack-memory-ingest.test.ts": 13878, - "test/gstack-next-version.test.ts": 1637, - "test/gstack-paths.test.ts": 949, - "test/gstack-question-log.test.ts": 2540, - "test/gstack-question-preference.test.ts": 7386, - "test/gstack-redact-cli.test.ts": 3399, - "test/gstack-render-cli.test.ts": 470, - "test/gstack-repo-mode.test.ts": 1212, - "test/gstack-retro-metrics.test.ts": 723, - "test/gstack-safe-git.test.ts": 999, - "test/gstack-schema-pack.test.ts": 13, - "test/gstack-session-kind.test.ts": 58, - "test/gstack-settings-hook-schema-aware.test.ts": 5595, - "test/gstack-settings-hook-symlink.test.ts": 1366, - "test/gstack-skill-start.test.ts": 6635, - "test/gstack-slug-cwd-walk-up.test.ts": 856, - "test/gstack-slug-get.test.ts": 414, - "test/gstack-slug-parity.test.ts": 4012, - "test/gstack-slug-sanitize.test.ts": 141, - "test/gstack-state-root-override.test.ts": 478, - "test/gstack-team-init-hook-schema.test.ts": 110, - "test/gstack-upgrade-fresh-shell.test.ts": 4110, - "test/gstack-upgrade-migration-v1_17_0_0.test.ts": 62, - "test/gstack-upgrade-migration-v1_37_0_0.test.ts": 94, - "test/gstack-upgrade-migration-v1_40_0_0.test.ts": 156, - "test/gstack-upgrade-migration-v1_78_0_0.test.ts": 38, - "test/gstack-upgrade-migration-v1_91_19_0.test.ts": 147, - "test/gstack-version-bump.test.ts": 1836, - "test/harness-version.test.ts": 100, - "test/health-capture.test.ts": 139, - "test/health-eval-fixture.test.ts": 178, - "test/helpers-unit.test.ts": 37, - "test/helpers/budget-override.test.ts": 16, - "test/helpers/capture-parity-baseline.test.ts": 143, + "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-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": 56, - "test/helpers/claude-pty-runner.classify.unit.test.ts": 41, - "test/helpers/claude-pty-runner.launch.unit.test.ts": 282, - "test/helpers/claude-pty-runner.plan-native.unit.test.ts": 41, - "test/helpers/claude-pty-runner.runners.unit.test.ts": 272, - "test/helpers/claude-pty-runner.scope-gate-floor.unit.test.ts": 43, - "test/helpers/claude-pty-runner.screen.unit.test.ts": 44, - "test/helpers/e2e-gate.unit.test.ts": 90, - "test/helpers/eval-store.test.ts": 254, - "test/helpers/hermetic-env.test.ts": 1014, - "test/helpers/observability.test.ts": 57, - "test/helpers/providers/gemini.test.ts": 22, + "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/helpers/claude-pty-runner.scope-gate-floor.unit.test.ts": 45, + "test/helpers/claude-pty-runner.screen.unit.test.ts": 67, + "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": 22, - "test/helpers/session-runner.test.ts": 95, - "test/helpers/sync-command-capture.test.ts": 1069, - "test/heredoc-pipe-deadlock.test.ts": 127, - "test/hermetic-skill-runtime.test.ts": 2120, - "test/hermetic-skills-seeding.test.ts": 133, - "test/hermetic-wiring.test.ts": 147, - "test/hook-log.test.ts": 260, - "test/hook-scripts.test.ts": 16635, + "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": 1529, - "test/host-conformance.test.ts": 70830, - "test/hostile-path-writers.test.ts": 2026, - "test/impeccable-fixtures.test.ts": 20, - "test/install-fixture.test.ts": 901, - "test/instruction-facts.test.ts": 51, - "test/investigate-freeze-path.test.ts": 3645, - "test/ios-debug-bridge-release-guard.test.ts": 16, - "test/ios-qa-daemon-cli.test.ts": 22, - "test/ios-qa-regen.test.ts": 231, - "test/ios-qa-stateserver-hardening.test.ts": 15, - "test/ios-qa-swift-build.test.ts": 20, - "test/ios-qa.test.ts": 327, - "test/is-conductor.test.ts": 11, - "test/jargon-list.test.ts": 29, - "test/jsonl-merge.test.ts": 286, - "test/jsonl-store.test.ts": 20, - "test/judge-calibration.test.ts": 49, - "test/land-and-deploy-ci-gate.test.ts": 2944, - "test/land-and-deploy-flow.test.ts": 555, - "test/land-and-deploy-postfail.test.ts": 36, - "test/learnings-callers-unavailable.test.ts": 1224, - "test/learnings-injection.test.ts": 15, - "test/learnings.test.ts": 4579, - "test/llm-judge-abort.test.ts": 28, - "test/llm-judge-frontier.test.ts": 96, - "test/llm-judge-stream.test.ts": 35, - "test/llms-txt-shape.test.ts": 28, - "test/maintenance-cli-args.test.ts": 195, - "test/memorable-user-prompt-hook.test.ts": 11526, - "test/memory-cache-injection.test.ts": 298, - "test/memory-ingest-include-gitignored.test.ts": 60, - "test/memory-ingest-landing.test.ts": 2005, - "test/memory-ingest-sources.test.ts": 1063, - "test/memory-ingest-timeout.test.ts": 24, - "test/memory-pipeline.test.ts": 584, - "test/migration-checkpoint-ownership.test.ts": 124, - "test/migrations-v1.27.0.0.test.ts": 714, - "test/migrations-v1.65.0.0.test.ts": 214, - "test/mktemp-portability.test.ts": 76, - "test/model-overlays.test.ts": 24, - "test/module-size-ratchet.test.ts": 104, - "test/native-auto-decide-pty.test.ts": 10141, - "test/native-auto-decide.test.ts": 279, - "test/no-quoted-tilde-assignments.test.ts": 37, - "test/no-stale-gstack-brain-refs.test.ts": 347, - "test/no-suicide-exit.test.ts": 101, - "test/office-hours-attempt.test.ts": 39397, - "test/office-hours-budget.test.ts": 38, - "test/office-hours-completion.test.ts": 213, - "test/office-hours-open-question-form.test.ts": 19, - "test/office-hours-phase4-caller.test.ts": 36, - "test/office-hours-review.test.ts": 450, - "test/office-hours-writeback-env.test.ts": 456, - "test/office-posture-recording.test.ts": 52, + "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/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/one-way-doors.test.ts": 11, - "test/open-gstack-browser-liveness.test.ts": 16, - "test/openclaw-native-skills.test.ts": 20, - "test/osv-config-wiring.test.ts": 15, - "test/osv-ignore-expiry.test.ts": 15, - "test/outside-review-result.test.ts": 171, + "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": 119, - "test/outside-voice-fixture.test.ts": 210, - "test/outside-voice-invocation.test.ts": 7327, - "test/outside-voice-preflight.test.ts": 389, - "test/outside-voice-provenance.test.ts": 823, - "test/outside-voice-receipt.test.ts": 336, - "test/outside-voice-routing.test.ts": 876, - "test/overlay-lifecycle.test.ts": 318, - "test/overlay-measurement.test.ts": 323, - "test/overlay-recording-order.test.ts": 30, - "test/overlay-sdk-cancel-eof.test.ts": 124, - "test/paid-free-boundary.test.ts": 1765, - "test/paid-orphan-tripwire.test.ts": 73, - "test/paid-overlay-scheduling.test.ts": 396, - "test/paid-pr-profile.test.ts": 1220, - "test/paid-report-census.test.ts": 51, - "test/paid-report-fail-open.test.ts": 910, - "test/paid-retry-supervision.test.ts": 1259, - "test/paid-run-manifest.test.ts": 1471, - "test/paid-selection-propagation.test.ts": 42, - "test/paid-shard-settlement.test.ts": 1264, - "test/paid-shards.test.ts": 2468, - "test/paid-slice-deadline.test.ts": 1539, - "test/pair-agent-token-hygiene.test.ts": 17, - "test/parity-baseline-integrity.test.ts": 22, - "test/parity-sectioned.test.ts": 18, - "test/parity-suite.test.ts": 100, - "test/pending-question-completion.test.ts": 122, - "test/periodic-exclude-policy.test.ts": 83, - "test/plan-count-artifacts.test.ts": 32, + "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": 57, - "test/plan-count-collection-completion.test.ts": 29806, - "test/plan-count-completion.test.ts": 13868, - "test/plan-count-cropped-wrap.test.ts": 81, - "test/plan-count-cross-cwd-ancestry.test.ts": 120, - "test/plan-count-design-ui-recovery.test.ts": 15671, - "test/plan-count-dx-handoff.test.ts": 79, - "test/plan-count-empty-review.test.ts": 1530, - "test/plan-count-file-permission.test.ts": 44605, - "test/plan-count-fixture.test.ts": 14980, - "test/plan-count-history.test.ts": 746, - "test/plan-count-long-edit.test.ts": 42, - "test/plan-count-native-input.test.ts": 11561, - "test/plan-count-owned-permission.test.ts": 11419, - "test/plan-count-pending-exit.test.ts": 310, - "test/plan-count-prerequisite.test.ts": 48, - "test/plan-count-preview-footer.test.ts": 3463, - "test/plan-count-session-cwd.test.ts": 85, - "test/plan-count-timeout.test.ts": 9578, - "test/plan-count-transcript.test.ts": 128, - "test/plan-count-truncated-border.test.ts": 71, - "test/plan-count-truncated-question.test.ts": 38, - "test/plan-create-combined-permission.test.ts": 139, - "test/plan-create-permission.test.ts": 77, - "test/plan-create-prepublication.test.ts": 127, - "test/plan-design-floor-fixture.test.ts": 290, - "test/plan-design-sdk-fixture.test.ts": 494, - "test/plan-design-with-ui-fixture.test.ts": 1484, - "test/plan-edit-cropped-permission.test.ts": 110, - "test/plan-eng-resume.test.ts": 15, - "test/plan-floor-dx-actor.test.ts": 82, - "test/plan-floor-permission.test.ts": 1718, - "test/plan-floor-review.test.ts": 59, - "test/plan-floor-target.test.ts": 12498, - "test/plan-format-kind-note.test.ts": 16, - "test/plan-mode-evidence.test.ts": 635, - "test/plan-pending-question-pty.test.ts": 449, - "test/plan-review-board-feedback.test.ts": 4791, - "test/plan-review-calibration.test.ts": 395, - "test/plan-review-cases.test.ts": 1166, - "test/plan-review-decisions.test.ts": 280, - "test/plan-review-report-recording.test.ts": 5427, - "test/plan-scope-selection.test.ts": 2877, - "test/plan-seed-submission.test.ts": 54088, - "test/plan-skill-question-events.test.ts": 2623, - "test/plan-skill-question-hook-scope.test.ts": 4070, - "test/plan-skill-questions.test.ts": 16275, - "test/plan-skill-read-permission.test.ts": 47, - "test/plan-skill-webfetch-permission.test.ts": 1300, - "test/plan-tune-cathedral.test.ts": 830, - "test/plan-tune-gates.test.ts": 1096, - "test/plan-tune.test.ts": 1244, - "test/platform-qualification-workflow.test.ts": 15, - "test/post-rename-doc-regen.test.ts": 28, - "test/pr-dependencies.test.ts": 1624, - "test/pr-direct-cases.test.ts": 1778, - "test/pr-shared-input-selection.test.ts": 632, - "test/pr-title-rewrite.test.ts": 90, - "test/pr-title-sync-workflow-safety.test.ts": 15, - "test/preamble-compose.test.ts": 20, - "test/preamble-first-task-scaffold.test.ts": 758, - "test/prompt-audit-manifest.test.ts": 226, - "test/provider-model-defaults.test.ts": 268, - "test/pty-askuserquestion-single-line.test.ts": 35, + "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/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-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-truncated-question.test.ts": 36, + "test/plan-create-combined-permission.test.ts": 92, + "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-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/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/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": 606, - "test/pty-output-wake.test.ts": 10216, - "test/pty-screen-session.test.ts": 8854, - "test/pty-screen-supervision.test.ts": 10449, - "test/pty-screen-unicode-ap.test.ts": 123, - "test/pty-screen.test.ts": 99, - "test/pty-skill-seeding-wiring.test.ts": 533, - "test/pty-trust-dialog.test.ts": 3098, - "test/pty-upgrade-isolation.test.ts": 744, - "test/pty-workspace-trust.test.ts": 367, - "test/qa-browser-deadline-evidence.test.ts": 3517, - "test/qa-browser-preservation.test.ts": 1293, - "test/qa-bugs-fixture.test.ts": 24, - "test/qa-caller-authority.test.ts": 67, - "test/qa-caller-freshness-order.test.ts": 36, - "test/qa-caller-report-observer.test.ts": 146, - "test/qa-checkpoint-evidence.test.ts": 89, - "test/qa-deadline-publication-observer.test.ts": 249, - "test/qa-deadline-selection.test.ts": 37, - "test/qa-deadline.test.ts": 19608, - "test/qa-evidence-producer.test.ts": 8176, - "test/qa-evidence-selection.test.ts": 65, - "test/qa-evidence.test.ts": 9951, - "test/qa-exploratory-callers.test.ts": 10604, - "test/qa-fix-loop-fixture.test.ts": 2062, - "test/qa-functional-evidence.test.ts": 4913, - "test/qa-functional-fixture.test.ts": 958, - "test/qa-functional-observer-atomic.test.ts": 266, - "test/qa-functional-observer.test.ts": 961, - "test/qa-functional-prompt.test.ts": 798, - "test/qa-health-rubric.test.ts": 13, - "test/qa-lazy-sections.test.ts": 7697, - "test/qa-only-browser-probe.test.ts": 753, - "test/qa-only-capability.test.ts": 1533, - "test/qa-only-cleanup.test.ts": 7534, - "test/qa-only-fixture.test.ts": 10977, - "test/qa-probe-gates.test.ts": 47, - "test/qa-supervision-selection.test.ts": 33, - "test/question-log-hook.test.ts": 1349, - "test/question-preference-hook.test.ts": 2606, - "test/question-tuning-registry-path.test.ts": 19, - "test/recover-receipts.test.ts": 291, - "test/redact-audit-log.test.ts": 38, - "test/redact-context-exemptions.test.ts": 37, - "test/redact-doc-resolver.test.ts": 12, + "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": 55, - "test/redact-parcel-id-false-positive.test.ts": 15, - "test/redact-pattern-lint.test.ts": 32, - "test/redact-prepush-hook.test.ts": 2270, - "test/redact-prepush-rebase-force-push.test.ts": 723, - "test/redact-prepush-scan-range.test.ts": 1204, - "test/redact-prepush-target.test.ts": 7510, - "test/redact-span-binding.test.ts": 44, - "test/redact-unicode-offsets.test.ts": 77, - "test/regression-1539-review-self-verify.test.ts": 18, - "test/regression-1611-gbrain-sync-resume.test.ts": 32, - "test/regression-1624-retro-stale-base.test.ts": 18, - "test/regression-2922-memory-ingest-sources.test.ts": 512, - "test/regression-dot-leading-slug.test.ts": 114, - "test/regression-issue2091-bsd-mktemp.test.ts": 167, - "test/regression-pr1169-build-app-sed.test.ts": 53, - "test/regression-pr1169-mktemp-fallbacks.test.ts": 45, - "test/regression-transcript-frontmatter-fence.test.ts": 26, - "test/regression-transcript-slug-collision.test.ts": 25, - "test/relink-disabled-router.test.ts": 752, - "test/relink.test.ts": 8534, - "test/remote-identity-vectors.test.ts": 588, - "test/render-sections-provenance.test.ts": 273, - "test/replay-pr-selection.test.ts": 611, - "test/resolver-ask-user-format.test.ts": 26, - "test/resolvers-gbrain-put-rewrite.test.ts": 24, - "test/resolvers-gbrain-save-results.test.ts": 14, - "test/retired-commands.test.ts": 26, - "test/review-army-budget.test.ts": 1749, - "test/review-consensus-lifecycle.test.ts": 34, - "test/review-count-markdown.test.ts": 96, - "test/review-entry-and-design-clarity-au.test.ts": 65, - "test/review-enum-lifecycle.test.ts": 28, - "test/review-finalization-budget.test.ts": 2584, - "test/review-log.test.ts": 1663, - "test/review-n-plus-one-contract.test.ts": 600, - "test/review-quality-provenance.test.ts": 38, - "test/review-start-evidence.test.ts": 14218, - "test/review-workflow-clarity.test.ts": 34, - "test/review-workflow-fixture.test.ts": 28, - "test/router-disabled-skills.test.ts": 521, - "test/routing-probe.test.ts": 27, - "test/run-in-background-guidance.test.ts": 562, - "test/run-shard-child.test.ts": 1243, - "test/safety-rule-registry.test.ts": 32, - "test/salience-allowlist.test.ts": 28, - "test/sandbox-doctor-shell.test.ts": 16, - "test/schema-version-migration.test.ts": 56, - "test/secret-sink-harness.test.ts": 48, - "test/section-capture-native-tools.test.ts": 3733, - "test/section-manifest-consistency.test.ts": 25, - "test/security-dashboard-fallback.test.ts": 1341, - "test/session-runner-browse-errors.test.ts": 677, - "test/session-runner-groupkill.test.ts": 4084, - "test/session-runner-startup-grace.test.ts": 13152, - "test/session-runner-stream-lifecycle.test.ts": 269, - "test/session-runner-timeout.test.ts": 3029, - "test/session-runner-tools.test.ts": 5249, - "test/session-update-autostash.test.ts": 5025, - "test/session-update-stages.test.ts": 2567, - "test/setup-alias-name-uniqueness.test.ts": 1347, - "test/setup-browser-hint.test.ts": 43, - "test/setup-bun-cmd-and-pipe-bugs.test.ts": 28, - "test/setup-claude-code-migration.test.ts": 10453, - "test/setup-claude-skill-assets.test.ts": 857, - "test/setup-cleanup-orphans.test.ts": 192, - "test/setup-codesign-restore.test.ts": 337, - "test/setup-codesign.test.ts": 25, - "test/setup-codex-design-pdf-runtime.test.ts": 131, - "test/setup-codex-model.test.ts": 17, - "test/setup-codex-scope-migrations.test.ts": 26060, - "test/setup-codex-scope-namespaces.test.ts": 43086, - "test/setup-codex-scope-review-boundaries.test.ts": 38312, - "test/setup-codex-scope.test.ts": 47656, - "test/setup-conductor-auq-hook.test.ts": 17398, - "test/setup-conductor-worktree.test.ts": 36, - "test/setup-cso-windows-probe.test.ts": 50, - "test/setup-deploy-key-presence.test.ts": 19, - "test/setup-emoji-font.test.ts": 62, - "test/setup-gbrain-bin-invocation-paths.test.ts": 16, - "test/setup-gbrain-fixture.test.ts": 2472, - "test/setup-gbrain-path4-caller.test.ts": 2591, - "test/setup-gbrain-path4-structure.test.ts": 16, - "test/setup-gbrain-remote-caller.test.ts": 8660, - "test/setup-help.test.ts": 57, + "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/regression-1539-review-self-verify.test.ts": 14, + "test/regression-1611-gbrain-sync-resume.test.ts": 30, + "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/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/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-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/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-install-registry.test.ts": 57854, - "test/setup-kiro-native.test.ts": 595, - "test/setup-link-ownership.test.ts": 700, - "test/setup-needs-build.test.ts": 185, - "test/setup-plan-tune-hooks-noninteractive.test.ts": 336, - "test/setup-playwright-best-effort.test.ts": 16814, - "test/setup-playwright-platform.test.ts": 5260, - "test/setup-prune-stale-generated.test.ts": 152, - "test/setup-runtime-lib-command.test.ts": 12166, - "test/setup-sections-linking.test.ts": 24, - "test/setup-skill-copies.test.ts": 340, - "test/setup-staged-copy.test.ts": 50, - "test/setup-timeline-hook-gate.test.ts": 198, - "test/setup-windows-fallback.test.ts": 43, - "test/setup-windows-rerun-refresh.test.ts": 137, - "test/shard-cli-parity.test.ts": 92, - "test/shard-engine-equivalence.test.ts": 3103, - "test/shard-engine.test.ts": 3685, - "test/shared-libs-cancellation.test.ts": 102, - "test/shared-libs-checker-interface-evidence.test.ts": 40661, - "test/shared-libs-evidence.test.ts": 23, - "test/shared-libs-fixture.test.ts": 8027, - "test/shared-libs-plan-actor.test.ts": 83, - "test/shared-libs-rendering.test.ts": 997, - "test/shared-libs-revalidation-prompt.test.ts": 10006, - "test/shared-libs-review-start-evidence.test.ts": 2475, - "test/shared-libs-snapshot-check.test.ts": 26813, - "test/shared-libs-source-reads.test.ts": 1318, - "test/shared-libs-stage-actor.test.ts": 106924, + "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": 297, - "test/ship-coverage-audit-af.test.ts": 56, - "test/ship-document-release-dispatch.test.ts": 4124, - "test/ship-hook-actor.test.ts": 1960, - "test/ship-hook-refresh.test.ts": 2208, - "test/ship-hook-windows-paths.test.ts": 300, - "test/ship-plan-completion-invariants.test.ts": 956, - "test/ship-pr-liveness-policy.test.ts": 17, - "test/ship-publication-gates.test.ts": 187, - "test/ship-reentry-gates.test.ts": 24, - "test/ship-review-loop.test.ts": 20, - "test/ship-section-fixture.test.ts": 391, - "test/ship-skip-actor.test.ts": 28529, - "test/ship-skip-requeue.test.ts": 34, - "test/ship-skip-selection.test.ts": 697, - "test/ship-template-redaction.test.ts": 21, - "test/ship-test-detection-markers.test.ts": 144, - "test/ship-triage-labels.test.ts": 17, - "test/ship-version-sync.test.ts": 508, - "test/ship-workflow-clarity.test.ts": 40, + "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/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-pr-liveness-policy.test.ts": 14, + "test/ship-publication-gates.test.ts": 680, + "test/ship-reentry-gates.test.ts": 25, + "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/skill-browse-state-extraction.test.ts": 32, - "test/skill-budget-regression.test.ts": 37, - "test/skill-census.test.ts": 34, - "test/skill-ceo-section-ordering.test.ts": 1979, - "test/skill-check-driver.test.ts": 106, - "test/skill-collision-sentinel.test.ts": 18, - "test/skill-coverage-floor.test.ts": 53, - "test/skill-cross-model-recommendation-emit.test.ts": 33, - "test/skill-fixture.test.ts": 50, - "test/skill-parser.test.ts": 27, - "test/skill-positional-literals.test.ts": 1051, - "test/skill-preflight-budget.test.ts": 17, - "test/skill-size-budget.test.ts": 428, - "test/skill-validation.test.ts": 961, - "test/skillify-host-paths.test.ts": 859, - "test/slop-diff-cli.test.ts": 346, - "test/sol-skill-fixture.test.ts": 697, - "test/spawnsync-timeout-tripwire.test.ts": 170, - "test/spec-quality-gate-secret-sink.test.ts": 1394, - "test/spec-template-invariants.test.ts": 23, - "test/state-root-config-merge.test.ts": 680, - "test/state-root-one-variable.test.ts": 4178, - "test/state-root-parity.test.ts": 143, - "test/state-root-ratchet.test.ts": 301, - "test/state-root-resolver-failure.test.ts": 36, - "test/static-no-legacy-writes.test.ts": 1068, - "test/strict-output-capture.test.ts": 85, - "test/strict-output-formats.test.ts": 984, - "test/strict-output-settlement.test.ts": 4276, - "test/strict-output.test.ts": 20, - "test/sync-gbrain-cycle-freshness.test.ts": 63, - "test/sync-gbrain-readiness-fixture.test.ts": 166, - "test/sync-gbrain-source-probe.test.ts": 529, - "test/takes-fence-fallback.test.ts": 15, - "test/tasks-section-jq.test.ts": 25, - "test/taste-engine.test.ts": 939, - "test/team-mode.test.ts": 1461, - "test/telemetry-repo-strip.test.ts": 30, - "test/telemetry.test.ts": 6614, - "test/template-context-parity.test.ts": 17, - "test/terse-build.test.ts": 23, - "test/test-free-shards-capture.test.ts": 1277, - "test/test-free-shards-sandbox-knobs.test.ts": 108, - "test/test-free-shards-settlement-lifecycle.test.ts": 46457, - "test/test-free-shards-settlement-ownership.test.ts": 38118, - "test/test-free-shards.test.ts": 9781, - "test/test-health-report.test.ts": 214, - "test/test-health-workflow.test.ts": 16, - "test/test-of-test-ratchet.test.ts": 164, - "test/test-pr-profile.test.ts": 33, - "test/test-value-bar.test.ts": 88, - "test/testing-internals-anchors.test.ts": 739, - "test/third-party-actions-recording.test.ts": 103, - "test/third-party-actions.test.ts": 267, - "test/timeline-stop-hook.test.ts": 1019, - "test/timeline.test.ts": 1816, - "test/touchfiles-facade.test.ts": 27, - "test/touchfiles-map-diff.test.ts": 171, - "test/touchfiles.test.ts": 1048, - "test/tracker-guard-wiring.test.ts": 53, - "test/tracker-guard.test.ts": 168, - "test/transcript-consent.test.ts": 908, - "test/transcript-gate-values.test.ts": 1348, - "test/transcript-scope-brain-sync.test.ts": 3974, - "test/transcript-scope-ingest.test.ts": 753, - "test/troubleshooting-anchors.test.ts": 18, - "test/typecheck-test-ratchet.test.ts": 42, - "test/ubicloud-runner.test.ts": 67, - "test/uninstall-windows-copies.test.ts": 1925, - "test/uninstall.test.ts": 5711, - "test/update-check-crash-sentinel.test.ts": 551, - "test/upgrade-migration-v1.test.ts": 50, - "test/upgrade-setup-recovery.test.ts": 81, - "test/upgrade-template-pins.test.ts": 15, - "test/user-render-out-dir-install.test.ts": 130, - "test/user-slug-fallback.test.ts": 558, - "test/v0-dormancy.test.ts": 31, - "test/verify-gate.test.ts": 1934, - "test/version-source.test.ts": 42, - "test/windows-free-selection-autoplan-guard.test.ts": 29, - "test/windows-native-workflows.test.ts": 213, - "test/workflow-action-pins.test.ts": 22, - "test/workflow-boundaries-fixture.test.ts": 2585, - "test/workflow-concurrency.test.ts": 18, - "test/workflow-excerpt.test.ts": 115, - "test/workflow-judge-cache.test.ts": 2105, - "test/workflow-judge-input.test.ts": 54, - "test/worktree-isolated-shapes.test.ts": 36, - "test/worktree.test.ts": 684, - "test/writing-style-resolver.test.ts": 26 + "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-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 } } diff --git a/scripts/free-test-seed-allowlist.json b/scripts/free-test-seed-allowlist.json index 92bf700bb..1b4c032ea 100644 --- a/scripts/free-test-seed-allowlist.json +++ b/scripts/free-test-seed-allowlist.json @@ -1,6 +1,9 @@ { "entries": [ {"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/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)"} ] } diff --git a/scripts/test-free-shards.ts b/scripts/test-free-shards.ts index e009f7be6..8b53a9f20 100755 --- a/scripts/test-free-shards.ts +++ b/scripts/test-free-shards.ts @@ -1490,6 +1490,24 @@ function logFreeRecovery(log: (line: string) => void, outcome: FreeShardOutcome, } } +/** + * Backstop for fixtures that commit and then list, watch or remove `.git`: + * git's detached auto-maintenance child creates and deletes + * `.git/objects/maintenance.lock` after `git commit` has returned. Appends + * `maintenance.auto=false` and `gc.auto=0` after any inherited GIT_CONFIG_* + * pairs; a malformed inherited count is left untouched so git still rejects it. + */ +export function disableGitAutoMaintenance(env: NodeJS.ProcessEnv): void { + const inherited = (env.GIT_CONFIG_COUNT ?? '').trim(); + if (inherited !== '' && !/^\d+$/.test(inherited)) return; + const count = inherited === '' ? 0 : Number(inherited); + env[`GIT_CONFIG_KEY_${count}`] = 'maintenance.auto'; + env[`GIT_CONFIG_VALUE_${count}`] = 'false'; + env[`GIT_CONFIG_KEY_${count + 1}`] = 'gc.auto'; + env[`GIT_CONFIG_VALUE_${count + 1}`] = '0'; + env.GIT_CONFIG_COUNT = String(count + 2); +} + /** One line per shard, printed after the run: `[test:free] shard i/N: M files, XXs, pass|fail|timed-out`. */ function shardEpilogue(outcome: FreeShardOutcome, totalShards: number): string { return `[test:free] shard ${outcome.shard}/${totalShards}: ${outcome.files.length} files, ` @@ -1559,6 +1577,7 @@ export async function runFreeShard( // shards and prior daemons replace each other's state; override inherited state. env.BROWSE_STATE_FILE = path.join(stateDir, '.gstack', 'browse.json'); env.GSTACK_FREE_SHARD_ID = randomUUID(); + disableGitAutoMaintenance(env); const home = options.homeGuard ? options.homeGuard(files, env, stateDir) : guardFreeHome(files, env); const startedAt = Date.now(); diff --git a/scripts/test-health-report.ts b/scripts/test-health-report.ts index 28a775a02..e4dc5da46 100644 --- a/scripts/test-health-report.ts +++ b/scripts/test-health-report.ts @@ -138,7 +138,7 @@ export function flakeCheck(window: FlakeWindow | Error): Check { export function unseededCheck(root: string): Check { const base = { id: 'unseeded-free-files', title: 'Free test files missing from the duration seed (CEO-10)', - fix: 'Refresh the seed: `bun run test:ubicloud --record-durations` (or a CI recording; a 4-core laptop recording is not acceptable), then commit scripts/free-test-durations.json (docs/TESTING_INTERNALS.md#free-suite-duration-seed).' }; + fix: 'Refresh the seed with UBICLOUD_API_KEY set: `bun run test:ubicloud --record-durations` times every free file on a CI-mirrored VM and copies scripts/free-test-durations.json back into this checkout; commit it (docs/TESTING_INTERNALS.md#free-suite-duration-seed). Without UBICLOUD_API_KEY, leave the refresh to a maintainer: a 4-core laptop or sandbox recording skips or slows browser and display tests, so it is not accepted.' }; const durations = loadFreeTestDurations(root); if (!durations) return { ...base, status: 'unavailable', detail: 'unavailable: scripts/free-test-durations.json is missing or unreadable; next: refresh the seed' }; const unseeded = unseededFreeFiles(collectFreeTestFiles(root), durations); @@ -243,12 +243,13 @@ export function collectHealth(inputs: HealthInputs): HealthReport { detail: window.files.slice(0, 15).map(file => `${file.file}: ${file.flakyRuns}/${window.runs} runs (${pct(file.rate)})${file.failing ? ' FAIL > 5%' : ''}`) }; })); - metrics.push(metric('free-wall', 'Free-suite and Windows wall', 'p50 of run_started_at to updated_at for successful main runs of free-tests.yml and windows-free-tests.yml', () => { - const wall = (workflow: string) => { - const walls = listWorkflowRuns(client, repo, workflow, { since, branch: 'main' }).filter(run => run.conclusion === 'success').map(run => span(run.startedAt, run.updatedAt)!); - return `${minutes(percentile(walls, 0.5))} (${walls.length} runs)`; - }; - return { value: `free-tests ${wall('free-tests.yml')}; windows-free-tests ${wall('windows-free-tests.yml')}` }; + metrics.push(metric('free-wall', 'Free-suite and Windows wall', 'p50 of run_started_at to updated_at for successful main runs of free-tests.yml and successful pull_request runs of windows-free-tests.yml (its workflow_dispatch duration recordings excluded)', () => { + const walls = (workflow: string, filter: { branch?: string; event?: string }) => + listWorkflowRuns(client, repo, workflow, { since, ...filter }).filter(run => run.conclusion === 'success').map(run => span(run.startedAt, run.updatedAt)!); + const free = walls('free-tests.yml', { branch: 'main' }); + const windows = walls('windows-free-tests.yml', { event: 'pull_request' }); + const windowsValue = windows.length ? `${minutes(percentile(windows, 0.5))} (${windows.length} runs)` : 'no successful PR runs in window'; + return { value: `free-tests ${minutes(percentile(free, 0.5))} (${free.length} runs); windows-free-tests (successful PR runs) ${windowsValue}` }; })); metrics.push(metric('free-serial', 'Free-suite serial time', 'sum of scripts/free-test-durations.json (the committed seed)', () => { diff --git a/test/free-seed-ratchet.test.ts b/test/free-seed-ratchet.test.ts index b53c4627f..31950be21 100644 --- a/test/free-seed-ratchet.test.ts +++ b/test/free-seed-ratchet.test.ts @@ -95,6 +95,7 @@ describe('seed ceiling and shrink-only allowlist', () => { }); test('the committed seed holds the ceiling and the allowlist only shrinks', () => { + expect(SEED_ALLOWLIST_FILE).toBe('scripts/free-test-seed-allowlist.json'); const seed = JSON.parse(fs.readFileSync(path.join(ROOT, FREE_TEST_DURATIONS_FILE), 'utf8')) as { durations: Record }; const allowlist = parseSeedAllowlist(fs.readFileSync(path.join(ROOT, SEED_ALLOWLIST_FILE), 'utf8')); const explicitBase = process.env.GSTACK_FREE_SEED_BASE; diff --git a/test/gstack-docs-candidate.test.ts b/test/gstack-docs-candidate.test.ts index 276d06b6c..2d1c8d59a 100644 --- a/test/gstack-docs-candidate.test.ts +++ b/test/gstack-docs-candidate.test.ts @@ -21,6 +21,7 @@ function repo() { fs.mkdirSync(path.join(dir, 'handbook'), { recursive: true }); git(root, 'init', '-q', '-b', 'main', dir); git(dir, 'config', 'user.email', 't@t'); git(dir, 'config', 'user.name', 't'); git(dir, 'config', 'commit.gpgsign', 'false'); + git(dir, 'config', 'maintenance.auto', 'false'); git(dir, 'config', 'gc.auto', '0'); fs.writeFileSync(path.join(dir, 'app.ts'), 'export const a = 1;\n'); fs.writeFileSync(path.join(dir, 'handbook', 'guide.md'), '# Guide\n'); git(dir, 'add', '.'); git(dir, 'commit', '-qm', 'base'); @@ -38,7 +39,7 @@ describe('gstack-docs-candidate', () => { test('snapshot records base, HEAD, index, NUL-safe path lists and content hashes without touching the repository', () => { const { dir, record } = repo(); const gitDir = path.join(dir, '.git'); - const before = fs.readdirSync(gitDir, { recursive: true }).length; + const before = fs.readdirSync(gitDir, { recursive: true }) as string[]; const indexBefore = fs.readFileSync(path.join(gitDir, 'index')); const result = run(dir, 'snapshot', '--out', record, '--audit-id', 'a1', '--mode', 'edit', '--base', 'main', '--docs', 'handbook'); expect(result.status, result.stderr).toBe(0); @@ -51,7 +52,9 @@ describe('gstack-docs-candidate', () => { expect(saved.hashes['app.ts']).toBe(git(dir, 'hash-object', 'app.ts')); expect(saved.index).toHaveLength(2); expect(fs.statSync(record).mode & 0o777).toBe(0o600); - expect(fs.readdirSync(gitDir, { recursive: true }).length).toBe(before); + const after = fs.readdirSync(gitDir, { recursive: true }) as string[]; + const changed = [...before.filter(entry => !after.includes(entry)).map(entry => `-${entry}`), ...after.filter(entry => !before.includes(entry)).map(entry => `+${entry}`)]; + expect(after.length, `.git entries changed during snapshot: ${changed.join(', ') || '(same names)'}`).toBe(before.length); expect(fs.readFileSync(path.join(gitDir, 'index')).equals(indexBefore)).toBe(true); }); diff --git a/test/gstack-next-version.test.ts b/test/gstack-next-version.test.ts index 9c8901318..83993db72 100644 --- a/test/gstack-next-version.test.ts +++ b/test/gstack-next-version.test.ts @@ -932,35 +932,90 @@ describe("width pinned on failed base read (3-digit repos)", () => { describe("integration (smoke)", () => { const SMOKE_SCRIPT = join(import.meta.dir, "..", "bin", "gstack-next-version"); - // Bumps timeout to 30s — the test spawns a real `bun run` subprocess that - // does a `gh pr list` against the live GitHub API to inspect claimed slots. - // Network latency makes 5s tight on developer machines. + const FAKE_OWNER = "fixture-owner"; + const CLAIM = { pr: 41, branch: "fixture/claim", version: "1.6.4.0", url: "https://github.com/fixture-owner/repo/pull/41" }; + // A named fake `gh` first on PATH answers every call the CLI makes in this + // checkout and logs each argv; anything else exits 2 so a fixture gap cannot + // silently change the path. The live GitHub API is never called. + function fakeGh(dir: string): { calls: () => string[][]; glabCalls: () => string } { + const log = join(dir, "gh-calls.log"); + const glabLog = join(dir, "glab-calls.log"); + const prList = JSON.stringify([{ number: CLAIM.pr, headRefName: CLAIM.branch, headRepositoryOwner: { login: FAKE_OWNER }, url: CLAIM.url, isDraft: false }]); + const content = Buffer.from(`${CLAIM.version}\n`).toString("base64"); + writeFileSync(join(dir, "gh"), [ + "#!/bin/sh", + `printf '%s\\037' "$@" >> '${log}'; printf '\\n' >> '${log}'`, + 'case "$*" in', + ' "auth status") exit 0 ;;', + ' "pr view --json number -q .number") exit 1 ;;', + ` "pr list --state open --base main --limit 200 --json number,headRefName,headRepositoryOwner,url,isDraft") printf '%s\\n' '${prList}'; exit 0 ;;`, + ` "repo view --json owner -q .owner.login") echo '${FAKE_OWNER}'; exit 0 ;;`, + ` "api repos/{owner}/{repo}/contents/VERSION?ref=${encodeURIComponent(CLAIM.branch)} -q .content") echo '${content}'; exit 0 ;;`, + "esac", + `echo "FAKE_GH_UNHANDLED $*" >> '${log}'`, + 'echo "FAKE_GH_UNHANDLED $*" >&2', + "exit 2", + "", + ].join("\n"), { mode: 0o755 }); + writeFileSync(join(dir, "glab"), `#!/bin/sh\necho "$*" >> '${glabLog}'\nexit 1\n`, { mode: 0o755 }); + return { + calls: () => readFileSync(log, "utf8").trimEnd().split("\n").map((line) => line.split("\x1f").filter(Boolean)), + glabCalls: () => { try { return readFileSync(glabLog, "utf8"); } catch { return ""; } }, + }; + } + test("CLI runs against real repo and emits parseable JSON", async () => { - const proc = Bun.spawnSync([ - "bun", - "run", - "./bin/gstack-next-version", - "--base", - "main", - "--bump", - "patch", - "--current-version", - "1.6.3.0", - "--workspace-root", - "null", // skip sibling scan in CI - ], { timeout: 30_000 }); - const out = new TextDecoder().decode(proc.stdout); - const parsed = JSON.parse(out); - expect(parsed).toHaveProperty("version"); - expect(parseVersion(parsed.version)).not.toBeNull(); - expect(parsed).toHaveProperty("bump", "patch"); - expect(parsed).toHaveProperty("host"); - expect(["github", "gitlab", "unknown"]).toContain(parsed.host); - expect(parsed).toHaveProperty("claimed"); - expect(Array.isArray(parsed.claimed)).toBe(true); - expect(parsed).toHaveProperty("siblings"); - expect(parsed.siblings).toEqual([]); // --workspace-root null disabled scanning - expect(parsed).toHaveProperty("version_path", "VERSION"); // default when no config + no flag + const stubDir = mkdtempSync(join(tmpdir(), "nextver-smoke-gh-")); + try { + const gh = fakeGh(stubDir); + const proc = Bun.spawnSync([ + "bun", + "run", + "./bin/gstack-next-version", + "--base", + "main", + "--bump", + "patch", + "--current-version", + "1.6.3.0", + "--workspace-root", + "null", // skip sibling scan in CI + ], { timeout: 30_000, env: { ...process.env, PATH: `${stubDir}:${process.env.PATH ?? ""}` } }); + const stderr = new TextDecoder().decode(proc.stderr); + expect(proc.exitCode, stderr).toBe(0); + const out = new TextDecoder().decode(proc.stdout); + const parsed = JSON.parse(out); + expect(parsed).toHaveProperty("version"); + expect(parseVersion(parsed.version)).not.toBeNull(); + expect(parsed).toHaveProperty("bump", "patch"); + expect(parsed).toHaveProperty("host"); + expect(["github", "gitlab", "unknown"]).toContain(parsed.host); + expect(parsed).toHaveProperty("claimed"); + expect(Array.isArray(parsed.claimed)).toBe(true); + expect(parsed).toHaveProperty("siblings"); + expect(parsed.siblings).toEqual([]); // --workspace-root null disabled scanning + expect(parsed).toHaveProperty("version_path", "VERSION"); // default when no config + no flag + + const remote = execFileSync("git", ["remote", "get-url", "origin"], { cwd: join(import.meta.dir, ".."), encoding: "utf8", timeout: 10_000 }).trim(); + expect(gh.calls()).toEqual([ + ...(remote.includes("github.com") ? [] : [["auth", "status"]]), + ["pr", "view", "--json", "number", "-q", ".number"], + ["pr", "list", "--state", "open", "--base", "main", "--limit", "200", "--json", "number,headRefName,headRepositoryOwner,url,isDraft"], + ["repo", "view", "--json", "owner", "-q", ".owner.login"], + ["api", `repos/{owner}/{repo}/contents/VERSION?ref=${encodeURIComponent(CLAIM.branch)}`, "-q", ".content"], + ]); + expect(gh.calls().flat().join(" ")).not.toContain("FAKE_GH_UNHANDLED"); + expect(stderr).not.toContain("FAKE_GH_UNHANDLED"); + expect(gh.glabCalls()).toBe(""); + expect(parsed.host).toBe("github"); + expect(parsed.offline).toBe(false); + expect(parsed.fallback).toBeNull(); + expect(parsed.warnings).toEqual([]); + expect(parsed.claimed).toEqual([CLAIM]); // the canned PR's owner matches the canned repo owner + expect(parsed.version).toBe("1.6.5.0"); // the canned claim on 1.6.4.0 is skipped + } finally { + rmSync(stubDir, { recursive: true, force: true }); + } }, 30_000); // Headroom over the 4-5s wall time of the spawned process under load test("CLI runs with --version-path and surfaces it in JSON output", async () => { diff --git a/test/plan-design-sdk-fixture.test.ts b/test/plan-design-sdk-fixture.test.ts index 04f18c4e3..0f53d5ed5 100644 --- a/test/plan-design-sdk-fixture.test.ts +++ b/test/plan-design-sdk-fixture.test.ts @@ -18,6 +18,7 @@ async function exercise(mode: 'success' | 'max-turns' | 'first-timeout' | 'secon const scratch = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'legacy-design-free-'))); const home = path.join(scratch, 'home'); fs.mkdirSync(home); const env = { PATH: process.env.PATH ?? '', HOME: home, GIT_CONFIG_NOSYSTEM: '1', + GIT_CONFIG_COUNT: '2', GIT_CONFIG_KEY_0: 'maintenance.auto', GIT_CONFIG_VALUE_0: 'false', GIT_CONFIG_KEY_1: 'gc.auto', GIT_CONFIG_VALUE_1: '0', GIT_CONFIG_GLOBAL: process.platform === 'win32' ? 'NUL' : '/dev/null', ...(process.env.SystemRoot ? { SystemRoot: process.env.SystemRoot } : {}) }; const callbacks: Array<{ name: string; fn: () => Promise; timeout: number }> = []; @@ -25,6 +26,8 @@ async function exercise(mode: 'success' | 'max-turns' | 'first-timeout' | 'secon const recordBudgets: number[] = []; let launched = false, sdkSignal: AbortSignal | undefined; let inputVerified = false, saved = '', resultError: unknown; + const removals: string[] = []; + const survivors = () => `surviving fixture dirs: ${dirs.filter(dir => fs.existsSync(dir)).join(', ') || '(none)'}; removals: ${removals.join('; ') || '(none)'}`; const owned = (p: string) => { const full = path.resolve(p); expect(full.startsWith(scratch + path.sep)).toBe(true); @@ -43,13 +46,17 @@ async function exercise(mode: 'success' | 'max-turns' | 'first-timeout' | 'secon }, copyFileSync(a: string, b: string) { owned(b); fs.copyFileSync(a, b); }, cpSync(a: string, b: string, opts: any) { owned(b); fs.cpSync(a, b, opts); }, - rmSync(p: string, opts: any) { owned(p); fs.rmSync(p, opts); }, + rmSync(p: string, opts: any) { + owned(p); + try { fs.rmSync(p, opts); } catch (error) { removals.push(`${p}: ${error}`); throw error; } + if (fs.existsSync(p)) removals.push(`${p}: rmSync returned but the path survived`); + }, }; const args = { ROOT, fs: localFs, path, os: { tmpdir: () => scratch }, expect, CAPTURE_MS, CAPTURE_LONG_MS, OFFICE_HOURS_BUN_GRACE_MS, resolveEvalModel, runId: 'free-legacy-design', evalCollector: { addTest(entry: any) { - expect(dirs.every(dir => !fs.existsSync(dir))).toBe(true); + expect(dirs.every(dir => !fs.existsSync(dir)), survivors()).toBe(true); rows.push(entry); } }, runRecordedOfficeHoursAttempt: (options: Parameters[0]) => { @@ -134,7 +141,7 @@ async function exercise(mode: 'success' | 'max-turns' | 'first-timeout' | 'secon expect(callbacks).toHaveLength(1); expect(callbacks[0]!.timeout).toBe(CAPTURE_LONG_MS); try { await callbacks[0]!.fn(); } catch (error) { resultError = error; } expect(inputVerified).toBe(true); expect(dirs).toHaveLength(1); - expect(dirs.every(dir => !fs.existsSync(dir))).toBe(true); + expect(dirs.every(dir => !fs.existsSync(dir)), survivors()).toBe(true); expect(recordBudgets).toEqual([CAPTURE_LONG_MS - OFFICE_HOURS_BUN_GRACE_MS]); expect(sdkSignal?.aborted).toBe(true); return { resultError, rows, saved }; diff --git a/test/test-free-shards-git-maintenance.test.ts b/test/test-free-shards-git-maintenance.test.ts new file mode 100644 index 000000000..3eb4e9bc3 --- /dev/null +++ b/test/test-free-shards-git-maintenance.test.ts @@ -0,0 +1,106 @@ +/** + * The free runner's git auto-maintenance backstop: every shard child gets + * maintenance.auto=false and gc.auto=0 appended to its inherited GIT_CONFIG_* + * pairs, so a fixture commit cannot leave a detached `git maintenance run` + * creating and deleting .git/objects/maintenance.lock under a later listing, + * watch or removal. Fixtures that build their own git env set the keys + * themselves (docs/TESTING_INTERNALS.md#flake-ledger). + */ +import { afterEach, describe, expect, test } from 'bun:test'; +import * as fs from 'node:fs'; +import * as os from 'node:os'; +import * as path from 'node:path'; +import { spawnSync } from 'node:child_process'; +import { disableGitAutoMaintenance, runFreeShard } from '../scripts/test-free-shards'; + +const roots: string[] = []; +afterEach(() => { for (const root of roots.splice(0)) fs.rmSync(root, { recursive: true, force: true }); }); +const scratch = () => { + const root = fs.realpathSync(fs.mkdtempSync(path.join(os.tmpdir(), 'free-git-maintenance-'))); + roots.push(root); + return root; +}; +const gitConfigEnv = (env: NodeJS.ProcessEnv) => Object.fromEntries(Object.entries(env).filter(([key]) => key.startsWith('GIT_CONFIG_')).sort()); +const cleanGitEnv = (home: string): NodeJS.ProcessEnv => ({ + PATH: process.env.PATH ?? '', HOME: home, GIT_CONFIG_NOSYSTEM: '1', GIT_CONFIG_GLOBAL: path.join(home, 'no-global-gitconfig'), + ...(process.env.SystemRoot ? { SystemRoot: process.env.SystemRoot } : {}), +}); + +/** The GIT_CONFIG_* entries the real runFreeShard child received. */ +async function childGitConfig(env: NodeJS.ProcessEnv | undefined): Promise { + const out = path.join(scratch(), 'child-env.json'); + const probe = `require('fs').writeFileSync(${JSON.stringify(out)}, JSON.stringify(Object.fromEntries(Object.entries(process.env).filter(([k]) => k.startsWith('GIT_CONFIG_')))));` + + `console.log('Ran 1 tests across 1 files. [1.00ms]');`; + const outcome = await runFreeShard(['probe'], 1, 1, { env, quiet: true, log: () => {}, + commandFor: () => ({ command: process.execPath, args: ['-e', probe] }) }); + expect(outcome.status).toBe('passed'); + return gitConfigEnv(JSON.parse(fs.readFileSync(out, 'utf8'))); +} + +const OFF = { maintenance: ['maintenance.auto', 'false'], gc: ['gc.auto', '0'] } as const; +const appended = (start: number) => ({ + [`GIT_CONFIG_KEY_${start}`]: OFF.maintenance[0], [`GIT_CONFIG_VALUE_${start}`]: OFF.maintenance[1], + [`GIT_CONFIG_KEY_${start + 1}`]: OFF.gc[0], [`GIT_CONFIG_VALUE_${start + 1}`]: OFF.gc[1], +}); + +describe('free runner: git auto-maintenance off for every shard child', () => { + test('absent and zero inherited GIT_CONFIG_COUNT both start the pairs at index 0', async () => { + const home = scratch(); + expect(await childGitConfig(cleanGitEnv(home))).toEqual(gitConfigEnv({ ...cleanGitEnv(home), GIT_CONFIG_COUNT: '2', ...appended(0) })); + expect(await childGitConfig({ ...cleanGitEnv(home), GIT_CONFIG_COUNT: '0' })) + .toEqual(gitConfigEnv({ ...cleanGitEnv(home), GIT_CONFIG_COUNT: '2', ...appended(0) })); + }); + + test('a nonzero inherited count keeps its pairs and appends after them', async () => { + const env = { ...cleanGitEnv(scratch()), GIT_CONFIG_COUNT: '1', GIT_CONFIG_KEY_0: 'user.name', GIT_CONFIG_VALUE_0: 'Fixture' }; + expect(await childGitConfig(env)).toEqual(gitConfigEnv({ ...env, GIT_CONFIG_COUNT: '3', ...appended(1) })); + }); + + test('an explicit options.env and the default process.env are both covered, and neither caller object changes', async () => { + const env = { ...cleanGitEnv(scratch()), GIT_CONFIG_COUNT: '1', GIT_CONFIG_KEY_0: 'core.autocrlf', GIT_CONFIG_VALUE_0: 'false' }; + const envBefore = structuredClone(env); + const processBefore = gitConfigEnv(process.env); + await childGitConfig(env); + expect(env).toEqual(envBefore); + const inherited = Number(process.env.GIT_CONFIG_COUNT || '0'); + expect(await childGitConfig(undefined)).toEqual({ ...processBefore, GIT_CONFIG_COUNT: String(inherited + 2), ...appended(inherited) }); + expect(gitConfigEnv(process.env)).toEqual(processBefore); + }); + + test('a malformed inherited count is passed through untouched and git still rejects it', async () => { + const env = { ...cleanGitEnv(scratch()), GIT_CONFIG_COUNT: 'abc', GIT_CONFIG_KEY_0: 'user.name', GIT_CONFIG_VALUE_0: 'Fixture' }; + const child = await childGitConfig(env); + expect(child).toEqual(gitConfigEnv(env)); + const result = spawnSync('git', ['config', '--get', 'user.name'], { env: { ...env, ...child }, encoding: 'utf8', timeout: 10_000 }); + expect(result.status, result.stderr).not.toBe(0); + expect(result.stderr).toContain('GIT_CONFIG_COUNT'); + }); + + test('a traced commit in the runner child env starts no git maintenance run; the default env does', async () => { + const root = scratch(); + const base = cleanGitEnv(root); + const traced = (env: NodeJS.ProcessEnv, name: string) => { + const repo = path.join(root, name); + const git = (...args: string[]) => { + const result = spawnSync('git', args, { cwd: repo, env: { ...env, GIT_TRACE: '1' }, encoding: 'utf8', timeout: 10_000 }); + expect(result.status, result.stderr).toBe(0); + return result.stderr; + }; + fs.mkdirSync(repo); + git('init', '-q', '-b', 'main'); + git('config', 'user.email', 't@t'); git('config', 'user.name', 't'); git('config', 'commit.gpgsign', 'false'); + fs.writeFileSync(path.join(repo, 'a.txt'), 'a\n'); + git('add', 'a.txt'); + return git('commit', '-qm', 'traced').split('\n').filter(line => /maintenance run|gc --auto/.test(line)); + }; + expect(traced(base, 'defaults').length, 'control: the default env must show the auto-maintenance child').toBeGreaterThan(0); + const runnerEnv = { ...base, ...(await childGitConfig(base)) }; + expect(traced(runnerEnv, 'runner')).toEqual([]); + }); + + test('disableGitAutoMaintenance mutates only the env it is given', () => { + const env: NodeJS.ProcessEnv = { GIT_CONFIG_COUNT: ' 2 ', GIT_CONFIG_KEY_0: 'a.b', GIT_CONFIG_VALUE_0: '1', GIT_CONFIG_KEY_1: 'c.d', GIT_CONFIG_VALUE_1: '2' }; + disableGitAutoMaintenance(env); + expect(env).toEqual({ GIT_CONFIG_KEY_0: 'a.b', GIT_CONFIG_VALUE_0: '1', GIT_CONFIG_KEY_1: 'c.d', GIT_CONFIG_VALUE_1: '2', GIT_CONFIG_COUNT: '4', ...appended(2) }); + }); +}); diff --git a/test/test-health-report.test.ts b/test/test-health-report.test.ts index 98a5a3f3c..75970cef3 100644 --- a/test/test-health-report.test.ts +++ b/test/test-health-report.test.ts @@ -149,6 +149,10 @@ describe('enforced checks and the tracking issue (DX-9)', () => { const failing = unseededCheck(freeRoot(2, 6)); expect(failing).toMatchObject({ status: 'fail', detail: expect.stringContaining('stale seed: 6 unseeded file(s) > 5') }); expect(failing.fix).toContain('bun run test:ubicloud --record-durations'); + expect(failing.fix).toContain('UBICLOUD_API_KEY'); + expect(failing.fix).toContain('copies scripts/free-test-durations.json back into this checkout'); + expect(failing.fix).toContain('leave the refresh to a maintainer'); + expect(failing.fix).not.toContain('CI recording'); expect(unseededCheck(freeRoot(2, 5))).toMatchObject({ status: 'pass', detail: expect.stringContaining('5 unseeded file(s) (limit 5)') }); }); @@ -162,7 +166,8 @@ describe('enforced checks and the tracking issue (DX-9)', () => { }); describe('collectHealth over recorded fixture data', () => { - function fixture() { + function fixture(windowsRuns: unknown[] = [run(70, { event: 'pull_request', head_branch: 'feature' }), + run(71, { event: 'workflow_dispatch', run_started_at: day(2), updated_at: day(1) })]) { const prTrials = formatTrialOutcomes([trialRecord('gate-a', 'passed', { tier: 'gate', lane: 'gate/pr', cost_usd: 2.5 }), trialRecord('gate-b', 'passed', { tier: 'gate', lane: 'gate/pr', execution: 'reused', cost_usd: 0 })]); const census = formatTrialOutcomes([ @@ -184,7 +189,7 @@ describe('collectHealth over recorded fixture data', () => { [/workflows\/free-tests\.yml\/runs/, () => ({ workflow_runs: [run(60), run(61, { conclusion: 'failure' })] })], [/runs\/60\/artifacts/, () => ({ artifacts: [{ id: 61, name: 'flake-ledger-2', size_in_bytes: 10 }] })], [/runs\/61\/artifacts/, () => ({ artifacts: [] })], - [/workflows\/windows-free-tests\.yml\/runs/, () => ({ workflow_runs: [run(70)] })], + [/workflows\/windows-free-tests\.yml\/runs/, () => ({ workflow_runs: windowsRuns })], ], { 11: { 'manifest.json': JSON.stringify({ prCoverage: { mode: 'full-fallback' } }) }, 12: { 'trial-outcomes.jsonl': prTrials }, @@ -207,7 +212,7 @@ describe('collectHealth over recorded fixture data', () => { expect(value('census-redispatch').value).toBe('0 of 1 census(es) re-dispatched; longest paid slice job 20.0 min'); expect(value('quarantine-evidence').value).toContain('insufficient evidence (not the same as healthy)'); expect(value('free-flaky-pass-rate').value).toStartWith('50.0% (1/2 main runs'); - expect(value('free-wall').value).toBe('free-tests 0.0 min (1 runs); windows-free-tests 0.0 min (1 runs)'); + expect(value('free-wall').value).toBe('free-tests 0.0 min (1 runs); windows-free-tests (successful PR runs) 0.0 min (1 runs)'); expect(value('free-serial').value).toBe('3 s over 3 files'); for (const entry of report.metrics.filter(entry => entry.id !== 'net-complexity')) { expect(entry.rule.length).toBeGreaterThan(10); @@ -218,6 +223,18 @@ describe('collectHealth over recorded fixture data', () => { expect(formatHealth(report)).toContain('rule: share of evals.yml pull_request runs'); }); + test('the Windows wall counts only successful pull_request runs and says so when there are none', () => { + const wall = (windowsRuns: unknown[]) => collectHealth({ client: fixture(windowsRuns), repo: 'o/r', now: NOW, sinceDays: 7, cacheDir: tmp('health-cache-'), root: freeRoot(3, 0) }) + .metrics.find(entry => entry.id === 'free-wall')!; + const pr = (id: number, minutes: number, extra: Record = {}) => run(id, { event: 'pull_request', head_branch: `pr-${id}`, + run_started_at: day(1), updated_at: new Date(Date.parse(day(1)) + minutes * 60_000).toISOString(), ...extra }); + expect(wall([pr(70, 6), pr(71, 7), pr(74, 8), pr(72, 30, { conclusion: 'failure' }), run(73, { event: 'workflow_dispatch', run_started_at: day(3), updated_at: day(1) })]).value) + .toBe('free-tests 0.0 min (1 runs); windows-free-tests (successful PR runs) 7.0 min (3 runs)'); + expect(wall([run(73, { event: 'workflow_dispatch', run_started_at: day(3), updated_at: day(1) })]).value) + .toBe('free-tests 0.0 min (1 runs); windows-free-tests (successful PR runs) no successful PR runs in window'); + expect(wall([]).rule).toContain('workflow_dispatch duration recordings excluded'); + }); + test('a rate-limited API degrades every remote metric to a named unavailable reason, never 0, and keeps the issue open', () => { const client = fakeClient([[/./, () => { throw new Error('gh api failed: HTTP 403: API rate limit exceeded for installation ID 1'); }]]); const report = collectHealth({ client, repo: 'o/r', now: NOW, sinceDays: 7, cacheDir: tmp('health-cache-'), root: freeRoot(3, 0) }); diff --git a/test/timeline.test.ts b/test/timeline.test.ts index eb4303cc4..d08c058a6 100644 --- a/test/timeline.test.ts +++ b/test/timeline.test.ts @@ -222,4 +222,64 @@ describe('gstack-timeline-read', () => { }); } } + + // --since/--branch used to read an unbound $2 (exit 1), and an unparseable + // --since silently returned unfiltered history. + const badFilters: Array<[string, string[], string]> = [ + ['--since missing value', ['--since'], '--since must be a relative time like "7 days ago" (got no value)'], + ['--since empty value', ['--since', ''], '--since must be a relative time like "7 days ago" (got an empty value)'], + ['--since followed by a flag', ['--since', '--limit', '5'], "(got flag '--limit')"], + ['--since yesterday', ['--since', 'yesterday'], "--since must be a relative time like \"7 days ago\" (got 'yesterday')"], + ['--since 2 weeks', ['--since', '2 weeks'], "(got '2 weeks')"], + ['--since 7days', ['--since', '7days'], "(got '7days')"], + ['--since impossible month', ['--since', '2026-13-01'], "(got '2026-13-01')"], + ['--since unanchored', ['--since', 'about 7 days ago, roughly'], "(got 'about 7 days ago, roughly')"], + ['--branch missing value', ['--branch'], '--branch must be a branch name (got no value)'], + ['--branch empty value', ['--branch', ''], '--branch must be a branch name (got an empty value)'], + ['--branch followed by a flag', ['--branch', '--limit', '5'], "--branch must be a branch name (got flag '--limit')"], + ['unknown flag', ['--bogus'], "unknown argument '--bogus'"], + ['stray argument', ['stray'], "unknown argument 'stray'"], + ]; + for (const history of ['empty', 'populated'] as const) { + for (const [label, args, message] of badFilters) { + test(`${label} exits 2 before any read on ${history} history`, () => { + if (history === 'populated') { + runLog(JSON.stringify({ skill: 'review', event: 'completed', branch: 'main', ts: '2026-03-28T10:00:00Z' })); + } + const result = runReadStatus(args); + expect(result.status, result.stderr).toBe(2); + expect(result.stdout).toBe(''); + expect(result.stderr).toContain(message); + if (label.startsWith('--since')) expect(result.stderr).toContain('accepted: " minute|hour|day|week|month[s] ago", "h|d|w", or an ISO date'); + if (label === 'unknown flag' || label === 'stray argument') expect(result.stderr).toContain('Usage: gstack-timeline-read'); + }); + } + + test(`--help prints the usage line and exits 0 on ${history} history`, () => { + if (history === 'populated') { + runLog(JSON.stringify({ skill: 'review', event: 'completed', branch: 'main', ts: '2026-03-28T10:00:00Z' })); + } + const result = runReadStatus(['--help']); + expect(result.status).toBe(0); + expect(result.stdout.trim()).toBe('Usage: gstack-timeline-read [--since "7 days ago"|7d|YYYY-MM-DD] [--limit N] [--branch NAME]'); + }); + + const yesterday = new Date(Date.now() - 86_400_000).toISOString().slice(0, 10); + for (const since of ['7 days ago', '3 Hours ago', '7d', '24h', '1w', yesterday, `${yesterday}T00:00:00Z`]) { + test(`--since '${since}' keeps recent events and drops old ones on ${history} history`, () => { + if (history === 'populated') { + runLog(JSON.stringify({ skill: 'review', event: 'completed', branch: 'main', ts: '2020-01-01T10:00:00Z' })); + runLog(JSON.stringify({ skill: 'ship', event: 'completed', branch: 'main', ts: new Date(Date.now() - 3_600_000).toISOString() })); + } + const result = runReadStatus(['--since', since]); + expect(result.status, result.stderr).toBe(0); + expect(result.stderr).toBe(''); + if (history === 'empty') expect(result.stdout).toBe(''); + else { + expect(result.stdout).toContain('/ship completed'); + expect(result.stdout).not.toContain('/review completed'); + } + }); + } + } });