Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
10779dd
feat(agents): a spent metered cap closes on Codex, not on a maintainer
bioedca Aug 11, 2026
0abcc82
fix(agents): the close must not re-create the deadlock it removes
bioedca Aug 11, 2026
f04daa6
fix(agents): shut the close to scope that landed after the cap was spent
bioedca Aug 11, 2026
a80c1a4
fix(agents): anchor the scope freeze at the reviewed commit, not the …
bioedca Aug 11, 2026
1e02fdc
fix(agents): the closing read must stamp its own head
bioedca Aug 11, 2026
37699bf
fix(agents): reconcile the stamped-head rule with the files it contra…
bioedca Aug 11, 2026
422c1dc
fix(agents): let a stamped read rebind a head the clean review no lon…
bioedca Aug 11, 2026
c51c160
Merge remote-tracking branch 'origin/main' into agent/issue-439
bioedca Aug 12, 2026
12b6b8b
fix(agents): give the rebinding path a template state and the summari…
bioedca Aug 12, 2026
4fb4f1b
Merge remote-tracking branch 'origin/main' into agent/issue-439
bioedca Aug 12, 2026
1932b09
fix(agents): stop the scope freeze from shutting on the closing read'…
bioedca Aug 12, 2026
9a617f6
fix(agents): stop the summaries contradicting the two paths they summ…
bioedca Aug 12, 2026
e541645
docs(prd): stop restating the close's conditions and point at the one…
bioedca Aug 12, 2026
f4d8956
fix(agents): close the rebinding read's own deadlock and the drift th…
bioedca Aug 12, 2026
94cbdbc
fix(agents): delete the rebinding mechanism and let the ordinary clos…
bioedca Aug 12, 2026
398491d
fix(agents): admit the conflict resolution this contract orders you t…
bioedca Aug 12, 2026
f5b147c
fix(agents): carry condition 2's narrowing into the summary that rest…
bioedca Aug 12, 2026
dac56da
fix(agents): state the allowed set as a principle, and report the ADR…
bioedca Aug 12, 2026
0e77eef
fix(agents): carry the provider-neutral allowed set into the two file…
bioedca Aug 12, 2026
dcabe31
fix(agents): pin the closing read's head, because nothing attests it
bioedca Aug 12, 2026
a21bf94
fix(agents): accept the pin in every prerequisite, not only where it …
bioedca Aug 12, 2026
9da3b46
fix(agents): say what "never the only reviewer" actually protects
bioedca Aug 12, 2026
fc3e930
fix(agents): drop the source dimension from the post-cap condition en…
bioedca Aug 12, 2026
06ccae1
fix(agents): stop claiming the cap-spent diff was read twice
bioedca Aug 12, 2026
ba62a89
fix(agents): test that nothing is outstanding, not which disposition …
bioedca Aug 12, 2026
2fe0bde
fix(agents): stop a rule-editing PR from supplying its own reviewer's…
bioedca Aug 12, 2026
c147d42
fix(agents): scope the isolation flag to the two files the CLI actual…
bioedca Aug 12, 2026
9db25d6
fix(agents): scope the isolation by property, after mis-scoping it in…
bioedca Aug 12, 2026
0b22dc3
fix(agents): stop guessing what Codex loads, and over-approximate on …
bioedca Aug 12, 2026
c26a683
fix(agents): close the second door the isolated read left open
bioedca Aug 12, 2026
0e3a279
fix(agents): the bot does post reviews — revert the detour built on i…
bioedca Aug 12, 2026
3e7a159
fix(agents): finish both sweeps the previous commit left half-done
bioedca Aug 12, 2026
856614f
fix(agents): say what the CLI is for, now that local output satisfies…
bioedca Aug 12, 2026
a1625c5
fix(agents): finish the CLI-is-not-a-leg sweep and give the trigger b…
bioedca Aug 12, 2026
ef797b2
fix(agents): say "posted review" on the three pointer surfaces too
bioedca Aug 12, 2026
c28052c
docs(agents): one word for the closer, since the other one caused thr…
bioedca Aug 12, 2026
13e311d
docs(agents): finish the rename the line-based grep could not see
bioedca Aug 12, 2026
bdf4bcd
fix(agents): scope the override to "anywhere" in the lists that had n…
bioedca Aug 12, 2026
742b8d3
fix(agents): measure what a clean Codex result actually is, and accep…
bioedca Aug 12, 2026
237541b
fix(agents): state the evidence shape once, and scope AGENTS.md anywh…
bioedca Aug 12, 2026
0970f4d
fix(agents): make the mirrors defer on evidence shape instead of rest…
bioedca Aug 12, 2026
3e1bf63
fix(agents): answer CodeRabbit review 1 — three Major, one Minor fixe…
bioedca Aug 12, 2026
bd3bd50
style(tests): wrap the budget diagnostic to the 100-column limit
bioedca Aug 12, 2026
9166b27
fix(agents): answer CodeRabbit review 2 — three fixed, one false posi…
bioedca Aug 13, 2026
353a4aa
fix(agents): answer CodeRabbit review 3 — the closing bar was "no maj…
bioedca Aug 13, 2026
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
5 changes: 4 additions & 1 deletion .agents/skills/tether-worker/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ gap — that is what invalidated reviews across three PRs at once under the old

