Remove invocation analyze projection
This commit is contained in:
@@ -79,18 +79,14 @@ do not replace the concrete configured key or infer family membership from a
|
|||||||
name, so older records without them remain valid.
|
name, so older records without them remain valid.
|
||||||
|
|
||||||
The session-stage collection is the reconciled authority across invocations.
|
The session-stage collection is the reconciled authority across invocations.
|
||||||
The corresponding collection on an invocation's `analyze` stage record is an
|
These records remain analyze-owned data inside the fixed stage; they are not
|
||||||
audit of only the artifacts evaluated or attempted by that run. These records
|
dynamic stages or generic subtasks.
|
||||||
remain analyze-owned data inside the fixed stage; they are not dynamic stages
|
|
||||||
or generic subtasks.
|
|
||||||
|
|
||||||
The stage result contract has one analyze-specific projection boundary. On
|
The stage result contract has one analyze-specific projection boundary. On
|
||||||
success, the runner validates and deep-copies the complete reconciled session
|
success, the runner validates and deep-copies the complete reconciled session
|
||||||
collection and the invocation subset. Aggregate session outputs are rebuilt in
|
collection. Aggregate session outputs are rebuilt in configured-key order from
|
||||||
configured-key order from current session records only; invocation outputs are
|
current session records only. Ordinary stage outputs cannot accompany this
|
||||||
limited to current records produced by that invocation's run ID. Ordinary
|
projection, so there is one source of artifact authority.
|
||||||
stage outputs cannot accompany this projection, so there is one source of
|
|
||||||
artifact authority.
|
|
||||||
|
|
||||||
Successful incremental execution replaces only evaluated artifact records and
|
Successful incremental execution replaces only evaluated artifact records and
|
||||||
preserves valid unrelated current records. Rebuilt outputs are compared by
|
preserves valid unrelated current records. Rebuilt outputs are compared by
|
||||||
@@ -111,14 +107,14 @@ the successful projection then restores the aggregate status.
|
|||||||
Analyze may return a projection together with an error. That restricted result
|
Analyze may return a projection together with an error. That restricted result
|
||||||
cannot carry ordinary outputs, skip state, aggregate logs, generated configs,
|
cannot carry ordinary outputs, skip state, aggregate logs, generated configs,
|
||||||
or metadata. The runner persists only the validated per-artifact collections,
|
or metadata. The runner persists only the validated per-artifact collections,
|
||||||
then marks the aggregate analyze and run state failed and invalidates delivery
|
then marks the aggregate analyze state failed and invalidates delivery
|
||||||
dependents conservatively. Unrelated current records survive because the
|
dependents conservatively. Unrelated current records survive because the
|
||||||
session projection is complete. A malformed projection is not applied, and a
|
session projection is complete. A malformed projection is not applied, and a
|
||||||
failed session projection save restores the prior per-artifact authority before
|
failed session projection save restores the prior per-artifact authority before
|
||||||
terminal failure persistence.
|
terminal failure persistence.
|
||||||
|
|
||||||
The incremental executor constructs this restricted projection at each
|
The incremental executor constructs this restricted projection over its
|
||||||
scheduled artifact boundary. The active record is failed without output,
|
scheduled artifact work. The active record is failed without output,
|
||||||
current transitive dependents are stale, unrelated current records survive, and
|
current transitive dependents are stale, unrelated current records survive, and
|
||||||
only earlier validated and materialized completions remain current in the
|
only earlier validated and materialized completions remain current in the
|
||||||
reconciled session collection. A terminal session-save failure is joined with
|
reconciled session collection. A terminal session-save failure is joined with
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ Supported source families:
|
|||||||
|
|
||||||
- when `pipeline.scriptorium` is absent or no configured artifact is
|
- when `pipeline.scriptorium` is absent or no configured artifact is
|
||||||
executable, completes successfully with no outputs and records explanatory
|
executable, completes successfully with no outputs and records explanatory
|
||||||
metadata. This is not an explicit self-skip: both manifests record success,
|
metadata. This is not an explicit self-skip: the session manifest records success,
|
||||||
satisfy publish's prerequisite, and an ordinary later run reuses the result
|
satisfy publish's prerequisite, and an ordinary later run reuses the result
|
||||||
while the effective set remains empty. Enabling or selecting an artifact
|
while the effective set remains empty. Enabling or selecting an artifact
|
||||||
later makes missing versioned evidence non-resumable and schedules it without
|
later makes missing versioned evidence non-resumable and schedules it without
|
||||||
@@ -118,11 +118,9 @@ Supported source families:
|
|||||||
remain current. If that semantic identity changes, unselected transitive
|
remain current. If that semantic identity changes, unselected transitive
|
||||||
dependents become stale without being executed; dependents included in the
|
dependents become stale without being executed; dependents included in the
|
||||||
invocation are evaluated in dependency order instead.
|
invocation are evaluated in dependency order instead.
|
||||||
- reports all evaluated targets and prerequisites in invocation state. The
|
- returns one complete reconciled session collection. The runner reconstructs
|
||||||
runner reconstructs aggregate session outputs from every current session
|
aggregate session outputs from every current session record; unrelated stale
|
||||||
record and invocation outputs from only records produced by the current run.
|
records do not make an otherwise successful partial invocation fail.
|
||||||
Unrelated stale records do not make an otherwise successful partial
|
|
||||||
invocation fail.
|
|
||||||
- resolves previous-session sources from local `previous/` cache only.
|
- resolves previous-session sources from local `previous/` cache only.
|
||||||
- runs optional render-debug, then artifact execution.
|
- runs optional render-debug, then artifact execution.
|
||||||
- validates non-empty output files and materializes canonical outputs.
|
- validates non-empty output files and materializes canonical outputs.
|
||||||
@@ -140,16 +138,17 @@ Supported source families:
|
|||||||
- a scheduled artifact failure returns the restricted analyze-state projection
|
- a scheduled artifact failure returns the restricted analyze-state projection
|
||||||
with the active artifact marked `failed`, a bounded error, and no output
|
with the active artifact marked `failed`, a bounded error, and no output
|
||||||
authority. Current transitive dependents become stale without execution.
|
authority. Current transitive dependents become stale without execution.
|
||||||
- earlier artifacts from the invocation remain current only after their
|
- earlier artifacts remain current only after their run-local output passed
|
||||||
run-local output passed validation and canonical materialization. They remain
|
validation and canonical materialization; unattempted later artifacts retain
|
||||||
in invocation history; unattempted later artifacts do not appear there.
|
their reconciled session state.
|
||||||
- unrelated current records survive a partial failure. Old canonical bytes for
|
- unrelated current records survive a partial failure. Old canonical bytes for
|
||||||
the failed artifact and newly materialized bytes whose projection cannot be
|
the failed artifact and newly materialized bytes whose projection cannot be
|
||||||
persisted are incidental, not current evidence.
|
persisted are incidental, not current evidence.
|
||||||
- the runner persists a valid partial projection before it marks aggregate
|
- the runner applies one valid partial projection at the existing end-of-stage
|
||||||
analyze failed and invalidates publish and notify through the application
|
save boundary before it marks aggregate analyze failed and invalidates publish
|
||||||
dependency relation. Projection-persistence errors retain the last durable
|
and notify through the application dependency relation. Projection-persistence
|
||||||
per-artifact authority and are joined with the original failure context.
|
errors retain the last durable per-artifact authority and are joined with the
|
||||||
|
original failure context. Per-artifact checkpoint persistence is future work.
|
||||||
|
|
||||||
## Invariants
|
## Invariants
|
||||||
|
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ preserving the existing session-ledger lifecycle and immediate command result.
|
|||||||
|
|
||||||
## Stage 3 — Remove Invocation-Only Analyze Projection
|
## Stage 3 — Remove Invocation-Only Analyze Projection
|
||||||
|
|
||||||
**Status: Pending**
|
**Status: Completed**
|
||||||
|
|
||||||
### Goal
|
### Goal
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
|
"gitea.maximumdirect.net/eric/narratio/internal/manifest"
|
||||||
@@ -10,8 +9,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type validatedAnalyzeProjection struct {
|
type validatedAnalyzeProjection struct {
|
||||||
session map[string]manifest.AnalyzeArtifactRecord
|
session map[string]manifest.AnalyzeArtifactRecord
|
||||||
invocation map[string]manifest.AnalyzeArtifactRecord
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type analyzeStateSnapshot struct {
|
type analyzeStateSnapshot struct {
|
||||||
@@ -70,23 +68,10 @@ func validateFailedAnalyzeProjection(stageName string, result *stage.StageResult
|
|||||||
|
|
||||||
func validateAndCloneAnalyzeProjection(projection *stage.AnalyzeStateProjection) (*validatedAnalyzeProjection, error) {
|
func validateAndCloneAnalyzeProjection(projection *stage.AnalyzeStateProjection) (*validatedAnalyzeProjection, error) {
|
||||||
session := manifest.CloneAnalyzeArtifactCollection(projection.Session)
|
session := manifest.CloneAnalyzeArtifactCollection(projection.Session)
|
||||||
invocation := manifest.CloneAnalyzeArtifactCollection(projection.Invocation)
|
|
||||||
if err := manifest.ValidateAnalyzeArtifactCollection(manifest.AnalyzeStateContractVersion, session); err != nil {
|
if err := manifest.ValidateAnalyzeArtifactCollection(manifest.AnalyzeStateContractVersion, session); err != nil {
|
||||||
return nil, fmt.Errorf("validate reconciled session analyze state: %w", err)
|
return nil, fmt.Errorf("validate reconciled session analyze state: %w", err)
|
||||||
}
|
}
|
||||||
if err := manifest.ValidateAnalyzeArtifactCollection(manifest.AnalyzeStateContractVersion, invocation); err != nil {
|
return &validatedAnalyzeProjection{session: session}, nil
|
||||||
return nil, fmt.Errorf("validate invocation analyze state: %w", err)
|
|
||||||
}
|
|
||||||
for key, invocationRecord := range invocation {
|
|
||||||
sessionRecord, ok := session[key]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("invocation analyze artifact %q is absent from reconciled session state", key)
|
|
||||||
}
|
|
||||||
if !reflect.DeepEqual(invocationRecord, sessionRecord) {
|
|
||||||
return nil, fmt.Errorf("invocation analyze artifact %q contradicts reconciled session state", key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return &validatedAnalyzeProjection{session: session, invocation: invocation}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyAnalyzeProjection(
|
func applyAnalyzeProjection(
|
||||||
|
|||||||
@@ -41,10 +41,6 @@ func TestExecuteStagesProjectsReconciledSessionAnalyzeState(t *testing.T) {
|
|||||||
Logs: []string{"aggregate-analyze.log"},
|
Logs: []string{"aggregate-analyze.log"},
|
||||||
AnalyzeState: &stage.AnalyzeStateProjection{
|
AnalyzeState: &stage.AnalyzeStateProjection{
|
||||||
Session: session,
|
Session: session,
|
||||||
Invocation: map[string]manifest.AnalyzeArtifactRecord{
|
|
||||||
"player_handout": oldRecord,
|
|
||||||
"session_recap": newRecord,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}}
|
}}
|
||||||
@@ -95,10 +91,6 @@ func TestExecuteStagesPersistsRestrictedAnalyzeStateOnPartialError(t *testing.T)
|
|||||||
}
|
}
|
||||||
return &stage.StageResult{AnalyzeState: &stage.AnalyzeStateProjection{
|
return &stage.StageResult{AnalyzeState: &stage.AnalyzeStateProjection{
|
||||||
Session: session,
|
Session: session,
|
||||||
Invocation: map[string]manifest.AnalyzeArtifactRecord{
|
|
||||||
"quest_log": failed,
|
|
||||||
"session_recap": completed,
|
|
||||||
},
|
|
||||||
}}, errors.New("quest log failed")
|
}}, errors.New("quest log failed")
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -141,8 +133,7 @@ func TestExecuteStagesRejectsInvalidAnalyzeProjectionWithoutReplacingPriorState(
|
|||||||
invalid := appAnalyzeRecord("session_recap", manifest.AnalyzeArtifactCurrent, m.RunID, time.Now().UTC())
|
invalid := appAnalyzeRecord("session_recap", manifest.AnalyzeArtifactCurrent, m.RunID, time.Now().UTC())
|
||||||
invalid.Output.Checksum = "invalid"
|
invalid.Output.Checksum = "invalid"
|
||||||
return &stage.StageResult{AnalyzeState: &stage.AnalyzeStateProjection{
|
return &stage.StageResult{AnalyzeState: &stage.AnalyzeStateProjection{
|
||||||
Session: map[string]manifest.AnalyzeArtifactRecord{"session_recap": invalid},
|
Session: map[string]manifest.AnalyzeArtifactRecord{"session_recap": invalid},
|
||||||
Invocation: map[string]manifest.AnalyzeArtifactRecord{"session_recap": invalid},
|
|
||||||
}}, errors.New("analysis failed")
|
}}, errors.New("analysis failed")
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -182,7 +173,6 @@ func TestExecuteStagesRollsBackAnalyzeAuthorityWhenProjectionSaveFails(t *testin
|
|||||||
"player_handout": prior,
|
"player_handout": prior,
|
||||||
"session_recap": newRecord,
|
"session_recap": newRecord,
|
||||||
},
|
},
|
||||||
Invocation: map[string]manifest.AnalyzeArtifactRecord{"session_recap": newRecord},
|
|
||||||
}}, nil
|
}}, nil
|
||||||
}}
|
}}
|
||||||
|
|
||||||
@@ -227,8 +217,7 @@ func TestExecuteStagesRejectsContradictoryAnalyzeResultWithError(t *testing.T) {
|
|||||||
return &stage.StageResult{
|
return &stage.StageResult{
|
||||||
Outputs: []artifacts.Ref{{Kind: "session_recap", RelativePath: "artifacts/session-recap.md"}},
|
Outputs: []artifacts.Ref{{Kind: "session_recap", RelativePath: "artifacts/session-recap.md"}},
|
||||||
AnalyzeState: &stage.AnalyzeStateProjection{
|
AnalyzeState: &stage.AnalyzeStateProjection{
|
||||||
Session: map[string]manifest.AnalyzeArtifactRecord{"session_recap": record},
|
Session: map[string]manifest.AnalyzeArtifactRecord{"session_recap": record},
|
||||||
Invocation: map[string]manifest.AnalyzeArtifactRecord{"session_recap": record},
|
|
||||||
},
|
},
|
||||||
}, errors.New("analysis failed")
|
}, errors.New("analysis failed")
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -151,22 +151,18 @@ func (analyzeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
|||||||
reusedArtifacts := []map[string]any{}
|
reusedArtifacts := []map[string]any{}
|
||||||
reusedSeen := map[string]struct{}{}
|
reusedSeen := map[string]struct{}{}
|
||||||
sessionRecords := manifest.CloneAnalyzeArtifactCollection(workPlan.ProjectedRecords)
|
sessionRecords := manifest.CloneAnalyzeArtifactCollection(workPlan.ProjectedRecords)
|
||||||
invocationRecords := make(map[string]manifest.AnalyzeArtifactRecord)
|
|
||||||
priorCurrentRecords := make(map[string]manifest.AnalyzeArtifactRecord)
|
priorCurrentRecords := make(map[string]manifest.AnalyzeArtifactRecord)
|
||||||
for _, item := range reconciliation.Ordered {
|
for _, item := range reconciliation.Ordered {
|
||||||
if item.Stored != nil && item.Stored.Status == manifest.AnalyzeArtifactCurrent {
|
if item.Stored != nil && item.Stored.Status == manifest.AnalyzeArtifactCurrent {
|
||||||
priorCurrentRecords[item.Key] = *item.Stored
|
priorCurrentRecords[item.Key] = *item.Stored
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invocationKeys := make(map[string]struct{}, len(workPlan.ExecutionOrder)+len(workPlan.ReusedCurrent))
|
currentKeys := make(map[string]struct{}, len(workPlan.ExecutionOrder)+len(workPlan.ReusedCurrent))
|
||||||
for _, item := range workPlan.ExecutionOrder {
|
for _, item := range workPlan.ExecutionOrder {
|
||||||
invocationKeys[item.Key] = struct{}{}
|
currentKeys[item.Key] = struct{}{}
|
||||||
}
|
}
|
||||||
for _, item := range workPlan.ReusedCurrent {
|
for _, item := range workPlan.ReusedCurrent {
|
||||||
invocationKeys[item.Key] = struct{}{}
|
currentKeys[item.Key] = struct{}{}
|
||||||
if record, ok := sessionRecords[item.Key]; ok {
|
|
||||||
invocationRecords[item.Key] = record
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, item := range workPlan.ExecutionOrder {
|
for _, item := range workPlan.ExecutionOrder {
|
||||||
@@ -185,7 +181,6 @@ func (analyzeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
|||||||
"",
|
"",
|
||||||
executionErr,
|
executionErr,
|
||||||
sessionRecords,
|
sessionRecords,
|
||||||
invocationRecords,
|
|
||||||
), executionErr
|
), executionErr
|
||||||
}
|
}
|
||||||
priorRecord, hadPriorRecord := priorCurrentRecords[item.Key]
|
priorRecord, hadPriorRecord := priorCurrentRecords[item.Key]
|
||||||
@@ -199,7 +194,6 @@ func (analyzeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
|||||||
fingerprint,
|
fingerprint,
|
||||||
err,
|
err,
|
||||||
sessionRecords,
|
sessionRecords,
|
||||||
invocationRecords,
|
|
||||||
), err
|
), err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,18 +230,16 @@ func (analyzeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
|||||||
fingerprint,
|
fingerprint,
|
||||||
recordErr,
|
recordErr,
|
||||||
sessionRecords,
|
sessionRecords,
|
||||||
invocationRecords,
|
|
||||||
), recordErr
|
), recordErr
|
||||||
}
|
}
|
||||||
sessionRecords[plan.Name] = record
|
sessionRecords[plan.Name] = record
|
||||||
invocationRecords[plan.Name] = record
|
|
||||||
|
|
||||||
sourceID, ok := runtimeCatalog.SourceIDForConfiguredKey(plan.Name)
|
sourceID, ok := runtimeCatalog.SourceIDForConfiguredKey(plan.Name)
|
||||||
if !ok {
|
if !ok {
|
||||||
catalogErr := fmt.Errorf("analyze: source id not found for artifact %q", plan.Name)
|
catalogErr := fmt.Errorf("analyze: source id not found for artifact %q", plan.Name)
|
||||||
return failedAnalyzeResult(
|
return failedAnalyzeResult(
|
||||||
execution, item, artifactCfg, fingerprint, catalogErr,
|
execution, item, artifactCfg, fingerprint, catalogErr,
|
||||||
sessionRecords, invocationRecords,
|
sessionRecords,
|
||||||
), catalogErr
|
), catalogErr
|
||||||
}
|
}
|
||||||
if err := runtimeCatalog.MarkAvailableGeneratedEvidence(
|
if err := runtimeCatalog.MarkAvailableGeneratedEvidence(
|
||||||
@@ -261,14 +253,14 @@ func (analyzeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
|||||||
catalogErr := fmt.Errorf("analyze: mark generated artifact %q available: %w", sourceID, err)
|
catalogErr := fmt.Errorf("analyze: mark generated artifact %q available: %w", sourceID, err)
|
||||||
return failedAnalyzeResult(
|
return failedAnalyzeResult(
|
||||||
execution, item, artifactCfg, fingerprint, catalogErr,
|
execution, item, artifactCfg, fingerprint, catalogErr,
|
||||||
sessionRecords, invocationRecords,
|
sessionRecords,
|
||||||
), catalogErr
|
), catalogErr
|
||||||
}
|
}
|
||||||
if !hadPriorRecord || !sameAnalyzeOutputIdentity(priorRecord, record) {
|
if !hadPriorRecord || !sameAnalyzeOutputIdentity(priorRecord, record) {
|
||||||
staleUnscheduledAnalyzeDependents(
|
staleUnscheduledAnalyzeDependents(
|
||||||
env.Config.Pipeline.Scriptorium.Artifacts,
|
env.Config.Pipeline.Scriptorium.Artifacts,
|
||||||
plan.Name,
|
plan.Name,
|
||||||
invocationKeys,
|
currentKeys,
|
||||||
sessionRecords,
|
sessionRecords,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -295,8 +287,7 @@ func (analyzeStage) Run(ctx context.Context, env *Env, m *manifest.Manifest) (*S
|
|||||||
GeneratedConfigs: dedupeAndSortPaths(generatedConfigs),
|
GeneratedConfigs: dedupeAndSortPaths(generatedConfigs),
|
||||||
Metadata: metadata,
|
Metadata: metadata,
|
||||||
AnalyzeState: &AnalyzeStateProjection{
|
AnalyzeState: &AnalyzeStateProjection{
|
||||||
Session: sessionRecords,
|
Session: sessionRecords,
|
||||||
Invocation: manifest.CloneAnalyzeArtifactCollection(invocationRecords),
|
|
||||||
},
|
},
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
@@ -308,7 +299,6 @@ func failedAnalyzeResult(
|
|||||||
fingerprint string,
|
fingerprint string,
|
||||||
cause error,
|
cause error,
|
||||||
sessionRecords map[string]manifest.AnalyzeArtifactRecord,
|
sessionRecords map[string]manifest.AnalyzeArtifactRecord,
|
||||||
invocationRecords map[string]manifest.AnalyzeArtifactRecord,
|
|
||||||
) *StageResult {
|
) *StageResult {
|
||||||
record := manifest.AnalyzeArtifactRecord{
|
record := manifest.AnalyzeArtifactRecord{
|
||||||
Key: item.Key,
|
Key: item.Key,
|
||||||
@@ -332,11 +322,9 @@ func failedAnalyzeResult(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sessionRecords[item.Key] = record
|
sessionRecords[item.Key] = record
|
||||||
invocationRecords[item.Key] = record
|
|
||||||
staleAnalyzeDependents(artifactCfgMap(execution), item.Key, sessionRecords)
|
staleAnalyzeDependents(artifactCfgMap(execution), item.Key, sessionRecords)
|
||||||
return &StageResult{AnalyzeState: &AnalyzeStateProjection{
|
return &StageResult{AnalyzeState: &AnalyzeStateProjection{
|
||||||
Session: manifest.CloneAnalyzeArtifactCollection(sessionRecords),
|
Session: manifest.CloneAnalyzeArtifactCollection(sessionRecords),
|
||||||
Invocation: manifest.CloneAnalyzeArtifactCollection(invocationRecords),
|
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ func TestAnalyzeAdapterFailureProjectsCompletedAndFailedArtifacts(t *testing.T)
|
|||||||
}
|
}
|
||||||
keys := []string{"alpha", "beta", "gamma"}
|
keys := []string{"alpha", "beta", "gamma"}
|
||||||
for index, key := range keys {
|
for index, key := range keys {
|
||||||
record, exists := result.AnalyzeState.Invocation[key]
|
record, exists := result.AnalyzeState.Session[key]
|
||||||
switch {
|
switch {
|
||||||
case index < failAt-1:
|
case index < failAt-1:
|
||||||
if !exists || record.Status != manifest.AnalyzeArtifactCurrent || record.Output == nil {
|
if !exists || record.Status != manifest.AnalyzeArtifactCurrent || record.Output == nil {
|
||||||
@@ -43,7 +43,7 @@ func TestAnalyzeAdapterFailureProjectsCompletedAndFailedArtifacts(t *testing.T)
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
if exists {
|
if exists {
|
||||||
t.Fatalf("unattempted %s appeared in invocation: %#v", key, record)
|
t.Fatalf("unattempted %s appeared in reconciled session state: %#v", key, record)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -86,8 +86,8 @@ func TestAnalyzeMiddleFailureStalesDependentsAndPreservesUnrelatedCurrent(t *tes
|
|||||||
got.Fingerprint != unrelated.Fingerprint || got.Output == nil || got.Output.Checksum != unrelated.Output.Checksum {
|
got.Fingerprint != unrelated.Fingerprint || got.Output == nil || got.Output.Checksum != unrelated.Output.Checksum {
|
||||||
t.Fatalf("unrelated record = %#v, want preserved %#v", got, unrelated)
|
t.Fatalf("unrelated record = %#v, want preserved %#v", got, unrelated)
|
||||||
}
|
}
|
||||||
if _, attempted := result.AnalyzeState.Invocation["gamma"]; attempted {
|
if result.AnalyzeState.Session["gamma"].Status != manifest.AnalyzeArtifactStale {
|
||||||
t.Fatal("dependent target was reported as attempted")
|
t.Fatalf("dependent target state = %#v, want stale", result.AnalyzeState.Session["gamma"])
|
||||||
}
|
}
|
||||||
if old := m.Stages["analyze"].AnalyzeArtifacts["beta"]; old.Output == nil {
|
if old := m.Stages["analyze"].AnalyzeArtifacts["beta"]; old.Output == nil {
|
||||||
t.Fatal("fixture did not retain old canonical evidence before failure")
|
t.Fatal("fixture did not retain old canonical evidence before failure")
|
||||||
|
|||||||
@@ -35,8 +35,8 @@ func TestAnalyzeReusesCurrentArtifactWithoutScriptorium(t *testing.T) {
|
|||||||
if got := second.Metadata["reused_current"]; !reflect.DeepEqual(got, []string{"session_recap"}) {
|
if got := second.Metadata["reused_current"]; !reflect.DeepEqual(got, []string{"session_recap"}) {
|
||||||
t.Fatalf("reused current = %#v, want session_recap", got)
|
t.Fatalf("reused current = %#v, want session_recap", got)
|
||||||
}
|
}
|
||||||
if second.AnalyzeState.Invocation["session_recap"].Status != manifest.AnalyzeArtifactCurrent {
|
if second.AnalyzeState.Session["session_recap"].Status != manifest.AnalyzeArtifactCurrent {
|
||||||
t.Fatalf("invocation state = %#v", second.AnalyzeState.Invocation)
|
t.Fatalf("session state = %#v", second.AnalyzeState.Session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,8 +70,8 @@ func TestAnalyzePartialForcePreservesUnrelatedCurrentRecord(t *testing.T) {
|
|||||||
if got := second.AnalyzeState.Session["player_handout"]; !reflect.DeepEqual(got, priorDependent) {
|
if got := second.AnalyzeState.Session["player_handout"]; !reflect.DeepEqual(got, priorDependent) {
|
||||||
t.Fatalf("unrelated dependent changed = %#v, want %#v", got, priorDependent)
|
t.Fatalf("unrelated dependent changed = %#v, want %#v", got, priorDependent)
|
||||||
}
|
}
|
||||||
if _, attempted := second.AnalyzeState.Invocation["player_handout"]; attempted {
|
if _, current := second.AnalyzeState.Session["player_handout"]; !current {
|
||||||
t.Fatal("unselected dependent appeared in invocation state")
|
t.Fatal("unselected dependent was removed from session state")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +102,9 @@ func TestAnalyzeExposesReusedPrerequisiteToScheduledDependent(t *testing.T) {
|
|||||||
if got := fake.RunRequests[0].InputPaths["recap"]; got != filepath.Join(paths.ArtifactsDir, "session_recap.md") {
|
if got := fake.RunRequests[0].InputPaths["recap"]; got != filepath.Join(paths.ArtifactsDir, "session_recap.md") {
|
||||||
t.Fatalf("reused prerequisite input = %q", got)
|
t.Fatalf("reused prerequisite input = %q", got)
|
||||||
}
|
}
|
||||||
if second.AnalyzeState.Invocation["session_recap"].Status != manifest.AnalyzeArtifactCurrent ||
|
if second.AnalyzeState.Session["session_recap"].Status != manifest.AnalyzeArtifactCurrent ||
|
||||||
second.AnalyzeState.Invocation["player_handout"].Status != manifest.AnalyzeArtifactCurrent {
|
second.AnalyzeState.Session["player_handout"].Status != manifest.AnalyzeArtifactCurrent {
|
||||||
t.Fatalf("invocation records = %#v, want reused prerequisite and produced dependent", second.AnalyzeState.Invocation)
|
t.Fatalf("session records = %#v, want reused prerequisite and produced dependent", second.AnalyzeState.Session)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,8 +131,8 @@ func TestAnalyzeChangedOutputStalesUnselectedDependents(t *testing.T) {
|
|||||||
if dependent.Status != manifest.AnalyzeArtifactStale || dependent.Output != nil || dependent.OutputSize != 0 {
|
if dependent.Status != manifest.AnalyzeArtifactStale || dependent.Output != nil || dependent.OutputSize != 0 {
|
||||||
t.Fatalf("dependent record = %#v, want stale without output", dependent)
|
t.Fatalf("dependent record = %#v, want stale without output", dependent)
|
||||||
}
|
}
|
||||||
if _, attempted := second.AnalyzeState.Invocation["player_handout"]; attempted {
|
if second.AnalyzeState.Session["player_handout"].Status != manifest.AnalyzeArtifactStale {
|
||||||
t.Fatal("changed-output invalidation executed the unselected dependent")
|
t.Fatalf("dependent state = %#v, want stale", second.AnalyzeState.Session["player_handout"])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func TestAnalyzeGeneratesSessionRecapFromTrimmedTranscript(t *testing.T) {
|
|||||||
t.Fatalf("session_id var = %q, want sticky narratio session id", req.Vars["session_id"])
|
t.Fatalf("session_id var = %q, want sticky narratio session id", req.Vars["session_id"])
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.AnalyzeState == nil || result.AnalyzeState.Invocation["session_recap"].Status != manifest.AnalyzeArtifactCurrent {
|
if result.AnalyzeState == nil || result.AnalyzeState.Session["session_recap"].Status != manifest.AnalyzeArtifactCurrent {
|
||||||
t.Fatalf("analyze state = %#v, want current session_recap", result.AnalyzeState)
|
t.Fatalf("analyze state = %#v, want current session_recap", result.AnalyzeState)
|
||||||
}
|
}
|
||||||
if len(result.Logs) != 2 {
|
if len(result.Logs) != 2 {
|
||||||
@@ -316,7 +316,7 @@ func TestAnalyzeUsesRunLocalPathsAndMaterializesCanonical(t *testing.T) {
|
|||||||
if !strings.Contains(fake.RunRequests[0].OutputPath, filepath.Join("runs", m.RunID, "analyze", "outputs")) {
|
if !strings.Contains(fake.RunRequests[0].OutputPath, filepath.Join("runs", m.RunID, "analyze", "outputs")) {
|
||||||
t.Fatalf("run output path = %q, want run-local path", fake.RunRequests[0].OutputPath)
|
t.Fatalf("run output path = %q, want run-local path", fake.RunRequests[0].OutputPath)
|
||||||
}
|
}
|
||||||
if result.AnalyzeState == nil || result.AnalyzeState.Invocation["session_recap"].Output == nil {
|
if result.AnalyzeState == nil || result.AnalyzeState.Session["session_recap"].Output == nil {
|
||||||
t.Fatalf("analyze state = %#v, want session recap output evidence", result.AnalyzeState)
|
t.Fatalf("analyze state = %#v, want session recap output evidence", result.AnalyzeState)
|
||||||
}
|
}
|
||||||
if err := requireNonEmptyFile(filepath.Join(paths.ArtifactsDir, "session_recap.md"), "materialized output"); err != nil {
|
if err := requireNonEmptyFile(filepath.Join(paths.ArtifactsDir, "session_recap.md"), "materialized output"); err != nil {
|
||||||
@@ -686,7 +686,7 @@ func TestAnalyzeAppliesSelectedArtifactsFilter(t *testing.T) {
|
|||||||
if fake.RunRequests[0].PromptID != "dnd.player_handout" {
|
if fake.RunRequests[0].PromptID != "dnd.player_handout" {
|
||||||
t.Fatalf("prompt id = %q, want dnd.player_handout", fake.RunRequests[0].PromptID)
|
t.Fatalf("prompt id = %q, want dnd.player_handout", fake.RunRequests[0].PromptID)
|
||||||
}
|
}
|
||||||
if result.AnalyzeState == nil || len(result.AnalyzeState.Invocation) != 1 || result.AnalyzeState.Invocation["player_handout"].Status != manifest.AnalyzeArtifactCurrent {
|
if result.AnalyzeState == nil || len(result.AnalyzeState.Session) != 1 || result.AnalyzeState.Session["player_handout"].Status != manifest.AnalyzeArtifactCurrent {
|
||||||
t.Fatalf("analyze state = %#v, want only current player_handout", result.AnalyzeState)
|
t.Fatalf("analyze state = %#v, want only current player_handout", result.AnalyzeState)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1391,7 +1391,7 @@ func TestAnalyzeRecordsRefsAndMetadata(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Run() error = %v", err)
|
t.Fatalf("Run() error = %v", err)
|
||||||
}
|
}
|
||||||
record, ok := result.AnalyzeState.Invocation["session_recap"]
|
record, ok := result.AnalyzeState.Session["session_recap"]
|
||||||
if !ok || record.Output == nil || record.Output.LocalPath != "artifacts/session_recap.md" {
|
if !ok || record.Output == nil || record.Output.LocalPath != "artifacts/session_recap.md" {
|
||||||
t.Fatalf("analyze output record = %#v, want session recap evidence", record)
|
t.Fatalf("analyze output record = %#v, want session recap evidence", record)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,9 +132,8 @@ type StageResult struct {
|
|||||||
AnalyzeState *AnalyzeStateProjection
|
AnalyzeState *AnalyzeStateProjection
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnalyzeStateProjection carries analyze-owned reconciled session authority and
|
// AnalyzeStateProjection carries the reconciled session authority proposed for
|
||||||
// the invocation subset evaluated by the current run.
|
// the runner's existing end-of-stage session-manifest save.
|
||||||
type AnalyzeStateProjection struct {
|
type AnalyzeStateProjection struct {
|
||||||
Session map[string]manifest.AnalyzeArtifactRecord
|
Session map[string]manifest.AnalyzeArtifactRecord
|
||||||
Invocation map[string]manifest.AnalyzeArtifactRecord
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user