# Fuzz Command

List and run generic fuzz workloads for a Homeboy component or rig.

## Synopsis

```bash
homeboy fuzz [<component>] [--rig <id>] [--workload <id>] [--run-id <id>] [--seed <seed>] [--inventory <path>] [--max-duration <duration>] [-- <runner-args>]
homeboy fuzz run [<component>] [--rig <id>] [--workload <id>] [--run-id <id>] [--seed <seed>] [--inventory <path>] [--max-duration <duration>] [-- <runner-args>]
homeboy fuzz list [<component>] [--rig <id>]
homeboy fuzz plan [<component>] [--rig <id>] [--workload <id>] [--inventory <path>]
homeboy fuzz validate <results-file>
homeboy fuzz report <results-file> [<component>] [--run-id <id>] [--inventory <path>] [--output-envelope <path>]
homeboy fuzz replay [<artifact-or-case>] [--artifact <path>] [--case-id <id>] [--run-id <id>] [-- <runner-args>]
```

## Description

`fuzz` is the generic contract surface for fuzz runners. Core owns the command
shape, manifest schema, JSON envelope, persisted run/artifact evidence, and Lab
portability metadata. Concrete fuzz engines remain extension-owned.

With `--rig <id>`, `fuzz` resolves the rig component path and extension config,
uses `fuzz.default_component` when no component is passed, and includes
rig-owned `fuzz_workloads` for the selected extension.

## Operator Workflow

Start by listing the workloads declared by the rig and the selected extension:

```bash
homeboy fuzz list --rig <rig-id>
```

`fuzz list` is the declared-workload view. It is not proof that a workload ran.
Use the listed workload id in `fuzz run`, then use `runs show` or `runs evidence`
to inspect the executable/proven state and recorded artifacts.

Run one workload through the fuzz command surface:

```bash
homeboy fuzz run --rig <rig-id> --workload <workload-id>
```

The run output should include a persisted run id. Inspect the recorded evidence
through `homeboy runs` instead of opening temporary runner paths directly:

```bash
homeboy runs show <run-id>
homeboy runs artifact get <run-id> <artifact-id> --output <path>
```

`homeboy runs show` renders the compact summary, coverage metadata when the
runner provides it, and fetch commands for recorded artifacts such as failing
cases, repro cases, and coverage reports. Use `homeboy runs artifact get` for
artifact bytes that are stored locally or mirrored from a runner.

Runner scripts receive `HOMEBOY_FUZZ_RESULTS_FILE` pointing at
`fuzz-results.json` in the command run directory. When a runner writes a
`homeboy/fuzz-campaign/v1` campaign object there, `homeboy fuzz run` parses it
and returns it as `results` in the JSON envelope. Malformed JSON fails the run
instead of being treated as proof.

`homeboy fuzz plan --inventory <path>`, `homeboy fuzz run --inventory <path>`,
and `homeboy fuzz report --inventory <path>`
accept a `homeboy/fuzz-target-inventory/v1` JSON file with discovered
`surfaces`, `targets`, `workloads`, and `seeds`. Homeboy validates the inventory,
merges it with the generated target inventory and declared workload metadata,
embeds it in generated result envelope metadata when reporting, and exposes the
path to runners as `HOMEBOY_FUZZ_INVENTORY_FILE`. The inventory contract is
product-neutral; product-specific details belong in `metadata` or flattened extra
fields on the inventory items.

Operations keep the free-form `kind` string for product-owned semantics and can
also carry a canonical `family` for cross-runner coverage reporting. When
`family` is omitted, Homeboy normalizes known neutral kinds and HTTP-style verbs
to families such as `read`, `create`, `update`, `delete`, `list`, `search`,
`navigate`, `render`, `query`, `load`, `submit`, `block_render`, and
`performance_probe`. Unknown `kind` values remain valid and are preserved without
a canonical family.