**Open the PR as a draft** and get the checks green there. Then follow `AGENTS.md` §Review: an
external provider reads the final head, you fix what is serious and defer or drop the rest, and
CodeRabbit with no actionable comments is the last gate before merge.
CodeRabbit with no actionable comments is the last metered gate before merge. If its two-review cap
is spent and no finding is left outstanding, a fresh **posted** Codex review of the final head
closes the gate in its place — §Review carries the conditions, and no maintainer is waited on for
it. Posted, because the closer has to name the head it read; a local CLI run satisfies no leg.

You do not have to sit and watch it. A review takes as long as it takes, and a short-lived worker
that polls is spending tokens to wait — so **write the state into the PR body before you go**:
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/tether-worker/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface:
display_name: "Tether Worker"
short_description: "Claim one accepted issue and open its draft PR onto the review lane"
default_prompt: "Use $tether-worker to claim issue #N with .agents/bin/claim.py, implement it in an isolated worktree, open a DRAFT PR, request the first Codex review, write the lane state into the PR body, and exit. Do not arm auto-merge: that happens at the end of the review lane, after the mandatory CodeRabbit gate."
default_prompt: "Use $tether-worker to claim issue #N with .agents/bin/claim.py, implement it in an isolated worktree, open a DRAFT PR, request the first Codex review, write the lane state into the PR body, and exit. Do not arm auto-merge: that happens at the end of the review lane, once the gate is closed — by a clean CodeRabbit review, or by a posted Codex review of the final head when CodeRabbit's two-review cap is spent. AGENTS.md §Review carries the conditions on that second path and this prompt states none of them, so read them there rather than inferring them from this line."
9 changes: 5 additions & 4 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ linked work maps to one. The checklist, not CI, enforces those fields.
- Risk rationale:
- Final head SHA:
- Codex — first, on the green diff, and not optional (the draft by default; a ready-opened PR whose reason is recorded is asked there, at the same point in the lane): reviewed, nothing blocking outstanding (quote it) | reviewed, findings answered below | not reviewed (say why). Unmetered, so uncapped
- Greptile: reviewed the final head — quote its verdict, not only the spend (spent N credits; a standard review is 1, a TREX review 3) | skipped — no budget this month | skipped (say why). Balance from `<py> .agents/bin/greptile_usage.py`, where `<py>` is your lane's interpreter
- **CodeRabbit — the last gate**: no actionable comments (quote the review — permalink, the **full 40-hex** `commit_id` it read **which must be the final head**, its `submitted_at`, its state — **`COMMENTED` or `APPROVED`**, since `DISMISSED` is a verdict withdrawn and `PENDING` is unsubmitted — and the opening of its body, which must show that **`Actionable comments posted:` is ABSENT**: zero is written by that line not being there, and a clean body opens straight onto `🧹 Nitpick comments` or `No actionable comments were generated`. A review of an earlier head does not qualify, a `PENDING` one is not submitted, a `DISMISSED` one is a verdict withdrawn, and a green status check with no review body is **not** the gate) | in flight (status check `pending` — never re-request, it aborts the run) | throttled, retrying after the stated interval *and* a non-pending status check (a wait, not a freeze) | unavailable (freezes the PR)
- Codex closing review — required whenever the CodeRabbit line below records a **spent cap**, whatever heads those two reviews read, **including where one came back clean at a head a permitted non-material push has since moved**: that review's evidence still stands, but no metered provider has named the commit the merge binds, and the cap forbids asking for a third to name it: n/a — a clean CodeRabbit review at the head being merged, with nothing since | **closed the gate** — quote it exactly as the CodeRabbit gate is quoted: permalink or run artifact, the **full 40-hex** head it read **which must be the final head**, when, and what it said. A re-quoted earlier Codex pass is **not** a closing review, since the head that pass read is not the head being merged. It must be **posted by the provider and name the commit it read** — asked with the Codex review command named in `AGENTS.md` §Review, written in prose here because a handle in this template would fire a real review on every PR opened from it. Two shapes both count: a run with findings posts a review whose `commit_id` is the full 40-hex, and a **clean** run posts a comment carrying `Reviewed commit: <short-sha>` — expand that with `git rev-parse` and record both. A local CLI run posts nothing and cannot close. Anything this read surfaces is disposed of above before it closes
Comment thread
bioedca marked this conversation as resolved.
- Greptile: reviewed — quote its verdict, not only the spend (spent N credits; a standard review is 1, a TREX review 3), and name the **full 40-hex** head it read, which need not be the final one: Greptile is asked before CodeRabbit, so a later finding-fix legitimately moves the head past it, and only the provider that *closes* the gate must reach the final head. Buying a second review to make a checkbox true is not a reason to spend a credit | skipped — no budget this month | skipped (say why). Balance from `<py> .agents/bin/greptile_usage.py`, where `<py>` is your lane's interpreter
- **CodeRabbit — the last metered gate**: no actionable comments (quote the review — permalink, the **full 40-hex** `commit_id` it read **which must be the final head when CodeRabbit is what closes the gate**, its `submitted_at`, its state — **`COMMENTED` or `APPROVED`**, since `DISMISSED` is a verdict withdrawn and `PENDING` is unsubmitted — and the opening of its body, which must show that **`Actionable comments posted:` is ABSENT**: zero is written by that line not being there, and a clean body opens straight onto `🧹 Nitpick comments` or `No actionable comments were generated`. A review of an earlier head does not qualify: where every push since it is non-material its evidence still stands and it is one of the two completed reviews, but it is the Codex closing review above that names the merging head, so that case is recorded as **cap spent, closed by Codex** and not here. A `PENDING` one is not submitted, a `DISMISSED` one is a verdict withdrawn, and a green status check with no review body is **not** the gate) | in flight (status check `pending` — never re-request, it aborts the run) | throttled, retrying after the stated interval *and* a non-pending status check (a wait, not a freeze) | unavailable (freezes the PR) | **cap spent, closed by Codex** — two *completed* reviews stand — each **submitted**, in state `COMMENTED` or `APPROVED`, carrying a body or inline findings of its own; a throttle, quota refusal, failed run, `PENDING` or `DISMISSED` review, bare status check or reply on someone else's thread is none of them; the second was asked only after the first one's findings were **disposed of** (by commits that answer them, or by the replies and resolutions recording a deferral or drop — same `commit_id` is fine, since disposal on the record moves no head); no finding from either is left outstanding, with the thread resolved on each — cleared by being fixed, deferred-and-tracked, dropped sub-floor, or **withdrawn by the provider that raised it**; *outstanding* is the test and those are the known ways of clearing one; **nothing but disposal and the non-material exceptions landed after the commit the second review read** — every hunk since answers something already recorded on this PR **that you were required to address** — a review finding from any provider, a CodeQL or `secret-scan` alert, a condition a human sign-off attached, the closing review's own finding; the test is the change, not who raised it — or is a clean `main` merge / formatting / comment or docstring edit / **ADR renumber-only** (a renumber that also edits a word of the decision is material, not an exception), or is the resolution of a conflict in the `main` merge the contract requires, which admits the reconciliation only — so no new scope reached the merge unread by an **external** provider — metered up to the commit the second review read, the closing review after it, which is the guarantee the conditions buy and not a metered read of everything; neither came back clean **at the head being merged with its evidence still standing** — all three, since a clean review that a later material push re-armed is not a gate that already closed, reading it as "neither was ever clean" would strand the case where review 1 was clean at an earlier head and review 2 then found something, and a clean review whose head a *non-material* push has since moved lands **here** rather than on the line above, because its evidence stands but no metered provider has named the commit the merge binds; and the Codex closing review above is quoted. That closing review is then the `<SHA>` the merge below binds to
- Provider that did not review: none | which, and why — a quota refusal means the provider **did not review**, and never counts as a pass
- Findings: `<N>` serious (fixed) | `<M>` below the floor (deferred to #____, or dropped if this is an agent-layer path — ADR-0064). Dropped is not silent: reply on the thread in the wording `AGENTS.md` §Review gives, and resolve it
- Findings: `<N>` serious (fixed) | `<M>` below the floor (deferred to #____, or dropped if this is an agent-layer path — ADR-0064) | `<W>` **withdrawn by the provider that raised them** — quote the withdrawal and resolve the thread, since a finding retracted by its author is cleared but is not something you fixed, deferred or dropped, and the cap-spent line above tests whether anything is left *outstanding* rather than which of the four cleared it. Dropped is not silent: reply on the thread in the wording `AGENTS.md` §Review gives, and resolve it
- Human sign-off: n/a | release/tag/signing | new scientific claim **or citation** (reviewer and evidence)

## Type of change
Expand All @@ -58,7 +59,7 @@ Confirm before requesting review:
- [ ] **Data policy respected** — no raw/private/unlicensed data or large data in ordinary Git; issue-authorized redistributable fixtures carry license and provenance in named small or LFS/gated paths.
- [ ] **No secrets committed** — no token, key, credential, or private path in code, tests, logs, or fixtures; `secret-scan` and push protection are green.
- [ ] **Code scanning clean** — CodeQL (GitHub code-scanning *default setup*, hence no `codeql.yml` workflow) reports no new alerts on this PR.
- [ ] **Review complete** (`AGENTS.md` §Review) — the diff went green before anything was asked to read it, on a draft by default or on a ready-opened PR whose reason is recorded above, and then **Codex on that green diff before any metered provider**; **every provider the lane reached** has a final-head result recorded above — a quoted verdict, or the reason it produced none — and at least one of them is an external provider that reviewed the **final head**, its verdict quoted with all six of **which provider it was** — its name, never its @-handle, since a mention in the PR body fires the bot — permalink, the **full 40-hex** `commit_id` it read, `submitted_at`, a state of **`COMMENTED` or `APPROVED`**, and **what it actually said**: the submitted review body, or enough of it to establish the verdict, since metadata alone records that a provider ran and not what it found; and **CodeRabbit returned no actionable comments at that head**, asked with the **full-review** command. Neither silence nor a green `CodeRabbit` status check is the gate — both are also what a request that reviewed *nothing* leaves behind. A provider that could not act is recorded above with the reason, and a quota refusal means the provider **did not review**, and never counts as a pass. Serious findings fixed; the rest deferred to one follow-up issue, or dropped without one if this is an agent-layer path (ADR-0064) — dropping still owes the thread the reply `AGENTS.md` §Review words, so the decision is on the record rather than inferred from silence. Every conversation resolved.
- [ ] **Review complete** (`AGENTS.md` §Review) — the diff went green before anything was asked to read it, on a draft by default or on a ready-opened PR whose reason is recorded above, and then **Codex on that green diff before any metered provider**; **every provider the lane reached** has a result recorded above — a quoted verdict at the head it read, or the reason it produced none — and **the provider that closed the gate reviewed the final head** — where that is Codex, quote what it emits and skip the fields that exist only on a review — but the **full 40-hex** head comes from the provider's own posted artifact, in either shape `AGENTS.md` §Review describes — a review's `commit_id`, or a clean run's `Reviewed commit: <short-sha>` expanded with `git rev-parse`, which is mechanical and redoable and so still the provider's head rather than yours. A head asserted by the author is never acceptable, since it could name a commit the provider never saw. Where the closer is CodeRabbit, its verdict quoted with all six of **which provider it was** — its name, never its @-handle, since a mention in the PR body fires the bot — permalink, the **full 40-hex** `commit_id` it read, `submitted_at`, a state of **`COMMENTED` or `APPROVED`**, and **what it actually said**: the submitted review body, or enough of it to establish the verdict, since metadata alone records that a provider ran and not what it found; and **the gate is closed at that head** — either **CodeRabbit returned no actionable comments** there, asked with the **full-review** command, or its two-review cap is spent under the conditions the CodeRabbit line above sets out and a **fresh posted Codex review of that head closed it in their place**. On the cap-spent path CodeRabbit's two reviews are recorded at **whatever heads they read** — earlier ones where a fix moved the head, the same one where the disposal was a deferral or drop — and it is the Codex closing review that names the final head; requiring CodeRabbit itself to reach the final head there would demand the third review the cap forbids. Neither silence nor a green `CodeRabbit` status check is the gate — both are also what a request that reviewed *nothing* leaves behind. A provider that could not act is recorded above with the reason, and a quota refusal means the provider **did not review**, and never counts as a pass. Serious findings fixed; the rest deferred to one follow-up issue, or dropped without one if this is an agent-layer path (ADR-0064) — dropping still owes the thread the reply `AGENTS.md` §Review words, so the decision is on the record rather than inferred from silence. Every conversation resolved.
- [ ] **Provenance stamped** — coordinates / corrections / app-version / parameters written into the `.tether` for any new analysis (NFR-REPRO).
- [ ] **New tunables registered in PRD §11.2** (single source of truth), not hardcoded.
- [ ] **Scientific/statistical claims carry a citation**; **SPDX `GPL-3.0-or-later`** header on every new source file (`reuse lint` green).
Expand Down
4 changes: 3 additions & 1 deletion .greptile/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,6 @@ reads the diff before any metered provider does. **One *review* in practice**, a
reviews per metered provider** in `AGENTS.md` §Review applies here as everywhere, but it is a
ceiling rather than a second credit to plan on, so ask again only if the first found something blocking and the seat still has
budget. A request that produced no review — a throttle, a quota refusal, a failed run — is not an
ask and spends nothing. CodeRabbit, not Greptile, is the gate.
ask and spends nothing. CodeRabbit, not Greptile, is the metered gate — and when CodeRabbit's own
cap is spent with no finding left outstanding, an unmetered **posted** Codex review closes it — §Review carries the
conditions on that, and this page states none of them. Greptile is never the closer either way.
Loading