{
  "ok": true,
  "tool": "webftr-js8-source-message174-crc12-contract",
  "tool_version": "step55-source-message174-crc12-contract",
  "source_dir": "/decoders/js8_decoder/runtime/src/JS8Call-improved",
  "target_file": "JS8_Mode/JS8.cpp",
  "target_exists": true,
  "rx_only_guard": {
    "tx": false,
    "ptt": false,
    "tune": false,
    "send": false,
    "js8call_runtime_control": false
  },
  "no_gui_runtime_started": true,
  "purpose": "Extract the source-confirmed JS8Call-Improved message174 CRC12 contract before patching JS8Lab bit/message validation.",
  "contract": {
    "crc_width": 12,
    "crc_poly_hex": "0xc06",
    "crc_xor_decimal": 42,
    "crc_xor_hex": "0x02a",
    "received_crc_extraction_detected": true,
    "crc_clear_detected": true,
    "message_reserve_12_detected": true,
    "word_loop_12_detected": true,
    "source_inference": {
      "payload_data_bits": 72,
      "crc_bits": 12,
      "message_words": 12,
      "word_bits": 6,
      "legacy_message91_crc14_assumption_valid_for_this_path": false,
      "why": "JS8Call-Improved source path shows extractmessage174/checkCRC12 with 12x6 data bits plus CRC12, not the earlier diagnostic 77+14 Message91 split."
    }
  },
  "keyword_lines": [
    {
      "line": 5,
      "text": " * (C) 2025 Allan Bazinet <w6baz@arrl.net> - All Rights Reserved"
    },
    {
      "line": 80,
      "text": "//   6. The Fortran version normalized `s1` by dividing by the median in"
    },
    {
      "line": 102,
      "text": "    constexpr auto RAD_360 = std::numbers::pi * 2;"
    },
    {
      "line": 108,
      "text": "    // itself is only 1-e16, so within the domain of doubles,"
    },
    {
      "line": 115,
      "text": "            0.041666666666666664,          // Coefficient for x^4"
    },
    {
      "line": 116,
      "text": "            -0.001388888888888889,         // Coefficient for x^6"
    },
    {
      "line": 118,
      "text": "            -0.00000027557319223986,       // Coefficient for x^10"
    },
    {
      "line": 119,
      "text": "            0.00000000208767569878681,     // Coefficient for x^12"
    },
    {
      "line": 120,
      "text": "            -0.00000000001147074513875176, // Coefficient for x^14"
    },
    {
      "line": 121,
      "text": "            0.0000000000000477947733238733 // Coefficient for x^16"
    },
    {
      "line": 126,
      "text": "        auto const x6 = x4 * x2;"
    },
    {
      "line": 129,
      "text": "        auto const x12 = x8 * x4;"
    },
    {
      "line": 130,
      "text": "        auto const x14 = x12 * x2;"
    },
    {
      "line": 131,
      "text": "        auto const x16 = x8 * x8;"
    },
    {
      "line": 134,
      "text": "               coefficients[3] * x6 + coefficients[4] * x8 +"
    },
    {
      "line": 135,
      "text": "               coefficients[5] * x10 + coefficients[6] * x12 +"
    },
    {
      "line": 136,
      "text": "               coefficients[7] * x14 + coefficients[8] * x16;"
    },
    {
      "line": 139,
      "text": "    // Reduce x to [0, RAD_360)"
    },
    {
      "line": 141,
      "text": "    x -= static_cast<long long>(x / RAD_360) * RAD_360;"
    },
    {
      "line": 146,
      "text": "        x = RAD_360 - x;"
    },
    {
      "line": 164,
      "text": "// parameter (KK=87)                     !Information bits (75 + CRC12)"
    },
    {
      "line": 174,
      "text": "// KK\t87\tNumber of information bits (75 message bits + 12 CRC bits)."
    },
    {
      "line": 185,
      "text": "constexpr int KK = 87;           // Information bits (75 + CRC12)"
    },
    {
      "line": 197,
      "text": "constexpr int NP2 = 2812;"
    },
    {
      "line": 225,
      "text": "    inline static constexpr int JZ = 62;"
    },
    {
      "line": 230,
      "text": "    inline static constexpr float AZ = (12000.0f / NSPS) * 0.64f;"
    },
    {
      "line": 240,
      "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
    },
    {
      "line": 242,
      "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
    },
    {
      "line": 260,
      "text": "    inline static constexpr float AZ = (12000.0f / NSPS) * 0.8f;"
    },
    {
      "line": 270,
      "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
    },
    {
      "line": 272,
      "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
    },
    {
      "line": 283,
      "text": "    inline static constexpr int NDOWNSPS = 12;"
    },
    {
      "line": 284,
      "text": "    inline static constexpr int NDD = 120;"
    },
    {
      "line": 290,
      "text": "    inline static constexpr float AZ = (12000.0f / NSPS) * 0.6f;"
    },
    {
      "line": 300,
      "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
    },
    {
      "line": 302,
      "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
    },
    {
      "line": 325,
      "text": "    inline static constexpr float AZ = (12000.0f / NSPS) * 0.64f;"
    },
    {
      "line": 335,
      "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
    },
    {
      "line": 337,
      "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
    },
    {
      "line": 348,
      "text": "    inline static constexpr int NDOWNSPS = 12;"
    },
    {
      "line": 349,
      "text": "    inline static constexpr int NDD = 125;"
    },
    {
      "line": 352,
      "text": "    inline static constexpr float BASESUB = 36.0f;"
    },
    {
      "line": 355,
      "text": "    inline static constexpr float AZ = (12000.0f / NSPS) * 0.64f;"
    },
    {
      "line": 365,
      "text": "    inline static constexpr float TSTEP = NSTEP / 12000.0f;"
    },
    {
      "line": 367,
      "text": "    inline static constexpr float DF = 12000.0f / NFFT1;"
    },
    {
      "line": 440,
      "text": "//     a0=0.3635819"
    },
    {
      "line": 442,
      "text": "//     a2=0.1365995;"
    },
    {
      "line": 443,
      "text": "//     a3=-0.0106411;"
    },
    {
      "line": 447,
      "text": "//             a3*cos(6*pi*(i-1)/(n))"
    },
    {
      "line": 566,
      "text": "// and the 12 bytes that result from decoding a message."
    },
    {
      "line": 581,
      "text": "            return h1 ^ (h2 + 0x9e3779b9 + (h1 << 6) + (h1 >> 2));"
    },
    {
      "line": 598,
      "text": "    {{0, 24, 68},  {1, 4, 72},   {2, 31, 67},  {3, 50, 60},  {5, 62, 69},"
    },
    {
      "line": 599,
      "text": "     {6, 32, 78},  {7, 49, 85},  {8, 36, 42},  {9, 40, 64},  {10, 13, 63},"
    },
    {
      "line": 600,
      "text": "     {11, 74, 76}, {12, 22, 80}, {14, 15, 81}, {16, 55, 65}, {17, 52, 59},"
    },
    {
      "line": 601,
      "text": "     {18, 30, 51}, {19, 66, 83}, {20, 28, 71}, {21, 23, 43}, {25, 34, 75},"
    },
    {
      "line": 602,
      "text": "     {26, 35, 37}, {27, 39, 41}, {29, 53, 54}, {33, 48, 86}, {38, 56, 57},"
    },
    {
      "line": 603,
      "text": "     {44, 73, 82}, {45, 61, 79}, {46, 47, 84}, {58, 70, 77}, {0, 49, 52},"
    },
    {
      "line": 604,
      "text": "     {1, 46, 83},  {2, 24, 78},  {3, 5, 13},   {4, 6, 79},   {7, 33, 54},"
    },
    {
      "line": 605,
      "text": "     {8, 35, 68},  {9, 42, 82},  {10, 22, 73}, {11, 16, 43}, {12, 56, 75},"
    },
    {
      "line": 606,
      "text": "     {14, 26, 55}, {15, 27, 28}, {17, 18, 58}, {19, 39, 62}, {20, 34, 51},"
    },
    {
      "line": 607,
      "text": "     {21, 53, 63}, {23, 61, 77}, {25, 31, 76}, {29, 71, 84}, {30, 64, 86},"
    },
    {
      "line": 608,
      "text": "     {32, 38, 50}, {36, 47, 74}, {37, 69, 70}, {40, 41, 67}, {44, 66, 85},"
    },
    {
      "line": 609,
      "text": "     {45, 80, 81}, {48, 65, 72}, {57, 59, 65}, {60, 64, 84}, {0, 13, 20},"
    },
    {
      "line": 610,
      "text": "     {1, 12, 58},  {2, 66, 81},  {3, 31, 72},  {4, 35, 53},  {5, 42, 45},"
    },
    {
      "line": 611,
      "text": "     {6, 27, 74},  {7, 32, 70},  {8, 48, 75},  {9, 57, 63},  {10, 47, 67},"
    },
    {
      "line": 612,
      "text": "     {11, 18, 44}, {14, 49, 60}, {15, 21, 25}, {16, 71, 79}, {17, 39, 54},"
    },
    {
      "line": 613,
      "text": "     {19, 34, 50}, {22, 24, 33}, {23, 62, 86}, {26, 38, 73}, {28, 77, 82},"
    },
    {
      "line": 614,
      "text": "     {29, 69, 76}, {30, 68, 83}, {21, 36, 85}, {37, 40, 80}, {41, 43, 56},"
    },
    {
      "line": 615,
      "text": "     {46, 52, 61}, {51, 55, 78}, {59, 74, 80}, {0, 38, 76},  {1, 15, 40},"
    },
    {
      "line": 616,
      "text": "     {2, 30, 53},  {3, 35, 77},  {4, 44, 64},  {5, 56, 84},  {6, 13, 48},"
    },
    {
      "line": 617,
      "text": "     {7, 20, 45},  {8, 14, 71},  {9, 19, 61},  {10, 16, 70}, {11, 33, 46},"
    },
    {
      "line": 618,
      "text": "     {12, 67, 85}, {17, 22, 42}, {18, 63, 72}, {23, 47, 78}, {24, 69, 82},"
    },
    {
      "line": 619,
      "text": "     {25, 79, 86}, {26, 31, 39}, {27, 55, 68}, {28, 62, 65}, {29, 41, 49},"
    },
    {
      "line": 620,
      "text": "     {32, 36, 81}, {34, 59, 73}, {37, 54, 83}, {43, 51, 60}, {50, 52, 71},"
    },
    {
      "line": 621,
      "text": "     {57, 58, 66}, {46, 55, 75}, {0, 18, 36},  {1, 60, 74},  {2, 7, 65},"
    },
    {
      "line": 622,
      "text": "     {3, 59, 83},  {4, 33, 38},  {5, 25, 52},  {6, 31, 56},  {8, 51, 66},"
    },
    {
      "line": 623,
      "text": "     {9, 11, 14},  {10, 50, 68}, {12, 13, 64}, {15, 30, 42}, {16, 19, 35},"
    },
    {
      "line": 624,
      "text": "     {17, 79, 85}, {20, 47, 58}, {21, 39, 45}, {22, 32, 61}, {23, 29, 73},"
    },
    {
      "line": 625,
      "text": "     {24, 41, 63}, {26, 48, 84}, {27, 37, 72}, {28, 43, 80}, {34, 67, 69},"
    },
    {
      "line": 626,
      "text": "     {40, 62, 75}, {44, 48, 70}, {49, 57, 86}, {47, 53, 82}, {12, 54, 78},"
    },
    {
      "line": 627,
      "text": "     {76, 77, 81}, {0, 1, 23},   {2, 5, 74},   {3, 55, 86},  {4, 43, 52},"
    },
    {
      "line": 628,
      "text": "     {6, 49, 82},  {7, 9, 27},   {8, 54, 61},  {10, 28, 66}, {11, 32, 39},"
    },
    {
      "line": 629,
      "text": "     {13, 15, 19}, {14, 34, 72}, {16, 30, 38}, {17, 35, 56}, {18, 45, 75},"
    },
    {
      "line": 630,
      "text": "     {20, 41, 83}, {21, 33, 58}, {22, 25, 60}, {24, 59, 64}, {26, 63, 79},"
    },
    {
      "line": 631,
      "text": "     {29, 36, 65}, {31, 44, 71}, {37, 50, 85}, {40, 76, 78}, {42, 55, 67},"
    },
    {
      "line": 632,
      "text": "     {46, 73, 81}, {39, 51, 77}, {53, 60, 70}, {45, 57, 68}}};"
    },
    {
      "line": 639,
      "text": "constexpr std::array<CheckNode, M> Nm = {{{6, {0, 29, 59, 88, 117, 146, 0}},"
    },
    {
      "line": 640,
      "text": "                                          {6, {1, 30, 60, 89, 118, 146, 0}},"
    },
    {
      "line": 641,
      "text": "                                          {6, {2, 31, 61, 90, 119, 147, 0}},"
    },
    {
      "line": 642,
      "text": "                                          {6, {3, 32, 62, 91, 120, 148, 0}},"
    },
    {
      "line": 643,
      "text": "                                          {6, {1, 33, 63, 92, 121, 149, 0}},"
    },
    {
      "line": 644,
      "text": "                                          {6, {4, 32, 64, 93, 122, 147, 0}},"
    },
    {
      "line": 645,
      "text": "                                          {6, {5, 33, 65, 94, 123, 150, 0}},"
    },
    {
      "line": 646,
      "text": "                                          {6, {6, 34, 66, 95, 119, 151, 0}},"
    },
    {
      "line": 647,
      "text": "                                          {6, {7, 35, 67, 96, 124, 152, 0}},"
    },
    {
      "line": 648,
      "text": "                                          {6, {8, 36, 68, 97, 125, 151, 0}},"
    },
    {
      "line": 649,
      "text": "                                          {6, {9, 37, 69, 98, 126, 153, 0}},"
    },
    {
      "line": 650,
      "text": "                                          {6, {10, 38, 70, 99, 125, 154, 0}},"
    },
    {
      "line": 651,
      "text": "                                          {6, {11, 39, 60, 100, 127, 144, 0}},"
    },
    {
      "line": 652,
      "text": "                                          {6, {9, 32, 59, 94, 127, 155, 0}},"
    },
    {
      "line": 653,
      "text": "                                          {6, {12, 40, 71, 96, 125, 156, 0}},"
    },
    {
      "line": 654,
      "text": "                                          {6, {12, 41, 72, 89, 128, 155, 0}},"
    },
    {
      "line": 655,
      "text": "                                          {6, {13, 38, 73, 98, 129, 157, 0}},"
    },
    {
      "line": 656,
      "text": "                                          {6, {14, 42, 74, 101, 130, 158, 0}},"
    },
    {
      "line": 657,
      "text": "                                          {6, {15, 42, 70, 102, 117, 159, 0}},"
    },
    {
      "line": 658,
      "text": "                                          {6, {16, 43, 75, 97, 129, 155, 0}},"
    },
    {
      "line": 659,
      "text": "                                          {6, {17, 44, 59, 95, 131, 160, 0}},"
    },
    {
      "line": 660,
      "text": "                                          {6, {18, 45, 72, 82, 132, 161, 0}},"
    },
    {
      "line": 661,
      "text": "                                          {6, {11, 37, 76, 101, 133, 162, 0}},"
    },
    {
      "line": 662,
      "text": "                                          {6, {18, 46, 77, 103, 134, 146, 0}},"
    },
    {
      "line": 663,
      "text": "                                          {6, {0, 31, 76, 104, 135, 163, 0}},"
    },
    {
      "line": 664,
      "text": "                                          {6, {19, 47, 72, 105, 122, 162, 0}},"
    },
    {
      "line": 665,
      "text": "                                          {6, {20, 40, 78, 106, 136, 164, 0}},"
    },
    {
      "line": 666,
      "text": "                                          {6, {21, 41, 65, 107, 137, 151, 0}},"
    },
    {
      "line": 667,
      "text": "                                          {6, {17, 41, 79, 108, 138, 153, 0}},"
    },
    {
      "line": 668,
      "text": "                                          {6, {22, 48, 80, 109, 134, 165, 0}},"
    },
    {
      "line": 669,
      "text": "                                          {6, {15, 49, 81, 90, 128, 157, 0}},"
    },
    {
      "line": 670,
      "text": "                                          {6, {2, 47, 62, 106, 123, 166, 0}},"
    },
    {
      "line": 671,
      "text": "                                          {6, {5, 50, 66, 110, 133, 154, 0}},"
    },
    {
      "line": 672,
      "text": "                                          {6, {23, 34, 76, 99, 121, 161, 0}},"
    }
  ],
  "snippets": [
    {
      "needle": "CRC12",
      "start_line": 156,
      "end_line": 186,
      "lines": [
        {
          "line": 156,
          "text": "// Constants"
        },
        {
          "line": 157,
          "text": "/******************************************************************************/"
        },
        {
          "line": 158,
          "text": ""
        },
        {
          "line": 159,
          "text": "namespace {"
        },
        {
          "line": 160,
          "text": "/* COMMON PARAMETERS */"
        },
        {
          "line": 161,
          "text": ""
        },
        {
          "line": 162,
          "text": "// !Common"
        },
        {
          "line": 163,
          "text": "//"
        },
        {
          "line": 164,
          "text": "// parameter (KK=87)                     !Information bits (75 + CRC12)"
        },
        {
          "line": 165,
          "text": "// parameter (ND=58)                     !Data symbols"
        },
        {
          "line": 166,
          "text": "// parameter (NS=21)                     !Sync symbols (3 @ Costas 7x7)"
        },
        {
          "line": 167,
          "text": "// parameter (NN=NS+ND)                  !Total channel symbols (79)"
        },
        {
          "line": 168,
          "text": "// parameter (ASYNCMIN=1.5)              !Minimum Sync"
        },
        {
          "line": 169,
          "text": "// parameter (NFSRCH=5)                  !Search frequency range in Hz (i.e.,"
        },
        {
          "line": 170,
          "text": "// +/- 2.5 Hz) parameter (NMAXCAND=300)              !Maximum number of"
        },
        {
          "line": 171,
          "text": "// candidate signals"
        },
        {
          "line": 172,
          "text": ""
        },
        {
          "line": 173,
          "text": "// Parameter\tValue\tDescription"
        },
        {
          "line": 174,
          "text": "// KK\t87\tNumber of information bits (75 message bits + 12 CRC bits)."
        },
        {
          "line": 175,
          "text": "// ND\t58\tNumber of data symbols in the JS8 transmission."
        },
        {
          "line": 176,
          "text": "// NS\t21\tNumber of synchronization symbols (3 Costas arrays of size 7)."
        },
        {
          "line": 177,
          "text": "// NN\t79\tTotal number of channel symbols (NN = NS + ND)."
        },
        {
          "line": 178,
          "text": "// ASYNCMIN\t1.5\tMinimum sync value for successful decoding."
        },
        {
          "line": 179,
          "text": "// NFSRCH\t5\tSearch frequency range in Hz (±2.5 Hz)."
        },
        {
          "line": 180,
          "text": "// NMAXCAND\t300\tMaximum number of candidate signals."
        },
        {
          "line": 181,
          "text": ""
        },
        {
          "line": 182,
          "text": "constexpr int N = 174;           // Total bits"
        },
        {
          "line": 183,
          "text": "constexpr int K = 87;            // Message bits"
        },
        {
          "line": 184,
          "text": "constexpr int M = N - K;         // Check bits"
        },
        {
          "line": 185,
          "text": "constexpr int KK = 87;           // Information bits (75 + CRC12)"
        },
        {
          "line": 186,
          "text": "constexpr int ND = 58;           // Data symbols"
        }
      ]
    },
    {
      "needle": "checkCRC12",
      "start_line": 887,
      "end_line": 917,
      "lines": [
        {
          "line": 887,
          "text": "static_assert(alphabetWord('a') == 36);"
        },
        {
          "line": 888,
          "text": "static_assert(alphabetWord('-') == 62);"
        },
        {
          "line": 889,
          "text": "static_assert(alphabetWord('+') == 63);"
        },
        {
          "line": 890,
          "text": ""
        },
        {
          "line": 891,
          "text": "template <typename T> std::uint16_t CRC12(T const &range) {"
        },
        {
          "line": 892,
          "text": "    return boost::augmented_crc<12, 0xc06>(range.data(), range.size()) ^ 42;"
        },
        {
          "line": 893,
          "text": "}"
        },
        {
          "line": 894,
          "text": ""
        },
        {
          "line": 895,
          "text": "bool checkCRC12(std::array<std::int8_t, KK> const &decoded) {"
        },
        {
          "line": 896,
          "text": "    std::array<uint8_t, 11> bits = {};"
        },
        {
          "line": 897,
          "text": ""
        },
        {
          "line": 898,
          "text": "    for (std::size_t i = 0; i < decoded.size(); ++i) {"
        },
        {
          "line": 899,
          "text": "        if (decoded[i])"
        },
        {
          "line": 900,
          "text": "            bits[i / 8] |= (1 << (7 - (i % 8)));"
        },
        {
          "line": 901,
          "text": "    }"
        },
        {
          "line": 902,
          "text": ""
        },
        {
          "line": 903,
          "text": "    // Extract the received CRC-12."
        },
        {
          "line": 904,
          "text": ""
        },
        {
          "line": 905,
          "text": "    uint16_t crc = (static_cast<uint16_t>(bits[9] & 0x1F) << 7) |"
        },
        {
          "line": 906,
          "text": "                   (static_cast<uint16_t>(bits[10]) >> 1);"
        },
        {
          "line": 907,
          "text": ""
        },
        {
          "line": 908,
          "text": "    // Clear bits that correspond to the CRC in the last bytes."
        },
        {
          "line": 909,
          "text": ""
        },
        {
          "line": 910,
          "text": "    bits[9] &= 0xE0;"
        },
        {
          "line": 911,
          "text": "    bits[10] = 0x00;"
        },
        {
          "line": 912,
          "text": ""
        },
        {
          "line": 913,
          "text": "    // Compute CRC and indicate if we have a match."
        },
        {
          "line": 914,
          "text": ""
        },
        {
          "line": 915,
          "text": "    return crc == CRC12(bits);"
        },
        {
          "line": 916,
          "text": "}"
        },
        {
          "line": 917,
          "text": ""
        }
      ]
    },
    {
      "needle": "extractmessage174",
      "start_line": 910,
      "end_line": 940,
      "lines": [
        {
          "line": 910,
          "text": "    bits[9] &= 0xE0;"
        },
        {
          "line": 911,
          "text": "    bits[10] = 0x00;"
        },
        {
          "line": 912,
          "text": ""
        },
        {
          "line": 913,
          "text": "    // Compute CRC and indicate if we have a match."
        },
        {
          "line": 914,
          "text": ""
        },
        {
          "line": 915,
          "text": "    return crc == CRC12(bits);"
        },
        {
          "line": 916,
          "text": "}"
        },
        {
          "line": 917,
          "text": ""
        },
        {
          "line": 918,
          "text": "std::string extractmessage174(std::array<int8_t, KK> const &decoded) {"
        },
        {
          "line": 919,
          "text": "    std::string message;"
        },
        {
          "line": 920,
          "text": ""
        },
        {
          "line": 921,
          "text": "    // Ensure received CRC matches computed CRC."
        },
        {
          "line": 922,
          "text": ""
        },
        {
          "line": 923,
          "text": "    if (checkCRC12(decoded)) {"
        },
        {
          "line": 924,
          "text": "        message.reserve(12);"
        },
        {
          "line": 925,
          "text": ""
        },
        {
          "line": 926,
          "text": "        // Decode the message from the 72 data bits"
        },
        {
          "line": 927,
          "text": ""
        },
        {
          "line": 928,
          "text": "        std::array<uint8_t, 12> words;"
        },
        {
          "line": 929,
          "text": ""
        },
        {
          "line": 930,
          "text": "        for (std::size_t i = 0; i < 12; ++i) {"
        },
        {
          "line": 931,
          "text": "            words[i] = (decoded[i * 6 + 0] << 5) | (decoded[i * 6 + 1] << 4) |"
        },
        {
          "line": 932,
          "text": "                       (decoded[i * 6 + 2] << 3) | (decoded[i * 6 + 3] << 2) |"
        },
        {
          "line": 933,
          "text": "                       (decoded[i * 6 + 4] << 1) | (decoded[i * 6 + 5] << 0);"
        },
        {
          "line": 934,
          "text": "        }"
        },
        {
          "line": 935,
          "text": ""
        },
        {
          "line": 936,
          "text": "        // Map 6-bit words to the alphabet"
        },
        {
          "line": 937,
          "text": ""
        },
        {
          "line": 938,
          "text": "        for (auto const word : words)"
        },
        {
          "line": 939,
          "text": "            message += alphabet[word];"
        },
        {
          "line": 940,
          "text": "    }"
        }
      ]
    },
    {
      "needle": "for (std::size_t i = 0; i < 12",
      "start_line": 922,
      "end_line": 952,
      "lines": [
        {
          "line": 922,
          "text": ""
        },
        {
          "line": 923,
          "text": "    if (checkCRC12(decoded)) {"
        },
        {
          "line": 924,
          "text": "        message.reserve(12);"
        },
        {
          "line": 925,
          "text": ""
        },
        {
          "line": 926,
          "text": "        // Decode the message from the 72 data bits"
        },
        {
          "line": 927,
          "text": ""
        },
        {
          "line": 928,
          "text": "        std::array<uint8_t, 12> words;"
        },
        {
          "line": 929,
          "text": ""
        },
        {
          "line": 930,
          "text": "        for (std::size_t i = 0; i < 12; ++i) {"
        },
        {
          "line": 931,
          "text": "            words[i] = (decoded[i * 6 + 0] << 5) | (decoded[i * 6 + 1] << 4) |"
        },
        {
          "line": 932,
          "text": "                       (decoded[i * 6 + 2] << 3) | (decoded[i * 6 + 3] << 2) |"
        },
        {
          "line": 933,
          "text": "                       (decoded[i * 6 + 4] << 1) | (decoded[i * 6 + 5] << 0);"
        },
        {
          "line": 934,
          "text": "        }"
        },
        {
          "line": 935,
          "text": ""
        },
        {
          "line": 936,
          "text": "        // Map 6-bit words to the alphabet"
        },
        {
          "line": 937,
          "text": ""
        },
        {
          "line": 938,
          "text": "        for (auto const word : words)"
        },
        {
          "line": 939,
          "text": "            message += alphabet[word];"
        },
        {
          "line": 940,
          "text": "    }"
        },
        {
          "line": 941,
          "text": ""
        },
        {
          "line": 942,
          "text": "    return message;"
        },
        {
          "line": 943,
          "text": "}"
        },
        {
          "line": 944,
          "text": ""
        },
        {
          "line": 945,
          "text": "// Parity matrix for JS8 message generation."
        },
        {
          "line": 946,
          "text": "//"
        },
        {
          "line": 947,
          "text": "// This should be 952 bytes in size; to store an 87x87 matrix of bits,"
        },
        {
          "line": 948,
          "text": "// you need 7569 bits, which requires 119 64-bit values, or 952 bytes."
        },
        {
          "line": 949,
          "text": "//"
        },
        {
          "line": 950,
          "text": "// Background here is that this is a low-density parity check code (LDPC),"
        },
        {
          "line": 951,
          "text": "// generated using the PEG algorithm. In short, true values in a row i of"
        },
        {
          "line": 952,
          "text": "// the matrix define which of the 87 message bits must be summed, modulo"
        }
      ]
    }
  ],
  "decodes": [],
  "warnings": [
    "This step does not decode JS8 text and does not start JS8Call GUI/Qt.",
    "The previous Message91/CRC14 probes are now treated as diagnostic-only for this JS8Call-Improved source path."
  ],
  "next_action": "Implement a source-aligned message174 CRC12 candidate probe: pack decoded bits MSB-first into bytes, extract CRC from bits[9]&0x1F and bits[10]>>1, clear bits[9]/bits[10], compute CRC12 poly 0xc06 xor 42, then test source-derived dewhitening/deinterleaver candidates.",
  "outputs": {
    "source_message174_crc12_contract_json": "/decoders/js8_decoder/logs/step55_source_message174_crc12_contract.json"
  }
}
