SENTINEL/i is a personal-lines (auto + property) insurance core system: party/producer
masters, policy administration across the full lifecycle (issue → endorse → renew → cancel),
risk/coverage items with rating-driven underwriting, installment billing and oldest-due-first cash
application, a claims workflow (FNOL → adjudication → payment), agent commissions, and a
balanced GL posting feed cross-checked debits=credits. It is a classic AS/400-native application:
column-exact DDS physical/logical/display/printer files, RPG (fixed-form C-spec and /free),
one ILE COBOL program, CL build and night-batch drivers, DB2 for i (one RUNSQLSTM table +
embedded SQL), 5250 WORKSTN screens (plain and SFL/SFLCTL subfile), PRTF spool, and journaling. Business
rules live in the RPG/COBOL programs themselves; there is no SQL-PL layer. This manual is the reference
for the operator who runs the screens and the night batch, and for the developer maintaining the
application. It is grounded entirely in the committed source (insurance2-app/src/sources.mjs,
src/seed.mjs, PLAN.md, and the test/sentinel_*.mjs drivers).
Everything runs in library SENTINEL.
SENTINEL/i administers one coherent line of business — personal auto and property insurance — end to end:
PARTYMS) and producer
(PRODMS) masters, a create/change/inquire maintenance path (PARTYMNT), and
a callable underwriting subprogram (UWCHK) that applies an age-band rating factor from
RATETB and hard-declines on excessive prior claims.POLBIND, which CALLs UWCHK to rate),
mid-term endorsement (POLENDT), renewal (POLRENEW), and cancellation
(POLCANCL). Each writes an immutable, journaled POLLOG transaction
row (LOGTYPE I / E / R / C) — the core-system audit trail.RISKMS, keyed
POLICYNO+RISKCD), each with a limit, deductible and premium.BILLRUN), oldest-due-first partial-pay-aware cash application (CASHAPP),
and an aged-receivables PRTF report (AGERUN).CLMOPEN) → adjudication
(CLMADJ, approve/cap the reserve against the covering coverage limit) → payment
(CLMPAYP, limit-checked, with a balanced GL pair).COMMRUN) and a
consolidated, self-balancing GL posting feed (GLRUN) that COMMITs only when
debits=credits.POLSUM2) that cross-checks inforce premium against the GL written-premium feed.Unlike a SQL-PL-centric design, SENTINEL/i keeps its business rules in the RPG and COBOL programs
themselves. There is no stored-procedure layer: rating math is in UWCHK, the payment
waterfall/aging/pro-rata math is in the RPG programs, and DB2 for i appears only as (1) one
RUNSQLSTM-created table, GLPOST2, the GL posting feed, and (2) embedded
EXEC SQL INSERT/SELECT/COMMIT/ROLLBACK in the three GL-touching programs
(COMMRUN, CLMPAYP, GLRUN) and the COBOL cross-check
(POLSUM2). All other I/O is native record-level access (CHAIN / READ / WRITE / UPDATE) over
DDS files.
The system is deliberately built as a broad platform-stress workload: it exercises DDS PFs/LFs,
keyed and arrival I/O, fixed-form and free-form RPG, program-to-program CALL (POLBIND→UWCHK),
an ILE COBOL + DB2 bridge, CL build and night-batch drivers, three DSPF screens (plain + subfile + menu),
a PRTF spool, journaling with a receiver roll, and commitment-controlled posting with a balanced control
total. All objects live in one library, SENTINEL.
SETUP / ISSUANCE ONLINE (5250) NIGHT BATCH (SNNIGHT, SBMJOB)
---------------- ------------- -----------------------------
SNSETUP (build+jrnl) MAINMENU (menu) STRCMTCTL LCKLVL(*CHG)
REFLD (seed rates, opt 1 -> POLVIEW BILLRUN (installments)
parties, prod) (POLSCRN, plain) CASHAPP (apply receipts)
POLBIND --CALL--> UWCHK opt 2 -> CLMVIEW COMMRUN (commission + GL)
(issue, journal 'I') (CLMSCRN, SFL/SFLCTL) CLMPAYP (claim pay + GL)
POLENDT/POLRENEW/POLCANCL GLRUN (premium GL, balance
(endorse/renew/cancel, \ / gate: COMMIT/ROLLBACK)
journal E/R/C) \ / ENDCMTCTL
CLMOPEN -> CLMADJ v v
(FNOL, adjudicate) POLICYMS / RISKMS / CLAIMMS / INSTMS ... SNJRN (journals POLLOG)
|
REPORTING +--> POLLOG (journaled txn/audit log: I/E/R/C)
AGERUN (PRTF spool) +--> GLPOST2 (DB2 GL feed: batch 10 prem, 20 claim, 30 comm)
POLSUM2 (COBOL+SQL x-check)
A single business event — say, issuing a policy — flows: REFLD seeds and
closes the rate/party/producer reference data → POLBIND CALLs
UWCHK for the rated premium → writes the POLICYMS header, its
RISKMS coverage rows, and a journaled POLLOG ‘I’ row → the
SNJRN journal captures the POLLOG write. Downstream, the night SNNIGHT chain
bills, applies cash, commissions, pays claims and posts a balanced GL under commitment control.
| Object | Type | Role |
|---|---|---|
| PARTYMS | PF | Party/insured master. |
| PRODMS | PF | Producer (agency) master with commission rate. |
| POLICYMS | PF | Policy header (the heart of the app). |
| POLLOG | PF (journaled) | Immutable policy transaction/audit log. |
| RISKMS | PF | Coverage/risk items (N per policy). |
| RATETB | PF | Underwriting rating-factor table. |
| INSTMS | PF | Billing installment schedule. |
| RCPTMS | PF (arrival) | Cash receipts. |
| CLAIMMS | PF | Claim header. |
| CLMLINE | PF (arrival) | Claim reserve/adjudication/payment lines. |
| COMMMS | PF | Commission line per bound transaction. |
| POLLOGLV / RISKLV / AGEDLV / CLMLINLV | LF (4) | Logical views (history / risks / aging / claim lines). |
| GLPOST2 | DB2 table | GL posting feed (RUNSQLSTM, not an objfs *FILE). |
| POLSCRN / CLMSCRN / MAINMNU | DSPF (3) | Policy inquiry / claim inquiry (subfile) / menu. |
| POLREGP2 | PRTF | Aged-receivables printer file. |
| UWCHK | RPGLE | Callable underwriting/rating subprogram. |
| REFLD | RPGLE | Reference/master seed loader. |
| POLBIND / POLENDT / POLRENEW / POLCANCL | RPGLE (4) | Policy lifecycle drivers. |
| PARTYMNT | RPGLE | Party master maintenance. |
| BILLRUN / CASHAPP / AGERUN | RPGLE (3) | Billing / cash / aging. |
| CLMOPEN / CLMADJ | RPGLE (2) | FNOL / adjudication. |
| CLMPAYP / COMMRUN / GLRUN | SQLRPGLE (3) | GL-posting programs (embedded SQL). |
| POLVIEW / CLMVIEW / MAINMENU | RPGLE (3) | Interactive 5250 programs. |
| POLSUM2 | CBLLE | ILE COBOL portfolio summary + DB2 cross-check. |
| SNSETUP / SNNIGHT | CLP (2) | Build+journal / night-batch chain drivers. |
| SNJRN / SNJRNR | *JRN / *JRNRCV | Journal + receiver for POLLOG. |
The catalogue is 11 PFs + 4 LFs + 1 DB2 table, 3 DSPF + 1 PRTF, 19 RPG/COBOL programs, 2 CL programs, and 1 journal/receiver pair. Sections D and F expand each.
SENTINEL/i has no CICS transaction identifiers and no transid switch. On IBM i, each program is
reached by name from a 5250 command-entry line (or a JOBQ/scheduler for the batch jobs). The
operator equivalent of “type a transid and Enter” is “type a CALL command
and Enter”. Before invoking anything, the job's library list must include SENTINEL —
the tested jobs run with LIBL = QSYS QGPL SENTINEL QTEMP and CURLIB = SENTINEL.
| To do this | Type on the command line |
|---|---|
| Open the operator menu (routes to the inquiries) | CALL SENTINEL/MAINMENU |
| Open the policy inquiry directly | CALL SENTINEL/POLVIEW |
| Open the claim inquiry (subfile) directly | CALL SENTINEL/CLMVIEW |
| Build/compile everything + arm journaling | CALL SENTINEL/SNSETUP (once, at install) |
| Seed reference/master data | CALL SENTINEL/REFLD |
| Issue the day's policies (calls UWCHK) | CALL SENTINEL/POLBIND |
| Party master maintenance (add/change/inquire) | CALL SENTINEL/PARTYMNT PARM('A' 'IN0009' 'name') |
| Run the night batch chain | SBMJOB CMD(CALL SENTINEL/SNNIGHT) JOBQ(SENTINEL/NITEQ) |
POLBIND
issues two specific policies (AUTO0001, PROP0001) with literal DOBs, premiums and
dates; POLENDT/POLCANCL act on literal policy numbers; POLRENEW's
renewal window is the literal EXPDT ≤ 20270101; billing/claim dates are literals in the
source. There is no run-date control table (contrast the LOANSVC/i LNCTL model). Only
PARTYMNT takes CALL parameters (a 1-char action code + party number + name). This is a
demonstration/stress workload; a production build would parameterise these.Three DSPF programs are interactive. MAINMENU (format MENUFMT over
MAINMNU) is the entry point: it prompts for a 1-char option and routes via a classic,
indicator-conditioned dynamic CALL — option 1 CALLs POLVIEW, option
2 CALLs CLMVIEW. Any other value redisplays with Invalid option.
F3 exits.
A non-subfile screen: key a policy number, Enter, and it CHAINs
POLICYMS and displays the header (insured party, line of business, status, annual premium,
balance) plus up to four risk/coverage lines read from the RISKLV logical (the
program loads at most 4 fixed slots, DRISK1–DRISK4). A not-found key shows
Policy not found:. The loop re-displays until F3.
The one subfile screen. Key a claim number, Enter: it CHAINs
CLAIMMS for the header (policy, loss date, cause, status, total reserved/paid), then loads a
subfile (DDS record CLMSFL under control record CLMCTL,
SFLPAG(0010), SFLSIZ(0020)) from the CLMLINLV logical — one
row per claim line (reserve R, adjudication A, payment P) with its
date, type and amount. The screen uses the standard indicator set *IN31=SFLDSP,
*IN32=SFLDSPCTL, *IN33=SFLCLR, *IN34=SFLEND(*MORE).
CLMSCRN, the CLMCTL column-header literals Date/Type/Amount
are placed at row 7 cols 4/14/18 — the identical coordinates as the CLMSFL subfile
record's first displayed row (SLINEDT/SLINETYP/SLINEAMT). On a real
5250 the header line and the first subfile row overlap (e.g. the “Type” header and a row's
“R” collapse to Rype). Authentic IBM i hardware reproduces this identically given
this DDS; the fix would be to move the headers to row 6 or start the SFL at row 8. Documented in
PLAN.md §6 (SIM-2026-D5). Operationally the data is correct; only the header row renders
overlapped.CA03(03) on every format; sets
*IN03 and the program's dow *in03 = *off loop ends, returning to the
caller (MAINMENU, or the command line).auto0001
does not match AUTO0001 (confirmed in PLAN.md §6).Honest statement: SENTINEL/i does not model a true four-eyes maker–checker /
separate-authorization workflow. There is no “one user enters, a second approves” gate: a
policy issued by POLBIND is inforce immediately; a claim adjudicated by CLMADJ
moves O→A in one program; a payment posted by CLMPAYP is applied at once.
Even the two 5250 screens (POLVIEW, CLMVIEW) are inquiry-only — they
read and display, they do not update. All state change happens in the batch/driver programs. The control
model the application does have:
POLLOG row
(LOGTYPE I issue / E endorse / R renew / C cancel)
carrying the amount or delta. POLLOG is journaled to SNJRN with
IMAGES(*BOTH) (see F.3), so even a direct UPDATE captures before/after images. A full
lifecycle leaves the history I,I,E,R,R,C (verified by sentinel_lifecycle.mjs).CLMLINE row (R/A/P), aggregated per claim through
the CLMLINLV logical — a complete, reconstructable claim history.UWCHK hard-declines when prior claims > 3;
CLMADJ caps a reserve at the covering RISKMS coverage limit;
CLMPAYP rejects a payment that would exceed RLIMIT − TOTPAY (remaining
limit); BILLRUN is idempotent (a dup-key CHAIN skips already-billed policies).STRCMTCTL LCKLVL(*CHG);
GLRUN EXEC SQL COMMITs the GL unit-of-work only when
SUM(DR)=SUM(CR), else ROLLBACK. POLSUM2 independently
cross-checks inforce premium against the GL written-premium feed.In sum, the control posture is immutable journaled audit + business-rule/limit gating + a balanced GL control total, rather than a segregation-of-duties approval workflow.
SENTINEL/i's batch work centres on one night chain, SNNIGHT, submitted as a single
SBMJOB onto a job queue and run under commitment control. Around it sit the on-demand lifecycle drivers
(issue/endorse/renew/cancel) and the two reporting programs. Because the programs carry hard-coded work
data (see B.1), a run is a bare CALL/SBMJOB with no run-date parameter.
-- install once: build all objects + arm journaling on POLLOG CRTCLPGM PGM(SENTINEL/SNSETUP) SRCFILE(SENTINEL/QCLSRC) SRCMBR(SNSETUP) CALL PGM(SENTINEL/SNSETUP) -- seed reference/master data, then issue the day's policies CALL PGM(SENTINEL/REFLD) CALL PGM(SENTINEL/POLBIND) -- submit the night chain onto a job queue (runs BILLRUN..GLRUN under STRCMTCTL) CRTJOBQ JOBQ(SENTINEL/NITEQ) TEXT('SENTINEL night batch queue') SBMJOB CMD(CALL SENTINEL/SNNIGHT) JOB(SNNITE) JOBQ(SENTINEL/NITEQ) HOLD(*NO)
| Program | Purpose | Files / calls | Outputs | Frequency |
|---|---|---|---|---|
| REFLD | Seed rate table, insured parties, producer; runs to completion so its rows are visible to UWCHK. | RATETB / PARTYMS / PRODMS (all O-A). | 3 rate bands (YNG 1.250, STD 1.000, SNR 0.900), 2 parties, 1 producer (AG01 @10%); DSPLY. | Install / on demand. |
| POLBIND | Issue the day's policies; CALLs UWCHK to rate the premium. | POLICYMS/RISKMS/POLLOG (O-A); CALLP UWCHK. | 2 inforce policies (AUTO0001 1200.00 std, PROP0001 1620.00 senior), 3 risk rows, 2 journaled 'I' POLLOG rows. | Per issuance run. |
| POLENDT | Mid-term endorsement: raise a coverage limit, re-rate the header by a delta. | POLICYMS/RISKMS (UF); POLLOG (O-A). | AUTO0001 PD limit +25000.00, ANNPREM +150.00 (1200→1350.00); journaled 'E' row (LOGAMT 150.00). | On demand. |
| POLRENEW | Renewal sweep: roll term +1yr, apply 5% load for inforce policies in the window. | POLICYMS (UF-A); POLLOG (O-A). | EXPDT +10000, ANNPREM ×1.05; journaled 'R' row per policy; DSPLY POLRENEW RENEWED=n. |
Renewal cycle. |
| POLCANCL | Cancellation: pro-rata unearned credit, POLSTAT→C. | POLICYMS (UF); POLLOG (O-A). | PROP0001 → STAT C, POLBAL=earned half; journaled 'C' row with NEGATIVE unearned credit. | On demand. |
| PARTYMNT | Party master maintenance (add/change/inquire) by 1-char action code. | PARTYMS (UF-A). | ADDED / CHANGED / INQ / NOTFOUND / DUP / BADACT DSPLY per action. | On demand. |
| BILLRUN | Idempotent quarterly installment generation (4 per inforce policy). | POLICYMS (IF); INSTMS (UF-A); dup-check CHAIN. | 8 installments (ANNPREM/4, remainder on inst 4); rerun skips (dup-key); DSPLY GENERATED=/SKIPPED=. |
Night chain (step 1). |
| CASHAPP | Apply RCPTMS receipts oldest-due-first, partial-pay aware; decrement POLBAL. | RCPTMS (IF arrival); INSTMS/POLICYMS (UF). | Inst ISTAT O→D (partial) / →P (full); POLBAL reduced by applied cash; DSPLY FULL=/PART=/NONE=. |
Night chain (step 2). |
| COMMRUN | Commission per bound 'I' POLLOG row; write COMMMS + balanced GL pair. | POLLOG/POLICYMS/PRODMS (IF); COMMMS (O-A); EXEC SQL GLPOST2. | Commission = LOGAMT×COMMPCT/100 (120.00 + 162.00 = 282.00); GL batch 30 DR/CR pair. | Night chain (step 3). |
| CLMPAYP | Post a claim payment within remaining limit; update TOTPAY; GL pair. | CLAIMMS (UF); RISKMS (IF); CLMLINE (O-A); EXEC SQL GLPOST2. | 'P' line 3000.00, TOTPAY→3000.00; GL batch 20 claim-expense DR / cash CR pair. | Night chain (step 4). |
| GLRUN | Post premium DR/CR per 'I' POLLOG row, then balance-gate the whole feed. | POLLOG (IF); EXEC SQL GLPOST2 + SUM + COMMIT/ROLLBACK. | GL batch 10 (premrec DR / written-prem CR, 2820.00); DSPLY IN BALANCE/OUT OF BALANCE. |
Night chain (step 5). |
| CLMOPEN / CLMADJ | FNOL intake / adjudication (approve+cap reserve vs coverage limit). | CLAIMMS (O-A/UF); RISKMS (IF); CLMLINE (O-A). | CLM00001 opened (reserve 5000.00, 'R' line); CLSTAT O→A, 'A' memo line. | Intraday / on demand. |
| AGERUN | Aging pass over AGEDLV (by due date); spooled aged-receivables report. | AGEDLV (IF); POLREGP2 (PRINTER). | PRTF spool (banner + detail + total); bucket PAID/PARTIAL/OPEN; DSPLY LINES=/OPEN=. |
Reporting / on demand. |
| POLSUM2 | ILE COBOL portfolio summary + DB2 cross-check. | POLICYMS (indexed FD, COMP-3); EXEC SQL GLPOST2. | Inforce count + premium; SUM of written-premium GL credits; IN BALANCE/OUT OF BALANCE. |
Reporting / on demand. |
SNNIGHT is a CL program that runs the five posting programs in one commitment boundary:
SNNIGHT (CL): STRCMTCTL LCKLVL(*CHG) MONMSG MSGID(SFF0000) CALL PGM(SENTINEL/BILLRUN) generate installments CALL PGM(SENTINEL/CASHAPP) apply receipts, reduce POLBAL CALL PGM(SENTINEL/COMMRUN) commission + GL batch 30 CALL PGM(SENTINEL/CLMPAYP) claim payment + GL batch 20 CALL PGM(SENTINEL/GLRUN) premium GL batch 10 + balance gate ENDCMTCTL
The three GL-touching programs' EXEC SQL INSERTs are staged inside the commit boundary;
GLRUN makes the final decision — COMMIT if the whole feed balances,
ROLLBACK otherwise. In the reference day the feed balances at DR = CR = 6102.00
(premium 2820.00 + claim 3000.00 + commission 282.00, each posted as a balanced pair), and the premium
batch (10) credit total persists at exactly 2820.00 post-COMMIT.
Expected DSPLY highlights across the chain:
BILLRUN GENERATED=2 SKIPPED=0
CASHAPP FULL=1 PART=1 NONE=0
COMMRUN ROWS=2 TOTAL=282.00
CLMPAYP PAID 3000.00
GLRUN IN BALANCE DR=6102.00 CR=6102.00
RATETB only sees rows written by a program
that has closed the file. REFLD seeds and ends (closing RATETB) so
POLBIND→UWCHK rates against real bands; seeding inline in POLBIND would
leave the CHAIN unsatisfied (factor defaults to 1.000). See F.4 and PLAN.md §6.BILLRUN bills only inforce policies,
COMMRUN/GLRUN post only against POLLOG 'I' rows, so policies
must be issued first.CLMOPEN → CLMADJ → CLMPAYP
— the payment posts against an approved, limit-checked claim.All files are in library SENTINEL, defined by column-exact DDS in sources.mjs.
Dates are stored as signed zoned 8S 0 in YYYYMMDD form; money is packed
9P 2 (or wider for GL); rating factors are packed 5P 3. UNIQUE-keyed PFs are the
masters; three PFs (POLLOG, RCPTMS, CLMLINE) are effectively arrival
logs keyed by a generated sequence.
Status-code legend: POLSTAT I=inforce C=cancelled
X=expired; LOGTYPE I=issue E=endorse R=renew
C=cancel; ISTAT O=open D=part-paid P=paid; CLSTAT
O=open A=adjudicated/approved C=closed D=denied;
LINETYP R=reserve A=adjudication P=payment; DRCR D=debit
C=credit.
| Field | Type | Meaning |
|---|---|---|
| PARTNO | 6A | Party number (key), e.g. IN0001. |
| PNAME | 25A | Party name. |
| PADDR / PCITY / PST / PZIP | 20A / 12A / 2A / 5A | Address, city, state, ZIP. |
| PDOB | 8S 0 | Date of birth (YYYYMMDD) — drives UWCHK's age band. |
| Field | Type | Meaning |
|---|---|---|
| PRODNO | 4A | Producer number (key), e.g. AG01. |
| PRODNAME | 20A | Producer name. |
| COMMPCT | 5P 2 | Commission percent (10.00 = 10%), used by COMMRUN. |
| PRSTAT | 1A | Producer status (A active). |
| Field | Type | Meaning |
|---|---|---|
| POLICYNO | 8A | Policy number (key), e.g. AUTO0001. |
| PARTNO | 6A | Insured party. |
| PRODNO | 4A | Producer/agency. |
| LOB | 1A | Line of business (A auto, P property). |
| EFFDT / EXPDT | 8S 0 | Effective / expiry dates (YYYYMMDD). |
| POLSTAT | 1A | Policy status (I inforce, C cancelled, X expired). |
| ANNPREM | 9P 2 | Annual premium (set by UWCHK, adjusted by endorse/renew). |
| POLBAL | 9P 2 | Outstanding policy balance (reduced by CASHAPP). |
| Field | Type | Meaning |
|---|---|---|
| LOGID | 8S 0 | Log sequence number (key). |
| POLICYNO | 8A | Policy the transaction is for. |
| LOGTYPE | 1A | I issue / E endorse / R renew / C cancel. |
| LOGDT | 8S 0 | Transaction date (YYYYMMDD). |
| LOGAMT | 9P 2 | Amount or delta (endorsement delta; cancel carries a NEGATIVE unearned credit). |
| Field | Type | Meaning |
|---|---|---|
| POLICYNO / RISKCD | 8A / 3A | Policy + coverage code (composite key), e.g. BI/PD/DWL. |
| RLIMIT | 9P 2 | Coverage limit (the adjudication/payment ceiling). |
| RDEDUCT | 7P 2 | Deductible. |
| RPREM | 9P 2 | Coverage premium. |
| Field | Type | Meaning |
|---|---|---|
| BANDCD | 3A | Age band (YNG / STD / SNR). |
| RFACTOR | 5P 3 | Multiplier on base premium (1.250 / 1.000 / 0.900). |
| BANDDESC | 20A | Band description. |
| Field | Type | Meaning |
|---|---|---|
| POLICYNO / INSTNO | 8A / 2S 0 | Policy + installment number 1–4 (composite key). |
| DUEDT | 8S 0 | Installment due date. |
| DUEAMT | 9P 2 | Amount due (ANNPREM/4; remainder on installment 4). |
| PAIDAMT | 9P 2 | Amount paid so far. |
| ISTAT | 1A | O open / D part-paid / P paid. |
| Field | Type | Meaning |
|---|---|---|
| RCPTNO | 8S 0 | Receipt number (key). |
| POLICYNO | 8A | Policy the receipt is for. |
| RCPTDT / RCPTAMT | 8S 0 / 9P 2 | Receipt date / amount (applied oldest-due-first by CASHAPP). |
| Field | Type | Meaning |
|---|---|---|
| CLAIMNO | 8A | Claim number (key), e.g. CLM00001. |
| POLICYNO | 8A | Policy the claim is against. |
| LOSSDT / CAUSE | 8S 0 / 20A | Loss date / cause description. |
| CLSTAT | 1A | O open / A adjudicated / C closed / D denied. |
| TOTRSV / TOTPAY | 9P 2 / 9P 2 | Total reserved / total paid. |
| RISKCD | 3A | Covering coverage code (the limit CLMADJ/CLMPAYP check against). |
| Field | Type | Meaning |
|---|---|---|
| LINEID | 8S 0 | Line sequence number (key). |
| CLAIMNO | 8A | Claim the line belongs to. |
| LINEDT / LINEAMT | 8S 0 / 9P 2 | Line date / amount. |
| LINETYP | 1A | R reserve / A adjudication / P payment. |
| Field | Type | Meaning |
|---|---|---|
| PRODNO | 4A | Producer earning the commission. |
| POLICYNO | 8A | Policy the commission is for. |
| LOGID | 8S 0 | Source POLLOG transaction (10001 / 10002). |
| COMMAMT | 9P 2 | Commission amount (LOGAMT × COMMPCT/100). |
| Column | Type | Meaning |
|---|---|---|
| BATCHNO | INTEGER | Posting batch: 10 premium (GLRUN), 20 claim (CLMPAYP), 30 commission (COMMRUN). |
| ACCTNO | CHAR(10) | GL account (e.g. 1200-PREMREC, 4000-WRTNPRM, 4100-CLMEXP, 1000-CASH, 5200-COMMEXP, 2100-COMMPAY). |
| DRCR | CHAR(1) | D debit / C credit. |
| GLAMT | DECIMAL(9,2) | Posting amount. |
| SRCPGM | CHAR(10) | Posting program (GLRUN / CLMPAYP / COMMRUN). |
GLPOST2 is created by RUNSQLSTM and lives
in the DB2/SQL catalogue, not the object filesystem — objExists('SENTINEL','GLPOST2','*FILE')
returns false even though INSERT/SELECT work. Verify it with a real SELECT COUNT(*), not an
object-existence check (PLAN.md §6).| LF | Over | Key | Use |
|---|---|---|---|
| POLLOGLV | POLLOG | POLICYNO+LOGID | Per-policy transaction history. |
| RISKLV | RISKMS | POLICYNO | A policy's coverage lines (POLVIEW). |
| AGEDLV | INSTMS | DUEDT | Aging pass by due date (AGERUN). |
| CLMLINLV | CLMLINE | CLAIMNO+LINEID | A claim's line history (CLMVIEW subfile source). |
CRTLIB SENTINEL, seed the source members, compile the two CL
programs, then CALL SENTINEL/SNSETUP — this creates all PF/LF/DSPF/PRTF objects,
the GLPOST2 DB2 table (RUNSQLSTM), compiles every RPG/COBOL program, and arms journaling
on POLLOG (CRTJRNRCV SNJRNR / CRTJRN SNJRN /
STRJRNPF POLLOG IMAGES(*BOTH)).CALL SENTINEL/REFLD (rates/parties/producer, runs to completion),
then CALL SENTINEL/POLBIND to issue the day's policies (rates via UWCHK, journals 'I').POLENDT), party maintenance
(PARTYMNT), open+adjudicate a claim (CLMOPEN → CLMADJ),
and record cash receipts into RCPTMS.CRTJOBQ SENTINEL/NITEQ) and
SBMJOB CMD(CALL SENTINEL/SNNIGHT) JOBQ(SENTINEL/NITEQ). Wait for the job to reach
OUTQ.CALL SENTINEL/MAINMENU
(option 1 → POLVIEW, option 2 → CLMVIEW). These are read-only.Pre-checks: confirm the job's library list includes SENTINEL; confirm
REFLD ran and closed before POLBIND (otherwise premiums come out at the
default 1.000 factor).
Post-checks after the night chain:
BILLRUN GENERATED=2 SKIPPED=0 on a first run (or SKIPPED=2 on an idempotent rerun); INSTMS holds 8 rows.CASHAPP FULL=1 PART=1 NONE=0; the applied installments flipped ISTAT and POLBAL dropped by the applied cash.COMMRUN ROWS=2 TOTAL=282.00; GLRUN IN BALANCE (never OUT OF BALANCE).SNNITE job reached OUTQ cleanly.CALL SENTINEL/AGERUN, then read the POLREGP2
spooled file. It shows a SENTINEL/i -- Aged Receivables banner, one detail line per
installment with a PAID/PARTIAL/OPEN bucket, and a total line.CALL SENTINEL/POLSUM2. It totals inforce annual premium from
POLICYMS and compares to SUM(GLAMT) of the written-premium GL credits
(BATCHNO=10, DRCR='C'), printing IN BALANCE or OUT OF BALANCE.Reconciling figures (the same ones the focused test suites assert against):
ANNPREM DIV 4 lands on installment 4).SUM(DR) = SUM(CR) = 6102.00 (2820 premium + 3000 claim +
282 commission, each a balanced pair).COMMRUN and
GLRUN read only POLLOG rows with LOGTYPE='I' (original
issuance). Endorsement ('E') and renewal ('R') premium increases earn no
commission and post no written-premium GL, and commission is computed from the historical
LOGAMT, never from the current ANNPREM. Over a period with endorsements/renewals
the GL written-premium stays frozen at the issue total while true inforce premium grows — and
POLSUM2 then correctly reports OUT OF BALANCE (e.g. INFORCE 3118.50 vs GLWRITTEN
2820.00). That is the cross-check doing its job, not a defect (PLAN.md §6, SIM-2026-W2/M3/Y4).| Situation | Behaviour | Action |
|---|---|---|
| UWCHK rated at 1.000 unexpectedly | RATETB CHAIN found nothing — REFLD did not run/close before POLBIND. | Run REFLD to completion first, then re-issue. See F.4. |
| Re-run BILLRUN | Dup-key CHAIN on INSTMS skips already-billed policies. | Idempotent — still exactly 8 installments, no double-billing. |
| Re-run POLRENEW same window | Policies whose EXPDT is now past the cutoff no longer match. | Idempotent — a same-window rerun renews 0 (EXPDT-driven guard). |
| GLRUN finds the feed out of balance | It EXEC SQL ROLLBACKs the whole commit unit and DSPLYs OUT OF BALANCE. | Correct the posting programs' pairs, then re-run under STRCMTCTL. Nothing is left half-posted. |
| CLMPAYP over the coverage limit | Payment exceeds RLIMIT − TOTPAY; rejected with REJECT OVER LIMIT. | No P line, no GL, no TOTPAY change. Re-adjudicate or pay within the remaining limit. |
| SNNIGHT job fails partway | Native file changes (BILLRUN/CASHAPP) persist; the staged GL INSERTs are inside the commit boundary and un-committed until GLRUN. | Re-submit SNNIGHT; BILLRUN is idempotent, and the GL only commits when it balances. |
| PARTYMNT add of an existing party | CHAIN finds it; program DSPLYs DUP and does not overwrite. | Use action C to change, or a new party number. |
POLLOG (with before/after images
under IMAGES(*BOTH)) and every claim movement is an immutable CLMLINE row, any
run's effect is fully reconstructable after the fact via DSPJRN and the logicals.The complete program surface, from sources.mjs. All objects are in library
SENTINEL; source members live in QDDSSRC, QRPGLESRC,
QCBLLESRC, QCLSRC, QSQLSRC.
pClaims > 3 (pOutStat 'D', premium 0).
Otherwise derives an age band from (today − pDob)/10000 (<25 YNG, ≥65 SNR,
else STD), CHAINs RATETB for the factor, and returns pBasePrem × RFACTOR
with pOutStat 'A'. Uses nested if/else (not free-form elseif) — see F.4.callp uwsub(...) to rate, writes the
POLICYMS header, RISKMS coverage rows, and a journaled 'I' POLLOG row per policy.EXPDT ≤ 20270101
rolls EFFDT/EXPDT +1yr (+10000 packed add), applies a 5% load, writes a journaled 'R'
row. Its EXPDT-past-cutoff test makes a same-window rerun renew 0.ANNPREM × 0.500 for a half-term
remaining), sets POLBAL to the earned half, flips POLSTAT 'C', writes a journaled 'C' POLLOG row with
the negative unearned credit.CHAIN(E) on INSTMS (skip if
installment 1 exists), else generate 4 installments (ANNPREM DIV 4, remainder via
MVR on installment 4). Idempotent.chain (policyno:instno) retry
1..4 for the oldest open/partial installment; full pay → ISTAT 'P', partial → ISTAT 'D';
then decrements POLICYMS.POLBAL by the applied amount.if/else for the bucket
(see F.4).RLIMIT − TOTPAY; if the 3000.00 payment fits,
writes a 'P' CLMLINE, bumps CLAIMMS.TOTPAY, and posts a balanced GL pair (batch 20:
4100-CLMEXP DR / 1000-CASH CR) via embedded SQL.LOGAMT × COMMPCT/100,
write COMMMS + a balanced GL pair (batch 30: 5200-COMMEXP DR / 2100-COMMPAY CR).1200-PREMREC DR / 4000-WRTNPRM CR).
Then SELECTs SUM(DR)/SUM(CR) over the whole feed and COMMITs if equal, else
ROLLBACK — the balance gate for the commit unit-of-work.CALL 'POLVIEW'/'CLMVIEW'.EXEC SQL SELECT SUM(GLAMT) ... WHERE BATCHNO=10 AND DRCR='C' and
prints IN/OUT OF BALANCE.RUNSQLSTM GLPOST2, CRTBNDRPG/CRTBNDCBL
every program, and CRTJRNRCV/CRTJRN/STRJRNPF POLLOG IMAGES(*BOTH).STRCMTCTL LCKLVL(*CHG): BILLRUN → CASHAPP → COMMRUN →
CLMPAYP → GLRUN → ENDCMTCTL.Rating. Premium = base × age-band factor (RATETB): YNG (<25) 1.250, STD
1.000, SNR (≥65) 0.900. Endorsement adds a flat delta; renewal applies a 5% load; cancellation credits
a pro-rata unearned fraction. A prior-claim count > 3 hard-declines.
GL feed. Three balanced DR/CR batches, all cross-checked SUM(DR)=SUM(CR):
| Batch | Source | Debit | Credit |
|---|---|---|---|
| 10 | GLRUN (per 'I') | 1200-PREMREC | 4000-WRTNPRM |
| 20 | CLMPAYP | 4100-CLMEXP | 1000-CASH |
| 30 | COMMRUN (per 'I') | 5200-COMMEXP | 2100-COMMPAY |
POLLOG is journaled to SNJRN (receiver SNJRNR) with
IMAGES(*BOTH), armed in SNSETUP. Effects verified by
sentinel_journal.mjs: WRITE puts appear as PT record-put images; a native UPDATE
captures a UB before-image and a UP after-image (UB seq < UP seq);
DSPJRN JRN(SENTINEL/SNJRN) FILE(SENTINEL/POLLOG) renders those lines; and a receiver roll
(CRTJRNRCV SNJRNR2 + CHGJRN) detaches SNJRNR (*ONLINE), attaches
SNJRNR2 (*ATTACHED), and a traversal spans both receivers with seq still increasing.
The three SQLRPGLE programs and the COBOL program use these embedded-SQL idioms; the app also carries
several documented adaptations to the emulator (from PLAN.md §6 — the app is adapted
AS-IS, the engine is never modified):
insert into SENTINEL.GLPOST2 (...) values(10,'1200-PREMREC','D',:wamt,'GLRUN');SUM(CASE WHEN DRCR='D' ...)) into
host variables; POLSUM2's SELECT SUM(GLAMT) INTO :G-PRM.STRCMTCTL LCKLVL(*CHG) boundary.REFLD (which ends, closing RATETB) before
POLBIND→UWCHK, rather than inline.if/else, never free-form elseif. Free-form
if/elseif/else/endif mis-scopes the trailing END-IF on this emulator (pulling loop-body
statements into the wrong branch); UWCHK and AGERUN use nested if/else everywhere a
multi-way branch is needed./free use the parenthesised form chain (policyno:instno) instr;
(BILLRUN/CASHAPP); fixed-form KLIST + fixed-form CHAIN is used where appropriate.SELECT COUNT(*), not
objExists (D, above).CLMADJ): approve the reserve against the covering coverage limit
(cap it if over-limit), move CLSTAT O→A, write an 'A' memo line.RATETB) whose factor multiplies the base premium at
underwriting (UWCHK).STRCMTCTL/ENDCMTCTL bracket a unit-of-work; SQL INSERTs stage until
COMMIT (or discard on ROLLBACK). SNNIGHT wraps the whole GL posting chain;
GLRUN decides.POLENDT): raise a coverage limit and re-rate the header by a
delta; journaled 'E'.CLMOPEN): the CLAIMMS header + an initial 'R' reserve line.POLSTAT='I'); the set BILLRUN bills and POLSUM2 totals.SNJRN with before/after images (IMAGES(*BOTH));
DSPJRN renders the entries (PT/UB/UP).POLCANCL), the fraction of premium for the unexpired term, refunded as a
negative 'C' POLLOG credit; the earned half stays as POLBAL.SBMJOB CMD(CALL SENTINEL/SNNIGHT) JOBQ(SENTINEL/NITEQ).