feat(recovery): route failed write-less stages to recovery instead of futile retry
Adds the failure-ticket + recovery-routing mechanism: a deterministic gate->capability table gates whether a stage has agency to fix its own failure, opens a FailureTicketOpenedEvent when it doesn't, and routes to a metadata role=recovery stage (per-stage budget, cap 2, not reset by TransitionExecuted) instead of retrying in place. Extends salvage decisions with a RECOVER option so the review-gate judge can also route to recovery, unifies deterministic-gate and review-gate routing through routeToRecovery(), and has ExecutionPlanCompiler synthesize a write-capable recovery stage + edge for freestyle plans. Read-only tools (file_read, list_dir) are now always available on any tool-granting stage so a recovery stage can inspect the write-less stage's failure without flooding context via shell ls -R.
This commit is contained in:
@@ -60,6 +60,7 @@ const (
|
||||
TypeHealthChecks = "health.checks"
|
||||
TypeFileList = "file.list"
|
||||
TypeGrantList = "grant.list"
|
||||
TypeReviewFindings = "review.findings"
|
||||
)
|
||||
|
||||
// ServerMessage is a flat decode of every server->client variant. Field names
|
||||
@@ -82,7 +83,9 @@ type ServerMessage struct {
|
||||
LastResponse string `json:"lastResponse"` // session_snapshot: last stage response (reopen)
|
||||
Content string `json:"content"`
|
||||
Diff *string `json:"diff"`
|
||||
Tier string `json:"tier"`
|
||||
// tool.completed: file/dir path(s) the tool read, wrote, or listed.
|
||||
AffectedEntities []string `json:"affectedEntities"`
|
||||
Tier string `json:"tier"`
|
||||
Message string `json:"message"`
|
||||
RequestID string `json:"requestId"`
|
||||
ArtifactID string `json:"artifactId"`
|
||||
@@ -136,6 +139,11 @@ type ServerMessage struct {
|
||||
AssessedIssues []AssessedIssueDto `json:"issues"`
|
||||
Artifacts []ArtifactDto `json:"artifacts"`
|
||||
|
||||
// review.findings
|
||||
ReviewVerdict string `json:"verdict"`
|
||||
ReviewFindings []ReviewFindingDto `json:"findings"`
|
||||
ReviewBlocked bool `json:"blocked"`
|
||||
|
||||
// config.snapshot
|
||||
ConfigFields []ConfigFieldDto `json:"fields"`
|
||||
ConfigRestartRequired []string `json:"restartRequired"`
|
||||
@@ -331,6 +339,17 @@ type AssessedIssueDto struct {
|
||||
Severity string `json:"severity"`
|
||||
}
|
||||
|
||||
// ReviewFindingDto is a PR-comment-style finding from the semantic reviewer (Gate 3).
|
||||
type ReviewFindingDto struct {
|
||||
Severity string `json:"severity"`
|
||||
Confidence float64 `json:"confidence"`
|
||||
Category string `json:"category"`
|
||||
Target string `json:"target"`
|
||||
Message string `json:"message"`
|
||||
SuggestedFix *string `json:"suggestedFix"`
|
||||
Correctness bool `json:"correctness"`
|
||||
}
|
||||
|
||||
type ProviderHealthDto struct {
|
||||
ProviderID string `json:"providerId"`
|
||||
Status string `json:"status"`
|
||||
@@ -396,7 +415,7 @@ func (m ServerMessage) IsEventBearing() bool {
|
||||
TypeWorkflowProposed,
|
||||
TypeWorkspaceBound, TypeArtifactCreated,
|
||||
TypeArtifactValid, TypePlanLocked,
|
||||
TypeRouterNarration:
|
||||
TypeRouterNarration, TypeReviewFindings:
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
|
||||
Reference in New Issue
Block a user