{
  "ok": true,
  "tool": "webftr-js8-real-wav-intake-validator-auto-handoff",
  "tool_version": "step90-real-wav-intake-validator-auto-handoff",
  "schema": "webftr-js8-real-wav-intake-validator-auto-handoff-v1",
  "created_utc": "2026-05-28T07:14:23Z",
  "rx_only": true,
  "safety": {
    "tx": false,
    "ptt": false,
    "tune": false,
    "send": false,
    "js8call_runtime_control": false
  },
  "root": "/decoders/js8_decoder",
  "purpose": "Validate the real WAV corpus before auto-handoff. This avoids long hunts on missing/broken files and makes ./start.sh useful once an extra real JS8 free-text WAV is added.",
  "primary_wav": "/decoders/js8_test.wav",
  "planned_wav_count": 3,
  "discovered_wav_count": 3,
  "extra_wav_count": 2,
  "valid_extra_wav_count": 2,
  "invalid_wav_count": 0,
  "invalid_extra_wav_count": 0,
  "primary_wav_valid": true,
  "planned_wavs": [
    {
      "path": "/decoders/js8_test.wav",
      "source": "primary",
      "stat": {
        "path": "/decoders/js8_test.wav",
        "exists": true,
        "is_file": true,
        "size": 4608442,
        "mtime_utc": "2026-05-26T06:05:27Z"
      }
    },
    {
      "path": "/decoders/js8_decoder/runtime/input_wavs/A_1_4.wav",
      "source": "dir:/decoders/js8_decoder/runtime/input_wavs",
      "stat": {
        "path": "/decoders/js8_decoder/runtime/input_wavs/A_1_4.wav",
        "exists": true,
        "is_file": true,
        "size": 360208,
        "mtime_utc": "2026-05-28T06:39:47Z"
      }
    },
    {
      "path": "/decoders/js8_wavs/A_1_4.wav",
      "source": "dir:/decoders/js8_wavs",
      "stat": {
        "path": "/decoders/js8_wavs/A_1_4.wav",
        "exists": true,
        "is_file": true,
        "size": 360208,
        "mtime_utc": "2026-05-28T06:39:47Z"
      }
    }
  ],
  "validation_results": [
    {
      "path": "/decoders/js8_test.wav",
      "source": "primary",
      "stat": {
        "path": "/decoders/js8_test.wav",
        "exists": true,
        "is_file": true,
        "size": 4608442,
        "mtime_utc": "2026-05-26T06:05:27Z"
      },
      "exists": true,
      "is_file": true,
      "readable_wav": true,
      "valid_for_corpus_hunt": true,
      "warnings": [],
      "errors": [],
      "sha256_first_2m": "c049995adf22be86b9acd8d57a566fba642f877fbcd24c1c120463a665956fbf",
      "channels": 1,
      "sample_width_bytes": 2,
      "sample_rate_hz": 12000,
      "frames": 2304199,
      "duration_seconds": 192.017,
      "compression_type": "NONE"
    },
    {
      "path": "/decoders/js8_decoder/runtime/input_wavs/A_1_4.wav",
      "source": "dir:/decoders/js8_decoder/runtime/input_wavs",
      "stat": {
        "path": "/decoders/js8_decoder/runtime/input_wavs/A_1_4.wav",
        "exists": true,
        "is_file": true,
        "size": 360208,
        "mtime_utc": "2026-05-28T06:39:47Z"
      },
      "exists": true,
      "is_file": true,
      "readable_wav": true,
      "valid_for_corpus_hunt": true,
      "warnings": [],
      "errors": [],
      "sha256_first_2m": "60b650c2090dff5e2144f164ebe692cde5f048c769518e1b1b9e67223f3da138",
      "channels": 1,
      "sample_width_bytes": 2,
      "sample_rate_hz": 12000,
      "frames": 180000,
      "duration_seconds": 15.0,
      "compression_type": "NONE"
    },
    {
      "path": "/decoders/js8_wavs/A_1_4.wav",
      "source": "dir:/decoders/js8_wavs",
      "stat": {
        "path": "/decoders/js8_wavs/A_1_4.wav",
        "exists": true,
        "is_file": true,
        "size": 360208,
        "mtime_utc": "2026-05-28T06:39:47Z"
      },
      "exists": true,
      "is_file": true,
      "readable_wav": true,
      "valid_for_corpus_hunt": true,
      "warnings": [],
      "errors": [],
      "sha256_first_2m": "60b650c2090dff5e2144f164ebe692cde5f048c769518e1b1b9e67223f3da138",
      "channels": 1,
      "sample_width_bytes": 2,
      "sample_rate_hz": 12000,
      "frames": 180000,
      "duration_seconds": 15.0,
      "compression_type": "NONE"
    }
  ],
  "valid_extra_wavs": [
    {
      "path": "/decoders/js8_decoder/runtime/input_wavs/A_1_4.wav",
      "source": "dir:/decoders/js8_decoder/runtime/input_wavs",
      "stat": {
        "path": "/decoders/js8_decoder/runtime/input_wavs/A_1_4.wav",
        "exists": true,
        "is_file": true,
        "size": 360208,
        "mtime_utc": "2026-05-28T06:39:47Z"
      },
      "exists": true,
      "is_file": true,
      "readable_wav": true,
      "valid_for_corpus_hunt": true,
      "warnings": [],
      "errors": [],
      "sha256_first_2m": "60b650c2090dff5e2144f164ebe692cde5f048c769518e1b1b9e67223f3da138",
      "channels": 1,
      "sample_width_bytes": 2,
      "sample_rate_hz": 12000,
      "frames": 180000,
      "duration_seconds": 15.0,
      "compression_type": "NONE"
    },
    {
      "path": "/decoders/js8_wavs/A_1_4.wav",
      "source": "dir:/decoders/js8_wavs",
      "stat": {
        "path": "/decoders/js8_wavs/A_1_4.wav",
        "exists": true,
        "is_file": true,
        "size": 360208,
        "mtime_utc": "2026-05-28T06:39:47Z"
      },
      "exists": true,
      "is_file": true,
      "readable_wav": true,
      "valid_for_corpus_hunt": true,
      "warnings": [],
      "errors": [],
      "sha256_first_2m": "60b650c2090dff5e2144f164ebe692cde5f048c769518e1b1b9e67223f3da138",
      "channels": 1,
      "sample_width_bytes": 2,
      "sample_rate_hz": 12000,
      "frames": 180000,
      "duration_seconds": 15.0,
      "compression_type": "NONE"
    }
  ],
  "invalid_wavs": [],
  "latest_step87_summary": {
    "path": "/decoders/js8_decoder/logs/js8_real_wav_corpus_data_frame_hunt_latest.json",
    "stat": {
      "path": "/decoders/js8_decoder/logs/js8_real_wav_corpus_data_frame_hunt_latest.json",
      "exists": true,
      "is_file": true,
      "size": 17875,
      "mtime_utc": "2026-05-28T07:14:22Z"
    },
    "available": true,
    "tool_version": "step87-real-wav-corpus-data-frame-hunt",
    "created_utc": "2026-05-28T07:14:22Z",
    "verdict": "step87_corpus_control_frames_only_no_data_frames",
    "tested_wav_count": 3,
    "planned_wav_count": 3,
    "data_frame_candidate_count": 0,
    "compressed_data_frame_candidate_count": 0,
    "unique_control_frame_total_across_wavs": 6
  },
  "previous_step89_summary": {
    "path": "/decoders/js8_decoder/logs/js8_real_wav_corpus_auto_handoff_latest.json",
    "stat": {
      "path": "/decoders/js8_decoder/logs/js8_real_wav_corpus_auto_handoff_latest.json",
      "exists": true,
      "is_file": true,
      "size": 4026,
      "mtime_utc": "2026-05-28T06:14:28Z"
    },
    "available": true,
    "tool_version": "step89-real-wav-corpus-auto-handoff",
    "created_utc": "2026-05-28T06:14:28Z",
    "verdict": "step89_waiting_for_additional_real_js8_freetext_wav",
    "action": "wait_for_extra_wav",
    "full_hunt_ran": false,
    "data_frame_candidate_count": 0,
    "compressed_data_frame_candidate_count": 0
  },
  "previous_step90_summary": {
    "path": "/decoders/js8_decoder/logs/js8_real_wav_intake_validator_auto_handoff_latest.json",
    "stat": {
      "path": "/decoders/js8_decoder/logs/js8_real_wav_intake_validator_auto_handoff_latest.json",
      "exists": true,
      "is_file": true,
      "size": 10100,
      "mtime_utc": "2026-05-28T07:01:53Z"
    },
    "available": true,
    "tool_version": "step90-real-wav-intake-validator-auto-handoff",
    "created_utc": "2026-05-28T07:01:53Z",
    "verdict": "step90_valid_extra_wav_detected_auto_handoff_to_step87",
    "action": "run_full_corpus_hunt_now",
    "full_hunt_ran": false,
    "valid_extra_wav_count": 2,
    "invalid_wav_count": 0,
    "data_frame_candidate_count": 0,
    "compressed_data_frame_candidate_count": 0
  },
  "operator_files": {
    "input_wavs_dir": "/decoders/js8_decoder/runtime/input_wavs",
    "fixtures_wavs_dir": "/decoders/js8_decoder/runtime/fixtures/wavs",
    "readme": "/decoders/js8_decoder/runtime/input_wavs/README_STEP88_WAV_CORPUS_INTAKE.md",
    "helper": "/decoders/js8_decoder/runtime/input_wavs/add_wav_to_corpus_step88.sh",
    "readme_stat": {
      "path": "/decoders/js8_decoder/runtime/input_wavs/README_STEP88_WAV_CORPUS_INTAKE.md",
      "exists": true,
      "is_file": true,
      "size": 427,
      "mtime_utc": "2026-05-28T07:14:23Z"
    },
    "helper_stat": {
      "path": "/decoders/js8_decoder/runtime/input_wavs/add_wav_to_corpus_step88.sh",
      "exists": true,
      "is_file": true,
      "size": 446,
      "mtime_utc": "2026-05-28T07:14:23Z"
    }
  },
  "step90_operator_files": {
    "input_wavs_dir": "/decoders/js8_decoder/runtime/input_wavs",
    "readme": "/decoders/js8_decoder/runtime/input_wavs/README_STEP90_WAV_INTAKE_VALIDATOR.md",
    "helper": "/decoders/js8_decoder/runtime/input_wavs/validate_wav_corpus_step90.sh",
    "readme_stat": {
      "path": "/decoders/js8_decoder/runtime/input_wavs/README_STEP90_WAV_INTAKE_VALIDATOR.md",
      "exists": true,
      "is_file": true,
      "size": 415,
      "mtime_utc": "2026-05-28T07:14:23Z"
    },
    "helper_stat": {
      "path": "/decoders/js8_decoder/runtime/input_wavs/validate_wav_corpus_step90.sh",
      "exists": true,
      "is_file": true,
      "size": 194,
      "mtime_utc": "2026-05-28T07:14:23Z"
    }
  },
  "after_hunt": true,
  "force_hunt": false,
  "full_hunt_ran": true,
  "data_frame_candidate_count": 0,
  "compressed_data_frame_candidate_count": 0,
  "action": "await_new_real_js8_freetext_wav",
  "verdict": "step90_full_hunt_completed_no_data_frames_waiting_for_new_wav",
  "warnings": [
    "Step90 still does not release JS8 free text directly.",
    "The primary /decoders/js8_test.wav is a control-frame reference and is not counted as an extra WAV.",
    "Only valid extra WAVs trigger the full Step87 corpus hunt automatically."
  ],
  "next_action": "Add a real JS8 WAV with free-text/Data/Compressed transmission to runtime/input_wavs or set JS8LAB_WAV_CORPUS_DIRS. Step90 validates the WAV first and then auto-runs the full corpus hunt only when a valid extra WAV is present. If Data/Compressed candidates appear, route them to the guarded release gate."
}