```json
{
  "id": "endpoint-list",
  "kind": "GET",
  "family": "read"
}
```

Campaigns can include a product-neutral coverage summary:

```json
{
  "schema": "homeboy/fuzz-campaign/v1",
  "id": "campaign-1",
  "safety_class": "read_only",
  "coverage_summary": {
    "schema": "homeboy/fuzz-coverage-summary/v1",
    "declared_targets": 2,
    "executable_targets": 2,
    "proven_targets": 2,
    "declared_operations": 4,
    "executable_operations": 4,
    "proven_operations": 4,
    "skipped_targets": [
      { "id": "target-3", "reason": "auth_required" }
    ],
    "surface_summaries": [
      {
        "id": "surface-a",
        "kind": "api",
        "declared_targets": 2,
        "executable_targets": 2,
        "proven_targets": 2,
        "declared_operations": 3,
        "executable_operations": 3,
        "proven_operations": 3
      }
    ],
    "kind_summaries": [
      {
        "id": "read",
        "kind": "operation_kind",
        "declared_targets": 1,
        "executable_targets": 1,
        "proven_targets": 1,
        "declared_operations": 2,
        "executable_operations": 2,
        "proven_operations": 2
      }
    ],
    "artifact_ids": ["coverage-report"]
  }
}
```

Coverage summaries can include selector breakdowns in `surface_summaries` and
`kind_summaries`. Each selector row uses the same declared, executable, proven,
and skipped-count shape as the aggregate summary, allowing gates and reports to
show which surface or operation kind is incomplete without embedding any
product-specific taxonomy.

Use standardized skip reason codes when a declared target or operation is not
executable in the current campaign: `unsafe`, `destructive`, `auth_required`,
`unavailable`, `legacy`, `unsupported`, and `config_required`. The codes are
reported in `coverage_completeness.skipped_reason_counts` for `fuzz validate`
and `fuzz report`, including per-selector counts for `surface_summaries` and
`kind_summaries`.

`homeboy fuzz replay` resolves replay metadata from a product-neutral campaign
or result envelope artifact. Pass a `homeboy/fuzz-campaign/v1` or
`homeboy/fuzz-result-envelope/v1` JSON file as the positional argument, or pass
it with `--artifact <path>` and use the positional argument as the case id:

```bash
homeboy fuzz replay fuzz-results.json --case-id case-1
homeboy fuzz replay case-1 --artifact fuzz-results.json
```

Replay currently returns a validated `dry_run` contract rather than executing a
runner. The output includes the campaign/envelope ids, selected case id, matching
`replay` metadata when present, passthrough args, and environment variables for
the originating extension-owned replay runner:

```text
HOMEBOY_FUZZ_REPLAY_ARTIFACT_FILE
HOMEBOY_FUZZ_REPLAY_CASE_ID
HOMEBOY_FUZZ_REPLAY_ID
HOMEBOY_FUZZ_REPLAY_SEED
HOMEBOY_FUZZ_REPLAY_ARTIFACT_ID
HOMEBOY_FUZZ_RUN_ID
```

Homeboy does not fake replay execution without a resolved component/extension
context. Extension scripts own concrete replay execution.

Full-coverage claims need persisted proof artifacts. A neutral coverage summary
can report declared, executable, and proven counts; operation totals; skipped
reason codes; and case/manifest artifacts. Treat missing `proven` counts or
missing coverage/case artifacts as incomplete evidence, not as full coverage.
`homeboy fuzz validate` and `homeboy fuzz report` evaluate coverage completeness
gates from `coverage_summary`: `target-coverage-complete` and
`operation-coverage-complete` pass only when every declared target/operation is
proven, or when the summary explicitly declares zero targets/operations. Missing
`coverage_summary` fails those completeness gates.

