- proposal row
- yes, linked to the run id
- Inbox item
- yes, if the call succeeds
- run review
- no, so the run page has nothing to show
FIMO-2706 · Agent review flow
What a person should see when an agent asks for review, what they see today, why, and what to change.
Outcome
The review flow is broken in three places, and each needs its own fix. First, the run page shows no changes, because the agent's "request review" step saves the work somewhere the run page does not read. Second, the request is hard to find: the run looks "done" everywhere, and the only signal is an Inbox item that exists only when the request succeeded. Third, merging from the preview leaves the branch open, because the Studio merge button never tells the agent's work session that it was merged.
The code changed on 28–29 September. Autonomous runs moved onto work sessions, the same save/merge/discard model chat uses (FIMO-2429). That code is on develop and on staging (main), but not on production yet. Production still runs the older flow, which has the same three symptoms from slightly different causes. The fix below targets the new code, because that is what the next production release ships.
One more production bug is independent of the rewrite. Every new "Welcome to Fimo" project starts with a prepared footer suggestion from the welcome-guide agent, and none of them ever reaches anyone's Inbox. That is 726 invisible review requests in three weeks.
The intended journey
A review request should be visible, inspectable, and finish cleanly
An autonomous agent works on its own copy of the project, a task/… branch. When it finishes, it either merges (only with the auto-merge permission), throws the work away, or asks a person to review it. For the review case, a person should get a signal, open the run, see exactly what changed, and accept or reject it. After acceptance, the task branch should go away.
The diagram shows that journey. Red marks where it breaks today.
flowchart TB Agent[Agent works on<br/>task branch] --> Ask[Agent calls<br/>request_review] Ask --> Signal[Person gets<br/>a signal] Signal --> Run[Run page shows<br/>the changes] Run --> Merge[Person merges] Merge --> Close[Task branch<br/>closed] classDef broken stroke:#e5484d,stroke-width:3px; class Signal,Run,Close broken
Gap 1 · Changes do not show
"Request review" saves the diff where the run page never looks
There are two places where a review can be stored. The run review sits on the run itself (agent_sessions.reviewSummary), and the run page reads only that. The proposal is a separate record that the Inbox links to. When the agent calls request_review, the code creates the proposal and the Inbox item, but it never writes the run review.
So the run page finds no review. Its Code / Content / Schema tabs stay disabled, and the "Accept changes" button never appears. The only path that writes a run review is the one where the agent merges or discards the work itself. That is exactly the case where nobody needs to review anything.
The onboarding "prepared run" already does both steps. The normal agent path just forgot the run-review half.
- run review
- yes, captured before closing
- publication
- merged, conflict, or not published
- side effect
- a discarded run shows "Accept changes" for a deleted branch
apps/api/src/jobs/run-agent-session.tsThe only place a run review is captured: on close2261async close(input) {
227 const session = await workSessionService.getOwned(input);
228 if (session.status === 'ready' && session.workingBranchName) {
2292 await captureSessionReview({ … })
236 }
237 const outcome = await workSessionService.close(input);
2383 await agentsBoot.reviewStore.markPublication(…)
- 1
Merge or discard only. This wrapper runs when the agent closes its work session.
request_reviewgoes throughreview/capture.tsinstead and never reaches it. - 2
The run page's data. This is what fills
reviewSummaryand the stored diff that the run page tabs render. - 3
Discard also marks "not published". The run page reads that as "waiting for review" and offers "Accept changes" for a branch that no longer exists.
Gap 2 · Request is invisible
Everything except one Inbox item says the run is "done"
With no run review, the rest of Studio also misreads the run. The status badge shows done, not needs attention. The runs-list "needs attention" filter skips it. The run notification cannot say "kept for review", because the code that builds it only knows three outcomes: merged, conflict, or nothing.
The only signal left is the Inbox item that request_review creates. It only exists if the call succeeded. The call can fail quietly: the agent gets requested: false back, and the person gets nothing. It fails on a diff time-out, when the branch moved mid-capture, at branch capacity, or on a target-branch mismatch.
Production has a second, bigger version of this problem: the onboarding welcome-guide run. It is prepared while the welcome project still sits unclaimed in the pool, with no members. At that point nobody can receive the Inbox item, and nothing creates it later when a user claims the project.
726 of 745 retained runs with changes in the last 21 days have no Inbox item. All 726 are welcome-guide, one per new welcome project.
19 retained reviews from real agents did get an agent_retained_review Inbox item (old flow).
13 runs since 28 Sep. The only retained welcome-guide run again has no Inbox item.
Needs the affected project id to check the run's tool-call outcomes.
Gap 3 · Branch stays open
Merging from the preview never tells the work session it is done
"Open preview" on the run opens Studio on the agent's task/… branch. From there, the normal Merge button runs a plain branch merge. That merge succeeds, but nobody tells the agent's work session. The session stays open, so its branch stays alive.
There is a cleanup hook, but it quits early: it only acts when the session already has a mergeId. The session gets a mergeId only when it closes itself. A Studio merge is a different merge, so the check always fails. A review session is also marked "keep forever" (no expiry), so the idle sweep never removes it either.
After the merge, the dialog offers "Keep branch" or "Delete". Since 3 Sep, "Keep branch" is the highlighted default. "Delete" closes the session, but records it as discarded, not merged.
apps/api/src/domain/work-sessions/service.tsWhy the merge cleanup does nothing617async reconcileCompletedMerge(input) {
618 const session = await this.store.findById(input.sessionId);
6191 if (!session || … || session.status !== 'ready' || !session.mergeId)
620 return false;
6212 const snapshot = await this.deps.readMerge({ …, mergeId: session.mergeId });
622 if (snapshot?.status !== 'complete') return false;
- 1
Studio merges never set this. Only the session's own close or resolve writes
mergeId, so a person's merge from the preview exits here. - 2
Wrong merge. Even with a
mergeIdfrom an earlier parked conflict, it checks that old merge, not the one the person just completed.
19 of 19 runs merged through the Studio merge dialog in the last 21 days still have an active task branch.
Smaller gap · Live refresh
The run page stops listening before the interesting part
The run page polls every five seconds while the run is active and stops when it finishes. After that it relies on a live agent:run event. That event fires only when the run starts, finishes, fails, or is cancelled. Nothing fires when a review is requested, when the work is merged, or when the publication state changes, so the page shows stale state until a reload or tab refocus.
apps/ui/src/features/agents/api/useGetAgentSession.tsPolling ends when the run finishesrefetchInterval: (query) =>
isAgentSessionActive(query.state.data?.status) ? ACTIVE_SESSION_REFETCH_MS : false,
- PollingStops once the run is finished (useGetAgentSession.ts).
- EventsOnly planned, started, completed, failed, cancelled (run-events.ts).
Proposal
Five focused fixes, each closing one gap
Each fix reuses a path that already exists and works somewhere else. None adds a new concept. Fixes 1 and 2 matter most, and between them they cover all three symptoms.
The order matters: fix 1 makes the review visible, and fix 2 makes it finish cleanly. Fixes 3 and 4 remove the confusing leftovers. Fix 5 is a production-only onboarding bug that affects every new welcome project. Each fix ships with E2E that runs the journey in its row, including the failure case.
request_review also writes the run review
- Starts with
- The agent finishes work and calls
request_review. - You do
- Open the run from the Inbox or the runs list.
- You see
- Code / Content / Schema tabs with the diff, a needs attention badge, and "Accept changes".
- Check
- Capture the run review and mark it
not_publishedin the same step, exactly as the onboarding prepared run already does. - Not proven
- Not built yet. E2E must drive a real agent run to a review.
A Studio merge of an agent branch closes its work session
- Starts with
- A review is waiting on a
task/…branch. - You do
- Open preview and press Merge.
- You see
- The work lands on main, the run shows merged, and the task branch is gone.
- Check
- On merge completed, find the ready work session for that source branch, close it as merged with this merge id, and delete the branch.
- Not proven
- Not built yet. The failure path (merge with conflicts) must keep the branch.
Refresh the run page when the review state changes
- Starts with
- The run page is open on a finished run.
- Trigger
- A review is requested, or the work is merged.
- Result
- The page updates without a reload.
- Check
- Broadcast the existing
agent:runevent after these writes. - Not proven
- Not built yet.
No "Accept changes" on discarded work
- Starts with
- The agent discarded its work.
- You do
- Open the run.
- You see
- The diff for reference, but no accept button.
- Check
- A discard is not "waiting for review".
- Not proven
- Not built yet.
The welcome suggestion reaches the new owner's Inbox
- Starts with
- A user claims a "Welcome to Fimo" project.
- You do
- Open the Inbox.
- You see
- "A footer update is ready to review".
- Check
- Create the review Inbox item when the claim finishes, once the project has members.
- Not proven
- Not built yet. Existing claimed projects stay without the item unless we backfill.
Evidence and limits
Diagnosis is grounded; nothing is fixed or tested yet
All findings come from reading develop at 8159c88ae, plus read-only queries against the production and staging databases. No code changed, and no test or E2E ran. The file list shows where each gap lives. Open a row to read the file at that revision.
All three gaps traced to specific lines on develop 8159c88ae.
Read-only aggregate queries, run on 2026-09-30.
Not identified yet; exact failure of that run unconfirmed.
Not started.