Checkpoint analyze artifacts incrementally

This commit is contained in:
2026-09-04 16:04:59 +00:00
parent 172e2d6a4f
commit 74977b4064
8 changed files with 343 additions and 35 deletions

View File

@@ -134,11 +134,11 @@ func executeSelectedStage(runtime *invocationRuntime, selected stage.Stage) (sta
operationErr := fmt.Errorf("save manifest after stage %q: %w", selected.Name(), err)
if analyzeProjection != nil {
restoreAnalyzeState(m, priorAnalyzeState)
failedAt := runtime.dependencies.now()
m.MarkStageFailed(selected.Name(), failedAt, operationErr.Error())
if _, invalidationErr := invalidateDependentSucceededStagesWithReason(m, selected.Name(), failedAt, staleReasonFailure); invalidationErr != nil {
operationErr = errors.Join(operationErr, fmt.Errorf("invalidate dependents after analyze projection persistence failure: %w", invalidationErr))
}
}
failedAt := runtime.dependencies.now()
m.MarkStageFailed(selected.Name(), failedAt, operationErr.Error())
if _, invalidationErr := invalidateDependentSucceededStagesWithReason(m, selected.Name(), failedAt, staleReasonFailure); invalidationErr != nil {
operationErr = errors.Join(operationErr, fmt.Errorf("invalidate dependents after stage %q persistence failure: %w", selected.Name(), invalidationErr))
}
return stageExecutionOutcome{}, runtime.persistTerminalFailure(operationErr)
}

View File

@@ -17,6 +17,31 @@ type terminalSessionStore struct {
saved *manifest.Manifest
}
type successfulStageSaveFailingStore struct {
delegate manifest.Store
stageName string
dependent string
failed bool
}
func (s *successfulStageSaveFailingStore) Create(ctx context.Context, sessionID string) (*manifest.Manifest, error) {
return s.delegate.Create(ctx, sessionID)
}
func (s *successfulStageSaveFailingStore) Load(ctx context.Context, path string) (*manifest.Manifest, error) {
return s.delegate.Load(ctx, path)
}
func (s *successfulStageSaveFailingStore) Save(ctx context.Context, path string, m *manifest.Manifest) error {
record := m.Stages[s.stageName]
if !s.failed && record != nil && record.Status == manifest.StatusSucceeded {
s.failed = true
m.MarkStageSucceeded(s.dependent, time.Now().UTC(), nil)
return errors.New("injected successful-stage save failure")
}
return s.delegate.Save(ctx, path, m)
}
func (s *terminalSessionStore) Create(_ context.Context, sessionID string) (*manifest.Manifest, error) {
return manifest.New(sessionID, time.Now().UTC()), nil
}
@@ -114,3 +139,30 @@ func TestExecuteStagesResumeValidationFailureRecordsSessionFailure(t *testing.T)
t.Fatalf("session manifest = %#v, want preserved success with terminal error", persisted)
}
}
func TestExecuteStagesSuccessfulSaveFailureMarksStageFailedAndInvalidatesDependents(t *testing.T) {
cfg := testConfig(t)
store := &successfulStageSaveFailingStore{
delegate: &manifest.LocalStore{},
stageName: "polish",
dependent: "normalize",
}
_, err := executeStages(context.Background(), cfg, []stage.Stage{
countingStage{name: "polish", runs: new(int)},
}, RunOptions{Env: &Env{ManifestStore: store}})
if err == nil || !strings.Contains(err.Error(), "save manifest after stage \"polish\"") {
t.Fatalf("executeStages() error = %v, want successful-stage save failure", err)
}
persisted, loadErr := store.delegate.Load(context.Background(), manifestPathFor(cfg))
if loadErr != nil {
t.Fatalf("load session manifest: %v", loadErr)
}
if got := persisted.Stages["polish"]; got == nil || got.Status != manifest.StatusFailed {
t.Fatalf("polish stage = %#v, want failed", got)
}
if got := persisted.Stages["normalize"]; got == nil || got.Status != manifest.StatusStale {
t.Fatalf("normalize stage = %#v, want stale", got)
}
}