diff --git a/apps/api/src/archive-har.ts b/apps/api/src/archive-har.ts index 204eaf124..54529719d 100644 --- a/apps/api/src/archive-har.ts +++ b/apps/api/src/archive-har.ts @@ -433,7 +433,12 @@ export async function packRunIntoTar( archiveResource.codebase.archiveBlobUrl = codebaseBlobUrl; archiveResource.codebase.archiveUrl = "codebase.tar.gz"; } - const yamlContent = yamlStringify(archiveResource, { lineWidth: 120 }); + // Ponytail: YAML comments clarify IDs without changing the importable schema. + const yamlContent = + "# _id is the request ID (the archive folder and Portal run URL).\n" + + "# run._id is this execution attempt's ID; retries keep the request ID.\n" + + "# submissionId groups requests created by one submission.\n" + + yamlStringify(archiveResource, { lineWidth: 120 }); const yamlBuf = Buffer.from(yamlContent, "utf-8"); pack.entry({ name: `${id}/run.yaml`, size: yamlBuf.length }, yamlBuf); diff --git a/apps/api/src/routes/requests/archive.test.ts b/apps/api/src/routes/requests/archive.test.ts index e6bc8a176..2ecf0329f 100644 --- a/apps/api/src/routes/requests/archive.test.ts +++ b/apps/api/src/routes/requests/archive.test.ts @@ -614,6 +614,7 @@ describe("run import/export — round-trip (export → import)", () => { if (srcKey === "") continue; expect(entries[entryName]).toEqual(blobStore.get(srcKey)); } + expect(entries[`${id}/run.yaml`].toString()).toContain("# run._id is this execution attempt's ID"); // 2. Re-import into a fresh blob store + Mongo. Importer ingests every // bundled artifact: HAR, chat-export, tool-calls, chat-result and diff --git a/docs/architecture/app-design.md b/docs/architecture/app-design.md index f1a243262..c208cf70b 100644 --- a/docs/architecture/app-design.md +++ b/docs/architecture/app-design.md @@ -88,6 +88,12 @@ erDiagram - **ResourceRevision** — Immutable lifecycle snapshot in `resource-revisions` containing normalized setup/teardown scripts, exported names, parameter declarations, `contentSha256`, and canonical `{slug}@r{N}` ref. Revisions deduplicate against the latest revision only. See [resources](resources.md). - **ProfileVersion.resources** — Immutable resource binding specs (`{ref, params}`) stored with a profile version. Submit resolves them to pinned request `resources[]` and merges profile preset parameters with run-supplied values using profile-wins precedence. +Downloaded run archives retain the importable `run.yaml` schema: the archive +folder and top-level `_id` identify the stable request, `run._id` identifies +the execution attempt (which changes on retry), and `submissionId` groups +requests submitted together. Every exported request folder includes a +`run.yaml` header explaining these IDs; YAML comments preserve import compatibility. + ### Typed prompts, AGENTS.md, and size-based storage Task prompts live in a single `task-prompts` collection that is now **typed** and