Skip to content

Spec: a Bar a release that changes nothing can pass #1252

Open
5 of 7 issues completed
Open

Description

@JacobStephens2

This was generated by AI from a grill-with-docs session.

Decided in docs/grill-with-docs/1252-1253-bar-and-rechecks.md (Q1.1–Q4.2; committed locally, on main once merged), which also holds the simulations behind every number here. It merges this issue with #1253, and builds on #977, which it is blocked by. This issue's earlier body is in its edit history.

Problem Statement

scripts/release.sh stops a release whose Experiment ends in a fail or inconclusive Verdict, and asks whether to release anyway. At our Eval suites' sizes, the standing Bar lets almost no real Experiment pass.

  • Code review can never pass. With 10 Eval tasks, even Arms that score identically on every task give an interval whose lower bound is −12.8 points, below the −10-point margin.
  • Spec review can barely pass. With 30 Eval tasks, it passes only if the Arms agree on every task. One task going each Arm's way gives −11.0.
  • A pass that close to the line makes every Score decisive. One flipped Score tips it, so a clean Spec-review pass would ask you to recheck about 30 Candidate Trials by hand (Batch rechecks, and say which flip makes a Score decisive #1253). Today this is hidden, because code review's permanent inconclusive already decides any Experiment that selects both suites.

So every release that touches an Eval suite would stop and ask, and you'd always answer yes. A prompt that's always answered yes protects nothing.

Nobody knows how noisy the Arms really are. #429's replays and #549's Trial each ran one session per cell, so how often two runs of one setup disagree on a task was never measured. #698's research had already noted that detecting a 10-point difference needs about 175 Eval tasks.

Solution

Keep the release prompt, and make the Bar passable by a release that changes nothing.

  • Two levels in the Bar. A pass needs the lower bound at a looser pass level above the −10-point margin. A fail still needs the upper bound at the 95% fail level below zero. Anything between is inconclusive. So "worse" still means 10 points, and a fail still means 95% sure the Candidate is worse at all. Only a pass asks for less certainty.
  • Measure, then set. One A/A Experiment on the thirdshift host, with one commit in both Arms, measures how often the Arms disagree when nothing differs. The default pass level is then the highest one at which such an Experiment passes at least 80% of the time. It never goes below 70%. If 70% isn't enough, the suite grows instead.
  • A bigger code-review suite. Seven bugs found since Security review: surface the session's reason when it deliberately ends incomplete #607, each visible in its PR's diff, become approved code-review Eval tasks, bringing the suite to 17.
  • Rechecks where they decide. The rule for a decisive Score stays. With room under a pass, few Scores are decisive. A batch command records your decision on a reviewed pending list, and thirdshift experiments <id> --json says which flip makes each Score decisive.

Until the new default ships, releases keep today's Bar and its override.

User Stories

The Bar:

  1. As the Day shift, I want a release that changes nothing to usually pass its Experiment, so that the release prompt stays rare enough to read.
  2. As the Day shift, I want the release to keep stopping on fail and on inconclusive, so that "we couldn't tell" never ships without a question.
  3. As the Day shift, I want a pass judged at the pass level against the −10-point margin, so that a pass is reachable at our suites' sizes.
  4. As the Day shift, I want a fail still judged at the 95% fail level against zero, so that noise rarely fails a good change.
  5. As the Day shift, I want the margin kept at −10 points, so that "worse" means what it meant under Spec: Experiments, which measure a change before it reaches production #977.
  6. As the Day shift, I want one Bar for every suite, so that there's one rule to understand.
  7. As the Day shift, I want the pass level and the fail level saved with the Experiment before its first Trial, and refused if they change afterwards, as the rest of the Bar is.
  8. As the Day shift, I want --pass-level and --fail-level flags in place of --credible-level, so that I can set either level for one Experiment.
  9. As the Day shift, I want the Verdict's method to name the two-level rule, so that an Experiment judged under the old rule is never mistaken for one under the new rule.
  10. As the Day shift, I want the "about N more Eval tasks would settle it" prediction to use the same two levels, so that it predicts the Verdict I would actually get.
  11. As the Day shift, I want each suite's intervals shown at the pass level and at the fail level, so that I can see which one decided its Verdict.
  12. As the Day shift, I want an Experiment saved under the old Bar to keep its old Verdict, so that a change of method doesn't rewrite past results.

Measuring the noise:

  1. As the Day shift, I want to run an A/A Experiment, with one commit and the same flags in both Arms, so that I can measure how often the Arms disagree when nothing differs.
  2. As the Day shift, I want the A/A Experiment run on the User config's Harness, Model and Effort, so that the measurement matches the setup releases are judged on.
  3. As the Day shift, I want the A/A Experiment run on the 17-task code-review suite and the 30-task Spec-review suite, so that it measures the suites the Bar will judge.
  4. As the Day shift, I want each suite's disagreement rate posted on this issue, so that the default pass level is chosen from recorded numbers.
  5. As the Day shift, I want the default pass level chosen as the highest one at which an A/A Experiment at that rate passes at least 80% of the time, so that the choice follows a written rule, not a feeling.
  6. As the Day shift, I want the default pass level never set below 70%, so that a pass never becomes a coin toss. If 70% isn't enough, I want the shortfall named, so that I know which suite has to grow.
  7. As the Day shift, I want the default pass level and the interval it gives at each suite's size written in docs/guide.md, where the standing Bar is described.

The code-review suite:

  1. As the Day shift, I want Spec: a Bar a release that changes nothing can pass #1252's seven strong bugs added to code review as Eval tasks, so that the suite has 17 tasks.
  2. As the Day shift, I want each one's success criteria drafted by an agent on the host and approved by me, so that no task runs that I haven't approved.
  3. As the Day shift, I want the five partly visible bugs left out, so that code review keeps measuring what a review can see in the diff.

Rechecks:

  1. As the Day shift, I want a Score to stay decisive when any one flip would change the provisional Verdict, so that a pass resting on one mis-scored Trial is still caught.
  2. As the Day shift, I want borderline Scores still always rechecked, as Your rechecks of borderline and decisive Scores #1006 requires.
  3. As the Day shift, I want thirdshift experiments <id> --json to say, for each pending recheck, which flip makes it decisive (its pass, or its wrong finding) and what the Verdict would become, so that the Experiment page (The Experiment pages in the Console #1020) can show why it's asked.
  4. As the Day shift, I want one command that lists every pending recheck, with its Trial and the reason it's pending, so that I can review them all in one place.
  5. As the Day shift, I want to record the same decision for every pending recheck in that list with one reason, so that a release doesn't cost me 30 commands.
  6. As the Day shift, I want the batch refused if the pending list changed since it was shown, so that I never confirm a Score I didn't see.
  7. As the Day shift, I want a batch recheck kept in each Score's history like any single recheck, so that the audit trail is the same either way.

Implementation Decisions

  • The Bar replaces its one credible level with a pass level and a fail level. The fail level defaults to 95%. The pass level defaults to 95% until Ticket 5 sets it from the A/A measurement, so nothing changes for releases before then.
  • The decision rule reads: fail when the upper bound at the fail level is below zero. Otherwise pass when the lower bound at the pass level is above the margin and the upper bound at the pass level is at least zero. Otherwise inconclusive. The posterior, the prior, the seed and the draws don't change. One set of draws gives both intervals.
  • The method gets a new name, replacing paired-dirichlet-v1, and an ADR records why a pass and a fail are judged at different levels.
  • The posterior-predictive prediction ("about N more Eval tasks…") uses the same two-level decision.
  • The Verdict's JSON gives each suite's intervals at both levels, and the Bar's JSON gives both levels. Experiments saved before the change keep their stored Bar and Verdict, and are read as the old method.
  • An Experiment may have the same commit and the same flags in both Arms. If anything refuses that today, it is allowed, and the A/A case is documented in docs/guide.md.
  • The rule for a decisive Score doesn't change. pending_rechecks in experiments <id> --json gains, for each Score, the flip that makes it decisive and the provisional Verdict that flip would give.
  • A batch recheck takes the Experiment, a decision and a reason, plus a fingerprint of the pending list it was shown. It refuses if the list has changed, and records one recheck per pending Score in a single locked write, as a single recheck does now. Rechecks stay in the CLI (ADR 0016).
  • The seven code-review Eval tasks are Pickup reservation pushes run the repository's git hooks #847, Check re-run reads CI as passed before the re-run's checks are listed, and Self-merges red CI #686, Unit test startup_failure_preserves_its_cause_without_completion_reporting runs a real installed opencode #652, thirdshift console uses 50-74% of a core while idle #1153 and the other three in the "Strong" table of Spec: a Bar a release that changes nothing can pass #1252's triage comment, with the base and change commits given there. Eval data stays private on the host (Spec: Experiments, which measure a change before it reaches production #977), so they're written there, not in a Ticket run.
  • scripts/release.sh doesn't change. It already prompts on fail and inconclusive, and waits on rechecks.

Testing Decisions

  • Test external behaviour only. Tests judge Scores through the Verdict's public function, and drive the commands against the fake Harness. They don't reach into how intervals are computed.

  • The Verdict, in its unit tests:

    • a pass at the pass level that the fail level alone wouldn't give;
    • a fail at the fail level;
    • an inconclusive between the two;
    • the new method name in the JSON;
    • the prediction under both levels;
    • a pinned case, the smallest code-review suite (3 Trials per task, identical Arms) that passes under the default Bar, so that a later change can't quietly bring Spec: a Bar a release that changes nothing can pass #1252 back.

    Prior art: the existing Verdict tests on the margin, wrong findings and the prediction budget.

  • The commands, in the Experiment integration tests:

    • an A/A Experiment with one commit in both Arms;
    • the level flags saved in the Bar, and refused after the first Trial;
    • which flip pending_rechecks names;
    • a batch recheck that records every pending Score;
    • a batch refused after the pending list changes.

    Prior art: the existing Experiment and recheck integration tests.

  • No release tests change, since release.sh doesn't.

  • The host work (the seven tasks and the A/A run) has no automated tests. Its output is the approved tasks and the numbers posted here.

Out of Scope

Further Notes

  • Tickets, in order:
    1. The two-level Verdict, with its ADR.
    2. Allowing an A/A Experiment.
    3. The seven code-review Eval tasks (ready-for-human).
    4. Running the A/A Experiment (ready-for-human, blocked by 2, 3 and Spec-review Trials have no Trial inputs or PR service #1251).
    5. Setting the default pass level (blocked by 1 and 4).
    6. Batch rechecks and which flip (Batch rechecks, and say which flip makes a Score decisive #1253, rewritten).
  • A Spec run on this issue fails until Tickets 3 and 4 are closed, because it doesn't start a ready-for-human Ticket. Run the agent Tickets one at a time until then.
  • The glossary's Bar entry already lists the pass level and the fail level.

Activity

  1. JacobStephens2 commented on Oct 24, 2026

    @JacobStephens2
    OwnerAuthor

    This was generated by AI during triage.

    Candidates for more code-review Eval tasks (option 1)

    All 10 existing tasks predate bug #607. I went through the 39 bug issues closed since then, tracing each back to the merged PR that introduced it, using git blame on the fix's lines and the issues' own references. base is the first parent of the PR's merge commit, and change is the PR's head, as in the existing tasks.

    12 pairs are usable. The 7 strong ones would bring the suite to 17; all 12 to 22. None is approved yet. Each needs its criteria written and checked, as the first 10 had.

    Strong: the bug can be seen in the PR's diff

    Bug PR (issue) base / change A catching finding says
    #847 #788 (#712) 7fd5d27f / f7c39404 The reserve and release pushes in pickup/reservation.rs leave out --no-verify, so the pre-push hook runs and can refuse the reservation or leave it stuck on origin.
    #686 #267 (#262) 3204f2d2 / 2095d6ed A re-run counts as started once the earlier attempt's failed check-run ids are gone, but GitHub drops those before it lists the queued job, so the watch can see only green checks.
    #652 #462 (#461) f0a48c43 / 9db097f2 Making the fake opencode mode 0644 doesn't stop the spawn: execvp remembers EACCES and keeps searching PATH, so the test can start a real OpenCode session.
    #1153 #855 (#818) 46836c92 / a3523c96 observe() re-renders the whole Inbox from the log store every second, watched or not, and each stream checks authorization every 250 ms.
    #1105 #861 (#826) 5af85a50 / 3a0d2844 Stage rows come from a BTreeSet<String>, so they sort by bytes, not in the order a Run goes through its stages.
    #947 #860 (#821) da440c47 / 5814d464 allowed_emails only needs an '@' and no whitespace, so a@b@c.com or owner@ is saved and nobody can sign in. The diff is 2,051 lines, which makes this harder to find.
    #1084 #1053 (#987) d56453d5 / d5349ba5 The 64 KiB tail window is reused for OTLP traces, whose events are about 3.6× larger, so the latest tool call can fall outside it.

    Partly visible: some context outside the diff is needed

    Bug PR (issue) base / change Note
    #687 #22 (#9) e0408a25 / 3da2f0b0 The CI-fix prompt counts "flaky" as not the branch's fault, even for a test the branch added. This would be a third task on #22.
    #722 #99 (#94) 5acf138f / 7372c3d2 Every batch of Foreign commits starts a Review Repair, even when the merged tree is the Run's own head. This would be a second task on #99.
    #670 #400 (#391) ffbec1ca / ed9a63e1 link_into follows a symlinked skills directory out of the worktree. Catching it takes reading the branch as untrusted.
    #671 #168 (#158) d68109cb / 63e355ea find_earlier_run picks any release-<version> PR by its head branch name, including a fork's.
    #1083 #848 (#816) 44470094 / f9f74826 Ready for review has no cutoff or exit. The PR's Spec gave no rule either, so a finding would flag a gap in the Spec.

    Short IDs are given here. git rev-parse expands them, or see the PR's merge commit, whose parents are base and head.

    Weak pairs and discarded bugs

    Weak: the bug needs context the PR's diff doesn't show.

    Discarded:

    • 667, 668, 669, 673: new trust rules, not a regression.
    • 712, 730, 731: design gaps.
    • 717: a question, not a bug.
    • 736, 737: the cause is unknown and may lie in the environment.
    • 740: spread across many files.
    • 806: the "not open" check predates PRs.
    • 839, 927: long-standing behaviour plus how GitHub handles concurrency.
    • 889, 906, 911: they predate the code that changed.
    • 936: the causing code isn't in the diff.
    • 1085: an outside change (codex-cli's record format).
    • 1126: two interacting causes.
  2. added
    enhancementNew feature or request
    and removed
    bugSomething isn't working
    on Oct 24, 2026
  3. changed the title [-]The code-review suite can't pass the standing Bar with 10 Eval tasks[/-] [+]Spec: a Bar a release that changes nothing can pass[/+] on Oct 24, 2026
  4. added
    ready-for-agentFully specified, ready for an AFK agent
    and removed
    needs-triageMaintainer needs to evaluate this issue
    on Oct 24, 2026
  5. added a commit that references this issue on Oct 24, 2026
  6. added
    in-progressA Claim: thirdshift has taken this issue
    and removed
    ready-for-agentFully specified, ready for an AFK agent
    on Oct 24, 2026
  7. JacobStephens2 commented on Oct 26, 2026

    @JacobStephens2
    OwnerAuthor

    The A/A Experiment's numbers for #1268 are on #1267: #1267 (comment) (provisional Verdict inconclusive; 11 non-decisive rechecks pending).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestin-progressA Claim: thirdshift has taken this issue

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions