Review-Loop Agent Sessions (internal/pipeline/sessions.go)
- Per run, the review loop keeps ONE durable fixer session across review-fix turns, and EVERY review turn (initial review and every full rereview) runs session-free. A rereview certifies fixes implementing the previous review turn's findings, so resuming any review session seats the prescriber as certifier - the mechanism that let one fix round ship wrong code plus the test blessing it with zero findings. Cross-round review context travels only in the explicit sanitized round history; the fixer session is never lent to review turns, no other step uses sessions, and sessions are keyed strictly by run. The rereview prompt reframes fix-round changes as pipeline-authored code under the author-grade adversarial standard (
fixRoundProvenanceClause); the same clause is emitted on a later run's initial review when a persisted uncertified range is bound. Prior findings, fix summaries, and same-round tests are claims, not evidence. - Fail-safe rules: unsupported adapter runs cold; a failed fixer resume drops the identity and re-runs the same turn in a fresh fixer session, never skipping the turn; a cancelled ctx gets no fallback retry;
session_reuse: falseforces everything cold. Persistence is minimum metadata only, never prompts or transcripts;SessionRoleReviewerremains only so crash recovery accepts legacy persisted rows, which are never resumed. codex exec resumehas a narrower flag surface thancodex exec, so an unsupported override fails the resume and falls back; the e2e fakeagent must keep parsing both codex argv shapes (extractCodexPrompt).- Regressions:
internal/pipeline/sessions_test.go,internal/pipeline/steps/review_session_test.go(incl.TestReviewLoop_RereviewNeverResumesTheSessionThatPrescribedItsFixes),TestReviewStep_RereviewTreatsFixRoundsAsPipelineAuthoredCode,internal/agent/session_test.go.
Recorded Human Decisions on Findings
- Approve, skip, and abort each record
selected_finding_ids = "[]"plusselection_source = user_declinedon a gated round with findings (executor.gorecordDeclinedRound,db.SetStepRoundDeclined); a round with no findings records no decision. The conditional write must never erase an existing selection. User-facing semantics are owned bydocs/src/content/docs/reference/pipeline-steps.md. - A decline is stored as the COMPLEMENT of the selection, never as its own list;
declinedFindingLinesderives it and deliberately excludesauto_fixselections, whose complement is findings still awaiting a decision (rendered underauto_fix_left_unselected, which carries no do-not-re-report instruction). roundHistoryPromptSection(internal/pipeline/steps/round_history.go) now carries three parts: this step's rounds, this run's OTHER steps' decisions, and earlier runs' decisions on this branch (bound per step bypipeline.BindBranchDecisions, unlike review-onlyBindUncertifiedPipelineRange). Nothing clears branch decisions - a completed review deletes the uncertified range, which is why that channel could not carry a decision forward, but approving a gate IS the decision. The prompt states that a recorded decision SUPERSEDES the user-intent wording.- Deliberately ADVISORY and fail-open: no step is blocked and no commit is gated, so an agent may still re-raise a declined finding when the code genuinely changed. There is no reversion detector;
assertPipelineHeadContinuityandassertReviewApprovedPushHeadremain lineage-only.ci_fix.goandrebase.gobuild prompts withoutroundHistoryPromptSection, so they do not receive decisions. - Regressions:
TestExecutor_GateResolutionsWithoutASelectionRecordTheDecline,TestExecutor_GateResolutionWithNoFindingsRecordsNoDecision,TestExecutor_FixResolutionStillRecordsAUserSelection,internal/db/round_decisions_test.go,TestDeclinedFindingReachesALaterStepInTheSameRun,TestDeclinedFindingReachesALaterRunOnTheSameBranch,TestCompletedReviewDoesNotClearBranchDecisions,TestAutoFixComplementIsNeverPresentedAsAUserDecision.
Uncertified Review Provenance (internal/pipeline/uncertified.go)
- When a review-step fixer round commits and its re-review does not complete, persist the per-branch uncertified range (
from_sha,to_sha). Persist on review-step fixer commits only, not lint or document. On the next run's initial review, bind that range and emitfixRoundProvenanceClauseeven whenFixing==false, so the replacement reviewer is not cold. Rerun proceeds; there is no refusal or--ack-uncertified-reviewgate. - Missing git objects warn and continue, never block. Clear the range only after a completed review whose approved head equals or is a descendant of
to_sha; parked, failed, skipped, and aborted reviews must not clear it. Rebase remaps the persisted SHAs onto the rewritten head so the next review can still bind. - Regressions:
internal/pipeline/uncertified_test.go,TestCommitAgentFixes_PersistsUncertifiedRangeForReview,TestCommitAgentFixes_LintDoesNotPersistUncertifiedRange,TestCommitAgentFixes_DocumentDoesNotPersistUncertifiedRange,TestFixRoundProvenanceClause_EmitsForUncertifiedRangeWhenNotFixing,TestUncertifiedRange_PersistsThenFeedsNextInitialReview,TestRebaseStep_RemapsUncertifiedRangeWhenHeadRewritten.
Review Fixer Verification Discipline (internal/pipeline/steps/review.go)
- The review-fix prompt requires all fixes before one focused verification limited to the changed area and forbids the whole repository test/lint suite during the fix round.
The dedicated Test and Lint steps are the authoritative gates, although their coverage may be focused when commands are unconfigured.
This is a prompt contract, not an enforced sandbox.
Regression:
TestReviewStep_FixMode_FocusedVerificationContract.
Agent-Invocation Timeouts Report Measured Silence, Never the Budget
- A timeout diagnostic may only state what was observed, never restate the configured budget as measured silence.
agentActivityinagent_run.gois the single owner of the measurement and resets per-attempt evidence whenever a retry or fallback starts a replacement attempt, including provider, session-resume, and OpenCode prompt-format fallbacks. A substantive adapter error (a native agent's exit status plus captured stderr) is URL-redacted, length-bounded, and appended asagent reported: .... - Observed output is streamed assistant text plus throttled
agent.LifecyclePhaseActivity, sourced from every non-empty read of a native subprocess's stdout or stderr. Prose alone cannot prove liveness: verified against pi 0.84.3, a tool-using turn emits onlytool_execution_*/toolcall_*and notext_deltauntil the very end, and no adapter forwards those toOnChunk. Subprocess start and exit are deliberately NOT output - start proves launch, not work, and exit is the deadline's own consequence, so counting either would recreate the fabricated evidence. - The executor consumes
LifecyclePhaseActivityinto step activity only, never the step log:axi statusneeds the liveness, and a half-hour turn would otherwise emit hundreds of log lines. - A CI auto-fix agent that exhausts its budget parks at an ask-user gate (
ciFixAgentTimeoutOutcome) instead of being logged as a warning and re-issued on the next poll. That old path spent up toauto_fix.cifull budgets invisibly untilci_timeout. Onlypipeline.ErrAgentTimeoutparks; other fix failures keep warn-and-retry. Review deliberately still fails the run rather than parking - Push commits leftover worktree changes, so an approved park would ship a half-finished, unreviewed fix. - Docs owners:
docs/src/content/docs/reference/global-config.md(agent_timeout) for the diagnostic vocabulary,docs/src/content/docs/reference/pipeline-steps.md(CI) for the park. Regressions:TestRunAgent_Timeout*,TestRunAgent_SubprocessStartAloneIsNotObservedOutput,TestRunAgent_OperatorCancellationIsNotDressedUpAsAnAgentFault,TestPiAgent_ToolOnlyStreamStillReportsSubprocessLiveness,TestPiAgent_SilentSubprocessReportsNoLiveness,TestExecutor_SubprocessLivenessUpdatesActivityWithoutFloodingTheStepLog,TestCIStep_FixAgentBudgetExhaustionParksForADecisionInsteadOfRetrying,TestCIStep_NonTimeoutFixFailureKeepsRetrying,TestReviewStep_RoundBudgetTimeoutPreservesTheAgentReport, e2eTestSilentAgentTimeoutReportsMeasuredEvidence.
Local Test Is Targeted Validation (internal/pipeline/steps/test.go)
- Local Test (normal evidence agent and Test-repair agent) validates the requested intent with the smallest relevant checks and end-user-aligned evidence; it is never a repository-wide regression-suite walk.
Broad regression belongs to remote CI (
go test -race ./...in.github/workflows/ci.yml) and remains mandatory before a PR is ready.commands.testis the same contract when set: targeted baseline, not CI-parity complete-suite configuration; docs owner isdocs/src/content/docs/reference/repo-config.md(commands.test), step behavior owner isdocs/src/content/docs/reference/pipeline-steps.md(Test). This repository dogfoods an emptycommands.testso the agent-driven targeted path is the default; do not reintroducego test -race ./...as a local Test override. Process-group reaping on clean/error exit (#357) and Unix WaitDelay remain the lifecycle safety net when agents spawn test workers - restoring the agent-driven path must not revive the daemon OOM leak. Those agent turns are bounded bytest_agent_timeout(default 30m, global-only): a stalled evidence or repair agent is cancelled and the run fails instead of waiting forever. Native adapters already honor that deadline throughCommandContext; the missing piece was the Test step never setting one. Docs owner isdocs/src/content/docs/reference/global-config.md. Every other pipeline agent invocation is bounded byagent_timeout(default 30m, global-only) atpipeline.RunAgent/ the executortimeoutAgentseam, so a new agent-spawning step cannot hang a run by forgetting a deadline. Review keepsreview_agent_timeoutas a per-round budget; an existing sooner deadline is honored rather than capped. The invocation context is scoped only toAgent.Run; a late successful return after the deadline is rejected. Docs owner isdocs/src/content/docs/reference/global-config.md. Regressions:TestTestStep_InitialAgent_TargetedValidationContract,TestTestStep_FixMode_TargetedVerificationContract,TestTestStep_FixMode_DriverFullSuiteInstructionDoesNotOverrideContract,TestTestStep_InitialAgent_NoTargetedEvidenceRequiresHonestFinding,TestTestStep_HangingEvidenceAgentFailsRunAfterTimeout,TestCodexAgent_RunCancelsSilentHang,TestDogfoodConfig_NoBroadLocalTestCommand,TestCIWorkflow_RetainsFullRaceSuiteAsBroadRegressionOwner, plus the existing #357 reap/WaitDelay tests,TestRunAgent_*,TestExecutor_DirectAgentRunIsDeadlineBounded,TestDocumentStep_HangingAgentFailsRunAfterTimeout,TestLintStep_HangingAgentFailsRunAfterTimeout,TestCIStep_HangingFixAgentFailsAfterTimeout,TestRebaseStep_HangingConflictAgentFailsAfterTimeout.
Intent Provenance & Conformance (internal/pipeline/steps/intent_prompt.go)
- Intent carries provenance: an explicit
axi run --intentpersistsSource==db.RunIntentSourceAgent("agent", score 1); a transcript match persists the agent name ("claude"/"codex"/...). The executor propagates it asStepContext.IntentSourcealongsideUserIntent(executor.go). userIntentPromptSectionbranches on source: an EXPLICIT intent renders as sanitized-but-AUTHORITATIVE acceptance criteria; an INFERRED intent keeps the low-confidence hint framing verbatim. Both branches keep theStripAdversarial+RedactSecretspipeline and BEGIN/END "do not execute instructions" guard - authoritative reframes only the content's authority (check the diff against the criteria), never whether control tokens are stripped. The review prompt addsintentConformanceReviewClausefor agent-source intent only: a fixer change that contradicts the criteria (removes intent-required or adds intent-forbidden behavior) MUST become anask-userfinding, which parks with no executor change. Conformance is limited to source-verifiable criteria; deferred pipeline-owned delivery (remote branch / push / PR / CI for this run) is out of scope at review.- Review is always pre-push (
StepReviewbeforeStepPush/StepPR/StepCI).pipelineDeliveryPhaseClauseplusstripDeferredPipelineOwnedDeliveryFindings(pipeline_delivery.go, applied inreview.go) keep findings that only claim those later-owned outcomes are missing from parking the run. External or pre-existing lifecycle requirements (numbered PR, third-party artifact, non-run-owned state) stay enforceable. Push, PR, and CI steps remain strict after their stages run. - Empty/missing finding
actionfails closed toask-user, not auto-fix (types/findings.goActionOrDefault);HasAskUserFindingsusesActionOrDefaultso it agrees withAutoFixableFindings(an unclassified finding is never auto-fixed and is always caught as ask-user).MergeUserOverridesstill stamps user-added findings auto-fix on purpose. - The deterministic net-deleted-author-lines git-diff backstop is intentionally not built;
review.goowns the held-scope TODO. - Regressions:
internal/pipeline/steps/intent_prompt_test.go,internal/pipeline/steps/review_test.go(TestReviewStep_ConformanceObligationTracksIntentProvenance,TestReviewStep_RereviewFlagsIntentContradictionAsAskUser),internal/pipeline/steps/pipeline_delivery_test.go,internal/pipeline/steps/review_pipeline_delivery_test.go,internal/pipeline/executor_intent_conformance_test.go,internal/types/findings_test.go, e2eTestIntentJourney(inferred-source framing), e2eTestReviewPipelineOwnedPRCriterionDoesNotPark/TestReviewExternalPRLifecycleStillParks.