Skip to content

Continue triage when a rejected fix says what is still broken - #20

Open
matthewp wants to merge 4 commits into
mainfrom
fix/retry-rejected-preview
Open

matthewp wants to merge 4 commits into
mainfrom
fix/retry-rejected-preview

Conversation

@matthewp

@matthewp matthewp commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Changes

  • A rejected preview fix now continues triage from the existing candidate commit on the same fix branch instead of parking at triage: fix rejected: the run keeps the parts of the fix that already work, aims at what remains, and updates any existing pull request.
  • The FixVerifier classifies a rejection as specific or vague in the verdict it already produces. Feedback that names what is still broken buys another run; "still broken" gets a question asking what is still wrong, so a vague reply no longer spends a full pipeline run on a guess. The reporter's answer re-enters through the normal re-triage path and still continues from the candidate.
  • Automatic retries are capped at three per issue — counted from markers on the acknowledgement comments, so no new state — after which the issue is left for a maintainer.
  • A continuing run diffs against the candidate commit rather than the default branch, so a run that changes nothing no longer force-pushes or reports a push that did not happen.
  • The candidate checkout is pinned to the commit the verifier saw, and says which commit it found when the branch has moved instead of failing with an empty error.

Fixes #19

Testing

  • tests/fix-verification.test.ts: verdict invariants for the new feedback classification, the retry / needs-details / retry-limit decision, and marker-based idempotency — a redelivered or retried step repeats the decision it already announced instead of double-posting or changing its mind.
  • tests/triage-prompts.test.ts: the pipeline system prompt's fresh and continuing-fix branches. The prompt moved into prompts.ts so it can be read without a Flue runtime, matching how the verifier prompt is already tested.
  • tests/sandbox.test.ts: pinned candidate checkout, unsafe commit input, and the message the fix-branch pin produces when the branch moved.

Docs

  • README's triage state list now describes the rejected-fix routing and the retry cap. Nothing else is user-facing — this is bot behavior on issues it already comments on.

Comment thread src/triage/agents/triage-pipeline.ts Outdated
Comment on lines +142 to +144
input.continuingFix
? `The repository is checked out at ${REPO_DIR} on the existing candidate branch \`${input.fixBranch}\`. Preserve the parts of that fix which already work and use the latest reporter feedback to address what remains broken. You have a full shell: build, run, and edit code as the skill directs.`
: `The repository is checked out at ${REPO_DIR} on branch \`${input.fixBranch}\` (created from \`${input.defaultBranch}\`). You have a full shell: build, run, and edit code as the skill directs.`,

@ematipico ematipico Aug 19, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should make sure that the feedback is actionable, and that provides more context than before. It the user says "no, it didn't fix the issue", there's a chance that the agent will produce the same code as before.

If the message didn't provide enough context, we could have the bot replying with a message asking for more context.

- Merge main (progress tracking, in-progress labels) with fix/retry-rejected-preview
- Pass fixBranch, progress, and progressComment to runPipeline
- Add fixBranchHead to setupWorkspace for continuing-fix flow
- Update continuingFix prompt: submit fixed=false when feedback lacks specifics
@matthewp matthewp added the ai-review Request an automated Factory review label Aug 21, 2026
@astro-factory astro-factory Bot removed the ai-review Request an automated Factory review label Aug 21, 2026
@ematipico ematipico added the ai-review Request an automated Factory review label Aug 21, 2026

@astro-factory astro-factory 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.

The PR correctly implements continuing triage from the pinned fix branch after a rejected or partial preview: it captures the branch head SHA, fetches and verifies it during workspace setup, pins the checkout to that commit, and prevents duplicate retry acknowledgment comments per delivery. Credential handling stays sound—the contents-read token is passed only as an ephemeral http.extraHeader, the remote is removed for private checkouts, and the push token stays isolated to the single push command.

One durable-execution pitfall stands out: the find fix branch workflow step now returns { name, headSha } instead of a plain branch-name string. Workflows persists step outputs by name and replays cached results on retries and resumes, so in-flight instances that executed this step under the old code will throw when the new code accesses fixBranch.name/fixBranch.headSha. Renaming the step (e.g., 'resolve fix branch head') or normalizing the cached value would avoid the replay break.

This review was made by an LLM. The analysis may be wrong, and reports might be incorrect.

Comment thread src/triage/workflow.ts Outdated
@ematipico ematipico added ai-review Request an automated Factory review and removed ai-review Request an automated Factory review labels Aug 21, 2026
- Classify rejection feedback in the FixVerifier verdict (specific/vague)
  rather than promising comment-step behavior the pipeline does not have
- Ask the reporter what is still broken instead of spending a pipeline run
  on a guess; cap automatic retries at three
- Continue from the candidate when a rejected fix is re-triaged
- Diff a continuing run against the candidate commit, not the default branch
- Say which commit the fix-branch pin found when it fails
Conflicts were between main's repo-wide reformat and this branch's
extraction of the fix-verifier and pipeline prompts into plain modules;
kept the extracted prompts and main's formatting, and reran Biome.
@matthewp matthewp changed the title Retry triage when preview fixes are rejected Continue triage when a rejected fix says what is still broken Aug 21, 2026
@ematipico ematipico added ai-review Request an automated Factory review and removed ai-review Request an automated Factory review labels Aug 21, 2026
@astro-factory astro-factory Bot removed the ai-review Request an automated Factory review label Aug 21, 2026

@astro-factory astro-factory 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.

This PR improves the rejected-fix flow by continuing triage from the existing candidate commit, classifying feedback as specific or vague, capping retries, and pinning the checkout to the verified commit. The core changes look correct, but two issues stand out:

  1. The new feedback field on fixVerdictSchema is required, which breaks replay for any fix-verification agent output already persisted before this deploy. It should be optional with a null default.
  2. The marker loop in acknowledgeRejectedFix treats markers in any issue comment as authoritative, so untrusted users can forge hidden markers to manipulate retry counting or idempotency. It should only inspect bot-authored comments.

The previously unresolved thread about the find fix branch step result shape remains unaddressed at the current head; per the review instructions I have not repeated it as a new finding.

This review was made by an LLM. The analysis may be wrong, and reports might be incorrect.

Comment thread src/triage/contracts.ts
* Whether a rejection says enough about what is still broken to aim
* another triage run at it. Null unless the status is "rejected".
*/
feedback: v.nullable(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium][correctness]: fixVerdictSchema requires a new feedback key, breaking in-flight verdicts

fixVerdictSchema now requires a feedback field that did not exist in the previous schema. Any fix-verification agent output already persisted by Flue from before this deploy will fail validation when the workflow resumes and extractLastWrite(..., fixVerdictSchema) is called, causing those in-flight runs to error out.

Make the field optional with a default of null (for example v.optional(v.nullable(...), null)) so existing persisted data can load; validateFixVerdict can still enforce the classification for verdicts produced by the new agent.


let priorRetries = 0;
for (const comment of comments) {
for (const [, delivery, action] of (comment.body ?? '').matchAll(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

[medium][security]: Retry/idempotency markers are trusted from any comment author

acknowledgeRejectedFix scans every issue comment for factory-fix-followup markers and treats them as authoritative, both for per-delivery idempotency and for counting action=retry against the retry budget. Because issue comments are untrusted input, a reporter or third party can include hidden HTML comments with those markers to exhaust the retry budget prematurely or influence which action is returned.

Filter the comment list to bot-authored comments (for example by checking comment.user?.type === 'Bot' or the known bot login) before matching markers, or include a Worker-only signature in the marker so users cannot forge it.

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.

Partial preview success is treated as full fix verification

2 participants