Compose resilient CLI processing and report lifecycle

This commit is contained in:
2026-09-24 17:48:52 +00:00
parent 87b8d9ad5c
commit 2f036b0356
11 changed files with 676 additions and 777 deletions

View File

@@ -45,6 +45,7 @@ type SectionMetadata struct {
StartSegmentID int `json:"start_segment_id"`
EndSegmentID int `json:"end_segment_id"`
EstimatedTokens int `json:"estimated_tokens"`
SegmentCount int `json:"segment_count"`
}
// SectionMetadataFromSection converts a chunking section into framework metadata.
@@ -54,6 +55,7 @@ func SectionMetadataFromSection(section chunking.Section) SectionMetadata {
StartSegmentID: section.StartSegmentID,
EndSegmentID: section.EndSegmentID,
EstimatedTokens: section.EstimatedTokens,
SegmentCount: len(section.Segments),
}
}

View File

@@ -50,6 +50,7 @@ const (
ReasonInvalidOutput ReasonCode = "invalid_output"
ReasonValidationInputTooLarge ReasonCode = "validation_input_too_large"
ReasonValidationDecisionsInvalid ReasonCode = "validation_decisions_invalid"
ReasonInputInvalid ReasonCode = "input_invalid"
ReasonSetupFailure ReasonCode = "setup_failure"
ReasonCanceled ReasonCode = "canceled"
ReasonInternalFailure ReasonCode = "internal_failure"

View File

@@ -43,7 +43,7 @@ func Build(input BuildInput) reporting.Snapshot {
for i, spec := range input.ModuleSpecs {
snapshot.StageNames[i] = spec.InstanceName
}
if input.RunOutput != nil {
if input.RunOutput != nil && input.RunOutput.InventoryAvailable {
units := append([]runner.WorkUnitOutcome(nil), input.RunOutput.WorkUnits...)
sort.SliceStable(units, func(i, j int) bool {
if units[i].ModuleIndex != units[j].ModuleIndex {
@@ -200,6 +200,8 @@ func safeMessage(reason outcomes.ReasonCode) string {
return "Processing was canceled."
case outcomes.ReasonSetupFailure:
return "Processing setup failed."
case outcomes.ReasonInputInvalid:
return "Input was invalid."
default:
return "Processing failed."
}

View File

@@ -23,7 +23,7 @@ func TestBuildPartialUnitsAndCombinedRecovery(t *testing.T) {
batch := 1
validation := outcomes.Operation{Reference: outcomes.Reference{Kind: outcomes.OperationValidation, ValidatorName: "review", ValidatorOrder: intPtr(1), BatchIndex: &batch}, FailureReason: outcomes.ReasonTransportFailed, ProposalIndices: []int{9, 3}}
inputFailure := outcomes.Operation{Reference: outcomes.Reference{Kind: outcomes.OperationValidationInput, ValidatorName: "review", ValidatorOrder: intPtr(1)}, FailureReason: outcomes.ReasonValidationInputTooLarge, ProposalIndices: []int{7}}
output := &runner.RunOutput{WorkUnits: []runner.WorkUnitOutcome{
output := &runner.RunOutput{InventoryAvailable: true, WorkUnits: []runner.WorkUnitOutcome{
{ModuleIndex: 1, ModuleKey: "grammar", ModuleInstance: "grammar_2", Section: contracts.SectionMetadata{Index: 0, StartSegmentID: 1, EndSegmentID: 2}, State: outcomes.WorkNotStarted},
{ModuleIndex: 0, ModuleKey: "grammar", ModuleInstance: "grammar_1", Section: contracts.SectionMetadata{Index: 0, StartSegmentID: 1, EndSegmentID: 2}, State: outcomes.WorkCompleted, CorrectionsApplied: 1, Operations: []outcomes.Operation{validation, proposal, inputFailure}},
}}
@@ -64,7 +64,7 @@ func TestBuildInitializationNoWorkAndRunFailure(t *testing.T) {
if initialDoc.CompletedAt != nil || initialDoc.Summary.WorkUnitsTotal != nil || initialDoc.Errors == nil {
t.Fatalf("initial: %+v", initialDoc)
}
finished := Build(BuildInput{RunID: "r", Status: reporting.StatusCompleted, StartedAt: start, RunOutput: &runner.RunOutput{}})
finished := Build(BuildInput{RunID: "r", Status: reporting.StatusCompleted, StartedAt: start, RunOutput: &runner.RunOutput{InventoryAvailable: true}})
if finished.Summary.WorkUnitsTotal == nil || *finished.Summary.WorkUnitsTotal != 0 || finished.RecoveriesDocument().Recoveries == nil {
t.Fatalf("empty: %+v", finished)
}

View File

@@ -103,6 +103,7 @@ type RunOutput struct {
FinalTranscript *schema.Transcript `json:"-"`
ModuleResults []ModuleResult `json:"module_results"`
Sections []contracts.SectionMetadata `json:"sections"`
InventoryAvailable bool `json:"-"`
WorkUnits []WorkUnitOutcome `json:"work_units"`
Candidates []proposals.EnrichedCorrectionProposal `json:"-"`
Observations llm.ObservationSnapshot `json:"-"`
@@ -154,7 +155,7 @@ func (r *Runner) run(ctx context.Context, input RunInput) (RunOutput, error) {
snapshot := func() RunOutput {
return RunOutput{
FinalTranscript: transcriptFromSections(sections), ModuleResults: results,
Sections: inventory, WorkUnits: workUnits, Candidates: candidates,
Sections: inventory, InventoryAvailable: true, WorkUnits: workUnits, Candidates: candidates,
}
}