Where the nwsync verbs live in the command surface #56

Closed
opened 2026-07-27 18:51:19 +00:00 by archvillainette · 1 comment
Owner

Question

Where do the nwsync verbs live in Crucible's command surface — a new crucible-nwsync binary, or folded into crucible-hak?

Part of #54. docs/command-surface.md and internal/dispatch are the authority; the dispatch registry maps a builder group to a crucible-<name> binary.

The tension: the repo's pattern says one group, one binary, and nwsync is a distinct concern with its own two verbs. But crucible-hak already reads ERFs, which is exactly what emit needs, and a new binary is a new cmd/ shim, a new dispatch group, a new release asset and a new thing for every consumer wrapper to resolve.

Settle: the group name, the binary, the verb names and their flags as they will actually appear in docs/command-surface.md, and whether assemble — which reads no ERF at all and is pure index merging — belongs in the same place as emit.

## Question Where do the `nwsync` verbs live in Crucible's command surface — a new `crucible-nwsync` binary, or folded into `crucible-hak`? Part of #54. `docs/command-surface.md` and `internal/dispatch` are the authority; the dispatch registry maps a builder group to a `crucible-<name>` binary. The tension: the repo's pattern says one group, one binary, and `nwsync` is a distinct concern with its own two verbs. But `crucible-hak` already reads ERFs, which is exactly what `emit` needs, and a new binary is a new `cmd/` shim, a new dispatch group, a new release asset and a new thing for every consumer wrapper to resolve. Settle: the group name, the binary, the verb names and their flags as they will actually appear in `docs/command-surface.md`, and whether `assemble` — which reads no ERF at all and is pure index merging — belongs in the same place as `emit`.
archvillainette added the wayfinder:grilling label 2026-07-27 18:51:19 +00:00
archvillainette self-assigned this 2026-07-28 07:24:45 +00:00
Author
Owner

Resolution

nwsync is its own builder group with its own binary, crucible-nwsync, holding both verbs.

The surface, as it will read in docs/command-surface.md

Builder Command Purpose
nwsync emit Emit an artifact's blobs and its per-artifact NSYM index.
nwsync assemble Merge per-artifact NSYM indices into one NWSync manifest.
crucible nwsync emit [--as <name>] [--out DIR] <artifact-key>

crucible nwsync assemble --group-id <n> [--tlk-key <key>] [--out DIR] <artifact-key>...
  • --out DIR — write locally instead of uploading. Absent means upload to the Bunny zone; present means the conformance path on a developer machine, and nothing touches the network. Same meaning on both verbs.
  • --as <name> — override the manifest entry name; --as sow_tlk.tlk for the TLK, per #62.
  • --group-id <n> — caller-supplied, per the map's settled decision (1 = current, 2 = testing). Crucible never derives it.
  • --tlk-key <key> — the TLK is not a hak and has no place in the precedence order, so it gets its own slot rather than a position in the list.

Keys are positional, in both verbs. emit takes exactly one, assemble takes N in Mod_HakList order. This overrides #62's --artifact-key spelling in favour of one uniform rule across the group; its meaning there is unchanged, and emit still derives the sibling NSYM key itself with the fail-closed digest check.

Why its own group and not folded into hak

The stated cost of a new binary does not survive contact with the build:

  • .gitea/workflows/build-binaries.yml and ci.yml build only ./cmd/crucible. A new cmd/ shim adds no release asset.
  • wrappers/crucible.sh resolves a single asset (crucible-${os}-${arch}). The three consumer repos in wrappers/consumers.txt need no wrapper change to reach a new group.
  • Real cost: one dispatch.Registry entry, a one-line cmd/crucible-nwsync/main.go, one line in flake.nix subPackages, one docs row.

Against that, hak is the wrong home on the merits. assemble reads no ERF at all — it is pure index merging over JSON — so folding it into hak would put a verb in a builder whose entire subject it never touches. Splitting the two verbs across builders is worse still: they share the artifact-key-to-NSYM-key rule that #62 deliberately kept in one place.

depot is the precedent, not the alternative: it is a separate group that bypasses internal/app entirely (dispatch.RunBuilder("depot", ...) straight into internal/depot.Run). nwsync takes the same shape — Wired: true, delegating to internal/nwsync.Run — while reusing internal/depot's httpBackend per #55.

