Relationships
#4347 workflow run: let a run skip the "Data produced" box, or make it show what each artifact holds
Opened by robin · 11/3/2026
Problem
swamp workflow run ends a successful run with a "Data produced" box that lists every data
handle a step returned. For a workflow whose step returns one fixed-name record, the box says
the same thing on every run and carries nothing a reader can act on:
┌───────────────────────────────────────┐
│ Data produced │
│ merge-all-latest from merge-all │
└───────────────────────────────────────┘Our case: a workflow with one step, mergeAll, which merges bot PRs across repos. The method
returns one handle (the run record, always named merge-all-latest), so swamp keeps the link
between the run and its data. The method logs its own per-PR summary as the last lines of the
step's log, and the box then prints below it as the last thing on screen.
Checked against swamp 20261103.134027.0-sha.ca9b876c:
-q/--quietdoes not suppress the box, and noworkflow runflag does.- The box filters out only names starting
report-and the namelog(isUserFacingArtifact). - In a workflow run the entry shows no attributes. The same record from
behavior runshows its attributes (dryRun,results, ...). #1401 / PR #1963 describe attributes reaching the terminal data box. If workflow runs are meant to show them too, this part may be a bug.
Proposed solution
Either would solve it; the first is simpler.
- A way to leave the box out. For example,
swamp workflow run --no-data-box, or--quietcovering it. Or, at the source, a resource spec marked as not user-facing (saydisplay: false), so a behavior author can say "this record is fordata query, not for the run summary" without dropping the handle. - Make the entry informative. Show the artifact's attributes in workflow runs as
behavior runalready does. Or let a method return a one-line description with each handle, shown in place of or besidefrom <job>.
Alternatives considered
- Return no data handles.
dataHandlesis optional, so the box disappears. But that breaks the link between the run and its data:swamp data list --workflowand the@swamp/method-summaryreport's data pointers lose the record. - Name the record
report-…. It would be filtered out, but that leans on a rule meant for reports. - Filter swamp's output in a wrapper script. It breaks live streaming and colour.
Open
No activity in this phase yet.
robin commented 11/4/2026, 4:35:43 PM
Diagnosis: why workflow runs show no attributes
The attribute gap is a bug, separate from whether the box can be hidden. The renderer already prints
attributes when the view has them (renderDataArtifacts in src/presentation/renderers/workflow_run.ts).
They never reach the view because of how the completed event is mapped.
toRunDatafillsdataArtifacts[].attributes(andsteps[].outputs) only from itsstepOutputsargument (src/libswamp/workflows/run.ts, theattributesByDataIdlookup).mapWorkflowExecutionEventcallstoRunData(event.run, path, verbose)forcompletedwithout that argument, so liveworkflow runandworkflow resumenever have attributes.- Only
workflow history get --include-outputspasses resolved outputs (resolveStepOutputsinsrc/libswamp/workflows/history_get.ts).
behavior run differs because it parses each JSON handle's content as it saves it
(src/libswamp/models/run.ts).
Fix approach
A fix for local workflow run and workflow resume, built test-first:
- Add an optional
resolveStepOutputstoWorkflowRunDeps, plus a matching optionalstepOutputsparameter onmapWorkflowExecutionEvent, used only forcompleted. - On
completed, resolve with aStepOutputResolverover the run's own data repository. That iscreateDataRepositoryAttributeReader, plusfindChildRunfrom the run repository. - Read through
wrapWithEphemeral(dataRepo, catalogStore, ephemeral).dataRepo, not the persistent repo. The execution service routeslifetime: ephemeralwrites to the per-run ephemeral store. A persistent-only reader finds nothing for those records, and raises no error either. - A failed read logs at debug level and maps without outputs. The run has already succeeded, so the box falls back to bare names and the exit code is unchanged.
- Wire the reader in the CLI
workflow runandworkflow resumeonly. Serve'screateWorkflowRunDepsleaves it unset and keeps today's output.
Two things to watch for:
- The ephemeral store (point 3). The first agent review caught it.
- The write-seams ratchet. Constructing
CompositeUnifiedDataRepositorydirectly tripsintegration/datastore_write_seams_rules_test.ts. Reusing the already-pinnedwrapWithEphemeralavoids that.
Result
A one-step command/shell workflow now prints exitCode, stdout, and the rest under result from main.
--json carries the same attributes, matching history get --include-outputs. On main the same run
shows only result from main.
Out of scope / known limits
- Runs through
swamp servestill show a bare box. Wiring serve needs the caller'scanReadpolicy (a follow-up issue). - Workflow-level data (
workflowDataArtifacts) is out of scope, and so is data from nested-workflow steps. renderDataBoxprintsdata queryhints only when it is given a singlemodelName. A workflow's complex attributes (arrays, objects) therefore show+N morewith no retrieval command.- The resume path's wiring has no dedicated test.
Reference implementation
An external contributor can't open a PR, so the change is on a branch in my fork: https://github.com/yo61/swamp/compare/main...fix/workflow-run-data-box-attributes
The branch has 3 commits. They passed the repo's own verify-build (9/9 steps), verify-reviews (code,
adversarial, UX, and comment reviews all passed) and verify-skills at fc8e99c6e.
robin commented 11/4/2026, 4:37:28 PM
The follow-up for runs through serve, and for leaving out the data box, is #4391: https://swamp-club.com/lab/4391
Sign in to post a ripple.