.omo/rules/test-discipline.md
Every test in this repo MUST pass bun test in one process, in one go - no isolation flags, no retries, no special ordering. That is the gate. A test that needs --only, its own process, or a specific run order to pass is BROKEN. Fix the test; do not pamper it.
A test that passes 9 of 10 times is failing 10% of the time. Not "occasional." BROKEN.
FORBIDDEN in test bodies unless time itself is the system under test (Date.now, real timers, debounce/throttle windows):
setTimeout(resolve, N) / await new Promise(r => setTimeout(r, N)) / await sleep(N)The replacement: subscribe BEFORE the trigger, await the signal with an explicit timeout.
When code under test emits an event, fires a callback, or resolves a promise:
"waited 5s for event 'X', never fired"). NEVER silently retry, NEVER fall through.Tests must work under arbitrary parallel ordering in a single bun test run, no matter how many mocks are involved.
FORBIDDEN:
.only / .skip to mask a flaky testscript/run-ci-tests.ts already auto-isolates files that use mock.module() - DO NOT add to that list to cover up a real cross-test bugdescribe / it blocks to mask cross-test contaminationCross-test contamination = state leak. Find the leak. Reset in beforeEach, add the reset to test-setup.ts if it is shared, or mock at the module boundary (mock.module) instead of mutating globals other tests will read.
When testing code that builds an LLM prompt, DO NOT pin the current wording.
BANNED - these tests guard a diff, not behavior:
expect(prompt).toContain("You are Sisyphus")
expect(prompt).toMatchSnapshot()
expect(prompt).toBe(EXPECTED_PROMPT)
The wording changes next sprint, the test fails, and the next engineer edits the assertion to match the new text without understanding what the test was guarding. The test guarded nothing.
REQUIRED - assert the structural invariant the prompt logic enforces:
teamMode.enabled === true, the prompt MUST mention team_send_message" -> test the conditional branchverbose === false, the prompt MUST NOT include the debug directive" -> test the negative branchTest what would break the behavior. Never test what would only break a diff.