crucible nwsync emit/assemble write their summary to stdout, corrupting any caller that captures it #81

Closed
opened 2026-07-31 17:49:39 +00:00 by archvillainette · 0 comments
Owner

Part of #54.

Question

crucible nwsync emit and assemble print their summary line to stdout. Any caller that captures a script's stdout as a value gets the summary glued onto it. This broke the first real tag release.

Evidence

sow-assets-manifest run 5009, tag v0.2.1-rc1, conclusion: failure after 17 minutes. Step Pack, publish, and link HAKs does:

release_dir="$(... scripts/pack-haks.sh)"

pack-haks.sh:115 calls nwsync_emit, which at scripts/lib.sh:815 runs crucible without redirecting stdout. All 11 emit summaries landed in $release_dir, so publish-release.sh:16 died:

[depot] ERROR: release dir not found: emitted 3046d008…: 9754 resources, 0 new blobs, index …
… (10 more) …
/var/lib/gitea-runner/…/sow-assets-pack/release

The last line is the correct path. lib.sh's own log "nwsync: emitted $key" goes to stderr correctly — only crucible's line leaks.

Fix

internal/nwsync/run.go, two lines to stderr:

  • :109emitted %s: %d resources, %d new blobs, index %s
  • :143assembled manifest %s: %d resources, %s

Neither is a machine-readable contract. sow-topdata's contract tests (tests/backfill-nwsync-contract.sh, tests/publish-topdata-release-contract.sh) grep an EMIT_LOG their own fake-crucible stub writes, not real stdout — so nothing parses these.

Blast radius

  • sow-assets-manifest — broken now, blocks #47's tag.
  • sow-topdata — latent. publish-topdata-release.sh doesn't capture stdout, so run 5011 passed and v0.2.3-rc1 published clean.
  • sow-module — latent, and :143 is the assemble path that sow-module#51 is about to build. Fixing now avoids repeating this.

Why not patch >&2 in sow-assets-manifest

It works, but leaves topdata and the unbuilt module assemble step still leaking into whatever captures them next. One line in crucible covers every caller.

Follow-up

Crucible reaches CI off the nix devshell, so after this lands sow-assets-manifest needs a flake.lock bump, then a re-run of the v0.2.1-rc1 tag.

State left by the failed run

Nothing to clean up. Haks and NWSync blobs uploaded (all 0 new blobs — backfill had them). publish-release.sh died before uploading anything, so no catalog landed and Promote channel was skipped. The tag stands; re-running is the break-glass republish path 23c15b6 added. No re-tag needed.

Part of #54. ## Question `crucible nwsync emit` and `assemble` print their summary line to **stdout**. Any caller that captures a script's stdout as a value gets the summary glued onto it. This broke the first real tag release. ### Evidence sow-assets-manifest [run 5009](https://git.westgate.pw/ShadowsOverWestgate/sow-assets-manifest/actions/runs/5009/jobs/5039), tag `v0.2.1-rc1`, `conclusion: failure` after 17 minutes. Step **Pack, publish, and link HAKs** does: ```bash release_dir="$(... scripts/pack-haks.sh)" ``` `pack-haks.sh:115` calls `nwsync_emit`, which at `scripts/lib.sh:815` runs crucible without redirecting stdout. All 11 emit summaries landed in `$release_dir`, so `publish-release.sh:16` died: ``` [depot] ERROR: release dir not found: emitted 3046d008…: 9754 resources, 0 new blobs, index … … (10 more) … /var/lib/gitea-runner/…/sow-assets-pack/release ``` The last line is the correct path. `lib.sh`'s own `log "nwsync: emitted $key"` goes to stderr correctly — only crucible's line leaks. ### Fix `internal/nwsync/run.go`, two lines to stderr: - `:109` — `emitted %s: %d resources, %d new blobs, index %s` - `:143` — `assembled manifest %s: %d resources, %s` Neither is a machine-readable contract. sow-topdata's contract tests (`tests/backfill-nwsync-contract.sh`, `tests/publish-topdata-release-contract.sh`) grep an `EMIT_LOG` their own fake-crucible stub writes, not real stdout — so nothing parses these. ### Blast radius - **sow-assets-manifest** — broken now, blocks #47's tag. - **sow-topdata** — latent. `publish-topdata-release.sh` doesn't capture stdout, so [run 5011](https://git.westgate.pw/ShadowsOverWestgate/sow-topdata/actions/runs/5011/jobs/5041) passed and `v0.2.3-rc1` published clean. - **sow-module** — latent, and `:143` is the assemble path that sow-module#51 is about to build. Fixing now avoids repeating this. ### Why not patch `>&2` in sow-assets-manifest It works, but leaves topdata and the unbuilt module assemble step still leaking into whatever captures them next. One line in crucible covers every caller. ### Follow-up Crucible reaches CI off the nix devshell, so after this lands sow-assets-manifest needs a `flake.lock` bump, then a re-run of the `v0.2.1-rc1` tag. ### State left by the failed run Nothing to clean up. Haks and NWSync blobs uploaded (all `0 new blobs` — backfill had them). `publish-release.sh` died before uploading anything, so no catalog landed and **Promote channel** was skipped. The tag stands; re-running is the break-glass republish path `23c15b6` added. No re-tag needed.
archvillainette added the wayfinder:task label 2026-07-31 17:49:39 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Blocks
You do not have permission to read 1 dependency
Reference: ShadowsOverWestgate/sow-tools#81