diff --git a/gitgalaxy/core/aperture.py b/gitgalaxy/core/aperture.py index 4718671d78..629004184f 100644 --- a/gitgalaxy/core/aperture.py +++ b/gitgalaxy/core/aperture.py @@ -402,8 +402,12 @@ def _check_artifact_integrity( # 15-318 KB of text were dropped whole). Every binary in the pinned crucible # carries 178+ NULs per 1000 characters (tar, .mat); text damaged in transfer # carries a handful. More than 1 per 1000 is binary. + # #4351: ... unless the member is short and the NULs are a handful: a 168-byte PL/I member + # with 2 NULs at the end of a comment (estate-crucible NULREST.pli, H-0037) is 12 per 1000. + # At most _STRAY_NULS NULs, with no more than as many other control characters, is + # transfer damage in text, whatever the size; a binary carries control bytes beyond its NULs. nuls = content.count("\x00") if "\x00" in content else 0 - if nuls and nuls * 1000 > len(content): + if nuls and nuls * 1000 > len(content) and not self._stray_nuls(content, nuls): report.update( { "valid": False, @@ -582,6 +586,19 @@ def _check_artifact_integrity( return report + # #4351: the most NULs (and, separately, other C0 control characters) a member may carry and + # still be text damaged in transfer rather than a binary. + _STRAY_NULS = 4 + _CONTROL_CHARS = re.compile(r"[\x01-\x08\x0e-\x1f\x7f]") + + @classmethod + def _stray_nuls(cls, content: str, nuls: int) -> bool: + """#4351: a handful of NULs in a member that is otherwise text (see Gate 3.1).""" + if nuls > cls._STRAY_NULS: + return False + # stops at the first control character past the limit + return all(n <= cls._STRAY_NULS for n, _ in enumerate(cls._CONTROL_CHARS.finditer(content), 1)) + def _check_ignore_rules(self, rel_path: str, has_intent: bool = False) -> bool: """ Determines if the path is in a blocked, ignored, or dynamically diff --git a/gitgalaxy/core/data_moves.py b/gitgalaxy/core/data_moves.py index a6903c949c..fea1f146a7 100644 --- a/gitgalaxy/core/data_moves.py +++ b/gitgalaxy/core/data_moves.py @@ -59,13 +59,24 @@ from typing import Any, Optional from gitgalaxy.core.db2_declare_table import _blank_sequence_fields +from gitgalaxy.core.special_names import special_names +from gitgalaxy.standards.language_standards.identifiers import NATIONAL, WIDE_DIGITS, WIDE_HYPHENS _LITERAL = r"[XNGZ]?'[^'\n]{0,320}'?|[XNGZ]?\"[^\"\n]{0,320}\"?" _NUMBER = r"[+-]?[0-9]*\.[0-9]+|[+-]?[0-9]+" -_WORD = r"[A-Z0-9][A-Z0-9-]{0,62}" -_NUMBER_TOKEN = rf"(?:{_NUMBER})(?![A-Z0-9-])" # a number, not the head of a name (1ST-X) +# #4353: a COBOL word takes the record reader's national, CJK and full-width characters (#3955 / +# #3991): `MOVE '000001' TO 社員コード` drew no row and `X項目` was cut to `X`. +_NAME_START = "A-Z" + NATIONAL + WIDE_DIGITS + "0-9" +_NAME_CHAR = _NAME_START + WIDE_HYPHENS + "-" +_WORD = rf"[{_NAME_START}][{_NAME_CHAR}]{{0,62}}" +_HAS_LETTER = re.compile(f"[A-Z{NATIONAL}]", re.I) # a name has a letter (national ones too, #4353) +_NUMBER_TOKEN = rf"(?:{_NUMBER})(?![{_NAME_CHAR}])" # a number, not the head of a name (1ST-X) _OPERATOR = r"\*\*|[()=:+*/,.<>-]" _TOKEN = re.compile("|".join((_LITERAL, _NUMBER_TOKEN, _WORD, _OPERATOR)), re.I) +# #4355: under DECIMAL-POINT IS COMMA, `0,5` is one numeric literal (a separator comma is followed by +# a space). The tokenizer split it into `0` `,` `5`, and `MOVE 0,5 TO T-WERT` drew no row. +_NUMBER_COMMA = r"[+-]?[0-9]*,[0-9]+|" + _NUMBER +_TOKEN_COMMA = re.compile("|".join((_LITERAL, rf"(?:{_NUMBER_COMMA})(?![{_NAME_CHAR}])", _WORD, _OPERATOR)), re.I) _STATEMENT_TOKENS = 600 _VERBS = frozenset( { @@ -124,8 +135,8 @@ def _is_literal(raw: str) -> bool: class _Stream: - def __init__(self, toks: list[tuple[str, int]], start: int, end: int): - self.toks, self.i, self.end = toks, start, end + def __init__(self, toks: list[tuple[str, int]], start: int, end: int, number: str = _NUMBER): + self.toks, self.i, self.end, self.number = toks, start, end, number def peek(self, k: int = 0) -> str: j = self.i + k @@ -146,7 +157,7 @@ def operand(self) -> Optional[tuple[str, str, Any]]: if _is_literal(raw): self.i += 1 return raw, "literal", False - if re.fullmatch(_NUMBER, raw): + if re.fullmatch(self.number, raw): self.i += 1 return raw, "literal", False # `ALL 'x'`, `ALL X'00'` (#4205: a hexadecimal literal, IBM DBB EPSCSMRD) or `ALL SPACES`. @@ -180,7 +191,7 @@ def operand(self) -> Optional[tuple[str, str, Any]]: self._skip_parens() arg = "".join(tok[0] for tok in self.toks[start + 1 : self.i - 1]).upper() return f"{t}({arg})", "cics_constant", False - if not re.fullmatch(_WORD, raw, re.I) or not re.search(r"[A-Z]", t): + if not re.fullmatch(_WORD, raw, re.I) or not _HAS_LETTER.search(t): return None name = t self.i += 1 @@ -235,7 +246,7 @@ def expression_items(self) -> list[tuple[str, str, bool]]: if t == "FUNCTION": self.i += 2 continue - if t in _NOISE or not re.search(r"[A-Z]", t) or t in _FIGURATIVE: + if t in _NOISE or not _HAS_LETTER.search(t) or t in _FIGURATIVE: self.i += 1 continue op = self.operand() @@ -377,7 +388,8 @@ def data_moves(code_stream: str) -> list[dict[str, Any]]: return [] text = _procedure_text(code_stream) newlines = [i for i, ch in enumerate(text) if ch == "\n"] - toks = [(m.group(0), m.start()) for m in _TOKEN.finditer(text)] + comma = any(sn["clause"] == "DECIMAL-POINT" for sn in special_names(code_stream)) # #4355 + toks = [(m.group(0), m.start()) for m in (_TOKEN_COMMA if comma else _TOKEN).finditer(text)] rows: list[dict[str, Any]] = [] i = 0 while i < len(toks): @@ -391,7 +403,7 @@ def data_moves(code_stream: str) -> list[dict[str, Any]]: i += 1 continue line = bisect.bisect_left(newlines, toks[i][1]) + 1 - s = _Stream(toks, i + 1, min(len(toks), i + 1 + _STATEMENT_TOKENS)) + s = _Stream(toks, i + 1, min(len(toks), i + 1 + _STATEMENT_TOKENS), _NUMBER_COMMA if comma else _NUMBER) for src, target, corr in _rows_of(word, s): rows.append( { @@ -475,7 +487,7 @@ def rounding_facts(code_stream: str) -> list[dict[str, Any]]: elif t == "SIZE" and j + 1 < end and toks[j + 1][0].upper() == "ERROR": size_error = True break # what follows is the imperative statement run on SIZE ERROR - elif re.fullmatch(_WORD, t, re.I) and re.search(r"[A-Z]", t) and t not in _NOISE and t not in _STOPS: + elif re.fullmatch(_WORD, t, re.I) and _HAS_LETTER.search(t) and t not in _NOISE and t not in _STOPS: last_name = toks[j][0] j += 1 if rounded or size_error: diff --git a/gitgalaxy/core/detector.py b/gitgalaxy/core/detector.py index a2c03efe47..39219b6c37 100644 --- a/gitgalaxy/core/detector.py +++ b/gitgalaxy/core/detector.py @@ -10178,7 +10178,9 @@ def _calculate_block_metrics( dict.fromkeys( c for c in raw_calls - if c not in _CALLS_OUT_GLOBAL_IGNORE + # #4305: a pattern alternative that only consumes text (COBOL `EXIT PERFORM`) captures "" + if c + and c not in _CALLS_OUT_GLOBAL_IGNORE and (c.casefold() if _fold_ignore else c) not in lang_ignore and c != self_name ) diff --git a/gitgalaxy/standards/language_standards/languages/cobol.py b/gitgalaxy/standards/language_standards/languages/cobol.py index 4120ce1b92..f65c310672 100644 --- a/gitgalaxy/standards/language_standards/languages/cobol.py +++ b/gitgalaxy/standards/language_standards/languages/cobol.py @@ -900,12 +900,21 @@ # #3359: `(? -- an unconditional transfer of control. diff --git a/tests/cobol_mainframe/ground_truth_ledger.json b/tests/cobol_mainframe/ground_truth_ledger.json index 7e809c99ff..5c395c27d1 100644 --- a/tests/cobol_mainframe/ground_truth_ledger.json +++ b/tests/cobol_mainframe/ground_truth_ledger.json @@ -11,11 +11,6 @@ "kind": "deliberate", "summary": "A GO TO back to the paragraph it is in (a read loop) is not recorded: the engine drops a unit's transfer to itself like recursion (detector, #3362 contract). The key keeps it, since it is a real edge." }, - "engine_inline_perform_phantom_callee": { - "issue": 4305, - "kind": "defect", - "summary": "An inline PERFORM form (PERFORM TEST AFTER / WITH TEST ...) is read as an out-of-line PERFORM of a paragraph named TEST." - }, "engine_main_line_in_no_unit": { "issue": 4302, "kind": "defect", @@ -1112,7 +1107,6 @@ "engine | dead | src/base/cobol_src/UPDCUST.cbl | PTD999 | fn": "engine_dead_is_unreferenced_by_name", "engine | dead | src/base/cobol_src/XFRFUN.cbl | A999 | fn": "engine_dead_is_unreferenced_by_name", "engine | dead | src/base/cobol_src/XFRFUN.cbl | GMOOH999 | fn": "engine_dead_is_unreferenced_by_name", - "engine | intra-program edges | src/base/cobol_src/BANKDATA.cbl | A010 -> PERFORM TEST | fp": "engine_inline_perform_phantom_callee", "engine | unit extents | src/base/cobol_src/BANKDATA.cbl | CDW010 L1407-1433 | fn": "engine_unit_end_counts_noncode_lines", "engine | unit extents | src/base/cobol_src/BANKDATA.cbl | CDW010 L1407-1436 | fp": "engine_unit_end_counts_noncode_lines" }, @@ -1454,7 +1448,7 @@ }, "intra-program edges": { "engine": { - "got": 374, + "got": 373, "tp": 373, "truth": 373 }, @@ -3418,10 +3412,7 @@ "engine | dead | COBOL/SAM1.cbl | 000-MAIN | fp": "engine_dead_is_unreferenced_by_name", "engine | dead | COBOL/SAM1LIB.cbl | 000-MAIN | fp": "engine_dead_is_unreferenced_by_name", "engine | dead | COBOL/SAM2.cbl | 000-MAIN | fp": "engine_dead_is_unreferenced_by_name", - "engine | dead | multiroot/sam/SAM2.cbl | 000-MAIN | fp": "engine_dead_is_unreferenced_by_name", - "engine | intra-program edges | COBOL/SAM1.cbl | 210-PROCESS-ADD-TRAN -> PERFORM TEST | fp": "engine_inline_perform_phantom_callee", - "engine | intra-program edges | COBOL/SAM1LIB.cbl | 210-PROCESS-ADD-TRAN -> PERFORM TEST | fp": "engine_inline_perform_phantom_callee", - "engine | intra-program edges | multiroot/sam/SAM1.cbl | 210-PROCESS-ADD-TRAN -> PERFORM TEST | fp": "engine_inline_perform_phantom_callee" + "engine | dead | multiroot/sam/SAM2.cbl | 000-MAIN | fp": "engine_dead_is_unreferenced_by_name" }, "scoreboard": { "BMS screen fields": { @@ -3737,7 +3728,7 @@ }, "intra-program edges": { "engine": { - "got": 96, + "got": 93, "tp": 93, "truth": 93 }, diff --git a/tests/cobol_mainframe/test_data_moves_decimal_comma_4355.py b/tests/cobol_mainframe/test_data_moves_decimal_comma_4355.py new file mode 100644 index 0000000000..88d5e1a55f --- /dev/null +++ b/tests/cobol_mainframe/test_data_moves_decimal_comma_4355.py @@ -0,0 +1,31 @@ +"""#4355: under DECIMAL-POINT IS COMMA a numeric literal is written `0,5`. data_moves tokenized it +as `0` `,` `5`, so `MOVE 0,5 TO T-WERT (2)` drew no row (estate-crucible ZINSBER.cbl:26, H-0043). +The literal is one token in such a program; a separator comma (followed by a space) still separates, +and a program without the clause is read as before.""" + +from gitgalaxy.core.data_moves import data_moves + +HEAD = ( + " IDENTIFICATION DIVISION.\n PROGRAM-ID. ZINSBER.\n ENVIRONMENT DIVISION.\n" + " CONFIGURATION SECTION.\n SPECIAL-NAMES.\n DECIMAL-POINT IS COMMA.\n" + " DATA DIVISION.\n WORKING-STORAGE SECTION.\n 01 T-WERT PIC 9V9 OCCURS 3.\n" + " 01 A PIC 9V99.\n 01 B PIC 9V99.\n PROCEDURE DIVISION.\n" +) +BODY = " MOVE 0,5 TO T-WERT (2)\n MOVE 1,25 TO A, B\n MOVE A TO B.\n" + + +def _rows(src: str) -> list: + return [(m["verb"], m["source"], m["source_kind"], m["target"]) for m in data_moves(src)] + + +def test_a_decimal_comma_literal_is_one_source(): + rows = _rows(HEAD + BODY) + assert rows[0][:3] == ("MOVE", "0,5", "literal") and rows[0][3].startswith("T-WERT") + # `, ` after the literal is a separator: both targets still get the move + assert [r[3] for r in rows if r[1] == "1,25"] == ["A", "B"] + assert ("MOVE", "A", "item", "B") in rows + + +def test_without_the_clause_a_comma_still_separates(): + plain = HEAD.replace(" DECIMAL-POINT IS COMMA.\n", "") + assert not any(r[1] in ("0,5", "1,25") for r in _rows(plain + BODY)) diff --git a/tests/cobol_mainframe/test_data_moves_national_4353.py b/tests/cobol_mainframe/test_data_moves_national_4353.py new file mode 100644 index 0000000000..3524dbb737 --- /dev/null +++ b/tests/cobol_mainframe/test_data_moves_national_4353.py @@ -0,0 +1,40 @@ +"""#4353: data_moves' word class lacked the national, CJK and full-width characters the record +reader takes (#3955 / #3991), and a name had to contain an ASCII letter. `MOVE '000001' TO +社員コード` and `MOVE 'Z' TO F02` drew no row, and `MOVE SPACE TO X項目` was recorded into `X` +(estate-crucible H-0040, H-0041, H-0046, part of H-0042).""" + +from gitgalaxy.core.data_moves import data_moves + +SRC = """\ + PROCEDURE DIVISION. + MOVE '000001' TO 社員コード + MOVE 'Z' TO F02 + MOVE SPACE TO X項目 + MOVE SPACES TO TEST-DATA1 + MOVE 見出し TO 社員番号 + ADD 1000 TO 賞与額 + MOVE 1 TO WS-COUNT + MOVE 'A' TO WS-X. +""" + + +def _moves() -> list: + return [(m["verb"], m["source"], m["target"]) for m in data_moves(SRC)] + + +def test_japanese_full_width_and_mixed_names_are_whole_operands(): + assert _moves() == [ + ("MOVE", "'000001'", "社員コード"), + ("MOVE", "'Z'", "F02"), + ("MOVE", "SPACE", "X項目"), + ("MOVE", "SPACES", "TEST-DATA1"), + ("MOVE", "見出し", "社員番号"), + ("ADD", "1000", "賞与額"), + ("MOVE", "1", "WS-COUNT"), + ("MOVE", "'A'", "WS-X"), + ] + + +def test_a_full_width_digit_run_is_not_a_name(): + # a name still needs a letter: a bare full-width number is not a data name + assert [m["target"] for m in data_moves(" PROCEDURE DIVISION.\n MOVE 1 TO 12.\n")] == [] diff --git a/tests/core_engine/test_aperture.py b/tests/core_engine/test_aperture.py index 196e7ec5a4..55ed1b6384 100644 --- a/tests/core_engine/test_aperture.py +++ b/tests/core_engine/test_aperture.py @@ -325,6 +325,34 @@ def test_aperture_admits_text_with_a_stray_nul(filter_engine, tmp_path): assert "Binary Format Detected" not in (result.get("reason") or "") +def test_a_short_member_with_a_few_stray_nuls_stays_source_4351(filter_engine, tmp_path): + """#4351 (estate-crucible H-0037): a 168-byte PL/I member with two NULs at the end of its + first comment is 12 NULs per 1000 characters -- over the density bar -- yet it is text.""" + src = tmp_path / "nulrest.py" # the fixture registry's extension; the gate is extension-blind + content = ( + " /* NULREST - RESTSALDO. OVERFOERT MED FTP (BINAER).\x00\x00 */\n" + " NULREST: PROC OPTIONS(MAIN);\n DCL SALDO FIXED DEC(9,2);\n SALDO = 0;\n END NULREST;\n" + ) + src.write_text(content, encoding="utf-8") + result = filter_engine.is_in_scope(src, content=content) + assert "Binary Format Detected" not in (result.get("reason") or "") + # five NULs is more than a handful: dense enough, it is binary again + content5 = content.replace("\x00\x00", "\x00\x00\x00\x00\x00") + assert "Binary Format Detected" in (filter_engine.is_in_scope(src, content=content5).get("reason") or "") + + +def test_a_short_binary_with_few_nuls_is_still_blocked_4351(filter_engine, tmp_path): + """#4351: a binary blob carries control bytes beyond its NULs, so a handful of NULs alone + does not make it text.""" + blob = tmp_path / "small_dat.py" + content = ( + "".join(chr(b) for b in (0x7F, 0x45, 0x4C, 0x46, 0x02, 0x01, 0x01, 0x00, 0x03, 0x05, 0x10, 0x1B, 0x06)) * 3 + ) + content = content.replace("\x00", "", 1) + "\x00" + blob.write_text(content, encoding="utf-8") + assert "Binary Format Detected" in (filter_engine.is_in_scope(blob, content=content).get("reason") or "") + + # ============================================================================== def test_aperture_binary_and_monolith_shields(filter_engine, tmp_path): """ @@ -332,7 +360,8 @@ def test_aperture_binary_and_monolith_shields(filter_engine, tmp_path): """ # 1. Opaque Binary Detected bin_file = tmp_path / "script.py" - content = "print('hello')\x00\x00" + # #4351: more than a handful of NULs -- two alone in short text are transfer damage, not a binary + content = "print('hello')\x00\x00\x00\x00\x00" bin_file.write_text(content, encoding="utf-8") result = filter_engine.is_in_scope(bin_file, content=content) diff --git a/tests/extraction/languages/test_cobol_inline_perform_4305.py b/tests/extraction/languages/test_cobol_inline_perform_4305.py new file mode 100644 index 0000000000..f2838e5c69 --- /dev/null +++ b/tests/extraction/languages/test_cobol_inline_perform_4305.py @@ -0,0 +1,64 @@ +"""#4305: inline PERFORM forms name no paragraph, yet calls_out read the word after PERFORM as a +callee: `PERFORM WS-N TIMES` / `PERFORM 3 TIMES` gave `WS-N` / `3`, `PERFORM FOREVER` `FOREVER`, +`PERFORM TEST BEFORE|AFTER` (WITH omitted) `TEST`, and `EXIT PERFORM [CYCLE]` the next word +(`END-IF`, `CYCLE`). Out-of-line `PERFORM PARA-X 3 TIMES` still calls PARA-X (estate-crucible H-0006).""" + +from gitgalaxy.core.detector import StructuralExtractor +from gitgalaxy.core.prism import Prism +from gitgalaxy.standards.gitgalaxy_config import LEXICAL_FAMILY_HEURISTICS +from gitgalaxy.standards.language_standards import LANGUAGE_DEFINITIONS + +P = Prism(LEXICAL_FAMILY_HEURISTICS, LANGUAGE_DEFINITIONS) +SRC = """ IDENTIFICATION DIVISION. + PROGRAM-ID. REPRO3. + DATA DIVISION. + WORKING-STORAGE SECTION. + 01 WS-I PIC 9(4) COMP VALUE 0. + 01 WS-N PIC 9(4) COMP VALUE 3. + PROCEDURE DIVISION. + MAIN-PARA. + PERFORM WS-N TIMES + ADD 1 TO WS-I + END-PERFORM + PERFORM 3 TIMES + ADD 1 TO WS-I + END-PERFORM + PERFORM FOREVER + ADD 1 TO WS-I + IF WS-I > 50 EXIT PERFORM END-IF + IF WS-I > 60 EXIT PERFORM CYCLE END-IF + END-PERFORM + PERFORM WITH TEST AFTER VARYING WS-I FROM 1 BY 1 + UNTIL WS-I > 2 + DISPLAY WS-I + END-PERFORM + PERFORM TEST BEFORE UNTIL WS-I > 9 + ADD 1 TO WS-I + END-PERFORM + PERFORM WORK-PARA WITH TEST AFTER UNTIL WS-I > 20 + PERFORM WORK-PARA 3 TIMES + PERFORM TIMES-PARA WS-N TIMES + PERFORM WORK-PARA THRU WORK-EXIT + CALL 'CBLTDLI' USING WS-I + STOP RUN. + WORK-PARA. + ADD 1 TO WS-I. + TIMES-PARA. + EXIT. + WORK-EXIT. + EXIT. +""" + + +def test_inline_perform_forms_draw_no_callee(): + st = P.split_streams(SRC, "cobol") + out = StructuralExtractor("cobol", LANGUAGE_DEFINITIONS).splice( + code_stream=st["code_stream"], + comment_stream=st["comment_stream"], + raw_content=SRC, + positional_comment_stream=P.split_positional_comment_stream(SRC, "cobol"), + ) + calls = {f["name"]: f["calls_out_to"] for f in out["functions"]} + # WORK-PARA (WITH TEST AFTER, and `3 TIMES` out of line) and TIMES-PARA (`WS-N TIMES` out of + # line) are real; CBLTDLI is a real CALL. + assert calls["MAIN-PARA"] == ["WORK-PARA", "TIMES-PARA", "CBLTDLI"] diff --git a/tests/golden_master_audit/12_scan_output_snapshots/graph_sqlite.json b/tests/golden_master_audit/12_scan_output_snapshots/graph_sqlite.json index 057b373a95..151ec2d559 100644 --- a/tests/golden_master_audit/12_scan_output_snapshots/graph_sqlite.json +++ b/tests/golden_master_audit/12_scan_output_snapshots/graph_sqlite.json @@ -7394,7 +7394,7 @@ "cobol/che-che4z_nist_ccvs85/ST1184.2.cbl": "d583a3bbc815", "cobol/che-che4z_nist_ccvs85/ST3014.2.cbl": "aa32e59508d4", "cobol/cics-banking-sample-application-cbsa/ABNDPROC.cbl": "a4cbb69cda43", - "cobol/cics-banking-sample-application-cbsa/BANKDATA.cbl": "f02449eb86d7", + "cobol/cics-banking-sample-application-cbsa/BANKDATA.cbl": "8dc2efc21302", "cobol/cics-banking-sample-application-cbsa/BNK1CAC.cbl": "d98b894e4b41", "cobol/cics-banking-sample-application-cbsa/BNK1CCA.cbl": "ac2132a0c169", "cobol/cics-banking-sample-application-cbsa/BNK1CCS.cbl": "01d3d4eda725", @@ -7477,9 +7477,9 @@ "cobol/cobol-programming-course/CBLDB23.cbl": "12af644814b8", "cobol/cobol-programming-course/DEPTPAY.CBL": "3298e9173408", "cobol/cobol-programming-course/EMPPAY.CBL": "f035bf541427", - "cobol/gnucobol/CBL_OC_DUMP.cob": "632f1032822d", + "cobol/gnucobol/CBL_OC_DUMP.cob": "b57ebcd448c0", "cobol/gnucobol/numeric-dump.cob": "f1400aa8eb6e", - "cobol/gnucobol/tutorial.cob": "c6e2f0ff5b23", + "cobol/gnucobol/tutorial.cob": "ffac4757f962", "cobol/gnucobol_internals/codegen.c": "90d52411a044", "cobol/gnucobol_internals/fileio.c": "2b006452abc1", "cobol/gnucobol_internals/numeric.c": "22b82ab13bf8", @@ -7489,7 +7489,7 @@ "cobol/zECS/ZECS000.cbl": "9dfbe010ad89", "cobol/zECS/ZECS003.cbl": "b0e8782e7a02", "cobol/zECS/ZECSPLT.cbl": "4d5fa10e6d3a", - "cobol/zopeneditor-sample/SAM1.cbl": "bb2316dbb512", + "cobol/zopeneditor-sample/SAM1.cbl": "e98936ccd3c8", "cobol/zopeneditor-sample/SAM2.cbl": "7db63493bf58", "cpp/NVDA/__init__.py": "ee727afe0885", "cpp/NVDA/braille.py": "219638ed6e59", diff --git a/tests/golden_master_audit/12_scan_output_snapshots/llm_brief.json b/tests/golden_master_audit/12_scan_output_snapshots/llm_brief.json index 673b02540a..13be6d917c 100644 --- a/tests/golden_master_audit/12_scan_output_snapshots/llm_brief.json +++ b/tests/golden_master_audit/12_scan_output_snapshots/llm_brief.json @@ -1486,7 +1486,7 @@ "## 15. FUNCTION CALL RESOLUTION (Call Graph Confidence)", "> **AI CONTEXT:** Each function's callee names, linked to the definition they most plausibly mean. *scoped* = same class/file, an imported file, or a class-qualified call; *unique* = the only definition in the repository; *ambiguous* = several candidates or an untyped receiver (never a graph edge); *external* = defined nowhere here (built-ins, packages). A high scoped/unique share means the resolver made a confident choice, not that the choice was correct; resolution accuracy is measured separately (gitgalaxy#3332). Detail in `fcall_data` / `fcall_rate_data`.", "", - "- **Repository:** 121830 call pairs -- scoped 26.0%, unique 1.8%, ambiguous 6.4%, external 65.8%", + "- **Repository:** 121826 call pairs -- scoped 26.0%, unique 1.8%, ambiguous 6.4%, external 65.8%", "", "| Language | Pairs | Scoped | Unique | Ambiguous | External |", "|---|---|---|---|---|---|", @@ -1495,7 +1495,7 @@ "| zig | 10114 | 18.7% | 0.0% | 14.0% | 67.4% |", "| cpp | 8508 | 16.4% | 1.5% | 7.1% | 75.0% |", "| rust | 7714 | 6.6% | 0.0% | 7.9% | 85.5% |", - "| cobol | 7435 | 98.3% | 0.6% | 0.0% | 1.1% |", + "| cobol | 7431 | 98.3% | 0.6% | 0.0% | 1.1% |", "| go | 6653 | 29.0% | 6.1% | 6.5% | 58.3% |", "| typescript | 6430 | 25.9% | 0.0% | 13.4% | 60.7% |", "| php | 6267 | 26.1% | 3.8% | 4.5% | 65.6% |", diff --git a/tests/golden_master_audit/6_parsed_files_scanned_artifacts/files/10_mainframe_system_facts/data_moves.json b/tests/golden_master_audit/6_parsed_files_scanned_artifacts/files/10_mainframe_system_facts/data_moves.json index df097f8ce8..b30360ce83 100644 --- a/tests/golden_master_audit/6_parsed_files_scanned_artifacts/files/10_mainframe_system_facts/data_moves.json +++ b/tests/golden_master_audit/6_parsed_files_scanned_artifacts/files/10_mainframe_system_facts/data_moves.json @@ -2,16 +2,12 @@ "groups": { "cobol/CICS-Cobol": { "cobol/CICS-Cobol/CBL0104v01ProcedureDivision.cbl": [ - "L17 MOVE \"ARQUITECTURA HOST \" -> WS", - "L17 MOVE \"ARQUITECTURA HOST \" -> NAME" + "L17 MOVE \"ARQUITECTURA HOST \" -> WS_NAME" ], "cobol/CICS-Cobol/CBL0105v01DeclararElementoGrupo.cbl": [ - "L20 MOVE \"ARQUITECTURA ALTAMIRA \" -> WS", - "L20 MOVE \"ARQUITECTURA ALTAMIRA \" -> HOST", - "L21 MOVE \"BM\" -> WS", - "L21 MOVE \"BM\" -> CANAL", - "L22 MOVE \"20181113\" -> WS", - "L22 MOVE \"20181113\" -> FECHA" + "L20 MOVE \"ARQUITECTURA ALTAMIRA \" -> WS_HOST", + "L21 MOVE \"BM\" -> WS_CANAL", + "L22 MOVE \"20181113\" -> WS_FECHA" ], "cobol/CICS-Cobol/CBL0106v01ClausulaImagen.cbl": [ "L19 MOVE 156.955 -> WS-NUM1", @@ -202,10 +198,8 @@ ], "cobol/CICS-Cobol/CBL0703v01StatementString.cbl": [ "L21 MOVE \"STATEMENT STRING\" -> WS-TEMA", - "L27 STRING WS-STR -> WS-STR", - "L27 STRING IN1 -> WS-STR", - "L27 STRING WS-STR -> WS-STR", - "L27 STRING IN2 -> WS-STR" + "L27 STRING WS-STR_IN1 -> WS-STR_OUT", + "L27 STRING WS-STR_IN2 -> WS-STR_OUT" ], "cobol/CICS-Cobol/CBL0704v01StatementNotString.cbl": [ "L23 MOVE \"STATEMENT UNSTRING\" -> WS-TEMA", diff --git a/tests/golden_master_audit/6_parsed_files_scanned_artifacts/files/11_scan_db_snapshot/calls_out_to.json b/tests/golden_master_audit/6_parsed_files_scanned_artifacts/files/11_scan_db_snapshot/calls_out_to.json index 605cdffe53..806b80c6e8 100644 --- a/tests/golden_master_audit/6_parsed_files_scanned_artifacts/files/11_scan_db_snapshot/calls_out_to.json +++ b/tests/golden_master_audit/6_parsed_files_scanned_artifacts/files/11_scan_db_snapshot/calls_out_to.json @@ -42812,7 +42812,6 @@ "GET-TODAYS-DATE", "DELETE-DB2-ROWS", "PROGRAM-DONE", - "TEST", "DEFINE-ACC" ], "A999@675": [], @@ -44658,7 +44657,6 @@ "cobol/gnucobol/CBL_OC_DUMP.cob": { "MAIN00@101": [ "C", - "end-if", "CBL_GC_PRINTABLE" ], "MAIN@100": [] @@ -51642,7 +51640,6 @@ "210-PROCESS-ADD-TRAN@315": [ "720-POSITION-CUST-FILE", "299-REPORT-BAD-TRAN", - "TEST", "740-WRITE-CUSTOUT-FILE" ], "220-PROCESS-DELETE-TRAN@335": [ diff --git a/tests/golden_master_audit/7_mainframe_skeleton_completeness/channels.json b/tests/golden_master_audit/7_mainframe_skeleton_completeness/channels.json index ff610dd7d4..0328a2c89e 100644 --- a/tests/golden_master_audit/7_mainframe_skeleton_completeness/channels.json +++ b/tests/golden_master_audit/7_mainframe_skeleton_completeness/channels.json @@ -33,12 +33,12 @@ }, "data flows": { "Gaps": { - "unresolved operand": 130 + "unresolved operand": 118 }, - "Ratio": "99.5%", - "Resolved": 27016, + "Ratio": "99.6%", + "Resolved": 27022, "System Names (Not Gaps)": 750, - "Total": 27146 + "Total": 27140 }, "program calls": { "Gaps": { diff --git a/tests/golden_master_zero_dep_audit/12_scan_output_snapshots/graph_sqlite.json b/tests/golden_master_zero_dep_audit/12_scan_output_snapshots/graph_sqlite.json index ec855e6697..546bb922af 100644 --- a/tests/golden_master_zero_dep_audit/12_scan_output_snapshots/graph_sqlite.json +++ b/tests/golden_master_zero_dep_audit/12_scan_output_snapshots/graph_sqlite.json @@ -7394,7 +7394,7 @@ "cobol/che-che4z_nist_ccvs85/ST1184.2.cbl": "d583a3bbc815", "cobol/che-che4z_nist_ccvs85/ST3014.2.cbl": "aa32e59508d4", "cobol/cics-banking-sample-application-cbsa/ABNDPROC.cbl": "a4cbb69cda43", - "cobol/cics-banking-sample-application-cbsa/BANKDATA.cbl": "f02449eb86d7", + "cobol/cics-banking-sample-application-cbsa/BANKDATA.cbl": "8dc2efc21302", "cobol/cics-banking-sample-application-cbsa/BNK1CAC.cbl": "d98b894e4b41", "cobol/cics-banking-sample-application-cbsa/BNK1CCA.cbl": "ac2132a0c169", "cobol/cics-banking-sample-application-cbsa/BNK1CCS.cbl": "01d3d4eda725", @@ -7477,9 +7477,9 @@ "cobol/cobol-programming-course/CBLDB23.cbl": "12af644814b8", "cobol/cobol-programming-course/DEPTPAY.CBL": "3298e9173408", "cobol/cobol-programming-course/EMPPAY.CBL": "f035bf541427", - "cobol/gnucobol/CBL_OC_DUMP.cob": "632f1032822d", + "cobol/gnucobol/CBL_OC_DUMP.cob": "b57ebcd448c0", "cobol/gnucobol/numeric-dump.cob": "f1400aa8eb6e", - "cobol/gnucobol/tutorial.cob": "c6e2f0ff5b23", + "cobol/gnucobol/tutorial.cob": "ffac4757f962", "cobol/gnucobol_internals/codegen.c": "90d52411a044", "cobol/gnucobol_internals/fileio.c": "2b006452abc1", "cobol/gnucobol_internals/numeric.c": "22b82ab13bf8", @@ -7489,7 +7489,7 @@ "cobol/zECS/ZECS000.cbl": "9dfbe010ad89", "cobol/zECS/ZECS003.cbl": "b0e8782e7a02", "cobol/zECS/ZECSPLT.cbl": "4d5fa10e6d3a", - "cobol/zopeneditor-sample/SAM1.cbl": "bb2316dbb512", + "cobol/zopeneditor-sample/SAM1.cbl": "e98936ccd3c8", "cobol/zopeneditor-sample/SAM2.cbl": "7db63493bf58", "cpp/NVDA/__init__.py": "ee727afe0885", "cpp/NVDA/braille.py": "219638ed6e59", diff --git a/tests/golden_master_zero_dep_audit/12_scan_output_snapshots/llm_brief.json b/tests/golden_master_zero_dep_audit/12_scan_output_snapshots/llm_brief.json index 4ebc068491..9a2bc791c7 100644 --- a/tests/golden_master_zero_dep_audit/12_scan_output_snapshots/llm_brief.json +++ b/tests/golden_master_zero_dep_audit/12_scan_output_snapshots/llm_brief.json @@ -1489,7 +1489,7 @@ "## 15. FUNCTION CALL RESOLUTION (Call Graph Confidence)", "> **AI CONTEXT:** Each function's callee names, linked to the definition they most plausibly mean. *scoped* = same class/file, an imported file, or a class-qualified call; *unique* = the only definition in the repository; *ambiguous* = several candidates or an untyped receiver (never a graph edge); *external* = defined nowhere here (built-ins, packages). A high scoped/unique share means the resolver made a confident choice, not that the choice was correct; resolution accuracy is measured separately (gitgalaxy#3332). Detail in `fcall_data` / `fcall_rate_data`.", "", - "- **Repository:** 121830 call pairs -- scoped 26.0%, unique 1.8%, ambiguous 6.4%, external 65.8%", + "- **Repository:** 121826 call pairs -- scoped 26.0%, unique 1.8%, ambiguous 6.4%, external 65.8%", "", "| Language | Pairs | Scoped | Unique | Ambiguous | External |", "|---|---|---|---|---|---|", @@ -1498,7 +1498,7 @@ "| zig | 10114 | 18.7% | 0.0% | 14.0% | 67.4% |", "| cpp | 8508 | 16.4% | 1.5% | 7.1% | 75.0% |", "| rust | 7714 | 6.6% | 0.0% | 7.9% | 85.5% |", - "| cobol | 7435 | 98.3% | 0.6% | 0.0% | 1.1% |", + "| cobol | 7431 | 98.3% | 0.6% | 0.0% | 1.1% |", "| go | 6653 | 29.0% | 6.1% | 6.5% | 58.3% |", "| typescript | 6430 | 25.9% | 0.0% | 13.4% | 60.7% |", "| php | 6267 | 26.1% | 3.8% | 4.5% | 65.6% |", diff --git a/tests/golden_master_zero_dep_audit/6_parsed_files_scanned_artifacts/files/10_mainframe_system_facts/data_moves.json b/tests/golden_master_zero_dep_audit/6_parsed_files_scanned_artifacts/files/10_mainframe_system_facts/data_moves.json index df097f8ce8..b30360ce83 100644 --- a/tests/golden_master_zero_dep_audit/6_parsed_files_scanned_artifacts/files/10_mainframe_system_facts/data_moves.json +++ b/tests/golden_master_zero_dep_audit/6_parsed_files_scanned_artifacts/files/10_mainframe_system_facts/data_moves.json @@ -2,16 +2,12 @@ "groups": { "cobol/CICS-Cobol": { "cobol/CICS-Cobol/CBL0104v01ProcedureDivision.cbl": [ - "L17 MOVE \"ARQUITECTURA HOST \" -> WS", - "L17 MOVE \"ARQUITECTURA HOST \" -> NAME" + "L17 MOVE \"ARQUITECTURA HOST \" -> WS_NAME" ], "cobol/CICS-Cobol/CBL0105v01DeclararElementoGrupo.cbl": [ - "L20 MOVE \"ARQUITECTURA ALTAMIRA \" -> WS", - "L20 MOVE \"ARQUITECTURA ALTAMIRA \" -> HOST", - "L21 MOVE \"BM\" -> WS", - "L21 MOVE \"BM\" -> CANAL", - "L22 MOVE \"20181113\" -> WS", - "L22 MOVE \"20181113\" -> FECHA" + "L20 MOVE \"ARQUITECTURA ALTAMIRA \" -> WS_HOST", + "L21 MOVE \"BM\" -> WS_CANAL", + "L22 MOVE \"20181113\" -> WS_FECHA" ], "cobol/CICS-Cobol/CBL0106v01ClausulaImagen.cbl": [ "L19 MOVE 156.955 -> WS-NUM1", @@ -202,10 +198,8 @@ ], "cobol/CICS-Cobol/CBL0703v01StatementString.cbl": [ "L21 MOVE \"STATEMENT STRING\" -> WS-TEMA", - "L27 STRING WS-STR -> WS-STR", - "L27 STRING IN1 -> WS-STR", - "L27 STRING WS-STR -> WS-STR", - "L27 STRING IN2 -> WS-STR" + "L27 STRING WS-STR_IN1 -> WS-STR_OUT", + "L27 STRING WS-STR_IN2 -> WS-STR_OUT" ], "cobol/CICS-Cobol/CBL0704v01StatementNotString.cbl": [ "L23 MOVE \"STATEMENT UNSTRING\" -> WS-TEMA", diff --git a/tests/golden_master_zero_dep_audit/6_parsed_files_scanned_artifacts/files/11_scan_db_snapshot/calls_out_to.json b/tests/golden_master_zero_dep_audit/6_parsed_files_scanned_artifacts/files/11_scan_db_snapshot/calls_out_to.json index 605cdffe53..806b80c6e8 100644 --- a/tests/golden_master_zero_dep_audit/6_parsed_files_scanned_artifacts/files/11_scan_db_snapshot/calls_out_to.json +++ b/tests/golden_master_zero_dep_audit/6_parsed_files_scanned_artifacts/files/11_scan_db_snapshot/calls_out_to.json @@ -42812,7 +42812,6 @@ "GET-TODAYS-DATE", "DELETE-DB2-ROWS", "PROGRAM-DONE", - "TEST", "DEFINE-ACC" ], "A999@675": [], @@ -44658,7 +44657,6 @@ "cobol/gnucobol/CBL_OC_DUMP.cob": { "MAIN00@101": [ "C", - "end-if", "CBL_GC_PRINTABLE" ], "MAIN@100": [] @@ -51642,7 +51640,6 @@ "210-PROCESS-ADD-TRAN@315": [ "720-POSITION-CUST-FILE", "299-REPORT-BAD-TRAN", - "TEST", "740-WRITE-CUSTOUT-FILE" ], "220-PROCESS-DELETE-TRAN@335": [ diff --git a/tests/golden_master_zero_dep_audit/7_mainframe_skeleton_completeness/channels.json b/tests/golden_master_zero_dep_audit/7_mainframe_skeleton_completeness/channels.json index ff610dd7d4..0328a2c89e 100644 --- a/tests/golden_master_zero_dep_audit/7_mainframe_skeleton_completeness/channels.json +++ b/tests/golden_master_zero_dep_audit/7_mainframe_skeleton_completeness/channels.json @@ -33,12 +33,12 @@ }, "data flows": { "Gaps": { - "unresolved operand": 130 + "unresolved operand": 118 }, - "Ratio": "99.5%", - "Resolved": 27016, + "Ratio": "99.6%", + "Resolved": 27022, "System Names (Not Gaps)": 750, - "Total": 27146 + "Total": 27140 }, "program calls": { "Gaps": {