Skip to content

Commit dd1c5a4

Browse files
committed
Restore eval CLI coverage and drop the content-pin lint rule
Unique CLI and web-brand contracts were deleted because they sat outside the suite path list. Membership owns that, not deletion. AGENTS.md owns the behavioral bar; an error-level shape-match lint rule does not. test:paths now requires paths so a zero-arg run cannot scan vendor/.
1 parent 7585f3c commit dd1c5a4

16 files changed

Lines changed: 480 additions & 434 deletions

‎.github/workflows/ci.yml‎

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,10 @@ jobs:
3131
uses: actions/cache@v4
3232
with:
3333
path: node_modules
34-
# The exact key keeps hits honest: only a cache built from this
35-
# bun.lock restores. restore-keys falls back to the newest cache
36-
# when the lockfile changed, so a dependency bump reinstalls the
37-
# delta instead of cold-installing on every job at once. bun
38-
# install --frozen-lockfile reconciles a stale tree to the new
39-
# lockfile, so a partial hit never leaves wrong deps behind.
34+
# Exact-key-only: a restore-keys prefix of bun- would hydrate
35+
# node_modules from a different lockfile. bun install then has to
36+
# reconcile a stale tree; missing that step leaves wrong deps.
4037
key: bun-${{ hashFiles('bun.lock') }}
41-
restore-keys: |
42-
bun-
4338

4439
- name: Install dependencies
4540
run: bun install --frozen-lockfile
@@ -77,8 +72,6 @@ jobs:
7772
with:
7873
path: node_modules
7974
key: bun-${{ hashFiles('bun.lock') }}
80-
restore-keys: |
81-
bun-
8275

8376
- name: Install dependencies
8477
run: bun install --frozen-lockfile
@@ -89,7 +82,7 @@ jobs:
8982
# The suite is sharded so the slowest slice, not the whole suite, sets the
9083
# wall clock. Every shard still goes through check:projects-dir-guard: the
9184
# guard forwards these path filters to the suite it wraps, and the union of
92-
# the shards' filters is exactly ./src ./tests ./evals, so the gate covers
85+
# the shards' filters is exactly ./src ./tests ./evals ./scripts, so the gate covers
9386
# the same tests as before, all of them sandboxed.
9487
test:
9588
runs-on: ubuntu-latest
@@ -100,8 +93,8 @@ jobs:
10093
shard:
10194
- name: src
10295
paths: ./src
103-
- name: tests-and-evals
104-
paths: ./tests ./evals
96+
- name: tests-evals-and-scripts
97+
paths: ./tests ./evals ./scripts
10598
name: test (${{ matrix.shard.name }})
10699
steps:
107100
- name: Checkout
@@ -127,8 +120,6 @@ jobs:
127120
with:
128121
path: node_modules
129122
key: bun-${{ hashFiles('bun.lock') }}
130-
restore-keys: |
131-
bun-
132123

133124
- name: Install dependencies
134125
run: bun install --frozen-lockfile

‎AGENTS.md‎

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ When refactoring replaces an old path, delete the old one. No back-compat shims,
3333
- Add or update tests with every behavior change.
3434
- Bug fixes start with a failing test that reproduces the bug. Do not start by patching.
3535
- `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 --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.
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.
3737
- 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. An eslint rule (`no-restricted-syntax` in `eslint.config.js`) rejects bare `mock.module` calls in `*.test.ts` files.
38-
- 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. An eslint rule (`corbits/no-content-pin-tests`, defined in `scripts/eslint-rules/no-content-pin-tests.ts`) rejects the known shapes in `*.test.ts` files; it is a heuristic shape match, not a semantic check, and its header documents what it does not catch.
38+
- 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 an eslint shape match.
3939

4040
## Build & Validation
4141

@@ -49,10 +49,15 @@ the projects-dir sandbox guard — in that order, matching CI.
4949

5050
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.
5151

52-
`bun run test` runs `bun test ./src ./tests ./evals --randomize --seed 424242` —
53-
the same suite CI runs. A bare `bun test` also
54-
scans `vendor/`, adding hundreds of unrelated results and making pass/fail
55-
counts meaningless to compare across branches — always use `bun run test`.
52+
`bun run test` runs `bun test ./src ./tests ./evals ./scripts --randomize --seed 424242`
53+
as a single process. CI shards the same path union via `test:paths`
54+
(`.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
56+
locally in the one-process suite but not in a CI shard (CL-6967). A bare
57+
`bun test` also scans `vendor/`, adding hundreds of unrelated results and
58+
making pass/fail counts meaningless to compare across branches — always use
59+
`bun run test`. `test:paths` with no path filters refuses to run for the
60+
same reason.
5661

5762
## Commits, pull requests, and issue tracking
5863

‎CONTRIBUTING.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ bun run build
3030
bun run test
3131
```
3232

33-
These match the CI workflow in `.github/workflows/ci.yml`. Run `bun run check`
33+
These match the local development loop. CI shards the same path union via
34+
`test:paths` rather than running the one-process `bun run test` suite.
35+
Run `bun run check`
3436
(lint, typecheck, build, and the guarded test suite) before opening a PR —
3537
`bun run test` alone skips the projects-dir sandbox guard, which only runs
3638
under `bun run check` and CI. Do

‎eslint.config.js‎

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import js from "@eslint/js";
22
import tseslint from "typescript-eslint";
3-
import noContentPinTests from "./scripts/eslint-rules/no-content-pin-tests.ts";
43

54
export default tseslint.config(
65
{
@@ -78,17 +77,4 @@ export default tseslint.config(
7877
],
7978
},
8079
},
81-
{
82-
// Content-pin tests — assertions that pin literal document wording, brand
83-
// hex values, or palette indexes — fail on copy/design edits and catch no
84-
// behavior regression. The rule is a heuristic shape match; see its header
85-
// for what it covers and what it deliberately does not.
86-
files: ["**/*.test.ts"],
87-
plugins: {
88-
corbits: { rules: { "no-content-pin-tests": noContentPinTests } },
89-
},
90-
rules: {
91-
"corbits/no-content-pin-tests": "error",
92-
},
93-
},
9480
);

‎package.json‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
"build": "bun build ./src/index.ts --outdir ./dist --target bun --external '@opentui/core-*' && bun scripts/copy-repo-plugins.ts",
3333
"build:bin": "bun build ./src/index.ts --compile --minify --define process.env.NODE_ENV='\"production\"' --outfile ./dist/corbits && bun scripts/copy-repo-plugins.ts",
3434
"typecheck": "tsc --noEmit",
35-
"test": "bun test ./src ./tests ./evals --randomize --seed 424242",
36-
"test:paths": "bun test --randomize --seed 424242",
35+
"test": "bun test ./src ./tests ./evals ./scripts --randomize --seed 424242",
36+
"test:paths": "bun scripts/test-paths.ts",
3737
"lint": "prettier --check --cache . && eslint --cache .",
3838
"check:projects-dir-guard": "bun scripts/guard-real-projects-dir.ts",
3939
"check": "bun run lint && bun run typecheck && bun run build && bun run check:projects-dir-guard",

‎scripts/eslint-rules/no-content-pin-tests.ts‎

Lines changed: 0 additions & 219 deletions
This file was deleted.

0 commit comments

Comments
 (0)