{
  "ok": true,
  "tool": "webftr-js8-data-frame-text-unpack-probe",
  "tool_version": "step70-data-frame-text-unpack-probe",
  "schema": "webftr-js8-data-frame-text-unpack-probe-v1",
  "rx_only_guard": {
    "tx": false,
    "ptt": false,
    "tune": false,
    "send": false,
    "js8call_runtime_control": false,
    "webftr_productive_integration": false
  },
  "no_gui_runtime_started": true,
  "root": "/decoders/js8_decoder",
  "log_dir": "/decoders/js8_decoder/logs",
  "input_reports": [
    {
      "path": "/decoders/js8_decoder/logs/20260527T183331Z_jsc_decompress_source_audit_output.json",
      "exists": true,
      "selected_input": true
    }
  ],
  "source_resolution": {
    "source_dir": "/decoders/js8_decoder/runtime/src/JS8Call-improved",
    "source_found": true,
    "checked": [
      {
        "path": "/decoders/js8_decoder/runtime/src/JS8Call-improved",
        "exists": true,
        "is_dir": true
      }
    ],
    "focused_files_present": [
      "JS8_Main/Varicode.cpp",
      "JS8_Main/Varicode.h",
      "JS8_JSC/JSC.cpp",
      "JS8_JSC/JSC.h",
      "JS8_JSC/JSC_map.cpp",
      "JS8_JSC/JSC_list.cpp",
      "JS8_Mode/JS8.cpp",
      "JS8_Mode/JS8.h"
    ],
    "focused_files_missing": [
      "JS8_JSC/jsc.cpp",
      "JS8_JSC/jsc.h"
    ]
  },
  "jsc_decode_path_evidence": {
    "has_jsc_decompress_reference": true,
    "has_unpack_fast_data_message": true,
    "has_unpack_legacy_data_message": true,
    "has_huff_fallback_evidence": true,
    "expected_source_flow": [
      "unpack72bits(message174_text) -> 72 bits",
      "FrameData/FrameDataCompressed bits are trimmed at the final zero padding marker",
      "compressed path calls JSC::decompress(bits)",
      "legacy non-compressed path uses Varicode::huffDecode(defaultHuffTable, bits)",
      "Step69 does not yet display free text; it only extracts and documents the source path for a safe Step70 port."
    ]
  },
  "source_trim_contract": {
    "message174_to_72_bits": "unpack72bits(message174_text) -> 64-bit value + 8-bit remainder",
    "legacy_data_flags": "bit0=data, bit1=compressed",
    "legacy_noncompressed_path": "payload bits between data/compressed flags and final zero delimiter -> Varicode::huffDecode(defaultHuffTable)",
    "compressed_path": "same trim family, then JSC::decompress(payload bits); still blocked in Step70",
    "chat_release": "disabled; this step is a guarded port/harness probe only"
  },
  "current_fixture_has_data_frames": false,
  "data_frame_candidate_count": 0,
  "data_frame_text_rows": [],
  "synthetic_selftest_fixtures": [
    {
      "fixture_kind": "legacy_noncompressed_huff_data_frame",
      "input_text": "TEST",
      "message174_text_12chars": "jbDV++++++++",
      "payload_bit_count": 16,
      "bits72_prefix": "1011011001010011010111111111111111111111",
      "unpack_result": {
        "message_text_12chars": "jbDV++++++++",
        "ok": true,
        "data_text_release_allowed": false,
        "release_guard": "step70_diagnostics_only_no_chat_release",
        "top2": 2,
        "top3": 5,
        "is_data_flag": true,
        "compressed_flag": false,
        "last_zero_index": 18,
        "payload_bit_count": 16,
        "payload_preview_bits": "1101100101001101",
        "source_trim_rule": "bits[2:last_zero] using final zero as padding delimiter for legacy data frames",
        "frame_text_path": "legacy_huff_noncompressed",
        "huff_decode": {
          "text": "TEST",
          "consumed_bits": 16,
          "remaining_bits": 0,
          "complete": true
        },
        "decoded_text": "TEST",
        "jsc_decompress_needed": false,
        "diagnostic_text_plausible": true,
        "warning": "Decoded only as a diagnostic legacy Huff data frame. It is not released to WebFTR chat rows in Step70."
      },
      "passes": true
    },
    {
      "fixture_kind": "legacy_noncompressed_huff_data_frame",
      "input_text": "CQ",
      "message174_text_12chars": "iI3+++++++++",
      "payload_bit_count": 13,
      "bits72_prefix": "1011000100100000111111111111111111111111",
      "unpack_result": {
        "message_text_12chars": "iI3+++++++++",
        "ok": true,
        "data_text_release_allowed": false,
        "release_guard": "step70_diagnostics_only_no_chat_release",
        "top2": 2,
        "top3": 5,
        "is_data_flag": true,
        "compressed_flag": false,
        "last_zero_index": 15,
        "payload_bit_count": 13,
        "payload_preview_bits": "1100010010000",
        "source_trim_rule": "bits[2:last_zero] using final zero as padding delimiter for legacy data frames",
        "frame_text_path": "legacy_huff_noncompressed",
        "huff_decode": {
          "text": "CQ",
          "consumed_bits": 13,
          "remaining_bits": 0,
          "complete": true
        },
        "decoded_text": "CQ",
        "jsc_decompress_needed": false,
        "diagnostic_text_plausible": true,
        "warning": "Decoded only as a diagnostic legacy Huff data frame. It is not released to WebFTR chat rows in Step70."
      },
      "passes": true
    }
  ],
  "selftest_fixture_pass_count": 2,
  "webftr_rx_rows": [],
  "webftr_display_count": 0,
  "webftr_adapter_hint": {
    "safe_to_poll_read_only": true,
    "productive_integration": false,
    "do_not_merge_as_chat_text_yet": true,
    "step68_contract_remains_current_ui_source": true
  },
  "verdict": "data_frame_trim_and_huff_harness_ready_no_current_data_frames",
  "warnings": [
    "Step70 remains RX-only and does not start JS8Call GUI/Qt.",
    "Step70 does not release decoded data text to WebFTR chat/RX rows.",
    "Compressed FrameData still needs a source-faithful JSC::decompress table port before free text can be considered displayable."
  ],
  "next_action": "Wait for or inject a real FrameData/FrameDataCompressed fixture, then run Step70 again; next implementation step is JSC table extraction/port for compressed frames.",
  "stable_latest_written": "/decoders/js8_decoder/logs/js8_data_frame_text_unpack_probe_latest.json"
}
