[webftr-js8-lab] command=source-confirmed-control-frame-rx-release [webftr-js8-lab] root=/decoders/js8_decoder [webftr-js8-lab] log=/decoders/js8_decoder/logs/20260527T174048Z_source-confirmed-control-frame-rx-release.log [webftr-js8-lab] manifest=/decoders/js8_decoder/logs/20260527T174048Z_source-confirmed-control-frame-rx-release_manifest.json [webftr-js8-lab] utc=20260527T174048Z [webftr-js8-lab] rx-only guard: no TX / no PTT / no Tune / no Send [webftr-js8-lab] Step67 source-confirmed fixed control frame RX release [webftr-js8-lab] input Step63/Step64/Step66 JSON or source-dir argument: auto-detect latest logs/source [webftr-js8-lab] JSON output: /decoders/js8_decoder/logs/20260527T174048Z_source_confirmed_message174_decode_output.json [webftr-js8-lab] JSON timeout guard: 180s { "ok": true, "tool": "webftr-js8-source-confirmed-message174-decode", "tool_version": "step64-source-confirmed-message174-decodes-output", "rx_only_guard": { "tx": false, "ptt": false, "tune": false, "send": false, "js8call_runtime_control": false }, "no_gui_runtime_started": true, "log_dir": "/decoders/js8_decoder/logs", "source_contract": { "source": "JS8Call-Improved JS8_Mode/JS8.cpp extractmessage174/checkCRC12", "alphabet": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+", "crc_width": 12, "crc_poly_hex": "0xc06", "crc_xor_decimal": 42, "message_bits": "first 72 data bits as 12 x 6-bit words", "crc_gate": "Only zero-distance CRC12 candidates are emitted as decodes[]." }, "step63_source_reports": [ { "path": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "exists": true, "zero_distance_candidates_extracted": 33, "tool_version": "step63-source-exact-interleaver-whitening-index-extract" } ], "runtime_fallback_reports": [], "candidate_source": "step63_source_exact_map_probe", "zero_distance_candidate_count": 2, "decode_count": 2, "top_candidates": [ { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.best_candidate.candidate_bits", "source_kind": "generic_bit_list", "row_index": 237, "map_name": "raw", "map_source": null, "distance": 0, "crc_match": true, "received_crc12": 2920, "computed_crc12": 2920, "message_words_6bit": [ 0, 0, 1, 33, 52, 24, 10, 2, 44, 13, 35, 0 ], "message_text_12chars": "001XqOA2iDZ0", "info87_bitstring": "000000000000000001100001110100011000001010000010101100001101100011000000000101101101000" }, { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.top_llr_row_exports[6].hard_bits", "source_kind": "generic_bit_list", "row_index": 82, "map_name": "raw", "map_source": null, "distance": 0, "crc_match": true, "received_crc12": 980, "computed_crc12": 980, "message_words_6bit": [ 26, 0, 31, 54, 20, 32, 52, 41, 19, 9, 6, 59 ], "message_text_12chars": "Q0VsKWqfJ96x", "info87_bitstring": "011010000000011111110110010100100000110100101001010011001001000110111011101001111010100" } ], "decodes": [ { "id": "js8-msg174-2b7db8e6", "mode": "JS8", "decoder": "webftr-js8lab-step64-message174-source-confirmed", "text": "001XqOA2iDZ0", "raw": "001XqOA2iDZ0", "message_text_12chars": "001XqOA2iDZ0", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 2920, "computed_crc12": 2920, "message_words_6bit": [ 0, 0, 1, 33, 52, 24, 10, 2, 44, 13, 35, 0 ], "alphabet": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+", "parsed": { "raw": "001XqOA2iDZ0", "normalized": "001XQOA2IDZ0", "message_type": "MESSAGE", "directed_to": null, "callsigns": [], "primary_callsign": null, "locators": [], "primary_locator": null, "body": "001XQOA2IDZ0" }, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.best_candidate.candidate_bits", "source_kind": "generic_bit_list", "row_index": 237, "map_name": "raw", "map_source": null }, "confidence": "crc12_zero_distance_source_extractmessage174", "rx_only": true, "sort_index": 0 }, { "id": "js8-msg174-369b0507", "mode": "JS8", "decoder": "webftr-js8lab-step64-message174-source-confirmed", "text": "Q0VsKWqfJ96x", "raw": "Q0VsKWqfJ96x", "message_text_12chars": "Q0VsKWqfJ96x", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 980, "computed_crc12": 980, "message_words_6bit": [ 26, 0, 31, 54, 20, 32, 52, 41, 19, 9, 6, 59 ], "alphabet": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+", "parsed": { "raw": "Q0VsKWqfJ96x", "normalized": "Q0VSKWQFJ96X", "message_type": "MESSAGE", "directed_to": null, "callsigns": [], "primary_callsign": null, "locators": [], "primary_locator": null, "body": "Q0VSKWQFJ96X" }, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.top_llr_row_exports[6].hard_bits", "source_kind": "generic_bit_list", "row_index": 82, "map_name": "raw", "map_source": null }, "confidence": "crc12_zero_distance_source_extractmessage174", "rx_only": true, "sort_index": 1 } ], "warnings": [ "Step64 emits source-confirmed message174 CRC12-zero-distance text candidates; it is not yet a full live JS8 decoder chain from audio to final chat UI.", "It starts no JS8Call GUI/Qt process and performs no TX/PTT/Tune/Send actions.", "Random-looking 12-character payloads can still be valid message174 candidates until higher JS8 text/Varicode framing is connected." ], "next_action": "Use Step64 decodes[] as the contract for the next step: connect source-confirmed message174 output into a richer JS8 text/Varicode/framing interpretation and then feed WebFTR RX display fields." } [webftr-js8-lab] JSON output: /decoders/js8_decoder/logs/20260527T174048Z_source_varicode_frame_unpack_probe_output.json [webftr-js8-lab] JSON timeout guard: 180s { "ok": true, "tool": "webftr-js8-source-varicode-frame-unpack-probe", "tool_version": "step66-source-varicode-frame-unpack-probe", "rx_only_guard": { "tx": false, "ptt": false, "tune": false, "send": false, "js8call_runtime_control": false }, "no_gui_runtime_started": true, "root": "/decoders/js8_decoder", "log_dir": "/decoders/js8_decoder/logs", "input_reports": [ { "path": "/decoders/js8_decoder/logs/20260527T174048Z_source_confirmed_message174_decode_output.json", "exists": true, "selected_input": true } ], "source_resolution": { "selected_source_dir": "/decoders/js8_decoder/runtime/src/JS8Call-improved", "checked": [ { "path": "/decoders/js8_decoder/runtime/src/JS8Call-improved", "exists": true, "is_dir": true } ] }, "source_snippets": { "source_available": true, "source_dir": "/decoders/js8_decoder/runtime/src/JS8Call-improved", "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" ], "focused_files_missing": [], "snippets": [ { "name": "unpack72bits", "path": "JS8_Main/Varicode.cpp", "line": 767, "context": { "start_line": 762, "end_line": 772, "lines": [ { "line": 762, "text": " quint32 b = packed & 0xFFFFFFFF;" }, { "line": 763, "text": " return pack32bits(a) + pack32bits(b);" }, { "line": 764, "text": "}" }, { "line": 765, "text": "" }, { "line": 766, "text": "// returns the first 64 bits and sets the last 8 bits in pRem" }, { "line": 767, "text": "quint64 Varicode::unpack72bits(QString const &text, quint8 *pRem) {" }, { "line": 768, "text": " quint64 value = 0;" }, { "line": 769, "text": " quint8 rem = 0;" }, { "line": 770, "text": " quint8 mask2 = ((1 << 2) - 1);" }, { "line": 771, "text": "" }, { "line": 772, "text": " for (int i = 0; i < 10; i++) {" } ] } }, { "name": "pack72bits", "path": "JS8_Main/Varicode.cpp", "line": 767, "context": { "start_line": 762, "end_line": 772, "lines": [ { "line": 762, "text": " quint32 b = packed & 0xFFFFFFFF;" }, { "line": 763, "text": " return pack32bits(a) + pack32bits(b);" }, { "line": 764, "text": "}" }, { "line": 765, "text": "" }, { "line": 766, "text": "// returns the first 64 bits and sets the last 8 bits in pRem" }, { "line": 767, "text": "quint64 Varicode::unpack72bits(QString const &text, quint8 *pRem) {" }, { "line": 768, "text": " quint64 value = 0;" }, { "line": 769, "text": " quint8 rem = 0;" }, { "line": 770, "text": " quint8 mask2 = ((1 << 2) - 1);" }, { "line": 771, "text": "" }, { "line": 772, "text": " for (int i = 0; i < 10; i++) {" } ] } }, { "name": "unpackDirectedMessage", "path": "JS8_Main/Varicode.cpp", "line": 1716, "context": { "start_line": 1711, "end_line": 1721, "lines": [ { "line": 1711, "text": " if (n)" }, { "line": 1712, "text": " *n = match.captured(0).length();" }, { "line": 1713, "text": " return Varicode::pack72bits(Varicode::bitsToInt(bits), packed_extra);" }, { "line": 1714, "text": "}" }, { "line": 1715, "text": "" }, { "line": 1716, "text": "QStringList Varicode::unpackDirectedMessage(const QString &text," }, { "line": 1717, "text": " quint8 *pType) {" }, { "line": 1718, "text": " QStringList unpacked;" }, { "line": 1719, "text": "" }, { "line": 1720, "text": " if (text.length() < 12 || text.contains(\" \")) {" }, { "line": 1721, "text": " return unpacked;" } ] } }, { "name": "packDirectedMessage", "path": "JS8_Main/Varicode.cpp", "line": 1605, "context": { "start_line": 1600, "end_line": 1610, "lines": [ { "line": 1600, "text": "" }, { "line": 1601, "text": "// J1Y ACK" }, { "line": 1602, "text": "// J1Y?" }, { "line": 1603, "text": "// KN4CRD: J1Y$" }, { "line": 1604, "text": "// KN4CRD: J1Y! HELLO WORLD" }, { "line": 1605, "text": "QString Varicode::packDirectedMessage(const QString &text," }, { "line": 1606, "text": " const QString &mycall, QString *pTo," }, { "line": 1607, "text": " bool *pToCompound, QString *pCmd," }, { "line": 1608, "text": " QString *pNum, int *n) {" }, { "line": 1609, "text": " QString frame;" }, { "line": 1610, "text": "" } ] } }, { "name": "unpackCompoundFrame", "path": "JS8_Main/Varicode.cpp", "line": 1420, "context": { "start_line": 1415, "end_line": 1425, "lines": [ { "line": 1415, "text": " bool *isAlt, quint8 *pBits3) {" }, { "line": 1416, "text": " quint8 type = Varicode::FrameHeartbeat;" }, { "line": 1417, "text": " quint16 num = nmaxgrid;" }, { "line": 1418, "text": " quint8 bits3 = 0;" }, { "line": 1419, "text": "" }, { "line": 1420, "text": " QStringList unpacked = unpackCompoundFrame(text, &type, &num, &bits3);" }, { "line": 1421, "text": " if (unpacked.isEmpty() || type != Varicode::FrameHeartbeat) {" }, { "line": 1422, "text": " return QStringList{};" }, { "line": 1423, "text": " }" }, { "line": 1424, "text": "" }, { "line": 1425, "text": " unpacked.append(Varicode::unpackGrid(num & ((1 << 15) - 1)));" } ] } }, { "name": "packCompoundFrame", "path": "JS8_Main/Varicode.cpp", "line": 1401, "context": { "start_line": 1396, "end_line": 1406, "lines": [ { "line": 1396, "text": " if (isAlt) {" }, { "line": 1397, "text": " packed_extra |= (1 << 15);" }, { "line": 1398, "text": " cqNumber = cqs.key(type, 0);" }, { "line": 1399, "text": " }" }, { "line": 1400, "text": "" }, { "line": 1401, "text": " frame = packCompoundFrame(callsign, Varicode::FrameHeartbeat, packed_extra," }, { "line": 1402, "text": " cqNumber);" }, { "line": 1403, "text": " if (frame.isEmpty()) {" }, { "line": 1404, "text": " if (n)" }, { "line": 1405, "text": " *n = 0;" }, { "line": 1406, "text": " return frame;" } ] } }, { "name": "unpackCompoundMessage", "path": "JS8_Main/Varicode.cpp", "line": 1491, "context": { "start_line": 1486, "end_line": 1496, "lines": [ { "line": 1486, "text": " if (n)" }, { "line": 1487, "text": " *n = parsedText.captured(0).length();" }, { "line": 1488, "text": " return frame;" }, { "line": 1489, "text": "}" }, { "line": 1490, "text": "" }, { "line": 1491, "text": "QStringList Varicode::unpackCompoundMessage(const QString &text, quint8 *pType," }, { "line": 1492, "text": " quint8 *pBits3) {" }, { "line": 1493, "text": " quint8 type = Varicode::FrameCompound;" }, { "line": 1494, "text": " quint16 extra = nmaxgrid;" }, { "line": 1495, "text": " quint8 bits3 = 0;" }, { "line": 1496, "text": "" } ] } }, { "name": "unpackHeartbeatMessage", "path": "JS8_Main/Varicode.cpp", "line": 1414, "context": { "start_line": 1409, "end_line": 1419, "lines": [ { "line": 1409, "text": " if (n)" }, { "line": 1410, "text": " *n = parsedText.captured(0).length();" }, { "line": 1411, "text": " return frame;" }, { "line": 1412, "text": "}" }, { "line": 1413, "text": "" }, { "line": 1414, "text": "QStringList Varicode::unpackHeartbeatMessage(const QString &text, quint8 *pType," }, { "line": 1415, "text": " bool *isAlt, quint8 *pBits3) {" }, { "line": 1416, "text": " quint8 type = Varicode::FrameHeartbeat;" }, { "line": 1417, "text": " quint16 num = nmaxgrid;" }, { "line": 1418, "text": " quint8 bits3 = 0;" }, { "line": 1419, "text": "" } ] } }, { "name": "unpackDataMessage", "path": "JS8_Main/Varicode.cpp", "line": 1912, "context": { "start_line": 1907, "end_line": 1917, "lines": [ { "line": 1907, "text": "}" }, { "line": 1908, "text": "" }, { "line": 1909, "text": "// TODO: DEPRECATED in 2.2 (still available for decoding legacy frames, but will" }, { "line": 1910, "text": "// eventually no longer be decodable) unpack data message using 70 bits" }, { "line": 1911, "text": "// available flagged as data by the first 2 bits" }, { "line": 1912, "text": "QString Varicode::unpackDataMessage(const QString &text) {" }, { "line": 1913, "text": " QString unpacked;" }, { "line": 1914, "text": "" }, { "line": 1915, "text": " if (text.length() < 12 || text.contains(\" \")) {" }, { "line": 1916, "text": " return unpacked;" }, { "line": 1917, "text": " }" } ] } }, { "name": "unpackFastDataMessage", "path": "JS8_Main/Varicode.cpp", "line": 1983, "context": { "start_line": 1978, "end_line": 1988, "lines": [ { "line": 1978, "text": "#endif" }, { "line": 1979, "text": "}" }, { "line": 1980, "text": "" }, { "line": 1981, "text": "// unpack data message using the full 72 bits available (with the data flag in" }, { "line": 1982, "text": "// the i3bit header)" }, { "line": 1983, "text": "QString Varicode::unpackFastDataMessage(const QString &text) {" }, { "line": 1984, "text": " QString unpacked;" }, { "line": 1985, "text": "" }, { "line": 1986, "text": " if (text.length() < 12 || text.contains(\" \")) {" }, { "line": 1987, "text": " return unpacked;" }, { "line": 1988, "text": " }" } ] } }, { "name": "unpackCallsign", "path": "JS8_Main/Varicode.cpp", "line": 1037, "context": { "start_line": 1032, "end_line": 1042, "lines": [ { "line": 1032, "text": " packed = 27 * packed + alphanumeric.indexOf(matched.at(5)) - 10;" }, { "line": 1033, "text": "" }, { "line": 1034, "text": " return packed;" }, { "line": 1035, "text": "}" }, { "line": 1036, "text": "" }, { "line": 1037, "text": "QString Varicode::unpackCallsign(quint32 value, bool portable) {" }, { "line": 1038, "text": " foreach (auto key, basecalls.keys()) {" }, { "line": 1039, "text": " if (basecalls[key] == value) {" }, { "line": 1040, "text": " return key;" }, { "line": 1041, "text": " }" }, { "line": 1042, "text": " }" } ] } }, { "name": "unpackAlphaNumeric50", "path": "JS8_Main/Varicode.cpp", "line": 905, "context": { "start_line": 900, "end_line": 910, "lines": [ { "line": 900, "text": " quint64 packed = a + b + c + d + e + f + g + h + i + j + k;" }, { "line": 901, "text": "" }, { "line": 902, "text": " return packed;" }, { "line": 903, "text": "}" }, { "line": 904, "text": "" }, { "line": 905, "text": "QString Varicode::unpackAlphaNumeric50(quint64 packed) {" }, { "line": 906, "text": " QChar word[11];" }, { "line": 907, "text": "" }, { "line": 908, "text": " quint64 tmp = packed % 38;" }, { "line": 909, "text": " word[10] = alphanumeric.at(tmp);" }, { "line": 910, "text": " packed = packed / 38;" } ] } }, { "name": "unpackGrid", "path": "JS8_Main/Varicode.cpp", "line": 1157, "context": { "start_line": 1152, "end_line": 1162, "lines": [ { "line": 1152, "text": " int ilat = pair.second + 90;" }, { "line": 1153, "text": "" }, { "line": 1154, "text": " return ((ilong + 180) / 2) * 180 + ilat;" }, { "line": 1155, "text": "}" }, { "line": 1156, "text": "" }, { "line": 1157, "text": "QString Varicode::unpackGrid(quint16 value) {" }, { "line": 1158, "text": " if (value > nbasegrid) {" }, { "line": 1159, "text": " return \"\";" }, { "line": 1160, "text": " }" }, { "line": 1161, "text": "" }, { "line": 1162, "text": " float dlat = value % 180 - 90;" } ] } }, { "name": "unpackCmd", "path": "JS8_Main/Varicode.cpp", "line": 1207, "context": { "start_line": 1202, "end_line": 1212, "lines": [ { "line": 1202, "text": " }" }, { "line": 1203, "text": "" }, { "line": 1204, "text": " return value;" }, { "line": 1205, "text": "}" }, { "line": 1206, "text": "" }, { "line": 1207, "text": "quint8 Varicode::unpackCmd(quint8 value, quint8 *pNum) {" }, { "line": 1208, "text": " // if the first bit is 1, this is an SNR with a number encoded in the lower" }, { "line": 1209, "text": " // 6 bits" }, { "line": 1210, "text": " if (value & (1 << 7)) {" }, { "line": 1211, "text": " if (pNum)" }, { "line": 1212, "text": " *pNum = value & ((1 << 6) - 1);" } ] } }, { "name": "huffDecode", "path": "JS8_Main/Varicode.cpp", "line": 597, "context": { "start_line": 592, "end_line": 602, "lines": [ { "line": 592, "text": " }" }, { "line": 593, "text": "" }, { "line": 594, "text": " return out;" }, { "line": 595, "text": "}" }, { "line": 596, "text": "" }, { "line": 597, "text": "QString Varicode::huffDecode(QMap const &huff," }, { "line": 598, "text": " QVector const &bitvec) {" }, { "line": 599, "text": " QString text;" }, { "line": 600, "text": "" }, { "line": 601, "text": " QString bits = Varicode::bitsToStr(bitvec);" }, { "line": 602, "text": "" } ] } }, { "name": "JSC::decompress", "path": "JS8_Main/Varicode.cpp", "line": 1938, "context": { "start_line": 1933, "end_line": 1943, "lines": [ { "line": 1933, "text": " // trim off the pad bits" }, { "line": 1934, "text": " bits = bits.mid(1, n - 1);" }, { "line": 1935, "text": "" }, { "line": 1936, "text": " if (compressed) {" }, { "line": 1937, "text": " // partial word (s,c)-dense coding with code tables" }, { "line": 1938, "text": " unpacked = JSC::decompress(bits);" }, { "line": 1939, "text": " } else {" }, { "line": 1940, "text": " // huff decode the bits (without escapes)" }, { "line": 1941, "text": " unpacked = Varicode::huffDecode(Varicode::defaultHuffTable(), bits);" }, { "line": 1942, "text": " }" }, { "line": 1943, "text": "" } ] } }, { "name": "unpack72bits", "path": "JS8_Main/Varicode.h", "line": 135, "context": { "start_line": 130, "end_line": 140, "lines": [ { "line": 130, "text": " static QString pack32bits(quint32 packed);" }, { "line": 131, "text": "" }, { "line": 132, "text": " static quint64 unpack64bits(QString const &value);" }, { "line": 133, "text": " static QString pack64bits(quint64 packed);" }, { "line": 134, "text": "" }, { "line": 135, "text": " static quint64 unpack72bits(QString const &value, quint8 *pRem);" }, { "line": 136, "text": " static QString pack72bits(quint64 value, quint8 rem);" }, { "line": 137, "text": "" }, { "line": 138, "text": " static quint32 packAlphaNumeric22(QString const &value, bool isFlag);" }, { "line": 139, "text": " static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag);" }, { "line": 140, "text": "" } ] } }, { "name": "pack72bits", "path": "JS8_Main/Varicode.h", "line": 135, "context": { "start_line": 130, "end_line": 140, "lines": [ { "line": 130, "text": " static QString pack32bits(quint32 packed);" }, { "line": 131, "text": "" }, { "line": 132, "text": " static quint64 unpack64bits(QString const &value);" }, { "line": 133, "text": " static QString pack64bits(quint64 packed);" }, { "line": 134, "text": "" }, { "line": 135, "text": " static quint64 unpack72bits(QString const &value, quint8 *pRem);" }, { "line": 136, "text": " static QString pack72bits(quint64 value, quint8 rem);" }, { "line": 137, "text": "" }, { "line": 138, "text": " static quint32 packAlphaNumeric22(QString const &value, bool isFlag);" }, { "line": 139, "text": " static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag);" }, { "line": 140, "text": "" } ] } }, { "name": "unpackDirectedMessage", "path": "JS8_Main/Varicode.h", "line": 185, "context": { "start_line": 180, "end_line": 190, "lines": [ { "line": 180, "text": "" }, { "line": 181, "text": " static QString packDirectedMessage(QString const &text," }, { "line": 182, "text": " QString const &mycall, QString *pTo," }, { "line": 183, "text": " bool *pToCompound, QString *pCmd," }, { "line": 184, "text": " QString *pNum, int *n);" }, { "line": 185, "text": " static QStringList unpackDirectedMessage(QString const &text," }, { "line": 186, "text": " quint8 *pType);" }, { "line": 187, "text": "" }, { "line": 188, "text": " static QString packDataMessage(QString const &text, int *n);" }, { "line": 189, "text": " static QString unpackDataMessage(QString const &text);" }, { "line": 190, "text": "" } ] } }, { "name": "packDirectedMessage", "path": "JS8_Main/Varicode.h", "line": 181, "context": { "start_line": 176, "end_line": 186, "lines": [ { "line": 176, "text": " static QString packCompoundFrame(const QString &callsign, quint8 type," }, { "line": 177, "text": " quint16 num, quint8 bits3);" }, { "line": 178, "text": " static QStringList unpackCompoundFrame(const QString &text, quint8 *pType," }, { "line": 179, "text": " quint16 *pNum, quint8 *pBits3);" }, { "line": 180, "text": "" }, { "line": 181, "text": " static QString packDirectedMessage(QString const &text," }, { "line": 182, "text": " QString const &mycall, QString *pTo," }, { "line": 183, "text": " bool *pToCompound, QString *pCmd," }, { "line": 184, "text": " QString *pNum, int *n);" }, { "line": 185, "text": " static QStringList unpackDirectedMessage(QString const &text," }, { "line": 186, "text": " quint8 *pType);" } ] } }, { "name": "unpackCompoundFrame", "path": "JS8_Main/Varicode.h", "line": 178, "context": { "start_line": 173, "end_line": 183, "lines": [ { "line": 173, "text": " static QStringList unpackCompoundMessage(const QString &text, quint8 *pType," }, { "line": 174, "text": " quint8 *pBits3);" }, { "line": 175, "text": "" }, { "line": 176, "text": " static QString packCompoundFrame(const QString &callsign, quint8 type," }, { "line": 177, "text": " quint16 num, quint8 bits3);" }, { "line": 178, "text": " static QStringList unpackCompoundFrame(const QString &text, quint8 *pType," }, { "line": 179, "text": " quint16 *pNum, quint8 *pBits3);" }, { "line": 180, "text": "" }, { "line": 181, "text": " static QString packDirectedMessage(QString const &text," }, { "line": 182, "text": " QString const &mycall, QString *pTo," }, { "line": 183, "text": " bool *pToCompound, QString *pCmd," } ] } }, { "name": "packCompoundFrame", "path": "JS8_Main/Varicode.h", "line": 176, "context": { "start_line": 171, "end_line": 181, "lines": [ { "line": 171, "text": "" }, { "line": 172, "text": " static QString packCompoundMessage(QString const &text, int *n);" }, { "line": 173, "text": " static QStringList unpackCompoundMessage(const QString &text, quint8 *pType," }, { "line": 174, "text": " quint8 *pBits3);" }, { "line": 175, "text": "" }, { "line": 176, "text": " static QString packCompoundFrame(const QString &callsign, quint8 type," }, { "line": 177, "text": " quint16 num, quint8 bits3);" }, { "line": 178, "text": " static QStringList unpackCompoundFrame(const QString &text, quint8 *pType," }, { "line": 179, "text": " quint16 *pNum, quint8 *pBits3);" }, { "line": 180, "text": "" }, { "line": 181, "text": " static QString packDirectedMessage(QString const &text," } ] } }, { "name": "unpackCompoundMessage", "path": "JS8_Main/Varicode.h", "line": 173, "context": { "start_line": 168, "end_line": 178, "lines": [ { "line": 168, "text": " static QStringList unpackHeartbeatMessage(const QString &text," }, { "line": 169, "text": " quint8 *pType, bool *isAlt," }, { "line": 170, "text": " quint8 *pBits3);" }, { "line": 171, "text": "" }, { "line": 172, "text": " static QString packCompoundMessage(QString const &text, int *n);" }, { "line": 173, "text": " static QStringList unpackCompoundMessage(const QString &text, quint8 *pType," }, { "line": 174, "text": " quint8 *pBits3);" }, { "line": 175, "text": "" }, { "line": 176, "text": " static QString packCompoundFrame(const QString &callsign, quint8 type," }, { "line": 177, "text": " quint16 num, quint8 bits3);" }, { "line": 178, "text": " static QStringList unpackCompoundFrame(const QString &text, quint8 *pType," } ] } }, { "name": "unpackHeartbeatMessage", "path": "JS8_Main/Varicode.h", "line": 168, "context": { "start_line": 163, "end_line": 173, "lines": [ { "line": 163, "text": " static bool isCompoundCallsign(const QString &callsign);" }, { "line": 164, "text": " static bool isGroupAllowed(const QString &group);" }, { "line": 165, "text": "" }, { "line": 166, "text": " static QString packHeartbeatMessage(QString const &text," }, { "line": 167, "text": " QString const &callsign, int *n);" }, { "line": 168, "text": " static QStringList unpackHeartbeatMessage(const QString &text," }, { "line": 169, "text": " quint8 *pType, bool *isAlt," }, { "line": 170, "text": " quint8 *pBits3);" }, { "line": 171, "text": "" }, { "line": 172, "text": " static QString packCompoundMessage(QString const &text, int *n);" }, { "line": 173, "text": " static QStringList unpackCompoundMessage(const QString &text, quint8 *pType," } ] } }, { "name": "unpackDataMessage", "path": "JS8_Main/Varicode.h", "line": 189, "context": { "start_line": 184, "end_line": 194, "lines": [ { "line": 184, "text": " QString *pNum, int *n);" }, { "line": 185, "text": " static QStringList unpackDirectedMessage(QString const &text," }, { "line": 186, "text": " quint8 *pType);" }, { "line": 187, "text": "" }, { "line": 188, "text": " static QString packDataMessage(QString const &text, int *n);" }, { "line": 189, "text": " static QString unpackDataMessage(QString const &text);" }, { "line": 190, "text": "" }, { "line": 191, "text": " static QString packFastDataMessage(QString const &text, int *n);" }, { "line": 192, "text": " static QString unpackFastDataMessage(QString const &text);" }, { "line": 193, "text": "" }, { "line": 194, "text": " static QList>" } ] } }, { "name": "unpackFastDataMessage", "path": "JS8_Main/Varicode.h", "line": 192, "context": { "start_line": 187, "end_line": 197, "lines": [ { "line": 187, "text": "" }, { "line": 188, "text": " static QString packDataMessage(QString const &text, int *n);" }, { "line": 189, "text": " static QString unpackDataMessage(QString const &text);" }, { "line": 190, "text": "" }, { "line": 191, "text": " static QString packFastDataMessage(QString const &text, int *n);" }, { "line": 192, "text": " static QString unpackFastDataMessage(QString const &text);" }, { "line": 193, "text": "" }, { "line": 194, "text": " static QList>" }, { "line": 195, "text": " buildMessageFrames(QString const &mycall, QString const &mygrid," }, { "line": 196, "text": " QString const &selectedCall, QString const &text," }, { "line": 197, "text": " bool forceIdentify, bool forceData, int submode," } ] } }, { "name": "unpackCallsign", "path": "JS8_Main/Varicode.h", "line": 145, "context": { "start_line": 140, "end_line": 150, "lines": [ { "line": 140, "text": "" }, { "line": 141, "text": " static quint64 packAlphaNumeric50(QString const &value);" }, { "line": 142, "text": " static QString unpackAlphaNumeric50(quint64 packed);" }, { "line": 143, "text": "" }, { "line": 144, "text": " static quint32 packCallsign(QString const &value, bool *pPortable);" }, { "line": 145, "text": " static QString unpackCallsign(quint32 value, bool portable);" }, { "line": 146, "text": "" }, { "line": 147, "text": " static QString deg2grid(float dlong, float dlat);" }, { "line": 148, "text": " static QPair grid2deg(QString const &grid);" }, { "line": 149, "text": " static quint16 packGrid(QString const &value);" }, { "line": 150, "text": " static QString unpackGrid(quint16 value);" } ] } }, { "name": "unpackAlphaNumeric50", "path": "JS8_Main/Varicode.h", "line": 142, "context": { "start_line": 137, "end_line": 147, "lines": [ { "line": 137, "text": "" }, { "line": 138, "text": " static quint32 packAlphaNumeric22(QString const &value, bool isFlag);" }, { "line": 139, "text": " static QString unpackAlphaNumeric22(quint32 packed, bool *isFlag);" }, { "line": 140, "text": "" }, { "line": 141, "text": " static quint64 packAlphaNumeric50(QString const &value);" }, { "line": 142, "text": " static QString unpackAlphaNumeric50(quint64 packed);" }, { "line": 143, "text": "" }, { "line": 144, "text": " static quint32 packCallsign(QString const &value, bool *pPortable);" }, { "line": 145, "text": " static QString unpackCallsign(quint32 value, bool portable);" }, { "line": 146, "text": "" }, { "line": 147, "text": " static QString deg2grid(float dlong, float dlat);" } ] } }, { "name": "unpackGrid", "path": "JS8_Main/Varicode.h", "line": 150, "context": { "start_line": 145, "end_line": 155, "lines": [ { "line": 145, "text": " static QString unpackCallsign(quint32 value, bool portable);" }, { "line": 146, "text": "" }, { "line": 147, "text": " static QString deg2grid(float dlong, float dlat);" }, { "line": 148, "text": " static QPair grid2deg(QString const &grid);" }, { "line": 149, "text": " static quint16 packGrid(QString const &value);" }, { "line": 150, "text": " static QString unpackGrid(quint16 value);" }, { "line": 151, "text": "" }, { "line": 152, "text": " static quint8 packNum(QString const &num, bool *ok);" }, { "line": 153, "text": " static quint8 packPwr(QString const &pwr, bool *ok);" }, { "line": 154, "text": " static quint8 packCmd(quint8 cmd, quint8 num, bool *pPackedNum);" }, { "line": 155, "text": " static quint8 unpackCmd(quint8 value, quint8 *pNum);" } ] } }, { "name": "unpackCmd", "path": "JS8_Main/Varicode.h", "line": 155, "context": { "start_line": 150, "end_line": 160, "lines": [ { "line": 150, "text": " static QString unpackGrid(quint16 value);" }, { "line": 151, "text": "" }, { "line": 152, "text": " static quint8 packNum(QString const &num, bool *ok);" }, { "line": 153, "text": " static quint8 packPwr(QString const &pwr, bool *ok);" }, { "line": 154, "text": " static quint8 packCmd(quint8 cmd, quint8 num, bool *pPackedNum);" }, { "line": 155, "text": " static quint8 unpackCmd(quint8 value, quint8 *pNum);" }, { "line": 156, "text": "" }, { "line": 157, "text": " static bool isSNRCommand(const QString &cmd);" }, { "line": 158, "text": " static bool isCommandAllowed(const QString &cmd);" }, { "line": 159, "text": " static bool isCommandBuffered(const QString &cmd);" }, { "line": 160, "text": " static int isCommandChecksumed(const QString &cmd);" } ] } }, { "name": "huffDecode", "path": "JS8_Main/Varicode.h", "line": 107, "context": { "start_line": 102, "end_line": 112, "lines": [ { "line": 102, "text": " static QStringList parseCallsigns(QString const &input);" }, { "line": 103, "text": " static QStringList parseGrids(QString const &input);" }, { "line": 104, "text": "" }, { "line": 105, "text": " static QList>>" }, { "line": 106, "text": " huffEncode(const QMap &huff, QString const &text);" }, { "line": 107, "text": " static QString huffDecode(const QMap &huff," }, { "line": 108, "text": " QVector const &bitvec);" }, { "line": 109, "text": " static QSet huffValidChars(const QMap &huff);" }, { "line": 110, "text": "" }, { "line": 111, "text": " static QVector bytesToBits(char *bitvec, int n);" }, { "line": 112, "text": " static QVector strToBits(QString const &bitvec);" } ] } }, { "name": "JSC::decompress", "path": "JS8_JSC/JSC.cpp", "line": 127, "context": { "start_line": 122, "end_line": 132, "lines": [ { "line": 122, "text": " * @brief Decompresses the given bit vector into a string." }, { "line": 123, "text": " *" }, { "line": 124, "text": " * @param bitvec" }, { "line": 125, "text": " * @return QString" }, { "line": 126, "text": " */" }, { "line": 127, "text": "QString JSC::decompress(Codeword const &bitvec) {" }, { "line": 128, "text": " const quint32 b = 4;" }, { "line": 129, "text": " const quint32 s = 7;" }, { "line": 130, "text": " const quint32 c = pow(2, b) - s;" }, { "line": 131, "text": "" }, { "line": 132, "text": " QStringList out;" } ] } } ] }, "source_contract": { "message174_alphabet": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+", "alphabet72": "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-+/?.", "frame_types": { "0": "FrameHeartbeat", "1": "FrameCompound", "2": "FrameCompoundDirected", "3": "FrameDirected", "4": "FrameData", "5": "FrameData", "6": "FrameDataCompressed", "7": "FrameDataCompressed" }, "implemented_rx_unpack": [ "unpack72bits", "frame_type", "directed", "heartbeat", "compound", "callsign", "grid", "legacy_huff_data_probe" ], "not_yet_ported": [ "JSC::decompress full compressed text", "multi-frame buffer assembly", "WebFTR live integration" ] }, "input_decode_count": 2, "frame_probe_count": 2, "webftr_display_count": 0, "hidden_candidate_count": 2, "frame_type_counts": { "FrameHeartbeat": 1, "FrameDirected": 1 }, "webftr_rx_rows": [], "candidate_rows": [ { "id": "js8-frame66-bf1ce62fdb4a", "source_decode_id": "js8-msg174-2b7db8e6", "mode": "JS8", "text": "001XqOA2iDZ0", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 2920, "computed_crc12": 2920, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.best_candidate.candidate_bits", "source_kind": "generic_bit_list", "row_index": 237, "map_name": "raw", "map_source": null }, "frame_probe": { "message_text_12chars": "001XqOA2iDZ0", "length": 12, "source_alphabet72_compatible": true, "ok": true, "unpack72": { "value": 107552465662168, "value_hex": "0x000061d18282b0d8", "rem": 192, "top3": 0, "top2": 0, "first_16_bits": "0000000000000000" }, "frame_type": "FrameHeartbeat", "frame_type_bits": 0, "displayable_after_frame_unpack": false, "frame_fields": { "packed_type": 0, "callsign": "004REY/0V4", "packed_callsign": 52515852374, "packed_num": 6936, "bits3": 0, "valid_callsign_hint": true, "kind": "heartbeat_or_cq", "is_cq_alt": false, "grid": "OJ16", "message_token": "HB", "valid_grid_hint": true }, "plausibility": { "score": 6, "reasons": [ "valid_heartbeat_callsign", "valid_heartbeat_grid" ] }, "frame_display_candidate": true, "display_guard_reason": "step66_annotation_only_pending_jsc_or_multiframe_text_confirmation", "candidate_class": "source_varicode_frame_candidate_guarded", "display_text_hint": "HB 004REY/0V4 OJ16" }, "show_in_rx_list": false, "display_text": "HB 004REY/0V4 OJ16", "candidate_class": "source_varicode_frame_candidate_guarded", "sort_index": 0 }, { "id": "js8-frame66-66ab29ded46c", "source_decode_id": "js8-msg174-369b0507", "mode": "JS8", "text": "Q0VsKWqfJ96x", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 980, "computed_crc12": 980, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.top_llr_row_exports[6].hard_bits", "source_kind": "generic_bit_list", "row_index": 82, "map_name": "raw", "map_source": null }, "frame_probe": { "message_text_12chars": "Q0VsKWqfJ96x", "length": 12, "source_alphabet72_compatible": true, "ok": true, "unpack72": { "value": 7496230937050041489, "value_hex": "0x6807f6520d294c91", "rem": 187, "top3": 3, "top2": 1, "first_16_bits": "0110100000000111" }, "frame_type": "FrameDirected", "frame_type_bits": 3, "displayable_after_frame_unpack": false, "frame_fields": { "from": "9I2TZR/P", "to": "0Z0PMP", "cmd_id": 17, "cmd": " INFO", "extra": 59, "extra_value": { "kind": "number", "value": 28 }, "portable_from": true, "portable_to": false, "valid_from_hint": true, "valid_to_hint": true }, "plausibility": { "score": 10, "reasons": [ "valid_directed_from", "valid_directed_to", "directed_command" ] }, "frame_display_candidate": true, "display_guard_reason": "step66_annotation_only_pending_jsc_or_multiframe_text_confirmation", "candidate_class": "source_varicode_frame_candidate_guarded", "display_text_hint": "9I2TZR/P 0Z0PMP INFO 28" }, "show_in_rx_list": false, "display_text": "9I2TZR/P 0Z0PMP INFO 28", "candidate_class": "source_varicode_frame_candidate_guarded", "sort_index": 1 } ], "suppressed_candidates": [ { "id": "js8-frame66-bf1ce62fdb4a", "source_decode_id": "js8-msg174-2b7db8e6", "mode": "JS8", "text": "001XqOA2iDZ0", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 2920, "computed_crc12": 2920, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.best_candidate.candidate_bits", "source_kind": "generic_bit_list", "row_index": 237, "map_name": "raw", "map_source": null }, "frame_probe": { "message_text_12chars": "001XqOA2iDZ0", "length": 12, "source_alphabet72_compatible": true, "ok": true, "unpack72": { "value": 107552465662168, "value_hex": "0x000061d18282b0d8", "rem": 192, "top3": 0, "top2": 0, "first_16_bits": "0000000000000000" }, "frame_type": "FrameHeartbeat", "frame_type_bits": 0, "displayable_after_frame_unpack": false, "frame_fields": { "packed_type": 0, "callsign": "004REY/0V4", "packed_callsign": 52515852374, "packed_num": 6936, "bits3": 0, "valid_callsign_hint": true, "kind": "heartbeat_or_cq", "is_cq_alt": false, "grid": "OJ16", "message_token": "HB", "valid_grid_hint": true }, "plausibility": { "score": 6, "reasons": [ "valid_heartbeat_callsign", "valid_heartbeat_grid" ] }, "frame_display_candidate": true, "display_guard_reason": "step66_annotation_only_pending_jsc_or_multiframe_text_confirmation", "candidate_class": "source_varicode_frame_candidate_guarded", "display_text_hint": "HB 004REY/0V4 OJ16" }, "show_in_rx_list": false, "display_text": "HB 004REY/0V4 OJ16", "candidate_class": "source_varicode_frame_candidate_guarded", "sort_index": 0 }, { "id": "js8-frame66-66ab29ded46c", "source_decode_id": "js8-msg174-369b0507", "mode": "JS8", "text": "Q0VsKWqfJ96x", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 980, "computed_crc12": 980, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.top_llr_row_exports[6].hard_bits", "source_kind": "generic_bit_list", "row_index": 82, "map_name": "raw", "map_source": null }, "frame_probe": { "message_text_12chars": "Q0VsKWqfJ96x", "length": 12, "source_alphabet72_compatible": true, "ok": true, "unpack72": { "value": 7496230937050041489, "value_hex": "0x6807f6520d294c91", "rem": 187, "top3": 3, "top2": 1, "first_16_bits": "0110100000000111" }, "frame_type": "FrameDirected", "frame_type_bits": 3, "displayable_after_frame_unpack": false, "frame_fields": { "from": "9I2TZR/P", "to": "0Z0PMP", "cmd_id": 17, "cmd": " INFO", "extra": 59, "extra_value": { "kind": "number", "value": 28 }, "portable_from": true, "portable_to": false, "valid_from_hint": true, "valid_to_hint": true }, "plausibility": { "score": 10, "reasons": [ "valid_directed_from", "valid_directed_to", "directed_command" ] }, "frame_display_candidate": true, "display_guard_reason": "step66_annotation_only_pending_jsc_or_multiframe_text_confirmation", "candidate_class": "source_varicode_frame_candidate_guarded", "display_text_hint": "9I2TZR/P 0Z0PMP INFO 28" }, "show_in_rx_list": false, "display_text": "9I2TZR/P 0Z0PMP INFO 28", "candidate_class": "source_varicode_frame_candidate_guarded", "sort_index": 1 } ], "verdict": "source_varicode_frames_classified_but_not_displayable", "warnings": [ "Step66 is still RX-only diagnostics. It classifies message174 text as JS8 Varicode frame families but does not start JS8Call GUI/Qt.", "Rows remain hidden unless callsign/grid/command/text plausibility survives source-style frame unpacking.", "Compressed Data frames still require a later JSC::decompress port before real JS8 chat text can be displayed." ], "next_action": "If frame types look plausible but hidden, port JSC::decompress and multi-frame assembly next; if a display row appears, wire webftr_rx_rows into the JS8 RX UI contract." } [webftr-js8-lab] JSON output: /decoders/js8_decoder/logs/20260527T174048Z_source_confirmed_control_frame_rx_release_output.json [webftr-js8-lab] JSON timeout guard: 180s { "ok": true, "tool": "webftr-js8-source-confirmed-control-frame-rx-release", "tool_version": "step67-source-confirmed-control-frame-rx-release", "rx_only_guard": { "tx": false, "ptt": false, "tune": false, "send": false, "js8call_runtime_control": false }, "no_gui_runtime_started": true, "root": "/decoders/js8_decoder", "log_dir": "/decoders/js8_decoder/logs", "input_reports": [ { "path": "/decoders/js8_decoder/logs/20260527T174048Z_source_varicode_frame_unpack_probe_output.json", "exists": true, "selected_input": true, "input_kind": "step66_source_varicode_frame_unpack_probe" } ], "source_step66_version": "step66-source-varicode-frame-unpack-probe", "source_frame_probe_count": 2, "source_webftr_display_count_before_release": 0, "frame_type_counts": { "FrameHeartbeat": 1, "FrameDirected": 1 }, "release_contract": { "allowed_to_display": [ "FrameCompound", "FrameCompoundDirected", "FrameDirected", "FrameHeartbeat" ], "blocked_until_future_steps": [ "FrameData", "FrameDataCompressed" ], "minimum_conditions": [ "valid_message174_crc12 == true", "crc12_distance == 0", "source Varicode frame unpack produced a supported fixed control frame", "frame_display_candidate == true" ], "data_text_rule": "FrameData and FrameDataCompressed stay hidden until JSC::decompress/multi-frame assembly is ported and tested." }, "input_candidate_count": 2, "webftr_display_count": 2, "hidden_candidate_count": 0, "webftr_rx_rows": [ { "id": "js8-rx67-de15d3110b0d", "source_candidate_id": "js8-frame66-bf1ce62fdb4a", "source_decode_id": "js8-msg174-2b7db8e6", "mode": "JS8", "raw_message174": "001XqOA2iDZ0", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 2920, "computed_crc12": 2920, "frame_type": "FrameHeartbeat", "confidence": "high", "confidence_score": 6, "confidence_reasons": [ "valid_heartbeat_callsign", "valid_heartbeat_grid" ], "show_in_rx_list": true, "candidate_class": "webftr_control_frame_display_ready", "release_guard": "step67_source_confirmed_fixed_control_frame_only", "sort_index": 0, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.best_candidate.candidate_bits", "source_kind": "generic_bit_list", "row_index": 237, "map_name": "raw", "map_source": null }, "status": "HB", "from": "004REY/0V4", "to": "@HB", "grid": "OJ16", "message": "HB 004REY/0V4 OJ16", "text": "HB 004REY/0V4 OJ16", "display_text": "HB 004REY/0V4 OJ16", "is_control_frame": true }, { "id": "js8-rx67-bd37f68199eb", "source_candidate_id": "js8-frame66-66ab29ded46c", "source_decode_id": "js8-msg174-369b0507", "mode": "JS8", "raw_message174": "Q0VsKWqfJ96x", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 980, "computed_crc12": 980, "frame_type": "FrameDirected", "confidence": "high", "confidence_score": 10, "confidence_reasons": [ "valid_directed_from", "valid_directed_to", "directed_command" ], "show_in_rx_list": true, "candidate_class": "webftr_control_frame_display_ready", "release_guard": "step67_source_confirmed_fixed_control_frame_only", "sort_index": 1, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.top_llr_row_exports[6].hard_bits", "source_kind": "generic_bit_list", "row_index": 82, "map_name": "raw", "map_source": null }, "status": "INFO", "from": "9I2TZR/P", "to": "0Z0PMP", "command": "INFO", "extra": 59, "extra_value": { "kind": "number", "value": 28 }, "message": "INFO 28", "text": "9I2TZR/P 0Z0PMP INFO 28", "display_text": "9I2TZR/P 0Z0PMP INFO 28", "is_control_frame": true } ], "candidate_rows": [ { "id": "js8-frame66-bf1ce62fdb4a", "source_decode_id": "js8-msg174-2b7db8e6", "mode": "JS8", "text": "001XqOA2iDZ0", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 2920, "computed_crc12": 2920, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.best_candidate.candidate_bits", "source_kind": "generic_bit_list", "row_index": 237, "map_name": "raw", "map_source": null }, "frame_probe": { "message_text_12chars": "001XqOA2iDZ0", "length": 12, "source_alphabet72_compatible": true, "ok": true, "unpack72": { "value": 107552465662168, "value_hex": "0x000061d18282b0d8", "rem": 192, "top3": 0, "top2": 0, "first_16_bits": "0000000000000000" }, "frame_type": "FrameHeartbeat", "frame_type_bits": 0, "displayable_after_frame_unpack": false, "frame_fields": { "packed_type": 0, "callsign": "004REY/0V4", "packed_callsign": 52515852374, "packed_num": 6936, "bits3": 0, "valid_callsign_hint": true, "kind": "heartbeat_or_cq", "is_cq_alt": false, "grid": "OJ16", "message_token": "HB", "valid_grid_hint": true }, "plausibility": { "score": 6, "reasons": [ "valid_heartbeat_callsign", "valid_heartbeat_grid" ] }, "frame_display_candidate": true, "display_guard_reason": "step66_annotation_only_pending_jsc_or_multiframe_text_confirmation", "candidate_class": "source_varicode_frame_candidate_guarded", "display_text_hint": "HB 004REY/0V4 OJ16" }, "show_in_rx_list": false, "display_text": "HB 004REY/0V4 OJ16", "candidate_class": "source_varicode_frame_candidate_guarded", "sort_index": 0 }, { "id": "js8-frame66-66ab29ded46c", "source_decode_id": "js8-msg174-369b0507", "mode": "JS8", "text": "Q0VsKWqfJ96x", "valid_message174_crc12": true, "crc12_distance": 0, "received_crc12": 980, "computed_crc12": 980, "source": { "source_file": "/decoders/js8_decoder/logs/20260527T150600Z_source_exact_map_probe_output.json", "json_path": "$.top_llr_row_exports[6].hard_bits", "source_kind": "generic_bit_list", "row_index": 82, "map_name": "raw", "map_source": null }, "frame_probe": { "message_text_12chars": "Q0VsKWqfJ96x", "length": 12, "source_alphabet72_compatible": true, "ok": true, "unpack72": { "value": 7496230937050041489, "value_hex": "0x6807f6520d294c91", "rem": 187, "top3": 3, "top2": 1, "first_16_bits": "0110100000000111" }, "frame_type": "FrameDirected", "frame_type_bits": 3, "displayable_after_frame_unpack": false, "frame_fields": { "from": "9I2TZR/P", "to": "0Z0PMP", "cmd_id": 17, "cmd": " INFO", "extra": 59, "extra_value": { "kind": "number", "value": 28 }, "portable_from": true, "portable_to": false, "valid_from_hint": true, "valid_to_hint": true }, "plausibility": { "score": 10, "reasons": [ "valid_directed_from", "valid_directed_to", "directed_command" ] }, "frame_display_candidate": true, "display_guard_reason": "step66_annotation_only_pending_jsc_or_multiframe_text_confirmation", "candidate_class": "source_varicode_frame_candidate_guarded", "display_text_hint": "9I2TZR/P 0Z0PMP INFO 28" }, "show_in_rx_list": false, "display_text": "9I2TZR/P 0Z0PMP INFO 28", "candidate_class": "source_varicode_frame_candidate_guarded", "sort_index": 1 } ], "suppressed_candidates": [], "release_decisions": [ { "source_candidate_id": "js8-frame66-bf1ce62fdb4a", "raw_message174": "001XqOA2iDZ0", "frame_type": "FrameHeartbeat", "decision": "released_source_confirmed_control_frame", "sort_index": 0, "released_row_id": "js8-rx67-de15d3110b0d" }, { "source_candidate_id": "js8-frame66-66ab29ded46c", "raw_message174": "Q0VsKWqfJ96x", "frame_type": "FrameDirected", "decision": "released_source_confirmed_control_frame", "sort_index": 1, "released_row_id": "js8-rx67-bd37f68199eb" } ], "verdict": "source_confirmed_control_frames_ready_for_webftr_rx_rows", "warnings": [ "Step67 is still RX-only and does not start JS8Call GUI/Qt.", "Only source-confirmed fixed control frames such as Heartbeat/Directed/Compound are released to webftr_rx_rows.", "Free-text Data/Compressed frames remain blocked until JSC::decompress and multi-frame assembly are source-ported and tested." ], "next_action": "Wire these guarded webftr_rx_rows into the JS8 RX display contract, then continue with JSC::decompress/multi-frame assembly for real JS8 chat text." } [webftr-js8-lab] OK [webftr-js8-lab] log file: /decoders/js8_decoder/logs/20260527T174048Z_source-confirmed-control-frame-rx-release.log [webftr-js8-lab] manifest: /decoders/js8_decoder/logs/20260527T174048Z_source-confirmed-control-frame-rx-release_manifest.json