Skip to content

#3933 / #3910 / #3911: floating currency editing, PICTURE SYMBOL precision, decimal-comma VALUEs -- the India slice passes - #3940

Merged
squid-protocol merged 4 commits into
mainfrom
fix/india-3933-3910-3911
Sep 28, 2026
Merged

squid-protocol merged 4 commits into
mainfrom
fix/india-3933-3910-3911

Conversation

@squid-protocol

@squid-protocol squid-protocol commented Sep 27, 2026 •

Copy link
Copy Markdown
Owner

The India slice of the Cultural Gauntlet (#3834 part 2) now passes: its baseline was 67 known failing cells, all three of these bugs, and is now empty (header only).

Fixes #3933
Fixes #3910
Fixes #3911

#3933: floating insertion in the generated CobolEdit.format

Problem: $$$,$$9.99 of 1234.50 printed $$$,$$4.50. The high-order digits were dropped and the symbols left in place. £, € and ₹ behaved the same way. A PICTURE SYMBOL (U / I / K) came out as a literal letter.

Change: cobol_to_java_repository_forge._COBOL_EDIT now implements floating insertion, following IBM Enterprise COBOL Language Reference, PICTURE clause, "Floating insertion editing":

  • What counts as floating: two or more of $ (or the currency symbol), + or -, with only , . B 0 / between them. A single $ / + / - is still a fixed insertion.
  • Symbol and digit positions: the leftmost symbol is the sign/currency position only. Every other symbol in the string is a digit position, so it counts toward the digits and the scale.
  • Where the symbol lands: it goes in the last position blanked before the first nonzero digit. Leading zeros and the , B 0 / insertion characters inside the string are blanked while suppression lasts, so $$$,$$9.99 of 234.50 prints $234.50, with the $ in the comma's position.
  • Decimal point: it ends suppression ($$$,$$$.$$ of 0.05 prints $.05).
  • Zero value: when every digit position is part of the floating string, a zero edits to all spaces.
  • Currency symbol: $, or any character in the PICTURE that is no editing symbol (U, I, K, £, ₹), stands for the currency argument, which is the CURRENCY SIGN string. With null the PICTURE's own character is printed.
  • Signature: unchanged (format(pic, value, decimalComma, currency)). The Javadoc and the port-ticket rule text now describe floating strings and the PICTURE SYMBOL.

Multi-character currency spacing (a decision). GnuCOBOL has no multi-character currency strings, so this follows IBM's rule:

  • The string floats as a unit into the one symbol position just left of the first significant digit. Every other PICTURE position is one character, so the edited field is len(string) − 1 wider.
  • This matches the 13-byte layout the engine already computes for these fields.
  • No space is added and none is removed: 'INR ' carries its own trailing space and 'Rs' has none. The results:
    • UUU,UU9.99 / 'EUR ' of 1234.50 prints " EUR 1,234.50"
    • III,II9.99 / 'INR ' prints " INR 1,234.50"
    • KK,KK,KK9.99 / 'Rs' prints " Rs1,234.50"
  • The brief's lakh example does not fit its PICTURE. KK,KK,KK9.99 has 6 integer digit positions (the first K is the symbol), so it cannot hold 1234567.89. COBOL truncates the high-order digit there, like any MOVE. The test pins KK,KK,KK9.99 of 123456.78 as Rs1,23,456.78, and KKK,KK,KK9.99 / K(3),KK,KK9.99 of 1234567.89 as Rs12,34,567.89.

Checked against GnuCOBOL 3. Every $ / + / - case in the new test (25 of them) was run under gitgalaxy-gnucobol:3 with cobc -std=ibm (MOVE of an S9(9)V99 into the edited item) and the output copied verbatim. That covers $, +, -, B inside the float, the float crossing the decimal point, the all-float zero, $$$9.99-, and DECIMAL-POINT IS COMMA $$$.$$9,99.

#3910: a PICTURE SYMBOL counts as a floating currency symbol

  • parse_pic_precision: takes currency_symbols. A declared symbol letter is read like $, so UUU,UU9.99 gives (7, 2) and KK,KK,KK9.99 gives (8, 2).
  • Schema forge (render_schemas / parse_cobol_picture / forge_schemas):
    • it passes the program's CURRENCY symbols through;
    • it records the non-Unicode symbol letters in the JSON schema as currency_symbols, only when there are any, so other schemas do not move.
  • Engine path (engine_sourcing.engine_schemas): takes the program's own symbols plus those its items took from the estate (galaxy_ir._attach_currency). This is the same source the record layout sizes from, so sizing and precision agree.
  • Spring forge: parse_pic_clause / _render_field / entity and DTO read currency_symbols from the schema.
  • Other digit counters: java_type treats edited PICTUREs as String, and _pic_numeric only reads plain numeric PICs, so neither needed a change.

#3911: DECIMAL-POINT IS COMMA VALUEs

  • Fact: mainframe_boundary._cobol_records keeps the literal as written (VALUE 12345,67 gives 12345,67), as decided.
  • When the comma is part of the literal: only when the file declares DECIMAL-POINT IS COMMA and the comma sits directly between digits. A comma followed by a space still separates (VALUE 1, 2, 3 gives 1), and so does any comma in a program without the clause.
  • Where the flag comes from: the caller passes the file's special_names (read once now). Other callers default to reading the file's SPECIAL-NAMES themselves.
  • Numeric consumers of VALUE: none today. I searched every reader of value / value_literal: the schema and Java forges, the port tickets, galaxy_ir._value_text (text for LINK / TRANSID resolution only), the equivalence harnesses and the refraction differential. None turns a COBOL VALUE into a number, so there was nothing to change there. The gauntlet's facts expectation (12345,67) already matches the literal as written.
  • Not handled (out of scope): a copybook COPYed into a decimal-comma program has no SPECIAL-NAMES of its own, so its VALUE 1,5 is still read the old way.

Cultural Gauntlet (--full --run, JDK 21)

overall India row
before (origin/main) 469/536 cells pass (67 failing, all ledgered), 104 skipped 168/192 pass, 24 ledgered, 56 skipped
after 536/536 cells pass, 104 skipped 192/192 pass, 0 ledgered, 56 skipped
  • --full --run --update-baseline leaves tests/cultural_gauntlet/baseline.txt header-only. --full --run --ci and --ci both exit 0.
  • The EUR/U, INR/I and Rs/K dialects now declare their edited value (above), so their runtime-run cells check it.
  • The skips are unchanged: characters a page cannot hold (the euro sign and ₹ in the pre-euro pages).

Snapshots / golden masters

  • Refraction snapshots: none moved. refraction_snapshot.py check (excerpts) and --corpus for all six full corpora both report 0 differ: no snapshotted project generates CobolEdit or a PICTURE SYMBOL / decimal-comma field.
  • Golden masters: none re-blessed. The golden gate passes unchanged.

Tests

  • tests/cobol_mainframe/test_floating_insertion.py: compiles and runs the generated CobolEdit with the JDK, using the gauntlet's jdk(). It covers 25 GnuCOBOL-run cases, 3 more single-character cases ($(3), £, ₹) by the same rule, 8 IBM multi-character cases, and DECIMAL-POINT IS COMMA.
  • tests/cobol_mainframe/test_picture_symbol_precision.py:
    • parse_pic_precision with symbols;
    • the schema forge on a program with the INR and Rs symbols;
    • Spring entity precision;
    • VALUE capture with and without DECIMAL-POINT IS COMMA, including an 88-level VALUE 1, 2, 3.
  • Both files fail on origin/main and pass here.

Gates

tests/tools/pr_gates.py (full) on the branch:

PASS  lint
PASS  audits
PASS  secrets
PASS  xray
PASS  gauntlet      58s
PASS  golden       103s
FAIL  suite        1 failed, 12954 passed, 11 skipped, 2 deselected, 9 xfailed, 3 xpassed
      FAILED tests/core_engine/test_lazy_re.py::test_a_forked_pool_inherits_every_claimant_compiled

The one suite failure was already failing on origin/main; this branch did not cause it.

  • pr_gates.py --only suite on a clean origin/main worktree (5d27aa1) fails the same test: 1 failed, 12937 passed. The 17 extra passes on this branch are the new tests.
  • The test passes on its own in both trees. It only fails in the full-suite run, so another test is affecting it.
  • It concerns objective-c rule precompilation, which this PR does not touch.

After git merge origin/main (already up to date), pr_gates.py --only lint audits golden gauntlet suite gives the same result: lint, audits, golden and gauntlet pass, and suite has only that one failure.

Also run: tests/cobol_mainframe/test_ground_truth_ledger.py and test_ground_truth_diff.py pass (21), and tests/cultural_gauntlet passes (108).

🤖 Generated with Claude Code

squid-protocol and others added 2 commits September 27, 2026 19:00
…ision, decimal-comma VALUEs

#3933: the generated CobolEdit.format implements IBM floating insertion ($ / currency symbol / + / -
strings float to just left of the first significant digit, blanking the insertion characters they pass)
and replaces a PICTURE SYMBOL letter (U / I / K) with the whole currency string.
#3910: parse_pic_precision counts a declared PICTURE SYMBOL as a floating currency symbol; the schema
forge records the program's symbol letters and the Spring forge reads them.
#3911: under DECIMAL-POINT IS COMMA a numeric VALUE keeps its decimal comma as written (12345,67); a comma
followed by a space still separates (VALUE 1, 2, 3).

