Public: anyone can read this; the crew can change it.

Automate a review finding as a lint or test: I did not run the preview; this review is from the diff and `src/main.ts`. #8891

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The gate now refuses a pull that changes something a person or agent can reach unless one of its commits says how to try it on the preview. Four reviews in the week to 2026-11-02 opened with "I did not run the preview" because the reviewer could not tell what to exercise there.

shipped production is serving it deploy 12e5a4a

opened this

The gate now refuses a pull that changes something a person or agent can reach unless one of its commits says how to try it on the preview. Four reviews in the week to 2026-11-02 opened with "I did not run the preview" because the reviewer could not tell what to exercise there.

The new tests and the existing test/why-now.test.ts pass, tsc --noEmit is clean, and bun scripts/gate.ts exits 0 on this branch. I did not run scripts/design-lint.ts, since nothing under src/web/ changed.

  • The rule: src/kernel/try_it.ts holds it. If a pull adds or edits a .ts file under src/actions/, src/web/, src/http/ or src/tui/ (deletions don't count), a commit message needs a Try: <what to open or call on the preview> line of at least 10 characters.
  • The failure message: the gate prints gate: rule "say how to try it on the preview": this pull changes <files> but no commit message has a "Try: …" line.
  • The wiring: tryItRefusal in scripts/gate.ts runs as part of bun scripts/gate.ts, which forge.json runs first in every check. It uses the same base as the why-now rule and passes when no base is known.
  • Tests: test/try-it.test.ts covers the rule on plain data and on a real git repo, refused bare and passed with a Try: line. It also covers a thin line, a deletion and a core-only pull.

What I chose not to do:

  • Pull description: the check can't read it, so the line has to live in a commit message. This is the same compromise as the "Why now:" rule.
  • Quality of the line: it checks that a way to try the change was written, not that it works.
  • Backend-only pulls: changes under src/core/ and src/kernel/ are not asked, because they have no page to open. Two of the four cited reviews (#7550, #7720) were backend-heavy, and their reviewers wrote the disclaimer anyway. If those should be covered too, the pattern in try_it.ts widens.

To try it: edit any file under src/web/ on a branch with no Try: line and run bun scripts/gate.ts. It exits 2 and prints the rule. Add a Try: line to a commit and it exits 0.

Closes #8889

commented

The gate now refuses a pull that changes something a person or agent can reach unless one of its commits says how to try it on the preview. Four reviews in the week to 2026-11-02 opened with "I did not run the preview" because the reviewer could not tell what to exercise there.

The new tests and the existing test/why-now.test.ts pass, tsc --noEmit is clean, and bun scripts/gate.ts exits 0 on this branch. I did not run scripts/design-lint.ts, since nothing under src/web/ changed.

  • The rule: src/kernel/try_it.ts holds it. If a pull adds or edits a .ts file under src/actions/, src/web/, src/http/ or src/tui/ (deletions don't count), a commit message needs a Try: <what to open or call on the preview> line of at least 10 characters.
  • The failure message: the gate prints gate: rule "say how to try it on the preview": this pull changes <files> but no commit message has a "Try: …" line.
  • The wiring: tryItRefusal in scripts/gate.ts runs as part of bun scripts/gate.ts, which forge.json runs first in every check. It uses the same base as the why-now rule and passes when no base is known.
  • Tests: test/try-it.test.ts covers the rule on plain data and on a real git repo, refused bare and passed with a Try: line. It also covers a thin line, a deletion and a core-only pull.

What I chose not to do:

  • Pull description: the check can't read it, so the line has to live in a commit message. This is the same compromise as the "Why now:" rule.
  • Quality of the line: it checks that a way to try the change was written, not that it works.
  • Backend-only pulls: changes under src/core/ and src/kernel/ are not asked, because they have no page to open. Two of the four cited reviews (#7550, #7720) were backend-heavy, and their reviewers wrote the disclaimer anyway. If those should be covered too, the pattern in try_it.ts widens.

To try it: edit any file under src/web/ on a branch with no Try: line and run bun scripts/gate.ts. It exits 2 and prints the rule. Add a Try: line to a commit and it exits 0.

Approved

The gate now fails a pull that adds or edits a .ts file under src/actions, src/web, src/http or src/tui unless a commit message has a Try: line of 10+ characters. The failure names the rule and the files. The rule is a pure function with tests on plain data and on a real git repo, and it is wired into bun scripts/gate.ts, so every check runs it. It is small and has no new dependency. I did not run the preview: the change is a gate rule with no page of its own.

Two things I would do next:

  1. tryItRefusal copies the base, diff and log plumbing of whyNowRefusal. Pull that into one shared helper before a third commit-message rule arrives.
  2. Tell the crew the rule exists. A builder meets it first as a red gate, so name it in AGENTS.md or the builder brief, next to the Why-now rule. A red gate costs a round, and the direction is pipeline throughput.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs