---
phase: 10-nyquist-validation-coverage
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - .planning/phases/04-snapshot-management/04-VALIDATION.md
  - .planning/phases/05-artifact-pipeline/05-VALIDATION.md
autonomous: true
requirements:
  - SNAP-01
  - SNAP-02
  - SNAP-03
  - SNAP-04
  - ART-01
  - ART-02
  - ART-03
  - ART-04
  - ART-05

must_haves:
  truths:
    - "04-VALIDATION.md exists and maps SNAP-01..04 to passing test names and assertion evidence"
    - "05-VALIDATION.md exists and maps ART-01..05 to passing test names and assertion evidence"
    - "Both VALIDATION.md files have nyquist_compliant: true in frontmatter"
  artifacts:
    - path: ".planning/phases/04-snapshot-management/04-VALIDATION.md"
      provides: "Test-evidence mapping for SNAP-01..04"
      contains: "nyquist_compliant: true"
    - path: ".planning/phases/05-artifact-pipeline/05-VALIDATION.md"
      provides: "Test-evidence mapping for ART-01..05"
      contains: "nyquist_compliant: true"
  key_links:
    - from: "04-VALIDATION.md Per-Task Verification Map"
      to: "tests/test_snapshot_create.py, test_snapshot_list.py, test_snapshot_revert.py, test_snapshot_delete.py"
      via: "requirement-to-test-name mapping"
      pattern: "SNAP-0[1-4]"
    - from: "05-VALIDATION.md Per-Task Verification Map"
      to: "tests/test_artifact_registry.py, test_artifact_sync.py, test_artifact_install.py"
      via: "requirement-to-test-name mapping"
      pattern: "ART-0[1-5]"
---

<objective>
Create VALIDATION.md artifacts for Phases 04 and 05 to achieve Nyquist compliance for Snapshot Management and Artifact Pipeline phases.

Purpose: Provide structured test-evidence mapping for all snapshot and artifact requirements so the Nyquist auditor confirms these phases as compliant.

Output: Two VALIDATION.md files — 04-VALIDATION.md and 05-VALIDATION.md — each with `nyquist_compliant: true` in frontmatter and a filled Per-Task Verification Map.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@$HOME/.claude/get-shit-done/templates/VALIDATION.md
</context>

<tasks>