Zone and credentials

Two storage zones exist. NWSync data does not live in the assets depot zone, so there is no --zone flag and no reuse of BUNNY_STORAGE_ZONE. sow-module already carries the secrets (created 2026-07-25): NWSYNC_STORAGE_ZONE and NWSYNC_STORAGE_PASSWORD.

internal/nwsync mirrors internal/depot/config.go's env resolution under the NWSYNC_ prefix, falling back to BUNNY_STORAGE_HOST for the host — it is the same Bunny storage endpoint, only a different zone. Credentials come from the environment; no flag carries them.

Follow-on, outside this map: --out DIR reads better than depot's --target local, so depot should adopt the same convention.

## Resolution `nwsync` is its own builder group with its own binary, `crucible-nwsync`, holding both verbs. ### The surface, as it will read in `docs/command-surface.md` | Builder | Command | Purpose | | --- | --- | --- | | `nwsync` | `emit` | Emit an artifact's blobs and its per-artifact NSYM index. | | `nwsync` | `assemble` | Merge per-artifact NSYM indices into one NWSync manifest. | ```text crucible nwsync emit [--as <name>] [--out DIR] <artifact-key> crucible nwsync assemble --group-id <n> [--tlk-key <key>] [--out DIR] <artifact-key>... ``` - `--out DIR` — write locally instead of uploading. Absent means upload to the Bunny zone; present means the conformance path on a developer machine, and nothing touches the network. Same meaning on both verbs. - `--as <name>` — override the manifest entry name; `--as sow_tlk.tlk` for the TLK, per #62. - `--group-id <n>` — caller-supplied, per the map's settled decision (1 = current, 2 = testing). Crucible never derives it. - `--tlk-key <key>` — the TLK is not a hak and has no place in the precedence order, so it gets its own slot rather than a position in the list. **Keys are positional, in both verbs.** `emit` takes exactly one, `assemble` takes N in `Mod_HakList` order. This overrides #62's `--artifact-key` spelling in favour of one uniform rule across the group; its *meaning* there is unchanged, and `emit` still derives the sibling NSYM key itself with the fail-closed digest check. ### Why its own group and not folded into `hak` The stated cost of a new binary does not survive contact with the build: - `.gitea/workflows/build-binaries.yml` and `ci.yml` build **only** `./cmd/crucible`. A new `cmd/` shim adds **no** release asset. - `wrappers/crucible.sh` resolves a single asset (`crucible-${os}-${arch}`). The three consumer repos in `wrappers/consumers.txt` need **no** wrapper change to reach a new group. - Real cost: one `dispatch.Registry` entry, a one-line `cmd/crucible-nwsync/main.go`, one line in `flake.nix` `subPackages`, one docs row. Against that, `hak` is the wrong home on the merits. `assemble` reads no ERF at all — it is pure index merging over JSON — so folding it into `hak` would put a verb in a builder whose entire subject it never touches. Splitting the two verbs across builders is worse still: they share the artifact-key-to-NSYM-key rule that #62 deliberately kept in one place. `depot` is the precedent, not the alternative: it is a separate group that bypasses `internal/app` entirely (`dispatch.RunBuilder("depot", ...)` straight into `internal/depot.Run`). `nwsync` takes the same shape — `Wired: true`, delegating to `internal/nwsync.Run` — while reusing `internal/depot`'s `httpBackend` per #55. ### Zone and credentials Two storage zones exist. NWSync data does **not** live in the assets depot zone, so there is no `--zone` flag and no reuse of `BUNNY_STORAGE_ZONE`. `sow-module` already carries the secrets (created 2026-07-25): `NWSYNC_STORAGE_ZONE` and `NWSYNC_STORAGE_PASSWORD`. `internal/nwsync` mirrors `internal/depot/config.go`'s env resolution under the `NWSYNC_` prefix, falling back to `BUNNY_STORAGE_HOST` for the host — it is the same Bunny storage endpoint, only a different zone. Credentials come from the environment; no flag carries them. Follow-on, outside this map: `--out DIR` reads better than `depot`'s `--target local`, so `depot` should adopt the same convention.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ShadowsOverWestgate/sow-tools#56