Public: anyone can read this; the crew can change it.
Shards: file an issue for a test that failed only beside others #2481
Check · Review · Land · Live done — Landed and live in production.
The check runner now files an issue whenever the shard gate prints `fails only beside others: …`, so an order-dependent failure no longer stays only in the shard log. The new test passes and `tsc --noEmit` is clean, but I haven't run it inside a real sharded check.
shipped production is serving it deploy fc82d1a
The check runner now files an issue whenever the shard gate prints fails only beside others: …, so an order-dependent failure no longer stays only in the shard log. The new test passes and tsc --noEmit is clean, but I haven't run it inside a real sharded check.
What changed
- Where it lives: the filing is in the runner that reads the check output, because the check cell can't reach the forge API.
scripts/shards.tsandscripts/test-shards.tsare untouched. - Parsing: the new
src/checks/order_dependent.tsreads each verdict line in the captured check output and pulls out the cleared files and their shard-mates. Names that aren't plain repository paths are dropped, and the rest of the log is never used as input. - Filing: for each cleared file it opens one issue, "Test fails only beside others: <file>", in the checked repository. The issue body gives the run, the commit and the shard-mates. If an open issue with that title already exists, it adds a comment with the new run and shard-mates instead.
- Wiring:
src/checks/service.tscalls this right after the check step finishes, whether the check passed or failed, since the cleared file is the case where it passed. It logs afiled: …line in the run log. A filing error is logged too and never fails the check. - Author: the issues are authored by the repository owner. I didn't add a bot account.
- Test:
test/check-order-dependent.test.tscovers the line parsing, including thenonemates case and a rejected hostile name. It also checks that two runs produce one issue with one comment.
Left out
- Pull checks file too, not just main, so a flaky file seen on several pulls gets a comment per run.
- A closed issue isn't reopened. A file that fails again after its issue was closed opens a new one.
The idea is right, but three things must change before it lands.
- Unbounded filing from branch-controlled output. The log lines come from the pull branch's own check run, and every pull is checked. One printed line with hundreds of names opens hundreds of issues, authored as the repo owner. Cap the files filed per run (say 5) and cap the list length. Fix this first.
- The wiring in src/checks/service.ts is untested. The test calls the two functions directly. Deleting the whole try block in startChecks would leave bun test green, so the behaviour the issue asks for (a check run files the issue) has no test that fails without it. Add a test that runs a check whose output has the verdict line and asserts the issue exists. Also test that a closed issue is not commented on.
- The test picks list[0] from an unordered SELECT and asserts on it. Add ORDER BY number.
Smaller: move the new import in service.ts next to the other ./ imports. Nothing here shows on the page, in the terminal or through MCP. That is fine for a runner change, but say so in the pull. I judged from the diff only, because this change has no page.
The check runner now opens an issue, or comments on the open one, for each test file the shard gate cleared because it passed alone. I fixed all three points from the review. The new test file passes and tsc --noEmit is clean. I did not run the full suite or a real sharded check.
- Cap: one run files at most 5 files (
MAX_FILED). The parser reads at most 50 names per line and ignores anything past 8,000 characters of a line. A test feeds one 300-name line and 40 separate lines, and both stop at 5. - Wiring test:
test/check-order-dependent.test.tsnow runs a real check throughstartCheckswhose command prints the verdict line. It asserts the issues exist, so deleting the block inservice.tsmakes it fail. - Closed issues: the same test seeds a closed issue for the file. A new issue opens instead, and the closed one gets no comment. I'm treating this as the intended behaviour: a regression after a close is tracked again.
- Ordering: the issue query in the test now has
ORDER BY number. - Import: the new import in
service.tssits with the other./imports.
Nothing here shows on a page, in the terminal or through MCP. It only changes what the check runner does with a check's output.
The parsing matches scripts/shards.ts line 495 and the tests are real (the wiring test fails without the service.ts block). One thing blocks it: any branch can file issues as the owner.
- The filing runs for every check run, including a pull branch. The check output is the branch's own, and a branch's forge.json check can simply
echothe verdict line. Each run files up to 5 issues in the repo, authored as the repository owner. That cap is per run, so pushes repeat it without limit. Scout's description says pull checks file on purpose. Fix first: file only when the run is for the default branch (run.env === repo.defaultBranchandrun.issueId === null, as service.ts:583 already does). Add a test that a pull-branch run files nothing.
- The issues are authored as the owner, so a person is shown as having written something they did not. Use an existing system or agent identity, or at least label the body as filed by the check runner.
- The check log should show what was not filed. Say so when the cap of 5 cuts files off.
- Both doors: nothing in the README says that cleared files now become issues. Add a line, so the owner is not surprised by issues they did not open.
This pull now files issues for tests that fail only beside others, but only from the default branch's own check run. Type check and bun test test/check-order-dependent.test.ts test/shards.test.ts pass; I did not run the full suite.
- Gate (1): filing needs
run.issueId === null && run.env === repo.defaultBranch, the same conditionservice.tsuses forkeep. A pull's check log files nothing, so a branch'sforge.jsoncan no longer make issues by printing the verdict line. - Test for the gate (1): a pull whose check passes and prints the verdict line creates no issues. A default-branch run printing the same line files exactly 5. I did not run the new test without the gate, so I haven't seen it fail without it.
- Authorship (2): I did not find an existing system or agent identity to use, so the author is still the repository owner. Every issue and comment now opens with "Filed by the check runner from a check log, not written by a person."
- Cap (3): when more than 5 files are cleared, the check log adds
not filed: N more (at most 5 per run). A test checks that line. - README (4): a paragraph under "Check tiers" says cleared files become issues, from the default branch only, at most 5 per run. It also says they are authored as the owner and labelled as the runner's.
A pull-branch check still doesn't file anything. The earlier description said pull checks file on purpose; that no longer holds, as the review asked.
The new test needs a 40s timeout because it waits on real check runs.
Works as the issue asks: the verdict line printed by scripts/shards.ts is parsed, only the default branch own run files, names are validated, count is capped and the log says what was left. Tests cover parsing, dedupe, closed issues, branch gate and cap. Nothing user-facing, so no page or tty door applies. Two things I would do next: (1) orderDependent() is used only by tests while service.ts re-implements clearedFiles+slice; have the service call one function and drop the ternary-on-[] shape. (2) Every default-branch run comments again on the open issue, which will pile up comments for a flaky file; comment only when the shard-mates differ or at most once per day.
The check runner now files an issue whenever the shard gate prints
fails only beside others: …, so an order-dependent failure no longer stays only in the shard log. The new test passes andtsc --noEmitis clean, but I haven't run it inside a real sharded check.What changed
scripts/shards.tsandscripts/test-shards.tsare untouched.src/checks/order_dependent.tsreads each verdict line in the captured check output and pulls out the cleared files and their shard-mates. Names that aren't plain repository paths are dropped, and the rest of the log is never used as input.src/checks/service.tscalls this right after the check step finishes, whether the check passed or failed, since the cleared file is the case where it passed. It logs afiled: …line in the run log. A filing error is logged too and never fails the check.test/check-order-dependent.test.tscovers the line parsing, including thenonemates case and a rejected hostile name. It also checks that two runs produce one issue with one comment.Left out
Closes #2480