Skip to content

equivalence: CALL USING items and COMMAREA trailing FILLER compared whole; BMS OCCURS refused (Fixes #4778) - #4780

Merged
squid-protocol merged 17 commits into
mainfrom
fix/4778-call-compare
Oct 9, 2026
Merged

squid-protocol merged 17 commits into
mainfrom
fix/4778-call-compare

Conversation

@squid-protocol

@squid-protocol squid-protocol commented Oct 9, 2026 •

Copy link
Copy Markdown
Owner

Fixes #4778. (Was stacked on #4772; that has merged and origin/main is merged in, so the diff is now only #4778.)

What changed

1. CALL USING / LINKAGE compare (tests/tools/equivalence_call.compare_dto → compare_item)

  • A group USING item is now read by its whole layout (layout_fields(..., occurrences=True)). Every field and every occurrence is compared by name and subscript (PARM-AMT(3)).
  • Ports that take the item's bytes. A det port now has withCallAreas(byte[]...) (det/program.py). The harness passes each item's bytes before handleCall, BY REFERENCE, and the port gives back what it left there. These are compared like a record (common.diff_records): every field by value and then by bytes, each FILLER as bytes (FILLER@<offset>), and any byte no field covers. When bytes are passed they are what the program runs over; the DTO is still filled on the way out. withCallAreas is added to proof_reach.PROOF_ROOTS, because the harness calls it.
  • DTO-only ports (model ports). Every named field and every active occurrence is compared. A field the DTO does not map counts as absent: it is compared, never assumed equal. A DTO cannot carry unnamed bytes, so the report lists them under not_compared with that reason.

2. Trailing FILLER

  • det.cics.Dto.size now covers the whole declared record whenever the record is longer than the DTO's properties reach. This is no longer limited to OCCURS DTOs. It affects CBSA CustctrlDfhcommarea (42→259 bytes) and AcctctrlDfhcommarea (46→98), and GenApp Lgicvs01 / Lgsetup / Lgwebst5 (24→84) and Lgipvs01 (32→90). With the full size, a LINK passes those bytes, a RETURN or XCTL hands them on (DetCics.commareaOut), and EIBCALEN matches the record length.
  • COMMAREA compare: decode_record(..., unnamed=True) reads each FILLER as hex. FILLER is compared when both sides give bytes: the COBOL side always does, and the Java side does for a det port LINKed with the area or a COMMAREA longer than its DTO. When the Java side gives back a DTO, FILLER is declared not_compared with the reason. An all-LOW-VALUES FILLER in a task that has no COMMAREA is undefined storage (X12) and is masked, like the named fields.

3. BMS OCCURS: screen_layout refuses a symbolic map with OCCURS (Unsupported: BMS OCCURS), because its screen compare would read only the first occurrence. test_no_case_map_has_occurs_today checks every case's maps, so the first map with OCCURS fails that test.

Mutation proof (the weakness, shown)

The mutant is the det port of mortgage-nbrvl, changed in two ways:

  • The contract DTO no longer maps EPSPARM-RETURN-ERROR.
  • The service writes 'X' into that field's last byte after the program runs.

Results:

  • origin/main harness: EPSNBRVL CALLS: 15/15 calls equal, proven.
  • this branch: 0/15 calls equal, EPS-NUMBER-VALIDATION.EPSPARM-RETURN-ERROR: cobol ' …' java ' …X', caught.

Re-sweeps (on the merged tree)

  • proof_sweep.py --det-only (Db2 local): 77/80 proven. The 3 that are not proven are the baseline's (carddemo-cardupdate, carddemo-intcalc-generated, mortgage-mpmt). Result: "sweep: as expected", no newly failing case. FILLER is now compared in cbsa-custctrl, cbsa-dbcrfun and carddemo-cardupdate.
  • proof_sweep.py --model-only: 28/28 proven, "as expected".
  • Coverage ledger re-measured (det_coverage_ledger.py update): the numbers did not change. Only fingerprints were refreshed: harness, oracle, and cbsa-inqacccu's case.
  • evidence.py status --ci: rc 0, so no record is blocking-stale. A harness change makes records stale only through the scheduled refresh.

Gates

pr_gates.py --fast passes 5/5 and --ratchets passes 7/7 (JDK 17).

🤖 Generated with Claude Code

https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D

squid-protocol and others added 5 commits October 9, 2026 04:56
… table travels (Fixes #4765)

The harness's record layout listed an OCCURS group's fields once (the first
occurrence), so a COMMAREA's table was compared at occurrence 1 only: a
cbsa-inqacccu port that never wrote account 3's type was PROVEN on main.

- layout_fields(..., occurrences=True): every occurrence a field, by name and
  subscript (COMM-ACC-TYPE(3), nested CELL(2,4)), with its OCCURS DEPENDING ON
  constraints; a COMMAREA is read by it, each side by its own ODO count
  (active_fields). A file's record names each occurrence (they were compared
  only as "bytes outside the layout").
- a scenario's COMMAREA is the whole record (it was cut at the first
  occurrence's end: INQACCCU's EIBCALEN was 123 of 1985 bytes, accounts 2..N
  written past it), every occurrence INITIALIZEd.
