-- Update proj-demo-full: replace single-file translation with multi-file array
UPDATE projects SET config = jsonb_set(
  config,
  '{analysisResults,translation}',
  '{
    "files": [
      {
        "id": "f1",
        "sourceFile": "src/ACCTMAIN.cbl",
        "targetFile": "src/main/java/com/secb/service/AccountMainService.java",
        "sourceLangId": "cobol",
        "targetLangId": "java",
        "confidence": 97.2,
        "linesSource": 48,
        "linesTarget": 52,
        "sourceCode": "      ******************************************************************\n      * PROGRAMMA:    ACCTMAIN                                         *\n      * DESCRIZIONE:  Programma principale di controllo flusso per il   *\n      *               Sistema Elaborazione Conti Bancari (SECB).       *\n      ******************************************************************\n       IDENTIFICATION DIVISION.\n       PROGRAM-ID. ACCTMAIN.\n       AUTHOR. ROSSI-MARIO.\n       DATE-WRITTEN. 15-MAR-1995.\n\n       ENVIRONMENT DIVISION.\n       INPUT-OUTPUT SECTION.\n       FILE-CONTROL.\n           SELECT LOG-FILE\n               ASSIGN TO UT-S-LOGFILE\n               FILE STATUS IS WS-LOG-STATUS.\n\n       DATA DIVISION.\n       WORKING-STORAGE SECTION.\n       01  WS-GENERALI.\n           05  WS-PROGRAMMA       PIC X(8) VALUE ''ACCTMAIN''.\n           05  WS-VERSIONE        PIC X(6) VALUE ''V2.3.1''.\n           05  WS-RC-PRINCIPALE   PIC 9(4) COMP VALUE 0.\n       01  WS-CONTATORI.\n           05  WS-CONTI-ELAB      PIC 9(8) COMP VALUE 0.\n           05  WS-CONTI-OK        PIC 9(8) COMP VALUE 0.\n           05  WS-CONTI-ERR       PIC 9(8) COMP VALUE 0.\n\n       PROCEDURE DIVISION.\n       MAIN-PROGRAM.\n           PERFORM INIZIALIZZA\n           PERFORM ELABORA-GIORNALIERA\n           PERFORM CHIUDI-ELABORAZIONE\n           STOP RUN.\n\n       INIZIALIZZA.\n           OPEN OUTPUT LOG-FILE\n           DISPLAY ''SECB V2.3.1 - Avvio elaborazione''.\n\n       ELABORA-GIORNALIERA.\n           CALL ''ACCTBAL''  USING WS-RC-PRINCIPALE\n           CALL ''ACCTOPEN'' USING WS-RC-PRINCIPALE\n           CALL ''ACCTPROC'' USING WS-RC-PRINCIPALE\n           CALL ''ACCTREPT'' USING WS-RC-PRINCIPALE.\n\n       CHIUDI-ELABORAZIONE.\n           CLOSE LOG-FILE\n           DISPLAY ''Elaborazione completata''.",
        "targetCode": "package com.secb.service;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.boot.CommandLineRunner;\nimport org.springframework.stereotype.Service;\n\n/**\n * ACCTMAIN — Main processing controller for SECB Banking System.\n * Manages the daily processing cycle.\n * @version 2.3.1\n * @migrated-from ACCTMAIN.cbl\n */\n@Slf4j\n@Service\n@RequiredArgsConstructor\npublic class AccountMainService implements CommandLineRunner {\n\n    private final AccountBalanceService accountBalanceService;\n    private final AccountOpenService accountOpenService;\n    private final AccountProcessingService accountProcessingService;\n    private final AccountReportService accountReportService;\n\n    private int processedCount = 0;\n    private int successCount = 0;\n    private int errorCount = 0;\n\n    @Override\n    public void run(String... args) {\n        log.info(\"SECB V2.3.1 — Starting daily processing\");\n        initialize();\n        executeDailyProcessing();\n        closeProcessing();\n    }\n\n    private void initialize() {\n        log.info(\"Initializing SECB processing engine\");\n        processedCount = 0;\n        successCount = 0;\n        errorCount = 0;\n    }\n\n    private void executeDailyProcessing() {\n        accountBalanceService.process();\n        accountOpenService.process();\n        accountProcessingService.process();\n        accountReportService.process();\n    }\n\n    private void closeProcessing() {\n        log.info(\"Processing complete — {} processed, {} OK, {} errors\",\n            processedCount, successCount, errorCount);\n    }\n}",
        "confidenceScores": [
          {"block": "IDENTIFICATION DIVISION → Class declaration", "score": 99, "lines": "1-8"},
          {"block": "WORKING-STORAGE → Fields", "score": 97, "lines": "18-26"},
          {"block": "CALL statements → Service injection", "score": 95, "lines": "37-44"},
          {"block": "PERFORM → Method calls", "score": 98, "lines": "30-35"},
          {"block": "FILE-CONTROL → SLF4J logging", "score": 93, "lines": "12-15"},
          {"block": "Error handling flow", "score": 96, "lines": "45-48"}
        ],
        "businessRules": [
          {"id": "BR-001", "description": "Daily processing must execute in sequence: Balance → Open → Process → Report", "source": "ELABORA-GIORNALIERA paragraph", "target": "executeDailyProcessing() method", "confidence": 98},
          {"id": "BR-002", "description": "Processing counters must track total, success, and error counts", "source": "WS-CONTATORI group", "target": "processedCount/successCount/errorCount fields", "confidence": 97},
          {"id": "BR-003", "description": "Log file must be opened before processing and closed after", "source": "OPEN/CLOSE LOG-FILE", "target": "SLF4J initialize()/closeProcessing()", "confidence": 95}
        ],
        "explanations": [
          "COBOL CALL statements mapped to Spring @RequiredArgsConstructor dependency injection",
          "WORKING-STORAGE variables converted to private instance fields with appropriate Java types",
          "FILE-CONTROL log file replaced with SLF4J structured logging",
          "PERFORM paragraph calls converted to private method invocations",
          "STOP RUN replaced by CommandLineRunner lifecycle completion"
        ],
        "reasonings": [
          "Spring Boot was chosen as the target framework because it provides dependency injection, lifecycle management, and enterprise-grade features that map naturally to COBOL batch processing patterns.",
          "The CALL/USING pattern in COBOL directly maps to Spring service injection — each called program becomes a @Service bean.",
          "Lombok @RequiredArgsConstructor eliminates boilerplate while maintaining the same dependency structure as the COBOL CALL graph."
        ]
      },
      {
        "id": "f2",
        "sourceFile": "src/ACCTBAL.cbl",
        "targetFile": "src/main/java/com/secb/service/AccountBalanceService.java",
        "sourceLangId": "cobol",
        "targetLangId": "java",
        "confidence": 96.5,
        "linesSource": 52,
        "linesTarget": 48,
        "sourceCode": "      ******************************************************************\n      * PROGRAMMA:    ACCTBAL                                          *\n      * DESCRIZIONE:  Calcolo e aggiornamento saldi conti correnti     *\n      ******************************************************************\n       IDENTIFICATION DIVISION.\n       PROGRAM-ID. ACCTBAL.\n\n       DATA DIVISION.\n       WORKING-STORAGE SECTION.\n       01  WS-SALDI.\n           05  WS-SALDO-CORRENTE  PIC S9(9)V99 COMP-3.\n           05  WS-MOVIMENTI-PEND  PIC S9(9)V99 COMP-3.\n           05  WS-SALDO-NUOVO     PIC S9(9)V99 COMP-3.\n           05  WS-NUM-CONTI       PIC 9(8) COMP VALUE 0.\n       01  WS-ACCOUNT-REC.\n           05  WS-ACCT-NUM        PIC X(10).\n           05  WS-ACCT-NAME       PIC X(30).\n           05  WS-ACCT-TYPE       PIC X(1).\n           05  WS-ACCT-BALANCE    PIC S9(9)V99 COMP-3.\n           05  WS-ACCT-STATUS     PIC X(1).\n\n       PROCEDURE DIVISION.\n       CALCOLO-SALDI.\n           PERFORM LEGGI-CONTI-ATTIVI\n           PERFORM VARYING WS-NUM-CONTI\n               FROM 1 BY 1\n               UNTIL WS-NUM-CONTI > WS-TOTALE-CONTI\n               PERFORM CALCOLA-SALDO-SINGOLO\n           END-PERFORM\n           DISPLAY ''Aggiornamento saldi completato''\n           GOBACK.\n\n       CALCOLA-SALDO-SINGOLO.\n           MOVE WS-ACCT-BALANCE TO WS-SALDO-CORRENTE\n           ADD WS-MOVIMENTI-PEND TO WS-SALDO-CORRENTE\n               GIVING WS-SALDO-NUOVO\n           MOVE WS-SALDO-NUOVO TO WS-ACCT-BALANCE\n           PERFORM AGGIORNA-RECORD.\n\n       LEGGI-CONTI-ATTIVI.\n           OPEN INPUT ACCOUNT-FILE\n           READ ACCOUNT-FILE INTO WS-ACCOUNT-REC\n               AT END SET WS-EOF TO TRUE\n           END-READ.\n\n       AGGIORNA-RECORD.\n           REWRITE ACCOUNT-RECORD FROM WS-ACCOUNT-REC.",
        "targetCode": "package com.secb.service;\n\nimport com.secb.model.Account;\nimport com.secb.repository.AccountRepository;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.math.BigDecimal;\nimport java.util.List;\n\n/**\n * ACCTBAL — Account Balance Service.\n * Computes and updates account balances based on pending transactions.\n * @migrated-from ACCTBAL.cbl\n */\n@Slf4j\n@Service\n@RequiredArgsConstructor\npublic class AccountBalanceService {\n\n    private final AccountRepository accountRepository;\n\n    @Transactional\n    public void process() {\n        log.info(\"Starting balance calculation\");\n        List<Account> accounts = accountRepository.findByStatus(\"ACTIVE\");\n\n        for (Account account : accounts) {\n            BigDecimal balance = computeBalance(account);\n            account.setBalance(balance);\n            account.setLastProcessedDate(java.time.LocalDate.now());\n            accountRepository.save(account);\n        }\n\n        log.info(\"Balance calculation complete — {} accounts updated\",\n            accounts.size());\n    }\n\n    private BigDecimal computeBalance(Account account) {\n        BigDecimal current = account.getBalance();\n        BigDecimal pending = account.getPendingAmount() != null\n            ? account.getPendingAmount() : BigDecimal.ZERO;\n        return current.add(pending);\n    }\n}",
        "confidenceScores": [
          {"block": "PIC S9(9)V99 COMP-3 → BigDecimal", "score": 98, "lines": "10-13"},
          {"block": "PERFORM VARYING → for loop", "score": 96, "lines": "24-29"},
          {"block": "REWRITE → JPA save()", "score": 97, "lines": "44-45"},
          {"block": "FILE-CONTROL → Repository", "score": 94, "lines": "38-42"}
        ],
        "businessRules": [
          {"id": "BR-004", "description": "Balance = Current Balance + Pending Movements", "source": "ADD WS-MOVIMENTI-PEND TO WS-SALDO-CORRENTE GIVING WS-SALDO-NUOVO", "target": "current.add(pending)", "confidence": 99},
          {"id": "BR-005", "description": "Only ACTIVE accounts are processed for balance update", "source": "LEGGI-CONTI-ATTIVI paragraph", "target": "findByStatus(\"ACTIVE\")", "confidence": 98}
        ],
        "explanations": [
          "COMP-3 packed decimal fields are mapped to java.math.BigDecimal for exact financial arithmetic",
          "The PERFORM VARYING loop becomes a standard Java enhanced for-loop over JPA query results",
          "REWRITE file record is replaced by JPA accountRepository.save() with @Transactional annotation",
          "OPEN INPUT / READ / AT END pattern replaced by Spring Data JPA findByStatus query"
        ],
        "reasonings": [
          "BigDecimal is mandatory for financial calculations — Java float/double would introduce rounding errors incompatible with COBOL COMP-3 precision.",
          "Spring Data JPA replaces VSAM file I/O because it provides the same sequential and random access patterns with a modern persistence layer."
        ]
      },
      {
        "id": "f3",
        "sourceFile": "src/ACCTOPEN.cbl",
        "targetFile": "src/main/java/com/secb/service/AccountOpenService.java",
        "sourceLangId": "cobol",
        "targetLangId": "java",
        "confidence": 97.8,
        "linesSource": 42,
        "linesTarget": 52,
        "sourceCode": "      ******************************************************************\n      * PROGRAMMA:    ACCTOPEN                                         *\n      * DESCRIZIONE:  Apertura nuovi conti correnti                    *\n      ******************************************************************\n       IDENTIFICATION DIVISION.\n       PROGRAM-ID. ACCTOPEN.\n\n       DATA DIVISION.\n       WORKING-STORAGE SECTION.\n       01  WS-NEW-ACCOUNT.\n           05  WS-NEW-ACCT-NUM    PIC X(10).\n           05  WS-NEW-ACCT-NAME   PIC X(30).\n           05  WS-NEW-ACCT-TYPE   PIC X(1).\n               88  TIPO-CORRENTE  VALUE ''C''.\n               88  TIPO-RISPARMIO VALUE ''R''.\n           05  WS-NEW-STATUS      PIC X(1) VALUE ''P''.\n               88  STATUS-PENDING VALUE ''P''.\n               88  STATUS-ACTIVE  VALUE ''A''.\n               88  STATUS-REJECT  VALUE ''R''.\n\n       PROCEDURE DIVISION.\n       APRI-CONTO.\n           PERFORM LEGGI-RICHIESTE-PENDING\n           PERFORM VALIDA-DATI-CONTO\n           IF WS-DATI-VALIDI\n               SET STATUS-ACTIVE TO TRUE\n               MOVE FUNCTION CURRENT-DATE TO WS-DATA-APERTURA\n               MOVE ZEROS TO WS-NEW-BALANCE\n               PERFORM SCRIVI-NUOVO-CONTO\n               DISPLAY ''Conto aperto: '' WS-NEW-ACCT-NUM\n           ELSE\n               SET STATUS-REJECT TO TRUE\n               PERFORM SCRIVI-RIFIUTO\n               DISPLAY ''Conto rifiutato: '' WS-NEW-ACCT-NUM\n           END-IF\n           GOBACK.\n\n       VALIDA-DATI-CONTO.\n           IF WS-NEW-ACCT-NAME = SPACES\n               SET WS-DATI-VALIDI TO FALSE\n           END-IF\n           IF WS-NEW-ACCT-TYPE NOT = ''C'' AND ''R''\n               SET WS-DATI-VALIDI TO FALSE\n           END-IF.",
        "targetCode": "package com.secb.service;\n\nimport com.secb.model.Account;\nimport com.secb.repository.AccountRepository;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.math.BigDecimal;\nimport java.time.LocalDate;\n\n/**\n * ACCTOPEN — Account Opening Service.\n * Processes new account requests and validates initial data.\n * @migrated-from ACCTOPEN.cbl\n */\n@Slf4j\n@Service\n@RequiredArgsConstructor\npublic class AccountOpenService {\n\n    private final AccountRepository accountRepository;\n\n    @Transactional\n    public void process() {\n        log.info(\"Processing pending account openings\");\n        var pending = accountRepository.findByStatus(\"PENDING_OPEN\");\n\n        for (Account account : pending) {\n            if (validateAccountData(account)) {\n                account.setStatus(\"ACTIVE\");\n                account.setOpenDate(LocalDate.now());\n                account.setBalance(BigDecimal.ZERO);\n                accountRepository.save(account);\n                log.info(\"Account {} opened successfully\",\n                    account.getAccountNumber());\n            } else {\n                account.setStatus(\"REJECTED\");\n                accountRepository.save(account);\n                log.warn(\"Account {} rejected — invalid data\",\n                    account.getAccountNumber());\n            }\n        }\n\n        log.info(\"Account opening complete — {} processed\", pending.size());\n    }\n\n    private boolean validateAccountData(Account account) {\n        if (account.getAccountName() == null\n            || account.getAccountName().isBlank()) return false;\n        if (account.getAccountType() == null) return false;\n        return true;\n    }\n}",
        "confidenceScores": [
          {"block": "88-level conditions → enum/status strings", "score": 98, "lines": "14-19"},
          {"block": "IF/ELSE validation → validateAccountData()", "score": 97, "lines": "36-42"},
          {"block": "SET STATUS-ACTIVE → setStatus(\"ACTIVE\")", "score": 99, "lines": "25-28"},
          {"block": "FUNCTION CURRENT-DATE → LocalDate.now()", "score": 99, "lines": "27"}
        ],
        "businessRules": [
          {"id": "BR-006", "description": "Account name must not be blank for opening approval", "source": "IF WS-NEW-ACCT-NAME = SPACES", "target": "getAccountName().isBlank()", "confidence": 99},
          {"id": "BR-007", "description": "Account type must be C (Current) or R (Savings)", "source": "88 TIPO-CORRENTE / TIPO-RISPARMIO", "target": "getAccountType() null check", "confidence": 96},
          {"id": "BR-008", "description": "New accounts start with zero balance", "source": "MOVE ZEROS TO WS-NEW-BALANCE", "target": "setBalance(BigDecimal.ZERO)", "confidence": 99}
        ],
        "explanations": [
          "COBOL 88-level condition names are mapped to String status constants — Java enums could also be used",
          "SET STATUS-ACTIVE TO TRUE becomes account.setStatus(\"ACTIVE\") — preserving the state machine semantics",
          "FUNCTION CURRENT-DATE is replaced by java.time.LocalDate.now() for the opening date",
          "MOVE ZEROS TO becomes BigDecimal.ZERO assignment"
        ],
        "reasonings": [
          "String-based status values were chosen over Java enums to maintain compatibility with the database schema and make status transitions explicit.",
          "The validation logic preserves the exact same checks as the COBOL source — no additional validation was added to maintain functional parity."
        ]
      },
      {
        "id": "f4",
        "sourceFile": "src/ACCTPROC.cbl",
        "targetFile": "src/main/java/com/secb/service/AccountProcessingService.java",
        "sourceLangId": "cobol",
        "targetLangId": "java",
        "confidence": 94.8,
        "linesSource": 68,
        "linesTarget": 82,
        "sourceCode": "      ******************************************************************\n      * PROGRAMMA:    ACCTPROC                                         *\n      * DESCRIZIONE:  Elaborazione movimenti e transazioni bancarie    *\n      * COMPLESSITA:  Alta — gestione errori, rollback, audit trail    *\n      ******************************************************************\n       IDENTIFICATION DIVISION.\n       PROGRAM-ID. ACCTPROC.\n\n       DATA DIVISION.\n       WORKING-STORAGE SECTION.\n       01  WS-TRANSAZIONE.\n           05  WS-TXN-ID          PIC 9(12).\n           05  WS-TXN-ACCT        PIC X(10).\n           05  WS-TXN-TIPO        PIC X(6).\n               88  TXN-CREDITO    VALUE ''CREDIT''.\n               88  TXN-DEBITO     VALUE ''DEBIT ''.\n           05  WS-TXN-IMPORTO     PIC S9(9)V99 COMP-3.\n           05  WS-TXN-STATUS      PIC X(10) VALUE ''PENDING''.\n       01  WS-CONTATORI-TXN.\n           05  WS-TXN-ELABORATI   PIC 9(8) COMP VALUE 0.\n           05  WS-TXN-ERRORI      PIC 9(8) COMP VALUE 0.\n\n       PROCEDURE DIVISION.\n       ELABORA-TRANSAZIONI.\n           OPEN INPUT TXN-FILE\n           PERFORM UNTIL WS-EOF\n               READ TXN-FILE INTO WS-TRANSAZIONE\n                   AT END SET WS-EOF TO TRUE\n                   NOT AT END PERFORM PROCESSA-SINGOLA-TXN\n               END-READ\n           END-PERFORM\n           CLOSE TXN-FILE\n           DISPLAY ''Transazioni: '' WS-TXN-ELABORATI\n                   '' errori: '' WS-TXN-ERRORI\n           GOBACK.\n\n       PROCESSA-SINGOLA-TXN.\n           PERFORM VALIDA-CONTO\n           IF WS-CONTO-VALIDO\n               EVALUATE TRUE\n                   WHEN TXN-CREDITO\n                       ADD WS-TXN-IMPORTO TO WS-ACCT-BALANCE\n                   WHEN TXN-DEBITO\n                       IF WS-ACCT-BALANCE >= WS-TXN-IMPORTO\n                           SUBTRACT WS-TXN-IMPORTO\n                               FROM WS-ACCT-BALANCE\n                       ELSE\n                           MOVE ''FAILED'' TO WS-TXN-STATUS\n                           ADD 1 TO WS-TXN-ERRORI\n                           DISPLAY ''Fondi insufficienti: ''\n                               WS-TXN-ACCT\n                       END-IF\n                   WHEN OTHER\n                       MOVE ''FAILED'' TO WS-TXN-STATUS\n                       ADD 1 TO WS-TXN-ERRORI\n               END-EVALUATE\n               MOVE ''COMPLETED'' TO WS-TXN-STATUS\n               ADD 1 TO WS-TXN-ELABORATI\n               PERFORM AGGIORNA-AUDIT-TRAIL\n           ELSE\n               MOVE ''FAILED'' TO WS-TXN-STATUS\n               ADD 1 TO WS-TXN-ERRORI\n           END-IF.",
        "targetCode": "package com.secb.service;\n\nimport com.secb.model.Account;\nimport com.secb.model.Transaction;\nimport com.secb.repository.AccountRepository;\nimport com.secb.repository.TransactionRepository;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.math.BigDecimal;\nimport java.time.LocalDateTime;\nimport java.util.List;\n\n/**\n * ACCTPROC — Account Transaction Processing Service.\n * Processes daily batch of financial transactions with audit trail.\n * @migrated-from ACCTPROC.cbl\n */\n@Slf4j\n@Service\n@RequiredArgsConstructor\npublic class AccountProcessingService {\n\n    private final AccountRepository accountRepository;\n    private final TransactionRepository transactionRepository;\n\n    @Transactional\n    public void process() {\n        log.info(\"Starting transaction processing batch\");\n        List<Transaction> pending = transactionRepository\n            .findByStatus(\"PENDING\");\n\n        int processed = 0;\n        int errors = 0;\n\n        for (Transaction txn : pending) {\n            try {\n                processTransaction(txn);\n                processed++;\n            } catch (Exception e) {\n                log.error(\"Transaction {} failed: {}\",\n                    txn.getId(), e.getMessage());\n                txn.setStatus(\"FAILED\");\n                txn.setErrorMessage(e.getMessage());\n                transactionRepository.save(txn);\n                errors++;\n            }\n        }\n\n        log.info(\"Transaction batch complete — {} processed, {} errors\",\n            processed, errors);\n    }\n\n    private void processTransaction(Transaction txn) {\n        Account account = accountRepository\n            .findByAccountNumber(txn.getAccountNumber())\n            .orElseThrow(() -> new IllegalStateException(\n                \"Account not found: \" + txn.getAccountNumber()));\n\n        if (!\"ACTIVE\".equals(account.getStatus())) {\n            throw new IllegalStateException(\"Account is not active\");\n        }\n\n        BigDecimal amount = txn.getAmount();\n\n        switch (txn.getTransactionType()) {\n            case \"CREDIT\" -> account.setBalance(\n                account.getBalance().add(amount));\n            case \"DEBIT\" -> {\n                if (account.getBalance().compareTo(amount) < 0) {\n                    throw new IllegalStateException(\n                        \"Insufficient funds\");\n                }\n                account.setBalance(\n                    account.getBalance().subtract(amount));\n            }\n            default -> throw new IllegalStateException(\n                \"Unknown transaction type: \"\n                + txn.getTransactionType());\n        }\n\n        account.setLastTransactionDate(LocalDateTime.now());\n        accountRepository.save(account);\n\n        txn.setStatus(\"COMPLETED\");\n        txn.setProcessedAt(LocalDateTime.now());\n        txn.setBalanceAfter(account.getBalance());\n        transactionRepository.save(txn);\n    }\n}",
        "confidenceScores": [
          {"block": "EVALUATE TRUE → switch expression", "score": 95, "lines": "39-55"},
          {"block": "COMP-3 arithmetic → BigDecimal ops", "score": 97, "lines": "42-49"},
          {"block": "PERFORM UNTIL EOF → List iteration", "score": 96, "lines": "25-31"},
          {"block": "Insufficient funds check", "score": 93, "lines": "44-51"},
          {"block": "AUDIT-TRAIL → transaction save", "score": 91, "lines": "56-63"}
        ],
        "businessRules": [
          {"id": "BR-009", "description": "CREDIT transactions add to balance, DEBIT transactions subtract", "source": "EVALUATE TRUE WHEN TXN-CREDITO/TXN-DEBITO", "target": "switch on transactionType", "confidence": 98},
          {"id": "BR-010", "description": "Debit fails if balance is less than transaction amount", "source": "IF WS-ACCT-BALANCE >= WS-TXN-IMPORTO", "target": "balance.compareTo(amount) < 0 → throw", "confidence": 97},
          {"id": "BR-011", "description": "Each transaction must update audit trail after processing", "source": "PERFORM AGGIORNA-AUDIT-TRAIL", "target": "transactionRepository.save(txn) with status+timestamp", "confidence": 94},
          {"id": "BR-012", "description": "Failed transactions must be marked with error status", "source": "MOVE ''FAILED'' TO WS-TXN-STATUS", "target": "txn.setStatus(\"FAILED\")", "confidence": 99}
        ],
        "explanations": [
          "EVALUATE TRUE with 88-level conditions maps to Java switch expression with String patterns",
          "COMP-3 packed decimal arithmetic uses BigDecimal.add() / .subtract() for exact precision",
          "The PERFORM UNTIL EOF loop over sequential file becomes iteration over JPA query results",
          "Error handling: COBOL IF/ELSE + MOVE status replaced by Java try-catch with exception propagation",
          "Audit trail PERFORM becomes explicit save of Transaction entity with timestamp"
        ],
        "reasonings": [
          "This was the highest-complexity file (cyclomatic: 28). The Java switch expression provides cleaner control flow than the EVALUATE TRUE pattern while preserving identical business logic.",
          "Exception-based error handling was chosen over return codes because it integrates with Spring @Transactional rollback on failure.",
          "The insufficient funds check preserves the exact same comparison as COBOL: balance >= amount (not >)."
        ]
      },
      {
        "id": "f5",
        "sourceFile": "src/ACCTCLSE.cbl",
        "targetFile": "src/main/java/com/secb/service/AccountCloseService.java",
        "sourceLangId": "cobol",
        "targetLangId": "java",
        "confidence": 98.1,
        "linesSource": 32,
        "linesTarget": 42,
        "sourceCode": "      ******************************************************************\n      * PROGRAMMA:    ACCTCLSE                                         *\n      * DESCRIZIONE:  Chiusura conti correnti con validazione saldo    *\n      ******************************************************************\n       IDENTIFICATION DIVISION.\n       PROGRAM-ID. ACCTCLSE.\n\n       DATA DIVISION.\n       WORKING-STORAGE SECTION.\n       01  WS-CLOSE-DATA.\n           05  WS-CLOSE-ACCT-NUM  PIC X(10).\n           05  WS-CLOSE-BALANCE   PIC S9(9)V99 COMP-3.\n           05  WS-CLOSE-STATUS    PIC X(1).\n               88  CHIUSURA-OK    VALUE ''Y''.\n               88  CHIUSURA-NO    VALUE ''N''.\n\n       PROCEDURE DIVISION.\n       CHIUDI-CONTO.\n           PERFORM LEGGI-RICHIESTE-CHIUSURA\n           PERFORM VALIDA-CHIUSURA\n           IF CHIUSURA-OK\n               MOVE ''CLOSED'' TO WS-ACCT-STATUS\n               MOVE FUNCTION CURRENT-DATE TO WS-DATA-CHIUSURA\n               PERFORM AGGIORNA-RECORD\n               DISPLAY ''Conto chiuso: '' WS-CLOSE-ACCT-NUM\n           ELSE\n               DISPLAY ''Impossibile chiudere: saldo residuo ''\n                   WS-CLOSE-BALANCE\n           END-IF\n           GOBACK.\n\n       VALIDA-CHIUSURA.\n           IF WS-CLOSE-BALANCE = ZEROS\n               SET CHIUSURA-OK TO TRUE\n           ELSE\n               SET CHIUSURA-NO TO TRUE\n           END-IF.",
        "targetCode": "package com.secb.service;\n\nimport com.secb.model.Account;\nimport com.secb.repository.AccountRepository;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\nimport org.springframework.transaction.annotation.Transactional;\n\nimport java.math.BigDecimal;\nimport java.time.LocalDate;\n\n/**\n * ACCTCLSE — Account Closure Service.\n * Handles account closure requests with balance validation.\n * @migrated-from ACCTCLSE.cbl\n */\n@Slf4j\n@Service\n@RequiredArgsConstructor\npublic class AccountCloseService {\n\n    private final AccountRepository accountRepository;\n\n    @Transactional\n    public void process() {\n        log.info(\"Processing account closures\");\n        var closing = accountRepository\n            .findByStatus(\"PENDING_CLOSE\");\n\n        for (Account account : closing) {\n            if (account.getBalance()\n                    .compareTo(BigDecimal.ZERO) == 0) {\n                account.setStatus(\"CLOSED\");\n                account.setCloseDate(LocalDate.now());\n                accountRepository.save(account);\n                log.info(\"Account {} closed\",\n                    account.getAccountNumber());\n            } else {\n                log.warn(\n                    \"Account {} has remaining balance {}, cannot close\",\n                    account.getAccountNumber(),\n                    account.getBalance());\n            }\n        }\n    }\n}",
        "confidenceScores": [
          {"block": "88-level CHIUSURA-OK/NO → compareTo check", "score": 99, "lines": "31-35"},
          {"block": "MOVE CLOSED → setStatus", "score": 99, "lines": "22-24"},
          {"block": "Balance zero validation", "score": 98, "lines": "31-35"}
        ],
        "businessRules": [
          {"id": "BR-013", "description": "Account can only be closed if balance is exactly zero", "source": "IF WS-CLOSE-BALANCE = ZEROS", "target": "balance.compareTo(BigDecimal.ZERO) == 0", "confidence": 99},
          {"id": "BR-014", "description": "Closure date is set to current date", "source": "MOVE FUNCTION CURRENT-DATE TO WS-DATA-CHIUSURA", "target": "setCloseDate(LocalDate.now())", "confidence": 99}
        ],
        "explanations": [
          "Simple program with clear validation logic — high confidence translation",
          "88-level condition CHIUSURA-OK mapped to BigDecimal.compareTo(ZERO) == 0",
          "MOVE ''CLOSED'' becomes setStatus(\"CLOSED\") — direct semantic mapping"
        ],
        "reasonings": [
          "This was the lowest-complexity file, allowing a very straightforward 1:1 mapping with minimal architectural decisions needed."
        ]
      },
      {
        "id": "f6",
        "sourceFile": "src/ACCTREPT.cbl",
        "targetFile": "src/main/java/com/secb/service/AccountReportService.java",
        "sourceLangId": "cobol",
        "targetLangId": "java",
        "confidence": 96.0,
        "linesSource": 45,
        "linesTarget": 35,
        "sourceCode": "      ******************************************************************\n      * PROGRAMMA:    ACCTREPT                                         *\n      * DESCRIZIONE:  Generazione report giornalieri e mensili         *\n      ******************************************************************\n       IDENTIFICATION DIVISION.\n       PROGRAM-ID. ACCTREPT.\n\n       DATA DIVISION.\n       WORKING-STORAGE SECTION.\n       01  WS-REPORT-DATA.\n           05  WS-RPT-DATE        PIC X(10).\n           05  WS-RPT-CONTI-ATT   PIC 9(8) COMP VALUE 0.\n           05  WS-RPT-TXN-OGGI    PIC 9(8) COMP VALUE 0.\n           05  WS-RPT-TOT-SALDI   PIC S9(13)V99 COMP-3.\n           05  WS-RPT-MEDIA-SALDO PIC S9(9)V99 COMP-3.\n       01  WS-PRINT-LINE.\n           05  FILLER             PIC X(40).\n           05  WS-PRT-VALUE       PIC Z(8)9.\n\n       PROCEDURE DIVISION.\n       GENERA-REPORT.\n           PERFORM CALCOLA-STATISTICHE\n           PERFORM STAMPA-INTESTAZIONE\n           PERFORM STAMPA-DETTAGLIO\n           PERFORM STAMPA-TOTALI\n           GOBACK.\n\n       CALCOLA-STATISTICHE.\n           OPEN INPUT ACCOUNT-FILE\n           PERFORM UNTIL WS-EOF\n               READ ACCOUNT-FILE INTO WS-ACCOUNT-REC\n               ADD 1 TO WS-RPT-CONTI-ATT\n               ADD WS-ACCT-BALANCE TO WS-RPT-TOT-SALDI\n           END-PERFORM\n           IF WS-RPT-CONTI-ATT > 0\n               DIVIDE WS-RPT-TOT-SALDI BY WS-RPT-CONTI-ATT\n                   GIVING WS-RPT-MEDIA-SALDO\n           END-IF\n           CLOSE ACCOUNT-FILE.\n\n       STAMPA-INTESTAZIONE.\n           DISPLAY ''=== SECB Report Giornaliero ===''.\n\n       STAMPA-DETTAGLIO.\n           DISPLAY ''Conti attivi: '' WS-RPT-CONTI-ATT\n           DISPLAY ''Transazioni oggi: '' WS-RPT-TXN-OGGI.\n\n       STAMPA-TOTALI.\n           DISPLAY ''Totale saldi: '' WS-RPT-TOT-SALDI\n           DISPLAY ''Media saldo: '' WS-RPT-MEDIA-SALDO\n           DISPLAY ''Report completato''.",
        "targetCode": "package com.secb.service;\n\nimport com.secb.repository.AccountRepository;\nimport com.secb.repository.TransactionRepository;\nimport lombok.RequiredArgsConstructor;\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype.Service;\n\n/**\n * ACCTREPT — Account Report Service.\n * Generates daily and monthly reports.\n * @migrated-from ACCTREPT.cbl\n */\n@Slf4j\n@Service\n@RequiredArgsConstructor\npublic class AccountReportService {\n\n    private final AccountRepository accountRepository;\n    private final TransactionRepository transactionRepository;\n\n    public void process() {\n        log.info(\"Generating daily report\");\n        long activeAccounts = accountRepository\n            .countByStatus(\"ACTIVE\");\n        long todayTransactions = transactionRepository\n            .countTodayTransactions();\n\n        log.info(\"=== SECB Daily Report ===\");\n        log.info(\"Active accounts: {}\", activeAccounts);\n        log.info(\"Transactions today: {}\", todayTransactions);\n        log.info(\"Report generation complete\");\n    }\n}",
        "confidenceScores": [
          {"block": "DISPLAY statements → SLF4J log.info", "score": 97, "lines": "38-47"},
          {"block": "COMPUTE statistics → JPA count queries", "score": 95, "lines": "27-36"},
          {"block": "PERFORM structure → single method", "score": 98, "lines": "21-25"}
        ],
        "businessRules": [
          {"id": "BR-015", "description": "Daily report must show active account count", "source": "DISPLAY ''Conti attivi:'' WS-RPT-CONTI-ATT", "target": "log.info(\"Active accounts: {}\", activeAccounts)", "confidence": 98},
          {"id": "BR-016", "description": "Daily report must show today''s transaction count", "source": "WS-RPT-TXN-OGGI", "target": "countTodayTransactions()", "confidence": 97}
        ],
        "explanations": [
          "DISPLAY statements converted to structured SLF4J logging with parameterized messages",
          "Manual file-based statistics computation replaced by JPA count/aggregate queries",
          "Multiple PERFORM paragraphs collapsed into a single clean method — the report structure is simpler in Java"
        ],
        "reasonings": [
          "SLF4J logging replaces DISPLAY because it provides configurable output (file, console, aggregation) without changing code.",
          "JPA aggregate queries are more efficient than the COBOL pattern of reading every record and accumulating counters."
        ]
      }
    ],
    "artifacts": {
      "unitTest": "package com.secb;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.BeforeEach;\nimport org.junit.jupiter.api.DisplayName;\nimport static org.junit.jupiter.api.Assertions.*;\nimport static org.mockito.Mockito.*;\n\n@DisplayName(\"AccountMainService Tests\")\nclass AccountMainServiceTest {\n\n    private AccountBalanceService balanceService;\n    private AccountOpenService openService;\n    private AccountProcessingService processingService;\n    private AccountReportService reportService;\n    private AccountMainService mainService;\n\n    @BeforeEach\n    void setUp() {\n        balanceService = mock(AccountBalanceService.class);\n        openService = mock(AccountOpenService.class);\n        processingService = mock(AccountProcessingService.class);\n        reportService = mock(AccountReportService.class);\n        mainService = new AccountMainService(\n            balanceService, openService, processingService, reportService);\n    }\n\n    @Test\n    @DisplayName(\"Daily processing executes all services in order\")\n    void testDailyProcessingOrder() {\n        mainService.run();\n        var order = inOrder(balanceService, openService, processingService, reportService);\n        order.verify(balanceService).process();\n        order.verify(openService).process();\n        order.verify(processingService).process();\n        order.verify(reportService).process();\n    }\n\n    @Test\n    @DisplayName(\"Processing completes without exceptions\")\n    void testProcessingCompletes() {\n        assertDoesNotThrow(() -> mainService.run());\n    }\n}",
      "integrationTest": "package com.secb;\n\nimport org.junit.jupiter.api.Test;\nimport org.junit.jupiter.api.DisplayName;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.boot.test.context.SpringBootTest;\nimport org.springframework.test.context.ActiveProfiles;\nimport static org.junit.jupiter.api.Assertions.*;\n\n@SpringBootTest\n@ActiveProfiles(\"test\")\n@DisplayName(\"SECB Integration Tests\")\nclass SecbIntegrationTest {\n\n    @Autowired\n    private AccountMainService mainService;\n\n    @Autowired\n    private AccountBalanceService balanceService;\n\n    @Test\n    @DisplayName(\"Spring context loads with all services\")\n    void contextLoads() {\n        assertNotNull(mainService);\n        assertNotNull(balanceService);\n    }\n\n    @Test\n    @DisplayName(\"Full daily processing cycle completes\")\n    void testFullCycle() {\n        assertDoesNotThrow(() -> mainService.run());\n    }\n}",
      "uiTest": "// No UI tests applicable — backend batch processing service.\n// API endpoint tests added when REST controllers are implemented.",
      "documentation": "# SECB Banking System — Migration Documentation\n\n## Overview\nThe SECB (Sistema Elaborazione Conti Bancari) system has been migrated from COBOL-85 to Java 22 with Spring Boot 3.2.\n\n## Architecture\n- **AccountMainService** — Main orchestrator (was ACCTMAIN)\n- **AccountBalanceService** — Balance calculations (was ACCTBAL)\n- **AccountOpenService** — Account opening (was ACCTOPEN)\n- **AccountCloseService** — Account closure (was ACCTCLSE)\n- **AccountProcessingService** — Transaction processing (was ACCTPROC)\n- **AccountReportService** — Report generation (was ACCTREPT)\n\n## Key Mappings\n| COBOL | Java |\n|-------|------|\n| CALL statement | @Autowired service |\n| WORKING-STORAGE | Instance fields |\n| PERFORM | Method call |\n| PIC 9(n)V99 | BigDecimal |\n| FILE-CONTROL | JPA Repository |\n\n## Testing\n- 147 unit tests (JUnit 5 + Mockito)\n- 42 integration tests (SpringBootTest)\n- 91.4% code coverage",
      "unitTestStats": {"cases": 147, "passed": 145, "failed": 2, "coverage": 91.4},
      "integrationTestStats": {"cases": 42, "passed": 41, "failed": 1, "coverage": 78.2},
      "uiTestStats": {"cases": 0, "passed": 0, "failed": 0, "coverage": 0},
      "docStats": {"pages": 12, "sections": 38, "apiEndpoints": 0},
      "archStats": {"services": 6, "repositories": 4, "controllers": 0, "configurations": 3}
    }
  }'::jsonb
)
WHERE id = 'proj-demo-full';
