diff --git a/docs/execution/checkpoints.mdx b/docs/execution/checkpoints.mdx index deed1b105..74771945b 100644 --- a/docs/execution/checkpoints.mdx +++ b/docs/execution/checkpoints.mdx @@ -50,7 +50,7 @@ After each node, the metadata branch is updated with: - **`run.json`** — Refreshed projection snapshot with the new current checkpoint - **`stages/{node_id}@{visit}/...`** — Per-stage execution trace files (prompts, responses, status, diffs, stdout/stderr, and tool metadata) -- **`retro/*.md`** — Retro prompt/response text when present +- **`stages/retro/*.md`** — Retro prompt/response text when present ## What's in a checkpoint diff --git a/docs/execution/retros.mdx b/docs/execution/retros.mdx index d0b5f6b63..879190803 100644 --- a/docs/execution/retros.mdx +++ b/docs/execution/retros.mdx @@ -143,4 +143,4 @@ Retros are also available via the REST API. See the [list retros](/api-reference ## Storage -Retros are stored in durable run state. If you need files on disk, `fabro store dump` materializes retro text under `retro/` alongside `run.json`, stage files, and the rest of the exported run data. +Retros are stored in durable run state. If you need files on disk, `fabro store dump` materializes retro text under `stages/retro/` alongside `run.json`, stage files, and the rest of the exported run data. diff --git a/docs/reference/run-directory.mdx b/docs/reference/run-directory.mdx index e88d11a91..d707afa35 100644 --- a/docs/reference/run-directory.mdx +++ b/docs/reference/run-directory.mdx @@ -38,14 +38,14 @@ Reconstructed metadata branches and `fabro store dump` exports now use the same - `run.json` for the current projection snapshot, including the current checkpoint - `graph.fabro` for workflow source -- `retro/*.md` for retro prompt/response text +- `stages/retro/*.md` for retro prompt/response text - `stages/{node_id}@{visit}/...` for per-stage prompt, response, status, diff, stdout, and stderr files `fabro store dump` adds export-only history surfaces on top of that shared layout: - `events.jsonl` for the durable event stream - `checkpoints/*.json` for checkpoint history snapshots -- `artifacts/nodes/{node_id}/visit-{n}/...` for exported artifact payloads +- `artifacts/{node_id}@{visit}/...` for exported artifact payloads ## Browsing runs diff --git a/lib/crates/fabro-checkpoint/src/metadata.rs b/lib/crates/fabro-checkpoint/src/metadata.rs index c75f6a0ae..c358863b3 100644 --- a/lib/crates/fabro-checkpoint/src/metadata.rs +++ b/lib/crates/fabro-checkpoint/src/metadata.rs @@ -390,12 +390,12 @@ mod tests { store .write_snapshot( &run_id, - &[("retro/prompt.md", b"how did it go?")], + &[("stages/retro/prompt.md", b"how did it go?")], "finalize run", ) .unwrap(); - let data = branch_entry(dir.path(), &run_id, "retro/prompt.md"); + let data = branch_entry(dir.path(), &run_id, "stages/retro/prompt.md"); assert_eq!(data, b"how did it go?"); let spec = MetadataStore::read_run_spec(dir.path(), &run_id) diff --git a/lib/crates/fabro-cli/src/commands/store/dump.rs b/lib/crates/fabro-cli/src/commands/store/dump.rs index 3e27dbcde..700e94783 100644 --- a/lib/crates/fabro-cli/src/commands/store/dump.rs +++ b/lib/crates/fabro-cli/src/commands/store/dump.rs @@ -783,11 +783,11 @@ mod tests { ); assert_eq!( - std::fs::read_to_string(output.path().join("retro/prompt.md")).unwrap(), + std::fs::read_to_string(output.path().join("stages/retro/prompt.md")).unwrap(), "How did it go?" ); assert_eq!( - std::fs::read_to_string(output.path().join("retro/response.md")).unwrap(), + std::fs::read_to_string(output.path().join("stages/retro/response.md")).unwrap(), "Smooth enough" ); @@ -815,19 +815,14 @@ mod tests { assert!(!output.path().join("blobs").exists()); assert_eq!( - std::fs::read( - output - .path() - .join("artifacts/nodes/code/visit-2/src/lib.rs") - ) - .unwrap(), + std::fs::read(output.path().join("artifacts/code@2/src/lib.rs")).unwrap(), b"fn main() {}" ); assert_eq!( std::fs::read( output .path() - .join("artifacts/nodes/artifact-only/visit-7/logs/output.txt") + .join("artifacts/artifact-only@7/logs/output.txt") ) .unwrap(), b"hello" diff --git a/lib/crates/fabro-cli/tests/it/cmd/store_dump.rs b/lib/crates/fabro-cli/tests/it/cmd/store_dump.rs index 6f01b2b50..1fedcf9e0 100644 --- a/lib/crates/fabro-cli/tests/it/cmd/store_dump.rs +++ b/lib/crates/fabro-cli/tests/it/cmd/store_dump.rs @@ -254,8 +254,7 @@ include = ["assets/**"] "run export should hydrate blob refs\n{run_json}" ); assert_eq!( - fs::read_to_string(output_dir.join("artifacts/nodes/big/visit-1/assets/shared/report.txt")) - .unwrap(), + fs::read_to_string(output_dir.join("artifacts/big@1/assets/shared/report.txt")).unwrap(), "exported" ); } diff --git a/lib/crates/fabro-workflow/src/run_dump.rs b/lib/crates/fabro-workflow/src/run_dump.rs index c9013bda7..f883797ee 100644 --- a/lib/crates/fabro-workflow/src/run_dump.rs +++ b/lib/crates/fabro-workflow/src/run_dump.rs @@ -120,10 +120,13 @@ impl RunDump { } if let Some(prompt) = state.retro_prompt.as_ref() { - entries.push(RunDumpEntry::text("retro/prompt.md", prompt.clone())); + entries.push(RunDumpEntry::text("stages/retro/prompt.md", prompt.clone())); } if let Some(response) = state.retro_response.as_ref() { - entries.push(RunDumpEntry::text("retro/response.md", response.clone())); + entries.push(RunDumpEntry::text( + "stages/retro/response.md", + response.clone(), + )); } Self { entries } @@ -402,9 +405,11 @@ fn artifact_dump_path(stage_id: &StageId, filename: &str) -> Result { let node_id_segment = validate_single_path_segment("node id", stage_id.node_id())?; let filename_path = validate_relative_path("artifact filename", filename)?; Ok(PathBuf::from("artifacts") - .join("nodes") - .join(node_id_segment) - .join(format!("visit-{}", stage_id.visit())) + .join(format!( + "{}@{}", + node_id_segment.display(), + stage_id.visit() + )) .join(filename_path)) } @@ -540,8 +545,8 @@ mod tests { assert!(paths.contains(&"run.json")); assert!(paths.contains(&"graph.fabro")); - assert!(paths.contains(&"retro/prompt.md")); - assert!(paths.contains(&"retro/response.md")); + assert!(paths.contains(&"stages/retro/prompt.md")); + assert!(paths.contains(&"stages/retro/response.md")); assert!(paths.contains(&"stages/build@2/prompt.md")); assert!(paths.contains(&"stages/build@2/response.md")); assert!(paths.contains(&"stages/build@2/status.json"));