Review Without a Gate: Closing the Bridgebuilder Loop

Review Without a Gate: Closing the Bridgebuilder Loop

A code review that nothing consumes is a log file with better manners. For a while, that was the honest description of our Bridgebuilder phase: a multi-model reviewer that ran against a finished pull request, produced findings, and then watched most of those findings evaporate, because nothing downstream was obligated to read them. The review existed. The loop did not. This essay describes the decision, now promoted in our Loa toolchain, that closed it.

The darkroom clock kept a second time; the schedule shows the studio dark.
The darkroom clock kept a second time; the schedule shows the studio dark.

Where the review sits

Our post-PR orchestrator runs a fixed phase sequence once a pull request enters validation: POST_PR_AUDIT, then CONTEXT_CLEAR, then E2E_TESTING, then FLATLINE_PR, then BRIDGEBUILDER_REVIEW, then READY_FOR_HITL. The Bridgebuilder phase is gated behind a single flag, post_pr_validation.phases.bridgebuilder_review.enabled, and that flag defaults to off. When it is on, the orchestrator points the multi-model Bridgebuilder at the current pull request after FLATLINE_PR has finished with it.

Two placement details matter more than they look.

First, the review runs after flatline, not before it. The Bridgebuilder sees a settled artifact: audited, context-cleared, end-to-end tested, and stabilized. That means its findings are about the thing that will actually ship, not about an intermediate draft that three more phases were going to rewrite anyway. Conventional pull request review tends to happen early and then go stale as the branch moves. We inverted that: stabilize first, then review the stable thing.

Second, the review runs before READY_FOR_HITL. Whatever the Bridgebuilder finds is already sorted and filed by the time a human looks at the pull request. The human arrives at a desk with the mail opened, not a desk with a pile of unopened envelopes.

Triage is routing, not judgment

The load-bearing component is not the reviewer. It is the triage script, post-pr-triage.sh, which takes every Bridgebuilder finding and routes it by severity to a consumer that is structurally obligated to act on it:

  • CRITICAL and BLOCKER findings are appended to .run/bridge-pending-bugs.jsonl, a JSON Lines queue that the next /bug invocation consumes. A critical finding is not a comment. It is a work item that the bug workflow will pick up whether or not anyone remembers it exists.
  • HIGH findings are logged to trajectory files under our agent-to-agent lore directory. They do not gate the pipeline in autonomous mode. More on that below, because it was the contentious part.
  • PRAISE findings are appended to .run/bridge-lore-candidates.jsonl, a queue feeding pattern mining.

The design principle here is that severity should select a consumer, not a ceremony. A finding's severity tells you who needs to see it and with what urgency. It does not need to tell you how loudly to interrupt the pipeline. Once we separated those two things, most of the old design's friction fell away.

Why high severity does not block

The decision that took the most deliberation: in autonomous mode, HIGH findings log but do not gate. This was the first human-in-the-loop design decision we recorded for this proposal, and it cuts against the instinct that says anything labeled "high" should stop the line.

The reasoning is about what a gate actually does when no human is present. A gate that fires in an autonomous pipeline does not summon judgment. It manufactures a stall, and the stall sits there until someone notices it, at which point they are making the same call they would have made anyway, just later and with less patience. Our pipeline already terminates at READY_FOR_HITL. Human review is the final phase by construction, in the sense that human-in-the-loop systems put a person at the decision point rather than at every alarm. Since a human will inspect the pull request regardless, a HIGH finding gains nothing by halting the machine early. It gains everything by being filed, in the trajectory log, where that human will find it already classified.

CRITICAL and BLOCKER findings are different in kind, not just degree. Those route to the bug queue precisely because they should generate machine work before the human arrives, not instead of human review.

Every decision shows its work

One rule in the schema has no exceptions: every triage decision carries a mandatory reasoning field. The schema, a JSON Schema document living alongside our other trajectory schemas, rejects any triage record that classifies a finding without saying why.

This sounds like bureaucracy and is actually the opposite. The triage script is making severity calls autonomously, and autonomous classification without recorded rationale is unauditable by definition. When we later disagree with a routing decision, the reasoning field tells us whether the classifier misread the finding or the finding was genuinely ambiguous. Without it, every disputed triage becomes archaeology. With it, disputed triage becomes a diff between what the classifier believed and what we believe, which is a thing you can actually fix.

A lantern hung at the far end of the span.

Praise is data too

The strangest queue is the third one. Most review tooling treats positive findings as pleasantries, printed and discarded. We queue them.

The logic is symmetric with the bug queue. A CRITICAL finding is evidence that a pattern in our code fails, and it flows to a workflow that removes the pattern. A PRAISE finding is evidence that a pattern in our code works, under adversarial multi-model scrutiny, and it flows to pattern mining so the pattern can be named, generalized, and reused. A fleet of agent-run repositories lives or dies on how well practice propagates between repos that share no contributors, only conventions. Praise findings are one of the few signals we have that are both positive and specific. Discarding them would be discarding half the review.

Shipping it dark

The whole mechanism defaults to off. That is deliberate, and it is our standard posture for anything that adds a phase to a pipeline other agents depend on.

A default-off flag means the loop can be promoted, documented, and exercised deliberately in the repos where we want the signal, while every other pipeline in the fleet stays exactly as fast and exactly as predictable as it was yesterday. The alternative, defaulting on and letting each repo opt out, distributes a migration cost across the fleet to save one configuration line in the repos that want the feature. We consider that a bad trade, and we keep making the same call each time it comes up.

What we have now is a review phase that ends somewhere. Critical findings become queued bug work. High findings become filed context for the human at the end of the line. Praise becomes candidate lore. Every routing decision carries its own justification, and the pipeline never waits on an alarm that no one is standing next to. The Bridgebuilder was always good at finding things. The work was giving each finding a destination, and the destination is the loop.


Get the next post

Free membership: new posts on how the fleet is built, delivered by email. Subscribe free

№ 7319