Fuzz workloads do not have a benchmark fallback. If `homeboy fuzz run` cannot
execute the selected workload, fix the fuzz runner, rig declaration, or Lab
routing and re-run `homeboy fuzz run`; do not substitute `homeboy bench` as fuzz
proof. Benchmark runs measure performance and baseline deltas, while fuzz runs
exercise generated or discovered cases and preserve fuzz-specific case evidence.

Heavy fuzz campaigns should run through Homeboy's offloaded Lab path. Use the
normal `homeboy fuzz run --rig ... --workload ...` command and let Lab routing
select the runner, or pass a runner explicitly with the global `--runner <id>`
flag when required. The reviewer-facing proof is the persisted run plus artifact
refs surfaced by `homeboy runs show` and `homeboy runs artifact get`, not a
controller-local hot run or a benchmark surrogate.

If `homeboy fuzz` is present in source but unavailable on a Lab runner, compare
the controller and runner Homeboy versions with `homeboy runner status <id>`.
The status output includes command availability checks such as
`homeboy fuzz --help`; refresh or upgrade the runner binary before rerunning the
campaign.

## Manifest Shape

Extensions declare fuzz support with a product-agnostic capability block:

```json
{
  "fuzz": {
    "workloads": [
      { "id": "parser", "label": "Parser fuzz" }
    ]
  }
}
```

The `fuzz` block is valid manifest support with only workload metadata. Add
`"extension_script": "scripts/fuzz.sh"` when the extension is ready to execute
workloads through `homeboy fuzz run`.

Extensions can also publish generic campaign metadata. Homeboy surfaces these
fields in `fuzz run` output without interpreting product-specific runner
details.

Fuzz workloads can declare a generic lifecycle contract when a mutable runtime
must be prepared, seeded, snapshotted, reset, rolled back, or torn down safely:

```json
{
  "fuzz": {
    "extension_script": "scripts/fuzz.sh",
    "case_artifact": "failing-case",
    "corpus_artifacts": ["seed-corpus", "generated-corpus"],
    "seed": "default-seed",
    "replay_command": "runner replay {case_artifact}",
    "minimize_command": "runner minimize {case_artifact}",
    "result_schema": "homeboy/fuzz-campaign/v1",
    "artifact_retention": "persisted-run-artifacts",
    "workloads": [
      {
        "id": "parser",
        "label": "Parser fuzz",
        "lifecycle": {
          "schema": "homeboy/lifecycle-contract/v1",
          "phases": [
            { "id": "prepare", "phase": "prepare", "extension_hook": "runtime.prepare" },
            { "id": "snapshot", "phase": "snapshot", "extension_hook": "runtime.snapshot" },
            { "id": "reset", "phase": "reset", "extension_hook": "runtime.reset" },
            { "id": "teardown", "phase": "teardown", "extension_hook": "runtime.teardown" }
          ]
        }
      }
    ]
  }
}
```

When a runner executes lifecycle phases, `run.results.lifecycle.snapshot_refs`
records the snapshot refs that reviewers and replay tooling can trace. See
`docs/architecture/lifecycle-contracts.md` for the shared shape.

Rigs can add private fuzz workloads keyed by extension id:

```json
{
  "fuzz": {
    "default_component": "package"
  },
  "fuzz_workloads": {
    "generic": [
      { "path": "${package.root}/fuzz/parser.json" }
    ]
  }
}
```

## Output

`contract`, `list`, `plan`, `run`, `validate`, `report`, and `replay` return
JSON envelopes with stable `variant` values.

`run.execution.results_file` is the path advertised to the runner through
`HOMEBOY_FUZZ_RESULTS_FILE`. `run.results` is present only when the runner wrote
a valid campaign result file.

`run.campaign_contract` always includes `case_artifact`, `corpus_artifacts`,
`seed`, `replay_command`, `minimize_command`, `result_schema`,
`artifact_retention`, and `unsupported`. Missing extension metadata is rendered
as empty/null values and named in `unsupported`, so automation can distinguish an
unsupported replay/minimize/corpus contract from a runner that provided one.