<task type="auto">
  <name>Task 1: Create 04-VALIDATION.md for Phase 4 (Snapshot Management)</name>
  <read_first>
    - $HOME/.claude/get-shit-done/templates/VALIDATION.md (template structure to follow exactly)
    - .planning/phases/04-snapshot-management/04-01-PLAN.md
    - .planning/phases/04-snapshot-management/04-02-PLAN.md
    - .planning/phases/04-snapshot-management/04-01-SUMMARY.md
    - .planning/phases/04-snapshot-management/04-02-SUMMARY.md
    - .planning/phases/04-snapshot-management/04-VERIFICATION.md (existing evidence)
    - tests/test_snapshot_create.py (SNAP-01 evidence: test_snapshot_create_returns_snapshot_info, test_snapshot_create_concurrent_for_all_nodes, test_snapshot_create_tool_returns_snapshot_info)
    - tests/test_snapshot_list.py (SNAP-01/03 evidence: test_snapshot_list_returns_snapshot_info_for_single_snapshot, test_snapshot_list_parses_creation_time_from_xml, test_snapshot_list_reports_per_node_disk_sizes)
    - tests/test_snapshot_revert.py (SNAP-02 evidence: test_revert_destroys_all_nodes_before_any_revert, test_revert_restart_after_true_starts_all_domains, test_revert_ssh_timeout_returns_failure)
    - tests/test_snapshot_delete.py (SNAP-04 evidence: test_delete_calls_client_delete_snapshot_once_per_node, test_delete_returns_per_node_confirmation)
  </read_first>
  <files>.planning/phases/04-snapshot-management/04-VALIDATION.md</files>
  <action>
    Create `.planning/phases/04-snapshot-management/04-VALIDATION.md` using the template structure exactly.

    **Frontmatter:**
    ```yaml
    ---
    phase: 4
    slug: snapshot-management
    status: complete
    nyquist_compliant: true
    wave_0_complete: true
    created: 2026-03-24
    ---
    ```

    **Test Infrastructure section:**
    - Framework: pytest 8.x (with pytest-asyncio)
    - Config file: pyproject.toml
    - Quick run command: `.venv/bin/pytest tests/test_snapshot_create.py tests/test_snapshot_list.py tests/test_snapshot_revert.py tests/test_snapshot_delete.py -x -q`
    - Full suite command: `.venv/bin/pytest tests/ -q`
    - Estimated runtime: ~10 seconds

    **Sampling Rate section:** Quick run command above after every task commit. Full suite after every wave. Max feedback latency: 15 seconds.

    **Per-Task Verification Map:**

    | Task ID | Plan | Wave | Requirement | Test Type | Automated Command | File Exists | Status |
    |---------|------|------|-------------|-----------|-------------------|-------------|--------|
    | 04-01-01 | 01 | 1 | SNAP-01 | unit | `.venv/bin/pytest tests/test_snapshot_create.py -x -q` | ✅ | ✅ green |
    | 04-01-02 | 01 | 1 | SNAP-03 | unit | `.venv/bin/pytest tests/test_snapshot_list.py -x -q` | ✅ | ✅ green |
    | 04-02-01 | 02 | 1 | SNAP-02 | unit | `.venv/bin/pytest tests/test_snapshot_revert.py -x -q` | ✅ | ✅ green |
    | 04-02-02 | 02 | 1 | SNAP-04 | unit | `.venv/bin/pytest tests/test_snapshot_delete.py -x -q` | ✅ | ✅ green |

    **Wave 0 Requirements section:** Write: "Existing infrastructure covers all phase requirements."

    **Manual-Only Verifications section:** Write: "All phase behaviors have automated verification."

    **Add a "## Requirement Coverage" section:**

    | Requirement | Description | Covered By | Test Names |
    |-------------|-------------|------------|------------|
    | SNAP-01 | Create named disk snapshot for all nodes simultaneously; appears in snapshot_list | tests/test_snapshot_create.py, tests/test_snapshot_list.py | `test_snapshot_create_returns_snapshot_info`, `test_snapshot_create_creates_directory`, `test_snapshot_create_uses_libvirt_disk_only_flag`, `test_snapshot_create_concurrent_for_all_nodes`, `test_snapshot_create_returns_failure_when_node_fails`, `test_snapshot_create_tool_returns_snapshot_info`, `test_snapshot_list_returns_snapshot_info_for_single_snapshot` |
    | SNAP-02 | Revert all nodes to named snapshot atomically; optionally restart and wait for SSH; failure on any node returns success=False | tests/test_snapshot_revert.py | `test_revert_destroys_all_nodes_before_any_revert`, `test_revert_calls_revert_to_snapshot_for_each_node`, `test_revert_restart_after_true_starts_all_domains`, `test_revert_restart_after_false_does_not_start_domains`, `test_revert_wait_for_ssh_calls_wait_per_node`, `test_revert_ssh_timeout_returns_failure`, `test_revert_nonexistent_snapshot_returns_error`, `test_revert_returns_cluster_status_with_per_node_entries` |
    | SNAP-03 | List all snapshots for a cluster with creation time and per-node disk size | tests/test_snapshot_list.py | `test_snapshot_list_returns_empty_when_no_snapshots`, `test_snapshot_list_returns_snapshot_info_for_single_snapshot`, `test_snapshot_list_parses_creation_time_from_xml`, `test_snapshot_list_reports_per_node_disk_sizes`, `test_snapshot_list_missing_file_size_returns_zero`, `test_snapshot_list_groups_by_name_across_nodes`, `test_snapshot_list_multiple_distinct_snapshots`, `test_snapshot_list_tool_returns_tool_result` |
    | SNAP-04 | Delete named snapshot from all nodes; return per-node confirmation | tests/test_snapshot_delete.py | `test_delete_calls_client_delete_snapshot_once_per_node`, `test_delete_returns_per_node_confirmation`, `test_delete_continues_on_individual_node_failure`, `test_delete_active_backing_guard_refuses_deletion`, `test_delete_nonexistent_snapshot_returns_per_node_error`, `test_delete_removes_overlay_file`, `test_delete_file_not_found_is_not_an_error` |

    **Validation Sign-Off:** All checkboxes checked. "Approval: approved 2026-03-24".
  </action>
  <verify>
    <automated>.venv/bin/python -c "import yaml; d=yaml.safe_load(open('.planning/phases/04-snapshot-management/04-VALIDATION.md')); assert d['nyquist_compliant'] is True; print('OK')"</automated>
  </verify>
  <acceptance_criteria>
    - File exists: `.planning/phases/04-snapshot-management/04-VALIDATION.md`
    - `grep "nyquist_compliant: true" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns a match
    - `grep "SNAP-01" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns at least 1 match
    - `grep "SNAP-02" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns at least 1 match
    - `grep "SNAP-03" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns at least 1 match
    - `grep "SNAP-04" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns at least 1 match
    - `grep "test_revert_destroys_all_nodes_before_any_revert" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns a match
    - `grep "test_snapshot_list_reports_per_node_disk_sizes" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns a match
    - `grep "test_delete_continues_on_individual_node_failure" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns a match
    - `grep "wave_0_complete: true" .planning/phases/04-snapshot-management/04-VALIDATION.md` returns a match
  </acceptance_criteria>
  <done>04-VALIDATION.md exists, maps all 4 SNAP requirements to their test functions, nyquist_compliant is true.</done>