- a LINKed task gets its COMMAREA's bytes too (CicsTask.withLinkArea); a port
  that takes them (a det port) is read from them; a DTO's values are the
  first occurrence (first_occurrences), the rest absent -- compared.
- det: a DTO whose OCCURS fields appear once spans its declared record with or
  without a POINTER (LINK span, EIBCALEN), and RETURN / XCTL pass its bytes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
# Conflicts:
#	tests/equivalence/det_sweep_coverage.json
…hole; BMS OCCURS refused (#4778)

- compare_dto: a group USING item is read by its whole layout, every occurrence by
  subscript; a port taking the items' bytes (det: withCallAreas) gives them back and
  they are compared as bytes (each FILLER too); a DTO-only port has every named field
  compared and its unnamed bytes listed as not compared, with the reason.
- det Dto.size spans the declared record when it ends in a FILLER (CBSA CUSTCTRL,
  GenApp LGICVS01/LGIPVS01/...); COMMAREA FILLER compared as bytes when both sides are
  bytes, declared not compared against a DTO.
- screen_layout refuses a symbolic map with OCCURS by name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
@squid-protocol squid-protocol added bug Unintended behavior or logic failure in the engine legacy-modernization COBOL refractor, dead-code extraction, and JCL forging testing Unit, integration, and E2E pipeline verification labels Oct 9, 2026
squid-protocol and others added 2 commits October 9, 2026 07:29
…LLER compare (#4778)

Numbers unchanged; harness fingerprints and measured_at refreshed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
# Conflicts:
#	gitgalaxy/tools/cobol_to_java/det/cics.py
#	tests/equivalence/det_sweep_coverage.json
#	tests/tools/equivalence_cics.py
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

Full det sweep on the merged tree: 77 proven, the 3 baseline cases not; numbers unchanged,
harness / oracle fingerprints refreshed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MQNoe4wPJgr7dbUvs3DG6D
@squid-protocol squid-protocol changed the title WIP: equivalence: CALL USING items and COMMAREA trailing FILLER compared whole (Fixes #4778) equivalence: CALL USING items and COMMAREA trailing FILLER compared whole; BMS OCCURS refused (Fixes #4778) Oct 9, 2026
squid-protocol and others added 5 commits October 9, 2026 08:44
# Conflicts:
#	tests/equivalence/det_sweep_coverage.json
# Conflicts:
#	tests/equivalence/det_sweep_coverage.json
# Conflicts:
#	tests/equivalence/det_sweep_coverage.json
# Conflicts:
#	tests/equivalence/det_sweep_coverage.json
…-swept next)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n, as expected; coverage unchanged)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…its full det sweep

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBJdDBRtJis5hzE244NQKV
@squid-protocol

Copy link
Copy Markdown
Owner Author

CI shepherd: this PR conflicts with main, so no checks ran. Merge origin/main into it and regenerate generated files with their tools (never hand-merge them; see .claude/agents/gitgalaxy-pr-worker.md), then push.

1 similar comment
@squid-protocol

Copy link
Copy Markdown
Owner Author

CI shepherd: this PR conflicts with main, so no checks ran. Merge origin/main into it and regenerate generated files with their tools (never hand-merge them; see .claude/agents/gitgalaxy-pr-worker.md), then push.

… split --base + update from the sweep

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBJdDBRtJis5hzE244NQKV
@squid-protocol

Copy link
Copy Markdown
Owner Author

CI shepherd: this PR conflicts with main, so no checks ran. Merge origin/main into it and regenerate generated files with their tools (never hand-merge them; see .claude/agents/gitgalaxy-pr-worker.md), then push.

…e; ledger re-applied from its sweeps

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TBJdDBRtJis5hzE244NQKV
@squid-protocol
squid-protocol marked this pull request as ready for review October 9, 2026 23:59
@squid-protocol
squid-protocol merged commit e60b93f into main Oct 9, 2026
51 checks passed
@squid-protocol
squid-protocol deleted the fix/4778-call-compare branch October 9, 2026 23:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Unintended behavior or logic failure in the engine legacy-modernization COBOL refractor, dead-code extraction, and JCL forging testing Unit, integration, and E2E pipeline verification

Projects

None yet

Development

Successfully merging this pull request may close these issues.

equivalence: batch CALL compare (equivalence_call.compare_dto) checks only DTO-mapped fields; DTOs with trailing FILLER keep a short extent

1 participant