Serialize restore recovery and rebase manifest paths

This commit is contained in:
2026-08-10 21:01:28 +00:00
parent 4158394dcf
commit 8375ad83f3
14 changed files with 581 additions and 78 deletions

View File

@@ -76,11 +76,13 @@ func TestExecuteRestoreRoundTripsPublishedExtractionAndManifestMetadata(t *testi
remoteManifest := manifest.New(cfg.Session.SessionID, time.Now().UTC())
remoteManifest.Campaign = cfg.Session.Campaign
remoteManifest.RunID = "20260519T010203Z-a1b2c3d4"
producerRoot := "/prior/workspace/work/sample-campaign/2026-05-03"
remoteManifest.LocalWorkDir = filepath.Join(producerRoot, "runs", remoteManifest.RunID)
remoteManifest.Stages["extract"] = &manifest.StageRecord{
Name: "extract", Status: manifest.StatusSucceeded,
Outputs: []manifest.ArtifactRecord{{
Kind: "notarius_lane", SourceID: artifacts.ExtractionArtifactSourceID("encounters"),
LocalPath: "/prior/workspace/artifacts/notarius/extract-run-1/lanes/encounters.json",
LocalPath: filepath.Join(producerRoot, "artifacts", "encounters.json"),
Contract: &artifactmodel.ContractMetadata{
MediaType: "application/json", SchemaID: "encounters", SchemaVersion: "1",
},
@@ -112,6 +114,9 @@ func TestExecuteRestoreRoundTripsPublishedExtractionAndManifestMetadata(t *testi
if lane.Contract == nil || lane.Contract.SchemaID != "encounters" || lane.ExternalProvenance == nil || lane.ExternalProvenance.RunID != "notarius-run-1" {
t.Fatalf("restored extraction metadata = %#v", lane)
}
if want := filepath.Join(sessionRoot, "artifacts", "encounters.json"); lane.LocalPath != want {
t.Fatalf("rebased extraction path = %q, want %q", lane.LocalPath, want)
}
}
func TestExecuteRestoreIncludeAudioRestoresAudio(t *testing.T) {
@@ -200,7 +205,7 @@ func TestExecuteRestoreRestoresPreviousCacheWhenPresent(t *testing.T) {
if err != nil {
t.Fatalf("read restored previous manifest: %v", err)
}
if !strings.Contains(string(previousManifestBytes), `"session_id":"2026-04-26"`) {
if !strings.Contains(string(previousManifestBytes), `"session_id": "2026-04-26"`) {
t.Fatalf("restored previous manifest = %q, want previous session id", string(previousManifestBytes))
}
mustReadEquals(t, filepath.Join(sessionRoot, "previous", "artifacts", "session_recap.md"), "# previous recap\n")
@@ -293,6 +298,9 @@ func TestExecuteRestoreForceOverwritesDifferingFile(t *testing.T) {
if !report.Force {
t.Fatalf("report force = %v, want true", report.Force)
}
if _, err := os.Stat(artifacts.SessionRestoreMarkerPathForCampaign(workspaceRoot, cfg.Session.Campaign, cfg.Session.SessionID)); !os.IsNotExist(err) {
t.Fatalf("restore marker should be cleared after success; stat err=%v", err)
}
}
func TestExecuteRestoreForceOverwritesDifferingPreviousCacheFile(t *testing.T) {
@@ -335,14 +343,11 @@ func TestExecuteRestoreLockConflictFailsAndWritesNothing(t *testing.T) {
restoreWithStoreAndRealPhases(t, fake)
var stdout bytes.Buffer
var stderr bytes.Buffer
code := Execute([]string{"session", "restore", "2026-05-03", "--config", pipelinePath, "--campaign-file", campaignPath, "--session", sessionPath}, &stdout, &stderr)
if code == 0 {
t.Fatal("exit code = 0, want non-zero")
}
if !strings.Contains(stderr.String(), "acquire session lock") {
t.Fatalf("stderr = %q, want lock failure", stderr.String())
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
err = Restore(ctx, []string{"2026-05-03", "--config", pipelinePath, "--campaign-file", campaignPath, "--session", sessionPath}, &bytes.Buffer{})
if err == nil || !strings.Contains(err.Error(), "acquire session lock") {
t.Fatalf("Restore() error = %v, want lock failure", err)
}
sessionRoot := artifacts.SessionWorkDirForCampaign(workspaceRoot, cfg.Session.Campaign, cfg.Session.SessionID)
@@ -406,6 +411,9 @@ func TestExecuteRestoreInvalidManifestDoesNotCorruptExistingManifest(t *testing.
if string(afterData) != string(existingData) {
t.Fatalf("local manifest changed after failed restore; before=%q after=%q", string(existingData), string(afterData))
}
if _, err := os.Stat(artifacts.SessionRestoreMarkerPathForCampaign(workspaceRoot, cfg.Session.Campaign, cfg.Session.SessionID)); err != nil {
t.Fatalf("incomplete restore marker should remain after failed forced restore: %v", err)
}
}
func TestExecuteRestorePlanPathMismatchFails(t *testing.T) {