</task>

<task type="auto">
  <name>Task 2: Create 05-VALIDATION.md for Phase 5 (Artifact Pipeline)</name>
  <read_first>
    - $HOME/.claude/get-shit-done/templates/VALIDATION.md (template structure to follow exactly)
    - .planning/phases/05-artifact-pipeline/05-01-PLAN.md
    - .planning/phases/05-artifact-pipeline/05-02-PLAN.md
    - .planning/phases/05-artifact-pipeline/05-03-PLAN.md
    - .planning/phases/05-artifact-pipeline/05-01-SUMMARY.md
    - .planning/phases/05-artifact-pipeline/05-02-SUMMARY.md
    - .planning/phases/05-artifact-pipeline/05-03-SUMMARY.md
    - .planning/phases/05-artifact-pipeline/05-VERIFICATION.md (existing evidence)
    - tests/test_artifact_registry.py (ART-01/04/05 evidence: test_register_returns_build_artifact, test_save_atomic_write, test_list_artifacts_returns_all, test_diff_returns_artifact_diff)
    - tests/test_artifact_sync.py (ART-02 evidence: test_sync_node_skips_when_dir_exists_no_force, test_sync_node_rsync_when_dir_not_exists, test_sync_all_fans_out_across_all_nodes)
    - tests/test_artifact_install.py (ART-03 evidence: test_modprobe_path_creates_correct_ssh_command, test_make_install_runs_correct_command, test_rpm_mode_runs_correct_command, test_deb_mode_runs_correct_command)
  </read_first>
  <files>.planning/phases/05-artifact-pipeline/05-VALIDATION.md</files>
  <action>
    Create `.planning/phases/05-artifact-pipeline/05-VALIDATION.md` using the template structure exactly.

    **Frontmatter:**
    ```yaml
    ---
    phase: 5
    slug: artifact-pipeline
    status: complete
    nyquist_compliant: true
    wave_0_complete: true
    created: 2026-03-24
    ---
    ```

    **Test Infrastructure section:**
    - Framework: pytest 8.x (with pytest-asyncio)
    - Config file: pyproject.toml
    - Quick run command: `.venv/bin/pytest tests/test_artifact_registry.py tests/test_artifact_sync.py tests/test_artifact_install.py -x -q`
    - Full suite command: `.venv/bin/pytest tests/ -q`
    - Estimated runtime: ~8 seconds

    **Sampling Rate section:** Quick run command above after every task commit. Full suite after every wave. Max feedback latency: 15 seconds.

    **Per-Task Verification Map:**

    | Task ID | Plan | Wave | Requirement | Test Type | Automated Command | File Exists | Status |
    |---------|------|------|-------------|-----------|-------------------|-------------|--------|
    | 05-01-01 | 01 | 1 | ART-01 | unit | `.venv/bin/pytest tests/test_artifact_registry.py -k "register" -x -q` | ✅ | ✅ green |
    | 05-01-02 | 01 | 1 | ART-04 | unit | `.venv/bin/pytest tests/test_artifact_registry.py -k "list" -x -q` | ✅ | ✅ green |
    | 05-01-03 | 01 | 1 | ART-05 | unit | `.venv/bin/pytest tests/test_artifact_registry.py -k "diff" -x -q` | ✅ | ✅ green |
    | 05-02-01 | 02 | 1 | ART-02 | unit | `.venv/bin/pytest tests/test_artifact_sync.py -x -q` | ✅ | ✅ green |
    | 05-03-01 | 03 | 1 | ART-03 | unit | `.venv/bin/pytest tests/test_artifact_install.py -x -q` | ✅ | ✅ green |

    **Wave 0 Requirements section:** Write: "Existing infrastructure covers all phase requirements."

    **Manual-Only Verifications section:** Write: "All phase behaviors have automated verification."

    **Add a "## Requirement Coverage" section:**

    | Requirement | Description | Covered By | Test Names |
    |-------------|-------------|------------|------------|
    | ART-01 | Register local build tree as content-addressed artifact (sha256); atomic write; immediately visible in artifact_list | tests/test_artifact_registry.py | `test_hash_tree_same_content_same_hash`, `test_hash_tree_different_content_different_hash`, `test_hash_tree_excludes_pycache`, `test_save_atomic_write`, `test_register_returns_build_artifact`, `test_register_iso8601_timestamp`, `test_register_scans_ko_modules`, `test_register_scans_elf_bins`, `test_register_dedup_same_tree`, `test_register_autodetects_kernel_version` |
    | ART-02 | Sync registered artifact to cluster nodes via rsync; skip nodes where artifact hash already matches | tests/test_artifact_sync.py | `test_sync_node_skips_when_dir_exists_no_force`, `test_sync_node_rsync_when_dir_not_exists`, `test_sync_node_rsync_when_force_even_if_dir_exists`, `test_sync_node_reports_rsync_failure`, `test_sync_node_rsync_command_includes_correct_flags`, `test_sync_all_fans_out_across_all_nodes`, `test_sync_all_per_node_failure_does_not_abort_others`, `test_sync_all_exception_in_node_returns_error_result` |
    | ART-03 | Install synced artifact on nodes using modprobe_path, make_install, rpm, or deb modes | tests/test_artifact_install.py | `test_modprobe_path_creates_correct_ssh_command`, `test_modprobe_path_returns_installed_module_paths`, `test_make_install_runs_correct_command`, `test_rpm_mode_runs_correct_command`, `test_deb_mode_runs_correct_command`, `test_install_all_fans_out_to_all_nodes`, `test_install_all_per_node_failure_does_not_abort_others` |
    | ART-04 | List all registered artifacts | tests/test_artifact_registry.py | `test_list_artifacts_empty`, `test_list_artifacts_returns_all` |
    | ART-05 | Diff two artifacts to see which .ko files and binaries changed | tests/test_artifact_registry.py | `test_diff_returns_artifact_diff`, `test_diff_unchanged_artifacts`, `test_diff_unknown_artifact_id` |

    **Validation Sign-Off:** All checkboxes checked. "Approval: approved 2026-03-24".
  </action>
  <verify>
    <automated>.venv/bin/python -c "import yaml; d=yaml.safe_load(open('.planning/phases/05-artifact-pipeline/05-VALIDATION.md')); assert d['nyquist_compliant'] is True; print('OK')"</automated>
  </verify>
  <acceptance_criteria>
    - File exists: `.planning/phases/05-artifact-pipeline/05-VALIDATION.md`
    - `grep "nyquist_compliant: true" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns a match
    - `grep "ART-01" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns at least 1 match
    - `grep "ART-02" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns at least 1 match
    - `grep "ART-03" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns at least 1 match
    - `grep "ART-04" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns at least 1 match
    - `grep "ART-05" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns at least 1 match
    - `grep "test_save_atomic_write" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns a match
    - `grep "test_sync_node_skips_when_dir_exists_no_force" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns a match
    - `grep "test_modprobe_path_creates_correct_ssh_command" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns a match
    - `grep "test_diff_returns_artifact_diff" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns a match
    - `grep "wave_0_complete: true" .planning/phases/05-artifact-pipeline/05-VALIDATION.md` returns a match
  </acceptance_criteria>
  <done>05-VALIDATION.md exists, maps all 5 ART requirements to their test functions, nyquist_compliant is true.</done>
</task>

</tasks>

<verification>
After both tasks complete:

```bash
grep "nyquist_compliant: true" \
  .planning/phases/04-snapshot-management/04-VALIDATION.md \
  .planning/phases/05-artifact-pipeline/05-VALIDATION.md
```

Both files should return matches.

```bash
for req in SNAP-01 SNAP-02 SNAP-03 SNAP-04; do
  grep -c "$req" .planning/phases/04-snapshot-management/04-VALIDATION.md
done

for req in ART-01 ART-02 ART-03 ART-04 ART-05; do
  grep -c "$req" .planning/phases/05-artifact-pipeline/05-VALIDATION.md
done
```

All counts should be >= 1.
</verification>

<success_criteria>
- 04-VALIDATION.md and 05-VALIDATION.md exist in their phase directories
- Both have `nyquist_compliant: true` in YAML frontmatter
- All 9 requirements (SNAP-01..04, ART-01..05) are mapped to named test functions
- Each mapped test function name matches actual functions in the test files
</success_criteria>

<output>
After completion, create `.planning/phases/10-nyquist-validation-coverage/10-02-SUMMARY.md`
</output>
