Skip to content

fix(flows): say why software-factory ends step_failed on a failed review - #113

Merged
kjgbot merged 1 commit into
mainfrom
fix/software-factory-failure-reason
Sep 22, 2026
Merged

kjgbot merged 1 commit into
mainfrom
fix/software-factory-failure-reason

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Sep 21, 2026

Copy link
Copy Markdown
Member

Why

When the software-factory review leaves no review.clean, the flow ends with done("step_failed"). The run outcome then says only:

Flow "software-factory" declared done("step_failed"): its own checks did not pass. No step failed, so there is no step-level evidence to inspect; ...

Evidence: Cloud run f92bf832-7848-58d8-b5ca-da8e3b849f1c (AgentWorkforce/cloud#3919). All 20 steps succeeded. The second reviewer wrote "One P2 remains: cleanup can report success while an ambiguous allocation stays invisible through all three sweeps ...", but the recorded outcome gave no reason.

What (interim, path B)

ctx.done() accepts only a reason in the pinned @relayflows/surface (2.0.22) and in the latest published version (2.0.25): done(reason: FlowCompletionReason): void. AgentWorkforce/flows#542 proposes done(reason, { detail }). Until that ships:

  • New FLOW_REPORT_REVIEW_FINDINGS_COMMAND runs as a deterministic step (report-review-findings) right after the review-blocked step and just before done("step_failed"). It prints an excerpt of review.md to stdout and always exits 0. The journal and flows status both show that stdout.
    • Blank lines and control characters are removed. The findings text is cut at 1,700 bytes, and the step's whole output stays under FLOW_REVIEW_FINDINGS_LIMIT (2,000 bytes). When text is cut, the output says so and points to review-blocked.md.
    • If review.md is missing or empty, the step prints the fixed sentence review.clean absent and review.md missing or empty.
  • The flow's stop message (console.error) now includes the same excerpt.
  • The generated flow has a comment citing done("step_failed") cannot say why: add a detail that reaches the run report and flows status --cloud flows#542: once that API ships, move this text into done("step_failed", { detail }).

Success and failure are decided exactly as before. A clean review never runs the new step.

Tests

  • web/lib/test/flow-workflows.test.ts: the real command runs under sh against fixtures. Covered cases: findings printed; a long review bounded and marked as cut; control characters and blank lines stripped; fallback for a missing, empty or whitespace-only review.md; exit code 0 in every case.
  • web/lib/test/flow-onboarding.test.ts: the generated flow is executed. On an unclean review the step runs after the review-blocked step and is the last step, and the findings appear in the stop message. On a clean review, for every preset, the step never runs.

Mutation proof (each mutation applied on its own, then reverted)

=== M1: remove the bound (head -c -> cat) ===
     × bounds a long review and says it was cut
AssertionError: expected 31710 to be less than or equal to 2000
      Tests  1 failed | 3 passed | 55 skipped (59)
=== M2: remove the summary (no findings printed) ===
     × prints the remaining findings from review.md
     × bounds a long review and says it was cut
     × drops terminal control characters and blank lines from the agent-written text
AssertionError: expected 'relayflow report-review-findings: rev…' to contain 'One P2 remains: cleanup can report su…'
      Tests  3 failed | 1 passed | 55 skipped (59)
=== M3: flow never runs the step ===
     × marks the pull request and parks, never approves, if all reviews fail
AssertionError: expected -1 to be greater than 27
=== M4: step also runs on clean reviews ===
     × hands every preset to a person without calling an unsupported interactive gate or merging
AssertionError: expected [ …(24) ] to not include 'export LC_ALL=C; findings() { tr -d \…'

Results

  • npm test (web): 231 passed, 1 failed. The failure is FLOW_CHECK_RUN_COMMAND > runs the resolved default end to end and it fails the same way on untouched origin/main on this machine. The cause is the local environment: bun sits in the same directory as node, and the test assumes it is absent.
  • npx tsc --noEmit in web and in router: clean.
  • npm run verify:recommended-flows: passes.

No changelog entry, because this is a web-only change.

🤖 Generated with Claude Code


Note

Low Risk
Web-only observability for an existing failure path; review pass/fail behavior is unchanged and output is bounded with exit 0.

Overview
When an adversarial review leaves no review.clean, the flow still ends with done("step_failed"), but the run outcome alone does not explain what the reviewer found. This PR adds an interim report-review-findings step (until done("step_failed", { detail }) in AgentWorkforce/flows#542).

A new FLOW_REPORT_REVIEW_FINDINGS_COMMAND runs right after the review-blocked step and before done("step_failed"). It prints a sanitized, byte-capped excerpt of review.md to stdout (always exit 0), so the journal and flows status show the reason. The same text is appended to the flow’s console.error stop message. Clean reviews never run this step.

Tests cover the real shell command (truncation, control-character stripping, empty/missing review.md) and generated-flow behavior (ordering on failed reviews; absent on success).

Reviewed by Cursor Bugbot for commit 04ac36f. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Adds a deterministic report-review-findings step so runs that end in done("step_failed") on an unclean review record why, instead of only "its own checks did not pass".

Written for commit 04ac36f. Summary will update on new commits.

Review in cubic

When the adversarial review leaves no review.clean, the run outcome only
says "its own checks did not pass" (Cloud run f92bf832, cloud#3919). done()
takes only a reason today, so a deterministic report-review-findings step
now prints a bounded excerpt of review.md (or a fixed fallback) to its
stdout, and the stop message repeats it, before done("step_failed").
Move the text into done("step_failed", { detail }) once
AgentWorkforce/flows#542 ships. Clean reviews are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 21, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-21T16:16:37.017509Z 04ac36f PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Review Change StackReview Change Stack

Understand this PR’s impact

Explore downstream dependencies and potential security impact with Blast Radius.

View blast radius →

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Advanced

Run ID: b96fe02e-bb45-4b89-8d1a-a0a94309136e

📥 Commits

Reviewing files that changed from the base of the PR and between 67d8ccb and 04ac36f.

📒 Files selected for processing (3)
  • web/lib/flow-workflows.ts
  • web/lib/test/flow-onboarding.test.ts
  • web/lib/test/flow-workflows.test.ts

Included review availability: Your plan provides up to 1 included review per hour; 0 remain after this review.


📝 Walkthrough

Walkthrough

The change adds a bounded command that reads filtered findings from review.md. Failed reviews run the command and include its output in the error. Tests cover filtering, truncation, fallback output, command order, and clean reviews.

Changes

Review findings reporting

Layer / File(s) Summary
Findings command and bounds
web/lib/flow-workflows.ts, web/lib/test/flow-workflows.test.ts
The exported command filters control characters and blank lines, limits output to 2,000 bytes, reports missing or empty findings, and exits 0. Tests cover these cases.
Failed-review integration
web/lib/flow-workflows.ts, web/lib/test/flow-onboarding.test.ts
Non-clean reviews run the findings command and append its output to the captured error. Onboarding tests verify ordering, generated source, and that clean reviews do not run the command.

Priority: ⬇️ Low

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Feature

Sequence Diagram(s)

sequenceDiagram
  participant GeneratedFlow
  participant FindingsCommand
  participant ReviewFile
  GeneratedFlow->>FindingsCommand: Run after a non-clean review
  FindingsCommand->>ReviewFile: Read and filter review.md
  FindingsCommand-->>GeneratedFlow: Return bounded findings or fallback text
  GeneratedFlow-->>GeneratedFlow: Append findings to console.error
Loading

Suggested reviewers: kjgbot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 3 functions across 3 files. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: explaining why the software-factory flow ends with step_failed after a failed review.
Description check ✅ Passed The description directly explains the new report-review-findings step, bounded review output, flow behavior, tests, and known test environment issue.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit reads each line,
The patch grows clear beneath the moon,
Small changes hop in place,
Tests guard the garden path,
Reviews bloom before the dawn.

Comment @coderabbitai help to get the list of available commands.

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 potential issue.

Devin Review

Comment thread web/lib/flow-workflows.ts
// did not pass", so this step prints why (a bounded excerpt of review.md)
// where the journal and flows status show it. Move this text into
// done("step_failed", { detail }) once AgentWorkforce/flows#542 ships.
const reviewFindings = (await f.run(reportReviewFindingsCommand)).trim();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Second review reports stale findings

When the second reviewer omits review.md, reviewFindings reports the first review's findings. Only review.clean is removed between rounds, so obsolete findings bypass the missing-review fallback.

Learn more

Traditional workflows can run two adversarial reviews. The first failed review writes review.md, then the fixer changes the branch before the second review. The loop removes review.clean before each reviewer but preserves review.md, so a second reviewer that creates neither artifact leaves the first review's file in place. The new report command sees a non-empty file and presents those earlier findings as the reason the final review failed.

Example: Round one reports “P2: retry is broken.” The fixer repairs retries. Round two fails to create either artifact, so the run reports the already-fixed retry finding instead of saying the final reviewer left no report.

Recommended fix: Remove review.md immediately before each adversary runs, alongside review.clean. This preserves round-one findings for the fixer, then clears them before round two so the reporter's missing-review fallback can activate.

Devin Review


Was this helpful? React with 👍 or 👎 to provide feedback.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 04ac36f424

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread web/lib/flow-workflows.ts
'if [ -s review.md ]; then size=$(findings | wc -c | tr -d " "); fi',
'if [ "$size" -eq 0 ]; then echo "relayflow report-review-findings: review.clean absent and review.md missing or empty" && exit 0; fi',
'echo "relayflow report-review-findings: review.clean absent; remaining findings from review.md:"',
`findings | head -c ${REVIEW_FINDINGS_BODY_LIMIT}`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve UTF-8 boundaries when truncating findings

When the sanitized review exceeds 1,700 bytes and this byte boundary falls inside a multibyte character, head -c emits invalid UTF-8; for example, 1,699 ASCII bytes followed by an emoji leaves only its first byte in stdout. Because f.run, the journal, and flows status consume this output as text, the excerpt can be rejected or rendered with a replacement character precisely where a finding is being reported. Truncate at the last complete UTF-8 character within the byte limit instead.

Useful? React with 👍 / 👎.

@github-actions

Copy link
Copy Markdown
Contributor

Preview deployed!

Environment URL
Web https://38c3904a-agentrelay-web.agent-workforce.workers.dev

This is a Cloudflare Workers preview version of this PR's build.

@kjgbot
kjgbot merged commit db022bc into main Sep 22, 2026
6 checks passed
@kjgbot
kjgbot deleted the fix/software-factory-failure-reason branch September 22, 2026 18:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants