Summary
Exporting a flagged trace writes five files and announces all five — Wrote 5 files: trace.json, spans.json, git_context.json, manifest.json, finding.json on stderr, and --json lists the same five — but manifest.json's files array lists only the four core files. The manifest is the bundle's self-describing index (ExportManifest, src/api/generated/schema.ts:279-291), so the bundle ships metadata that contradicts its own contents: anything iterating manifest.files silently skips the finding — the most important file in a flagged trace's bundle.
Applies to the finding-export logic introduced on feat/cli-traces-finding (src/commands/traces/export.ts); worth fixing on that branch before it merges.
How to replicate
traceroot traces export <flagged-trace-id> --output ./bundle (a trace with a detector finding).
- stderr:
Wrote 5 files: … finding.json plus the flagged-finding callout; finding.json exists on disk.
jq '.files' ./bundle/manifest.json → ["trace.json", "spans.json", "git_context.json", "manifest.json"] — four entries, no finding.json.
- With
--json, the CLI's own summary lists 5 files, disagreeing with the manifest it just wrote.
- Control: export a trace without a finding — the manifest matches the bundle exactly.
Root cause (confirmed)
In src/commands/traces/export.ts (finding-export branch):
- The server-provided manifest is written verbatim (
"manifest.json": response.manifest); the server has no knowledge of the finding, which the CLI fetches separately.
- The CLI then appends
finding.json to its local files array and writes the finding — but never patches the already-written manifest.json.
- The console line and the
--json summary use the patched local array, so every CLI-side report says 5 while the on-disk index says 4.
Note the --force re-export path correctly cleans up a stale finding.json, but the write path never adds it to the manifest.
Impact
- The export bundle's whole value is being a self-contained, self-describing evidence folder. A consumer that does the correct thing — read
manifest.json, iterate files — never sees the finding.
- Bundle validators keyed on the manifest will either drop
finding.json or flag it as an untracked stray file.
- Three sources of truth (stderr,
--json, manifest.json) disagree about the same bundle.
Acceptance criteria
- For a flagged trace,
manifest.json's files includes finding.json; manifest, stderr summary, and --json files are identical.
- For an unflagged trace, the manifest is unchanged — including after a
--force re-export over a previously flagged directory (stale finding.json removed and absent from the manifest).
- If patched client-side, only
files is touched; bundle_version, project_id, trace_id pass through byte-identical.
- Tests cover: flagged export (5 listed), unflagged (4), and
--force flagged→unflagged over the same directory.
Summary
Exporting a flagged trace writes five files and announces all five —
Wrote 5 files: trace.json, spans.json, git_context.json, manifest.json, finding.jsonon stderr, and--jsonlists the same five — butmanifest.json'sfilesarray lists only the four core files. The manifest is the bundle's self-describing index (ExportManifest,src/api/generated/schema.ts:279-291), so the bundle ships metadata that contradicts its own contents: anything iteratingmanifest.filessilently skips the finding — the most important file in a flagged trace's bundle.Applies to the finding-export logic introduced on
feat/cli-traces-finding(src/commands/traces/export.ts); worth fixing on that branch before it merges.How to replicate
traceroot traces export <flagged-trace-id> --output ./bundle(a trace with a detector finding).Wrote 5 files: … finding.jsonplus the flagged-finding callout;finding.jsonexists on disk.jq '.files' ./bundle/manifest.json→["trace.json", "spans.json", "git_context.json", "manifest.json"]— four entries, nofinding.json.--json, the CLI's own summary lists 5 files, disagreeing with the manifest it just wrote.Root cause (confirmed)
In
src/commands/traces/export.ts(finding-export branch):"manifest.json": response.manifest); the server has no knowledge of the finding, which the CLI fetches separately.finding.jsonto its localfilesarray and writes the finding — but never patches the already-writtenmanifest.json.--jsonsummary use the patched local array, so every CLI-side report says 5 while the on-disk index says 4.Note the
--forcere-export path correctly cleans up a stalefinding.json, but the write path never adds it to the manifest.Impact
manifest.json, iteratefiles— never sees the finding.finding.jsonor flag it as an untracked stray file.--json,manifest.json) disagree about the same bundle.Acceptance criteria
manifest.json'sfilesincludesfinding.json; manifest, stderr summary, and--jsonfilesare identical.--forcere-export over a previously flagged directory (stalefinding.jsonremoved and absent from the manifest).filesis touched;bundle_version,project_id,trace_idpass through byte-identical.--forceflagged→unflagged over the same directory.