gate: next reconciles by default, -cached opts out - #254
Conversation
`gate next` is the operator's inbox, and it was answering a strictly older question than the one it claims to answer. The log records what gate DECIDED; nothing ever records that the merge later happened, so an un-reconciled projection can only accumulate. Measured on the operator's state 2026-08-22: 149 rows, and all 149 named work already merged or closed — some for nineteen days. A view whose whole contract is "what needs you" cannot default to that. The reconcile already existed and was already correct; it just sat behind -live. This makes it the default and gives the log-only projection its own flag: gate next reconciled (was: -live) gate next -cached the log alone (was: the default) gate next -live accepted and ignored, so pasted commands keep working The default is safe offline because the reconcile fails safe: a repo whose fetch errors keeps its rows and marks them PRState "unknown" with the reason (observe.reconcileLive), so a rate-limited or disconnected run degrades to the old output plus an honest marker rather than to a hidden gap. cmdNext splits into runNext(args, fetch) so the flag routing is testable without a network and without a mutable package-level seam a test could leave swapped — the shape lookupOpenPRsContext already uses. The two existing verb tests inject a seam reporting their fixture PR open, so they keep asserting the projection rather than accidentally asserting the reconcile. On the operator's real state this takes the inbox from 162 rows to 7. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
@claude review this PR |
|
@codex review this PR |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
|
Claude finished @itsHabib's task in 1m 57s —— View job PR Review
Head commit reviewed: Verdict: Ready to merge. The change is correct, the fail-safe property is real, the test coverage pins all three cases, and the backward compatibility guarantee is properly tested. A few observations below, none blocking. What the PR DoesPromotes
Code ReviewFlag routing ( if *cached && *asJSON {
return observe.NextJSON(...)
}
if *cached {
return observe.NextText(...)
}
if *asJSON {
return observe.NextJSONLive(...)
}
return observe.NextTextLive(...)All four Test: Test: Test: Existing tests updated correctly —
Observations (non-blocking)1. 2. The long block comment in 3. No test covers 4. Note in PR description is accurate. The PR correctly scopes itself to the read path and defers the durable closing artifact (the write-side fix) explicitly. That deferral is sound — this change is safe to ship independently. |
|
Reviewer: claude |
|
Closing as superseded by #258, which landed first and made the opposite call deliberately: |
Why
gate nextis the operator's inbox. It was answering a strictly older question than the one it claims to answer.The log records what gate decided. Nothing ever records that the merge later happened — gate emits an
actionartifact carrying the pinned merge command and never learns the outcome. So an un-reconciled projection can only accumulate, and every row it accumulates is a job already finished.Measured on the operator's state, 2026-08-22:
gate next(before)All 138 ready-to-merge rows were checked against
gh pr list: zero still open. All 12 awaiting-judgment rows were spot-checked individually: every one merged or closed, the oldest on 2026-08-02 — nineteen days stale. A view whose whole contract is "what needs you" cannot default to that.What
The reconcile already existed and was already correct. It just sat behind
-live. This promotes it and gives the log-only projection its own flag.gate next-live)gate next -cachedgate next -liveThe default is safe offline. The reconcile fails safe: a repo whose fetch errors keeps its rows and marks them
PRState: "unknown"with the reason (observe.reconcileLive), so a rate-limited or disconnected run degrades to the old output plus an honest marker — never to a hidden gap. That property is what makes this promotable to a default rather than a footgun.cmdNextsplits intorunNext(args, fetch)so the flag routing is testable without a network and without a mutable package-level seam a test could leave swapped — the shapelookupOpenPRsContextalready uses.Verification
On the operator's real state, the same command before and after:
162 rows → 7, and the 7 are genuinely open.
Tests:
TestNextReconcilesByDefault(a merged subject is dropped, and the seam is actually reached),TestNextCachedSkipsTheReconcile(-cachednever touches the seam),TestNextLiveFlagStillAccepted(compat). The two existing verb tests now inject a seam reporting their fixture PR open, so they keep asserting the projection rather than accidentally asserting the reconcile.gofmt,go vet,golangci-lint(0 issues),go test ./cmd/gate/...all green.Note for review
This is the read half.
-livereconciles in memory, re-paid on every call — the ledger still carries those 149 obligations as open forever. The durable fix is a closing artifact appended when ground truth says merged/closed, which is a new artifact kind in a hash-chained log and wants its own design pass. It is also the invariant the org TDD (#245) rests on: "holding the tip of that chain is being the role" only holds if a tip cannot claim work that finished three weeks ago. Filed here as context, not proposed in this PR.🤖 Generated with Claude Code