Skip to content

Modernize the position valuation and update slice: COBOL behavioural spec + Java 21 / Spring Boot port with COBOL-parity tests - #271

Open
devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1788184467-position-valuation-modernization
Open

devin-ai-integration[bot] wants to merge 1 commit into
mainfrom
devin/1788184467-position-valuation-modernization

Conversation

@devin-ai-integration

@devin-ai-integration devin-ai-integration Bot commented Aug 31, 2026

Copy link
Copy Markdown

Summary

Forward-engineers one coherent slice of the COBOL system — position valuation and update — into Java 21 / Spring Boot, with the behavioural specification that drives it and parity tests asserted against vectors captured from the compiled COBOL. No COBOL source or seed data is modified.

Program set migrated, and why. The slice is everything on the read → compute → write path for a position, and nothing else (6 programs of 42):

Program Why in scope
PORTTRAN.cbl The entire transaction validation, position update and audit path
PORTVALD.cbl The field-validation authority (IDs, accounts, types, amounts)
PORTUPDT.cbl The only other writer of PORT-TOTAL-VALUE
RPTPOS00.cbl2110 only The only place a position is valued rather than accumulated
ERRPROC.cbl, AUDPROC.cbl Called on every failure / every update

Copybooks: TRNREC, POSREC, PORTFLIO, PORTVAL, AUDITLOG, ERRHAND.

The task named src/programs/batch/POSUPDT.cbl as the starting point. That file is zero bytes. The behaviour the documentation attributes to POSUPDT (system-architecture.md L95-97, L502) is implemented paragraph-for-paragraph in PORTTRAN 2200-UPDATE-POSITIONS, so PORTTRAN is treated as the position update step — stated explicitly rather than invented (OQ-2). Two other findings of the same kind are load-bearing and are recorded, not papered over: PORTTRAN copies a PORTREC copybook that does not exist in the repository (so the PIC clauses of the two fields carrying all the money are not recoverable from source — OQ-1), and PORTTRAN never performs 2200-UPDATE-POSITIONS — no such PERFORM exists anywhere in the program, so as committed it validates a transaction file and no balance ever changes. Both behaviours ship, switched by config, defaulting to the faithful one:

clbs.porttran.apply-updates: false   # reproduces the COBOL exactly: validate, count, log
                                     # true: also runs the dead buy/sell/transfer/fee paragraphs

Deliverables

  • docs/modernization/position-valuation-spec.md52 numbered business rules, every one citing its program and paragraph, each tagged [golden] (pinned by a vector from the compiled COBOL) or [read] (derived from source text), plus record layouts and 12 open questions.
  • modernization/position-valuation/ — the Java 21 / Spring Boot 3.3.5 module.
  • modernization/position-valuation/README.md — the paragraph → method map.
  • modernization/position-valuation/parity/ — four GnuCOBOL harnesses plus the script that regenerates the golden CSVs.

Rounding and precision, and their COBOL justification. BigDecimal throughout (COMP-3 is fixed-point decimal; binary floating point diverges on the first fee). Every store names its receiving field, because in COBOL the receiving field — not the operands — fixes scale and rounding. cobol/PackedField is the whole of it:

public BigDecimal store(BigDecimal value) {
    BigDecimal scaled = value.setScale(scale, RoundingMode.DOWN);   // R-5.1: no statement in the
    BigDecimal modulus = BigDecimal.TEN.pow(intDigits);             //  slice carries ROUNDED
    return scaled.abs().compareTo(modulus) >= 0                     // R-5.2: none carries
        ? scaled.remainder(modulus) : scaled;                       //  ON SIZE ERROR -> silent wrap
}
  • Scale 4 for quantities (S9(11)V9(4)), scale 2 for money (S9(13)V9(2)), from TRNREC/POSREC.
  • RoundingMode.DOWN at every store: no ROUNDED phrase exists in the slice, and COBOL truncates toward zero. 9999999999999.99 + 0.01 is 0.00, not an error, and the tests assert exactly that.
  • COMPUTE intermediates at DECIMAL128, truncated once into the receiving field, matching IBM's ≥30-digit fixed-point intermediates.
  • PIC +ZZ9.99 is modelled as a real field, not a format string: 12245.67% prints +245.67 because three integer digits with no ON SIZE ERROR discard the rest.

Test evidence. mvn clean test115 tests, 0 failures. 90 of them are golden-vector rows: parity/cobol/PVDRIVE.cbl calls the unmodified PORTVALD (34 inputs), PARITHM.cbl/PDIVZER.cbl re-execute the ADD/SUBTRACT/COMPUTE statements of PORTTRAN 2210-2240 and RPTPOS00 2110 on the production PIC clauses, and PUPDMOV.cbl re-executes the two MOVEs of PORTUPDT 2200. Their stdout is committed as CSV and asserted row by row, so a divergence from the COBOL fails the build. The remaining tests cover the error and abend paths: insufficient units, missing portfolio, unimplemented transfer, overflow wrap, divide-by-zero, and the 101-error batch halt.

Defects reproduced rather than fixed (each pinned by a vector and raised as an open question): PORTVALD 1000-VALIDATE-ID rejects every portfolio ID, including a well-formed PORT0001, because it moves 4 characters into a PIC X(10) field and then class-tests the space-filled result; 2000-VALIDATE-ACCOUNT class-tests all 50 linkage bytes, so only a 50-digit account passes; 4000-VALIDATE-AMOUNT bounds equal the receiving field's own range, so it can never fail. Three deviations are deliberate and listed in the README — the audit timestamp/field-overlay corruption is not reproduced, a non-numeric amendment value throws instead of inventing a number, and a zero divisor returns an explicit size-error outcome.

Open questions a human must answer (full table in the spec): OQ-1 real PIC clauses of PORT-TOTAL-UNITS/PORT-TOTAL-COST (missing copybook); OQ-2 should PORTTRAN update at all; OQ-3/OQ-4 the two validators that can never succeed; OQ-5 where POS-CURRENT-VALUE/POS-PREVIOUS-VALUE come from (absent from POSREC, so RPTPOS00 does not compile); OQ-6 sell reduces cost basis by proceeds, not by cost of units sold, and no realised P&L exists; OQ-7 transfers are exempt from the price and amount checks but not the quantity check; OQ-8 the audit "before image" is written after the rewrite; OQ-9 does the zero-divisor COMPUTE abend on z/OS; OQ-10 PORTUPDT can write an unrecognised PORT-STATUS; OQ-11 "12500.00" in an amendment file means different money under GnuCOBOL and IBM Enterprise COBOL; OQ-12 the 101-error halt ends the job normally with the file half-read.

Devin-Org: engineering

Link to Devin session: https://app.devin.ai/sessions/ccae8de8ed00434ab0e6d275c4d376d4
Open in Devin Desktop: https://app.devin.ai/desktop/session/ccae8de8ed00434ab0e6d275c4d376d4?variant=devin
Requested by: @schaudhry123


Devin Review

Status Commit
⚪ Not started

Run Devin Review

Devin Review (Staging)

…21 / Spring Boot

Adds a behavioural spec derived from PORTTRAN/PORTVALD/PORTUPDT/RPTPOS00, a
Java 21 Spring Boot port using BigDecimal with COBOL truncation semantics, and
parity tests asserted against golden vectors captured from the compiled COBOL.

Co-Authored-By: Samir Chaudhry <samir@cognition.ai>
@devin-ai-integration

Copy link
Copy Markdown
Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

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.

1 participant