Skip to content

det: a numeric-edited item compared with a number is a text comparison (#4665) - #4668

Merged
squid-protocol merged 7 commits into
mainfrom
fix/4665-edited-compare
Oct 8, 2026
Merged

squid-protocol merged 7 commits into
mainfrom
fix/4665-edited-compare

Conversation

@squid-protocol

Copy link
Copy Markdown
Owner

Fixes #4665 (part of #4270).

Decision

A numeric-edited item belongs to the alphanumeric class: compared with a number it is a nonnumeric (text) comparison, the numeric operand taken as its characters (IBM Enterprise COBOL 6.4 LR, "Comparison of numeric and alphanumeric operands"; GnuCOBOL 3.1.2 -std=ibm measured to do the same). The det runtime de-edited it and compared by value. Where IBM and the oracle disagree the comparison is refused by name; recorded as register entry C13 in oracle_assumptions.md.

Oracle facts measured (cobc probes, 2026-10-07):

  • E PIC ZZZ,ZZ9.99 = 1500 vs 1499.99 / 1499: LE / LE (issue repro).
  • A literal is its characters as written: 0012 ≠ 12; 1499.99 → 149999; 0.12 → 012.
  • Zoned item: bytes with the overpunched sign unpunched; packed / binary: value in PICTURE digits (S9(4) COMP-3 12 → 0012); sign dropped.
  • Differ from IBM → refused (C13): a signed literal (+1234 compares its +), a SIGN SEPARATE item (its sign char), a P-scaled item (stored digits), an arithmetic expression vs a nonnumeric item (oracle text of its own making). A non-integer literal or item, which IBM does not allow, is modelled as the oracle's digits.

Changes

Tests / sweeps

  • test_det_programs.py::EDCMP, end to end against cobc in bytes / typed / groups modes: the repro plus edited vs literal (incl. 0012, 1499.99), vs zoned / signed zoned / COMP-3 / COMP / 9V9 items, edited vs edited, ZERO, EVALUATE subject + THRU, 88s on an edited item, alphanumeric vs literal/item. Fails on origin/main (all 3 modes), passes here.
  • test_a_numeric_operand_compared_as_text_refuses_by_name_…: 7 refusals by name (C13). Fails on main, passes here.
  • All tests/cobol_mainframe/test_det_*.py with EQUIVALENCE_E2E=1: 528 passed, 0 skipped.
  • det_port.py check --base-ref origin/main: all 68 ports change in Cobol.java (the runtime is shipped in every port). Service code changes only in carddemo-cotrtlic (alphanumeric vs 0: D0 → "0", same bytes). A static scan of every port found no Cobol.compare(Field, Field) that pairs a signed/packed/binary item with a text item, so the new runtime branch is not reached by any port. proof_sweep.py --det-only --cases carddemo-cotrtlic,carddemo-intcalc: 2/2 proven, "sweep: as expected".
  • pr_gates.py --fast: 5/5 pass. pr_gates.py --ratchets: 7 pass, 0 fail, 0 skipped.

Follow-ups (not in this PR)

  • PIC SVPP99 COMP-3 crashes the translator (ValueError: non-hexadecimal number in layout.encode_number) instead of refusing by name.
  • MOVE 1200 TO a PIC 99PP item throws at run time in the det runtime (Cobol.store).
  • A group vs numeric item comparison is not modelled or measured.

🤖 Generated with Claude Code

#4665)

A numeric-edited item is not numeric: against a number it is compared as
characters (IBM "Comparison of numeric and alphanumeric operands"; GnuCOBOL
likewise), not de-edited and compared by value. The generator passes a
numeric literal against a nonnumeric item as written (expr.NumLit keeps the
spelling: leading zeros, point), the runtime compares a numeric item against
an elementary nonnumeric one as its digits (sign dropped). Where IBM and the
oracle differ -- a signed literal, a SIGN SEPARATE or P-scaled item, an
arithmetic expression -- the comparison is a hole by name (register C13).

Fixes #4665

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread gitgalaxy/tools/cobol_to_java/det/layout.py Fixed
@github-actions

github-actions Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

squid-protocol and others added 6 commits October 8, 2026 10:58
…et/layout.py)

layout -> expr -> det.cics -> layout: expr's DFHRESP(...) now takes the table from
gitgalaxy.standards.cics.resp, the very object det.cics re-exports, so expr no longer
imports det.cics. det_port check vs 431ceb7: 68/68 ports unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
Main's #4653 Lit.digits and #4665's NumLit both pass a numeric literal
compared with a nonnumeric item as its characters. Measured against cobc
3.1.2 -std=ibm (IF and EVALUATE): unsigned integer literals as written
agree on both; a signed literal is compared with its sign character
('12' is not +12/-12, '+12' is +12, '-12' is -12), which main's
sign-stripping digits got wrong and IBM differs on (C13: refused); a
decimal literal against an alphanumeric item is its digits as written
('012' = 0.12, which main got wrong). Kept NumLit/literal_text as the one
path and dropped Lit.digits.

New measurement: a numeric-edited item compared for equality with a
literal of more decimal places than its own is decided by cobc when it
compiles (ZZ9 holding 125: not = 12.5, NOT = 12.5, yet neither < nor >),
so that shape is refused by name too (C13); IBM rejects the non-integer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
…rds.cics.resp)

det/expr.py imports DFHRESP from the RESP table directly (the CodeQL
import-cycle fix, same as #4654); pin it in test_cics_spec.IMPORTERS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
expr.py: keep this PR's NumLit (a numeric literal keeps its spelling)
and main's module-level DFHRESP import; #4654's Lit.text (the literal
as written, for det/osvs.py's literal identity) becomes a property read
from the NumLit's spelling instead of a second copy of it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
…value, text)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
@squid-protocol
squid-protocol marked this pull request as ready for review October 8, 2026 19:44
@squid-protocol
squid-protocol merged commit eb6a1d3 into main Oct 8, 2026
37 checks passed
@squid-protocol
squid-protocol deleted the fix/4665-edited-compare branch October 8, 2026 19:44
squid-protocol added a commit that referenced this pull request Oct 8, 2026
oracle_assumptions.md: both register entries kept, C13 (#4668) then C14
(this PR), in the table and the sections.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
squid-protocol added a commit that referenced this pull request Oct 8, 2026
…/4681-condition-holes

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
squid-protocol added a commit that referenced this pull request Oct 8, 2026
…/4675-4676-size-error

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

det runtime: numeric-edited item compared with a numeric literal numerically; GnuCOBOL compares it as text

2 participants