The Cultural Gauntlet declares the EUR / INR / Rs edited values and its baseline is now empty.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@squid-protocol squid-protocol changed the title Fix/india 3933 3910 3911 #3933 / #3910 / #3911: floating currency editing, PICTURE SYMBOL precision, decimal-comma VALUEs -- the India slice passes Sep 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

…ness (order-dependent in CI)

The language registry is a process-wide global compiled in place, so an earlier test in the same
xdist worker may already have compiled python's / objective-c's rules, and deepcopy copies that.
The test then asserted they were still lazy and failed depending on test distribution (#3940's
CI). It now snapshots rule identities and asserts _precompile_for_fork leaves non-claimants (and
everything under spawn) untouched. Reproduced: the old test fails after a test that compiles
python's rules first; the new one passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@squid-protocol
squid-protocol merged commit b75eb8f into main Sep 28, 2026
37 checks passed
@squid-protocol
squid-protocol deleted the fix/india-3933-3910-3911 branch September 28, 2026 00:07
squid-protocol added a commit that referenced this pull request Sep 28, 2026
…remaining runtime locales (#3947)

* #3834 (part 3): the Cultural Gauntlet's DB collation, input data and remaining runtime locales

D (target DB collation): a PIC X(8) KSDS that CICS browses and a batch step reads sequentially, generated
for H2 / PostgreSQL / MySQL. collation-static checks #3822's contract; the opt-in --db layer creates the
generated table in the databases this machine has (H2 from ~/.m2, a throwaway PostgreSQL cluster with C and
en_US.UTF-8 databases; MySQL skipped, never faked) and reads the keys back through the generated finders'
SQL against the keys' EBCDIC byte order. Found #3945 (batch sequential READ is findAll(): no key order).

E (input data): DATUM / FECHA typed by PICTURE and SQL type, DB2 EUR / USA / ISO forms through Db2Dates,
ROUNDED ties and NUMVAL / zoned over full-width, Arabic-Indic, Thai and Devanagari digits, pinned from
GnuCOBOL 3 -std=ibm. Found #3946 (Db2Dates.parseTimestamp takes Arabic-Indic digits).

C (rest): tr-TR, ar-EG, th-TH-u-nu-thai, de-DE x UTC / Asia/Kolkata / Europe/Berlin join --run's JVM
environments (-Duser.extensions keeps -u-nu-thai); runtime-static traps locale-bound date formatters,
SimpleDateFormat, Collator and Character.isDigit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* #3834 (part 3): the baseline after #3940 -- only part 3's ledgered cells (#3945, #3946)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant