You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 065075f
Browse filesBrowse the repository at this point in the historyBrowse files
test: add scripted-inference e2e layer and slim the unit suite (#1221)
* fix(session): classify persisted tool calls by engine name
Persisted tool_call blocks keep the wire name the model emitted
(read, glob, bash), but the compactor's replay/supersession index
and the subagent thrash tracker classify against engine-keyed sets
(read_file, search_files). After the one-wire migration that left
read supersession and thrash bookkeeping dead for the advertised
tools; route stored names through canonicalToolName before
classification.
* test(e2e): add scenario harness over the integration session
The e2e layer wraps the existing agent-loop harness (live tool
dispatch, chat director, posix tools, git-backed context store)
with fixture-repo seeding and a sendOperatorTurn driver that
surfaces terminal failures instead of asserting a reply. The
integration session gains the seams scenarios need: fleet
passthroughs, retry-policy and scheduler overrides, alternate
inference sources plus credential records, and access to the live
chat director. The toolset forwards the fleet's documented
retry-timing overrides to spawned runs.
* test(e2e): migrate orchestration suites and prune weak pins
Three orchestration scenarios now run through the real agent loop
on scripted inference: compaction read-paging (the wire-name
coverage that exposed the engine-name classification bug),
recoverable subagent failure (failed lane reports continuable
through wait_agents), and credential recovery (oauth refresh,
retry, terminal 401, accepted backup serves the replayed prompt).
The bespoke unit versions are deleted where the e2e covers the
same contract; constant-equal-literal tool-alias pins and a
decisions-diagnostics-only tail test are dropped for asserting
the same thing behavior already proves. AGENTS.md documents the
split and the v1 non-goals.
* test(subagent): pin wire-name classification in thrash tracking
The engine-name fix for persisted calls had no fixture proving
wire names reach the same evidence keys — regression coverage for
the read/search/mutation path that silently went dark after the
one-wire migration.
* test(e2e): harden collector teardown and per-test budgets
A stream error in the background collector would surface as an
unhandled rejection in the shared test process; the catch mirrors
runUntilSuspended. Explicit timeouts replace the 5s bun:test
default so a loaded CI worker fails a genuinely stuck scenario
rather than flaking at the default.
* refactor: drop write-only telemetry and consumer-less exports
* test: prune weak pins and collapse duplicate scaffolding
Cuts ~10.6k lines of co-located unit tests (~7%) plus ~1.4k of
assertion-level copy/literal/diagnostic pins, and folds ~3.4k lines of
copy-pasted arrange scaffolding into file-local helpers with zero
assertion loss. Moves the ask_director handshake and outer-retry
recovery scenarios into tests/e2e driven through the real agent loop.
* test: co-locate unit tests and lift e2e to the repo root
* test: prune low-value suites and extract shared fixtures
* test: extract shared harnesses and collapse remaining clone groups
* test: table-drive repeated cases and collapse module scaffolding
* test(permission): collapse clustered-option classification to one wiring smoke
* refactor(tui): drop dead index-based operatorResultFromSelection
* test(tui): drop wave6 palette re-runs covered by palette-paint and slash-popup-gate
* test(tui): drop sequential-operator paint re-run covered by gate-wire
* test(director): consolidate the split director suites into the co-located file
* test(director): drop the two recovery cases the merged file already pins
* test: drop a dead status assertion and prose-copy pins the flags already pin
* test(tui): table-drive the immediate-remove plugin origins
* test(e2e): table-drive the tool_search promotion schema matrix
* test(config): table-drive the skip-permissions precedence matrix
* test(session): drop the straggler-write re-run; state.test pins the fence
* test: table-drive exec status truth table and share the Codex limit body
* style: format touched test files
* test: replace personal identifiers with generic acme/alice examples
* docs: use generic acme/alice examples in provider and path comments
* test(agent): share one connectMCPServer mock kit across the two mcp fixture files
* test(mcp): extract the shared SDK mock kit and collapse the auth episode loops
* test(session): merge the duplicated approval-resume fixtures into one harness
* test(compaction): table-drive the handoff-arming and verify-pass cases
* test(subagent): share envelope fixtures and collapse repeated scaffolds
* test(config): extract shared settings-write and loadFor fixture helpers
* style: format worker-touched test files and drop an unused mock parameter
* refactor(testkit): move shared test helpers to the repo root
* test(e2e): pin the recoverable-failure successor round trip
Copy file name to clipboardExpand all lines: AGENTS.md
+7-5Lines changed: 7 additions & 5 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -32,9 +32,11 @@ When refactoring replaces an old path, delete the old one. No back-compat shims,
32
32
33
33
- Add or update tests with every behavior change.
34
34
- Bug fixes start with a failing test that reproduces the bug. Do not start by patching.
35
-
-`tests/unit/` shared unit tests and helpers · co-located `src/**/*.test.ts` for module logic · `tests/fixtures/` fixture repos · `tests/integration/` reactor/permission harness. Planned: `tests/e2e/` (fixture-repo runs).
36
-
- A test must not depend on another file having run, or on the default file order. It must pass under `bun test ./src ./tests ./evals ./scripts --randomize`. If a test mutates module-level state or calls `mock.module`, it must restore that state itself (`afterEach`/`afterAll`), not rely on the process happening to reset it. When capturing a module's real exports to restore later, shallow-copy them (`{ ...moduleNamespace }`) at capture time, whether the namespace came from `await import(path)` or a static `import * as ns from "path"` — Bun mutates the live namespace object in place when the module is mocked, so holding a bare reference to it (either form) silently turns into the mocked exports.
37
-
- Never call `mock.module` directly. Bun runs every test file in one process, so a `mock.module` call without its own teardown stays installed for the rest of the run and silently replaces the real module for other files — producing failures in files the change never touched, with no obvious link to the cause and no signal from `tsc` or a per-file run (CL-6967). Use `withMockedModule`/`withMockedModuleDuring` from `tests/helpers/mock-module.ts`, which capture the real module and register their own restore. The oxlint plugin (`corbits/no-bare-mock-module` in `.oxlintrc.json` / `scripts/oxlint-plugin-corbits.js`) rejects bare `mock.module` calls in `*.test.ts` files.
35
+
- Co-located `src/**/*.test.ts` for module logic · `testkit/` shared test helpers (repo root, shared by unit and e2e) · `fixtures/` fixture repos · `e2e/` scenario runs over the production agent loop (fixture-repo seeding, scripted inference via `@intx/inference-testing`, `runUntilDone`/`runUntilSuspended`/`sendOperatorTurn` drivers — see `e2e/harness.ts`; the session plumbing lives in `e2e/integration-harness.ts`).
36
+
- Unit vs e2e split: keep parser tables, race/atomicity tests, and small pure-function contracts co-located unit tests; put multi-step agent-loop orchestration (permission flows, compaction end-to-end, subagent lanes, credential recovery) in `e2e/` where a scripted model reply replaces pages of per-file fakes. Do not pin constants or `record.decisions` diagnostics — assert the behavior the contract exposes.
37
+
- e2e v1 non-goals: TUI overlay/PTY driving, race tests, parser tables, crash-atomicity, and any second agent-loop stack — the integration harness already is one.
38
+
- A test must not depend on another file having run, or on the default file order. It must pass under `bun test ./src ./e2e ./evals ./scripts --randomize`. If a test mutates module-level state or calls `mock.module`, it must restore that state itself (`afterEach`/`afterAll`), not rely on the process happening to reset it. When capturing a module's real exports to restore later, shallow-copy them (`{ ...moduleNamespace }`) at capture time, whether the namespace came from `await import(path)` or a static `import * as ns from "path"` — Bun mutates the live namespace object in place when the module is mocked, so holding a bare reference to it (either form) silently turns into the mocked exports.
39
+
- Never call `mock.module` directly. Bun runs every test file in one process, so a `mock.module` call without its own teardown stays installed for the rest of the run and silently replaces the real module for other files — producing failures in files the change never touched, with no obvious link to the cause and no signal from `tsc` or a per-file run (CL-6967). Use `withMockedModule`/`withMockedModuleDuring` from `testkit/mock-module.ts`, which capture the real module and register their own restore. The oxlint plugin (`corbits/no-bare-mock-module` in `.oxlintrc.json` / `scripts/oxlint-plugin-corbits.js`) rejects bare `mock.module` calls in `*.test.ts` files.
38
40
- A test earns its place only if a real behavior change can fail it. Document copy, brand colors, marketing assets, and splash text are not behavior: assertions that pin an asset's literal wording, an exact palette hex/ANSI value, or rendered copy fail on copy/design edits and catch no regressions — assert the contract instead (parsing, formatting, ranges, aliases, invariants). Tests are code too: pinning a source file's own text is the same trap. This bar is a review and authorship rule, not a linter shape match.
39
41
40
42
## Build & Validation
@@ -49,10 +51,10 @@ the projects-dir sandbox guard — in that order, matching CI.
49
51
50
52
Run the full suite before declaring any task complete. Do not substitute individual targets. If a failure is pre-existing and unrelated to your change, say so explicitly.
51
53
52
-
`bun run test` runs `bun test ./src ./tests ./evals ./scripts --randomize --seed 424242`
54
+
`bun run test` runs `bun test ./src ./e2e ./evals ./scripts --randomize --seed 424242`
53
55
as a single process. CI shards the same path union via `test:paths`
54
56
(`.github/workflows/ci.yml`) for wall clock. Path-union is not the same
55
-
isolation domain: a `mock.module` leak across `./src` vs `./tests` fails
57
+
isolation domain: a `mock.module` leak across `./src` vs `./e2e` fails
56
58
locally in the one-process suite but not in a CI shard (CL-6967). A bare
57
59
`bun test` also scans `vendor/`, adding hundreds of unrelated results and
58
60
making pass/fail counts meaningless to compare across branches — always use
renderer.ts Event-stream renderer (stderr + live cost; used by tests/utilities)
77
+
renderer.ts Event-stream renderer (stderr + live cost; used by tests and utilities)
78
78
session/
79
79
index.ts Session lifecycle
80
80
state.ts RunState JSON save/load
@@ -523,7 +523,7 @@ See `docs/PLUGINS.md` for the full design. Summary:
523
523
524
524
## Hardening wave — deferred and upstream-owned items
525
525
526
-
Corbits Code v0.3 memory and stall hardening is implemented under `src/`, `tests/`, and `scripts/` only. The `vendor/` tree is out of scope for that wave (`scripts/verify-corbits-only-scope.sh` enforces this on landing branches). The items below were **not** closed in Corbits Code because they do not apply to the default CLI/TUI path or require upstream Interchange packages.
526
+
Corbits Code v0.3 memory and stall hardening is implemented under `src/`, `e2e/`, and `scripts/` only. The `vendor/` tree is out of scope for that wave (`scripts/verify-corbits-only-scope.sh` enforces this on landing branches). The items below were **not** closed in Corbits Code because they do not apply to the default CLI/TUI path or require upstream Interchange packages.
527
527
528
528
### Child-supervisor IPC awaiter deadlines
529
529
@@ -560,12 +560,11 @@ Run all three before declaring work complete.
560
560
561
561
## Testing
562
562
563
-
-**Unit tests** are co-located with source as `*.test.ts` (e.g. `config.test.ts`, `director.test.ts`, `prompts.test.ts`, `renderer.test.ts`, `permission/permission.test.ts`, each `plugins/*.test.ts`, and TUI tests under `tui/`).
564
-
-**`tests/unit/`** holds shared unit helpers and focused packages (e.g. TUI geometry tests).
565
-
-**`tests/fixtures/`** holds fixture repos and comparison assets (e.g. `demo-comparison/`, `multi-file-service/`).
566
-
-**`tests/integration/`** holds the reactor permission / multi-turn harness (scripted models via `@intx/inference-testing`). **`tests/e2e/`** (fixture-repo runs) is still planned. Until e2e exists, broader harness coverage also lives in co-located `*.test.ts` files and `tests/unit/`.
563
+
-**Unit tests** are co-located with source as `*.test.ts` (e.g. `config.test.ts`, `director.test.ts`, `prompts.test.ts`, `renderer.test.ts`, `permission/permission.test.ts`, each `plugins/*.test.ts`, and TUI tests under `tui/`). Shared test helpers live in `testkit/` (repo root, shared by unit and e2e).
564
+
-**`fixtures/`** holds fixture repos and comparison assets (e.g. `demo-comparison/`, `multi-file-service/`).
565
+
-**`e2e/`** holds scenario tests driven over the production agent loop with scripted models (`@intx/inference-testing`) — fixture-repo seeding, `runUntilDone`/`runUntilSuspended`/`sendOperatorTurn` drivers (see `e2e/harness.ts`), and the reactor permission / multi-turn exercises formerly under `tests/integration/`.
567
566
-**Capability evals** (`evals/capability/`) are **not** the integration harness: they drive the product path (`corbits exec` / `runExec`) with real models against fixture copies and objective `verify.sh` graders. Case format + loader tests live under `evals/capability/`; run with `bun run eval:capability` (see `evals/capability/README.md`). Use `--baseline` to detect improve/regress across models or commits.
568
-
-**TUI tests** are co-located `*.test.ts` files under `src/tui/` (e.g. `shell.test.ts`, `runner-host.test.ts`, `stream.test.ts`), run as part of `bun test` along with everything else; there is no separate `test:tui` script or test-setup preload.
567
+
-**TUI tests** are co-located `*.test.ts` files under `src/tui/` (e.g. `shell.test.ts`, `runner-host.test.ts`, `stream.test.ts`), run as part of `bun test` along with everything else; there is no separate `test:tui` script. `bunfig.toml` preloads `testkit/preload.ts` for every test file, which strips ambient env (`COLORTERM`, `CORBITS_*`, telemetry) and hard-fails when `rg` is absent.
569
568
-**Parallel local runs** — `bun run test:parallel [N]` (default 4 workers) runs the same seeded suite with `--parallel=N`, wrapped in an output-stall watchdog (`scripts/test-parallel.ts`). Bun 1.4.x intermittently livelocks under `--parallel` (one worker spins at 100 % CPU holding a zombie git child while the main process idles; no output, no summary — upstream oven-sh/bun#36235), and `bun test` has no run-level timeout, so a stalled run hangs forever. The watchdog kills the suite's own process group after 90 s of silence and retries up to 3 times; a child that exits on its own (pass or fail) is never retried. CI keeps sharded sequential runs (`test:paths`) and does not use `--parallel`.
0 commit comments