# Kickoff prompt: build a test suite for `replicate`

Use this to resume the (currently out-of-scope, deferred) work of building an automated test suite for `replicate/replicate`, modeled on the one already built for `sneakernet` at `sneakernet/testing/` (see `sneakernet/Documentation/TESTING_automation.md` for the full design rationale).

## Context to give the assistant

`replicate/replicate` is a standalone ZFS send/receive replication script that depends on `ZFS_Utils.pm` (`use ZFS_Utils;`, default-exported functions). It has no automated test suite today - the only evidence it has ever run is a single `--dryrun` invocation on this workstation (which has no real ZFS) against example hostnames in `replicate/replicate.conf.yaml`/`replicate.log`. It uses `zfs receive -F` on the target, same destructive-power profile as sneakernet.

## What's reusable from `sneakernet/testing/`

Most of the infrastructure should transfer directly rather than be rebuilt:

- `sneakernet/testing/Harness/Safe.pm` - the sandbox enforcement layer: per-primitive allow-lists, no-shell exec, audit logging, the four execution modes (`explain`/`dry-run`/`run`/`confirm_destructive`), and critically the **production tripwire** - reusable almost as-is, since `replicate` is exactly the kind of script that must never be allowed to touch a real pool by accident.
- `sneakernet/testing/Harness/Catalogue.pm` + the JSON-catalogue approach (`sneakernet/testing/catalogue/part*.json`) - transcribing a test plan as data, not code, worked well and should be repeated for `replicate`.
- `sneakernet/testing/Harness/Runner.pm` - the action-dispatch/assertion-vocabulary engine. Will need a few new primitives specific to `replicate` (see below) but the core loop, capture/assertion machinery, and config-mutation-with-restore pattern all apply unchanged.
- `sneakernet/testing/Harness/Report.pm` and `sneakernet/testing/run-tests` - the TESTING.log renderer and CLI entry point are generic enough to reuse with a different catalogue.
- `YAMLPatch.pm` (top-level, standalone) - for surgical edits to `replicate.conf.yaml` between steps, same as sneakernet's config mutations.

## What's genuinely new / different

- `replicate` supports **remote (SSH) source and/or target hosts** - sneakernet's folder-based transport design never needed to simulate SSH. A new primitive (or a fake/stubbed `ssh` shim, allow-listed like `zfs`/`openssl` are today) is needed to test the remote-hostname code paths without real network hosts.
- `bwlimit`/`pv` pipeline wrapping is unique to `replicate` and untested by anything in sneakernet's harness.
- Smaller surface overall: no report-drive delivery, no cleanup-script mechanism, no config-rotation one-shot, no upgrade-builder utility - so the catalogue itself should be substantially shorter than sneakernet's ~110 steps.
- The underlying `ZFS_Utils.pm` functions `replicate` calls (`makeReplicateCommands`, `estimateReplicationStreamSize`, `validateSizeEstimateHistory`, `checkConfigKeys`) already have some unit-level coverage in `testLibrary/` (`test_zfs_utils.pl`, `test_sendIsIncremental.pl`, `test_findCommonBaseSnapshot.pl`) - the gap is at the `replicate` script's own integration level (its `replicate()` main loop, config bootstrap from `replicate.datastructure`, dry-run vs. real execution, remote-vs-local dispatch), not the shared primitives.

## Rough scope estimate (order of magnitude, not a commitment)

A few focused sessions if built on the existing harness infrastructure rather than from scratch - most of the heavy lifting (sandboxed primitives, audit logging, catalogue engine, reporting) already exists.

## Suggested first step

Read `sneakernet/Documentation/TESTING_automation.md` in full for the design rationale, then draft an equivalent `TESTING.md`-style manual test plan for `replicate` before writing any harness code - that's the order sneakernet's own effort followed (plan first, then automate).
