Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions .claude/skills/pr-review/rubric.md
Original file line number Diff line number Diff line change
Expand Up @@ -397,8 +397,11 @@ execution, never an impression.
- The review must cite the **Harness Execution** job's result for this PR (`node
tools/test-tools.mjs` + `node .claude/hooks/test-hooks.mjs`). A red job is **Critical**; a
job that never ran on a diff in scope is **High** (the evidence is missing, not clean).
- A new or changed script under `tools/` with no matching coverage in `tools/test-tools.mjs`
is **High**: it merges unexecuted, and the next tool inherits the same hole.
- A new or changed script under `tools/` with no matching coverage is **High**: it merges
unexecuted, and the next tool inherits the same hole. Coverage is that tool's own case
module at `tools/__tests__/<tool>.mjs` plus its row in `tools/test-tools.mjs`, the runner
that injects `TOOLS_DIR` and loads every module; a case key naming no real script fails
the runner by name rather than being skipped.
- **"Verified" without an execution is itself a finding** (**High**). A claim that a tool,
hook, skill, or agent works - in the PR body, a code comment, or the review - must trace to
a command that ran and its output. Reading the diff is not verification.
Expand Down
4 changes: 2 additions & 2 deletions tools/CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ The pattern, as implemented by `surface-manifest.mjs` + `redesign-coverage.mjs`:

## The gate

`test-tools.mjs` is the executable half of this document, and it is the reason a broken tool cannot be read, approved and merged: the CI reviewer reads the diff, this runs the code. It proves, per script, that `--help` exits `0` with usage on stdout and that invalid input is refused before the tool does any work, then exercises each tool's real decision paths with orca stubbed and every side effect staged in a temp dir. It also enumerates `tools/*.{mjs,sh,ps1}` and fails on any script with no coverage entry, so tool N+1 cannot land uncovered.
`test-tools.mjs` is the executable half of this document, and it is the reason a broken tool cannot be read, approved and merged: the CI reviewer reads the diff, this runs the code. It is a thin runner: it resolves `TOOLS_DIR` once from its own location, injects it into the shared prelude at `__tests__/_harness.mjs`, and loads one case module per tool from `__tests__/<tool>.mjs`, so a case body never re-derives its own directory. It proves, per script, that `--help` exits `0` with usage on stdout and that invalid input is refused before the tool does any work, then exercises each tool's real decision paths with orca stubbed and every side effect staged in a temp dir. It also enumerates `tools/*.{mjs,sh,ps1}` and fails on any script with no coverage entry, so tool N+1 cannot land uncovered, and fails naming any registered case key that matches no real script, so a renamed or deleted tool cannot silently drop its cases.

A new tool therefore lands with its coverage entry in the same PR: an `INVALID_INPUT` row (the argv that must be refused, and the exit code), plus a `gateCases` entry when the tool has decision paths worth driving. Keep the cases hermetic: no network, no worktree, no Linear, no writes outside the suite's temp root.
A new tool therefore lands with its coverage in the same PR: an `INVALID_INPUT` row in the runner (the argv that must be refused, and the exit code), plus, when the tool has decision paths worth driving, a `__tests__/<tool>.mjs` module exporting its cases and a `CASE_MODULES` row registering it. Import every helper from `__tests__/_harness.mjs` rather than copying one into a second module, and keep the cases hermetic: no network, no worktree, no Linear, no writes outside the suite's temp root.

## Adding one

Expand Down
10 changes: 9 additions & 1 deletion tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ Read `CONVENTIONS.md` before adding one. Use the `/make-tool` skill to scaffold
| `check-tier-labels.mjs` | Fails closed unless the under-30-day committed Linear team-label snapshot contains every `tier:<name>` selector implied by non-default worker model tiers in `.claude/orchestrator.json`. Reports the expected, snapshotted, and missing label inventory without requiring CI network access. | `node tools/check-tier-labels.mjs` (`--help`) |
| `refresh-tier-labels.mjs` | Reads the configured Linear team's live labels through Orca and atomically rewrites `.claude/linear-team-labels.json` with a canonical timestamped inventory for `check-tier-labels.mjs`. | `node tools/refresh-tier-labels.mjs` (`--help`) |
| `check-push-target.mjs` | The lefthook `pre-push` guard: reads git's pre-push stdin and rejects a push whose remote ref is a protected branch. | `node tools/check-push-target.mjs < <pre-push stdin>` |
| `test-tools.mjs` | The harness execution gate: runs every script in this directory and asserts the `CONVENTIONS.md` CLI contract plus each tool's real decision paths, with orca stubbed and every side effect staged in a temp dir. Fails when a script here has no coverage entry. Backs the Harness Execution CI job. | `node tools/test-tools.mjs` |
| `test-tools.mjs` | The harness execution gate, and a thin runner: it resolves `TOOLS_DIR` once, injects it into `__tests__/_harness.mjs`, and loads one case module per tool. Runs every script in this directory and asserts the `CONVENTIONS.md` CLI contract plus each tool's real decision paths, with orca stubbed and every side effect staged in a temp dir. Fails when a script here has no coverage entry, and when a registered case key matches no real script. Backs the Harness Execution CI job. | `node tools/test-tools.mjs` |
Comment thread
thomasluizon marked this conversation as resolved.
| `__tests__/` | Not tools, the harness case modules `test-tools.mjs` loads: `_harness.mjs` holds the shared prelude (reporter, temp root, `run`/`check`, the orca and gh stubs, the staging helpers) and every other file holds one tool's decision-path cases. No file here is a lockstep twin and none is invoked directly. | imported by `tools/test-tools.mjs`, never invoked |
| `check-ticket.mjs` | Validates a Linear ticket body against the ticket template (D2); rejects an incomplete ticket rather than letting a worker guess. | `node tools/check-ticket.mjs --help` |
| `preflight.mjs` | Fast, fail-loud environment gate for autonomous runs: prints a PASS/FAIL table for the selected worker invocation, GitHub CLI installation and authentication, Orca reachability, target repo branch and cleanliness, repo defaults, and every repeated ticket-specific `--require <cli>`. Reports remedies and exits non-zero without repairing any failure. | `node tools/preflight.mjs --repo <ui\|api\|landing> [--base-branch <ref>] [--require <cli> ...]` (`--json`, `--help`) |
| `new-ticket.mjs` | Thin wrapper over `orca linear create` that validates the issue it just created, using the identifier orca REPORTED rather than one typed by hand. Use it instead of calling `orca linear create` directly whenever the result must be a valid ticket. | `node tools/new-ticket.mjs --help` |
Expand Down Expand Up @@ -75,3 +76,10 @@ justification in `lockstep-declarations.json`; the checker prints the fingerprin
undeclared hunk. Stale declarations fail so the exception set shrinks when twins converge.
The JavaScript twin accepts no declarations and compares byte for byte. Missing roots,
files, or malformed declarations are failures, never skips.

The list is closed at exactly those six paths: `check-lockstep.mjs` hardcodes them as
`REQUIRED_PATHS` and rejects any manifest declaring a different set. **Nothing under
`tools/__tests__/` carries a lockstep obligation, and no path there is ever added to that
list.** `test-tools.mjs` and the per-tool case modules it loads exist only in
orbit-ui-mobile; orbit-api ships no twin of them, so there is nothing to compare and a
seventh entry would fail the checker rather than gate anything.
Loading
Loading