← BBS SG Bank submission · All documents
Create a minimal Python project scaffold so modernization engineers can install and test the prototype runtime repeatably instead of relying only on the legacy COBOL source. The change belongs at the repository root in pyproject.toml, with README.md updated to describe the new local Python package alongside the existing bank.cob baseline. The current repository has only bank.cob and README.md, so there is no package metadata, test runner configuration, or typed module namespace for future fixed-width contract work. Stakeholders need this foundation because parity, fixture validation, and the modern CLI must be automated from a predictable runtime rather than ad hoc interpreter commands. When the story is complete, a developer can install the project in editable mode, import the modern_bank package, and run pytest without external service dependencies. This story does not implement the ledger engine, fixed-width record parsing, Dockerized COBOL execution, fixture allow-listing, or the modern batch CLI. It depends only on the existing modernization objective in README.md and the legacy contract documented in bank.cob. The scaffold should stay intentionally small, local-only, and synthetic-data oriented so the one-day prototype does not drift into production platform scope. It should also make later automation easy for DevOps teams by keeping commands deterministic and avoiding hidden global environment assumptions.
| Field | Value |
|---|---|
| Story Points | 2 |
| Hours | 20h |
| Priority | P0 |
| Labels | epic:runtime-foundation, type:devex, type:modernization, complexity:low |
Acceptance Criteria
Add a Dockerfile and a scripts/run_legacy.sh wrapper so engineers can execute the authoritative COBOL baseline reproducibly for parity evidence. The change belongs at the repository root in Dockerfile and under scripts/run_legacy.sh, with README.md updated to show how the wrapper runs bank.cob against accounts.dat and operations.dat in a controlled working directory. Today bank.cob assumes current-directory files and there is no build script, compiler pin, or containerized runtime path for DevOps teams to reproduce baseline results. Stakeholders need this because the modern Python implementation cannot be trusted unless every parity fixture can run against the same legacy behavior on demand. When the story is complete, a developer can build a local GnuCOBOL image and run the baseline wrapper against synthetic fixture files to produce the legacy stdout summary and mutated accounts.dat. This story does not change bank.cob logic, implement the Python engine, add the fixed-width codec, or create the full golden-file parity harness. It depends on the existing COBOL compiler model and the flat-file names documented directly in bank.cob. The wrapper should be automation-first, fail fast on missing inputs, avoid shell interpolation of untrusted arguments, and preserve run artifacts so failures are debuggable. The operational outcome is a small repeatable baseline run path that later tests and benchmark jobs can call without hand-written compiler commands.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P0 |
| Labels | epic:runtime-foundation, type:devops, type:baseline, complexity:medium |
Acceptance Criteria
Implement modern_bank/records.py with a FixedWidthCodec so the Python prototype has one canonical parser and serializer for the legacy account and operation row contracts. The new module must mirror the offsets embedded in bank.cob, specifically account ID from bank-row positions 1 through 8, balance from positions 10 through 21, operation kind from ops-row position 1, source ID from positions 3 through 10, destination ID from positions 12 through 19, and amount from positions 21 through 32. Today those contracts exist only in bank.cob comments, COBOL substring expressions, and README.md prose, which makes later parity work fragile if each Python component re-creates offsets separately. Stakeholders need a single executable contract because byte-identical ledgers and cent-accurate summaries are the primary acceptance gate for modernization. When the story is complete, tests can parse and format accounts.dat rows as IIIIIIII|BBBBBBBBBBBB and operations.dat rows as K|SSSSSSSS|TTTTTTTT|AAAAAAAAAAAA without using floats. The codec must reject malformed row shape, nonnumeric account IDs, nonnumeric balances, nonnumeric amounts, zero amounts where operation parsing validates amount semantics, unsupported operation kinds, and duplicate account IDs when parsing a ledger collection. This story does not process a batch, mutate balances, publish accounts.dat, call bank.cob, build benchmarks, or implement a CLI. It depends on the Python package scaffold capability and on the legacy offsets documented in the COBOL baseline. The implementation should make safety divergences explicit by rejecting duplicate account records and balance values outside the 12-digit ledger field instead of reproducing legacy truncation defects. This module becomes the low-blast-radius seam that later engine, fixture, parity, and operator tooling should import rather than duplicating fixed-position string slicing.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P0 |
| Labels | epic:runtime-foundation, type:contract, type:testing, complexity:medium |
Acceptance Criteria
Create tests/fixtures/fixture_catalog.json as an allow-list of synthetic accounts.dat and operations.dat fixture IDs so parity and demo tooling never accept arbitrary local paths. The catalog belongs under tests/fixtures/fixture_catalog.json, with fixture files stored under tests/fixtures and README.md updated to explain the allow-list boundary. The current repository has no tests directory, no fixture inventory, and no governed way to distinguish approved synthetic inputs from accidental or real data files. Stakeholders need this control because later parity, benchmark, and local UI flows must be able to select known fixture IDs without exposing the filesystem as an input surface. When the story is complete, a test can load the catalog, resolve every listed accounts.dat and operations.dat path relative to tests/fixtures, and validate the listed rows with the Python fixed-width codec. This story does not generate the full golden-file parity suite, run the COBOL baseline, compare modern and legacy outputs, or produce benchmark timings. It depends on the fixed-width codec capability so the catalog test can validate row shapes using the same contract as the modern engine. The catalog should include stable IDs, fixture categories, relative file paths, parity-critical flags, and synthetic-data labeling so later automation can fail closed on unknown fixture IDs. From an operational perspective, this story reduces blast radius by establishing an allow-list before the modern CLI or demo surface starts accepting fixture selections. The committed sample fixtures should be small, deterministic, and safe for local execution.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P0 |
| Labels | epic:runtime-foundation, type:fixtures, type:security, complexity:medium |
Acceptance Criteria
Depends on: WO-003
Add scripts/run_modern.py as the first Python CLI entry point so operators and automation can validate accounts.dat and operations.dat inputs through the modern record contract before the full engine exists. The script belongs under scripts/run_modern.py and must import modern_bank.records rather than duplicating offsets from bank.cob. Today the only executable path is bank.cob, which mutates accounts.dat directly and provides no Python command boundary for later indexed processing, safe publication, or parity automation. Stakeholders need a thin CLI seam because fixture-based validation, benchmark harnesses, and future demo surfaces should all call one local command instead of hand-wiring Python modules. When the story is complete, a developer can run the CLI with explicit accounts and operations file paths, receive a deterministic contract-validation result, and get a nonzero exit with a safe message for malformed inputs. This story does not implement balance mutation, indexed lookups, overdraft logic, final ledger publication, parity comparison, Docker invocation, audit logging, or web UI behavior. It depends on the Python package scaffold and the fixed-width codec capability. The CLI should remain a skeleton with clear extension points for the later batch processor, keeping business rules out of the script and limiting the blast radius of future changes. For reliability, the command must fail closed on missing files or invalid rows and must not leak stack traces or absolute host paths in user-facing error output. The initial system test should use committed synthetic fixture files so DevOps teams can exercise the boundary without external data.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P0 |
| Labels | epic:runtime-foundation, type:cli, type:operability, complexity:medium |
Acceptance Criteria
Depends on: WO-001, WO-003
Implement an ordered in-memory ledger account map so the modern batch can look up accounts without reopening and scanning the full ledger for every operation. The work belongs in the LedgerIndex module at modern_bank/ledger.py, created alongside the existing legacy reference program in bank.cob. The current COBOL path treats accounts.dat as the source of truth but pays an O(m x n) file-I/O cost because every operation scans account rows repeatedly. Stakeholders need the same fixed-width ledger behavior with materially less file work so parity and benchmark evidence can be produced on the required synthetic fixtures. When this story is complete, loading accounts.dat will produce a deterministic account order list plus an indexed lookup keyed by each 8-digit account ID. Developers should be able to inspect modern_bank/ledger.py and see parsing for the account contract IIIIIIII|BBBBBBBBBBBB, integer-cent balances, and serialization that preserves the same field widths and delimiter. The module must preserve original ledger ordering for final output rather than sorting accounts by key unless a later requirement explicitly changes ordering. This story does not implement operation processing, rejection counters, summary formatting, benchmark reporting, web APIs, or final safe ledger publication. It depends on the capability to create the Python package scaffold and run local tests in this repository, while bank.cob remains the authoritative behavior reference. The implementation should keep blast radius low by making ledger parsing and lookup testable without invoking the COBOL runtime or any external service.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P0 |
| Labels | epic:EPIC-002, modernization, ledger-index, flat-file, complexity:medium |
Acceptance Criteria
Depends on: WO-003
Add duplicate account and 12-digit balance preflight checks so the modern batch refuses unsafe ledger input before any balance mutation can occur. The work belongs in the LedgerIndex module at modern_bank/ledger.py, extending the ordered account map created for accounts.dat. The legacy COBOL source in bank.cob assumes unique 8-digit account IDs and 12-digit balances but does not enforce those assumptions as a full preflight gate. Stakeholders explicitly need the modern Python prototype to characterize and avoid known legacy defects such as duplicate account rewrites or balance field overflow. When this story is complete, a malformed account ledger will fail during load with a clear row-level diagnostic and no processor will receive a partially trusted ledger. Developers should observe that duplicate 8-digit account IDs are detected before operation processing starts and that balance fields must be exactly 12 numeric digits. This story does not add operation-row rejection paths, overdraft logic, summary formatting, final publication, or benchmark claims. It depends on the ordered ledger index capability being present so validation can be integrated with the single ledger load path instead of a second scan. The failure behavior should be operationally safe: fail closed, preserve original inputs, and produce a deterministic error that can be asserted in tests. The implementation must still preserve parity for well-formed in-range fixtures and document that stricter preflight behavior is an intentional safety divergence from the legacy defect surface.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P0 |
| Labels | epic:EPIC-002, modernization, input-validation, ledger-preflight, complexity:medium |
Acceptance Criteria
Depends on: WO-007
Implement the modern operation processor for accepted deposit, withdrawal, and transfer rows so balances mutate in memory using integer cents and source-file order. The work belongs in OperationProcessor at modern_bank/processor.py, consuming the LedgerIndex behavior in modern_bank/ledger.py and preserving the process-operation semantics from bank.cob. The current COBOL path validates and applies each operation by scanning and rewriting accounts.dat, which creates repeated full-ledger file work for every accepted operation. Stakeholders need the same accepted-operation outcomes with the mutation cost moved into a deterministic in-memory engine that later can be published once. When this story is complete, valid D, W, and T records from operations.dat will be parsed from the legacy fixed positions and applied sequentially to the ordered ledger index. Deposits must add amount cents to the source account, withdrawals must subtract amount cents from the source account, and transfers must subtract from source and add to destination. Accepted rows must increment the processed count and leave the rejected count unchanged for this happy-path story. The implementation must not use floating-point arithmetic, must not write accounts.dat or accounts.tmp per operation, and must not implement malformed-row rejection paths that belong to the rejection-focused processor story. It depends on the ledger index and ledger preflight capabilities so operation code can rely on a trusted in-memory account map. The observable outcome is a processor result object that exposes processed count, rejected count, and the mutated LedgerIndex state for later summary and publication components.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P0 |
| Labels | epic:EPIC-002, modernization, operation-processing, integer-cents, complexity:medium |
Acceptance Criteria
Depends on: WO-007, WO-010
Add processor rejection paths for malformed operation rows, invalid amounts, missing accounts, self-transfers, unsupported types, overdrafts, and 12-digit balance overflow so invalid rows increment rejection counts without aborting the batch. The work belongs in OperationProcessor at modern_bank/processor.py, extending the accepted mutation engine that consumes modern_bank/ledger.py. The legacy process-operation paragraph in bank.cob rejects invalid operation rows and continues processing, and that behavior is a primary parity requirement for the modernization prototype. Stakeholders need high-confidence rejection semantics because a behavior drift here would change final balances, processed counts, rejected counts, and total cents. When this story is complete, invalid rows from operations.dat will be classified as rejected, the rejected count will increment by one per invalid row, and no balance mutation will be applied for that row. The processor must parse operation kind from position 1, source account from positions 3 through 10, destination account from positions 12 through 19, and amount text from positions 21 through 32. This story must also implement the modern safety divergence that rejects any deposit or transfer whose resulting balance would exceed the 12-digit ledger field, rather than allowing COBOL-style truncation defects. It does not implement summary formatting, final safe ledger publication, parity harness orchestration, UI, API endpoints, or benchmark reporting. It depends on the valid D, W, and T in-memory mutation capability and the ledger preflight behavior that guarantees account records are unique and well-formed. The operational goal is reject-and-continue for row-level business problems while reserving fail-closed behavior for file-level ledger preflight failures.
| Field | Value |
|---|---|
| Story Points | 8 |
| Hours | 80h |
| Priority | P0 |
| Labels | epic:EPIC-002, modernization, rejection-semantics, parity-risk, complexity:high |
Acceptance Criteria
Depends on: WO-011
Implement fixed-width summary formatting so the modern batch emits PROCESSED, REJECTED, and TOTAL_CENTS lines compatible with the legacy COBOL output contract. The work belongs in the SummaryReporter module at modern_bank/summary.py, consuming processed and rejected counts from modern_bank/processor.py and final balances from modern_bank/ledger.py. The current COBOL program in bank.cob prints these three metrics at the end using picture-clause widths of 8, 8, and 16 digits. Stakeholders need exact summary formatting because parity approval compares not only final ledger bytes but also processed count, rejected count, and total cents. When this story is complete, the modern formatter will return or write three newline-separated lines in the order PROCESSED, REJECTED, and TOTAL_CENTS. The numeric fields must be zero-padded to 8 digits for processed and rejected counts and 16 digits for total cents. TOTAL_CENTS must be computed from the final in-memory ledger using integer cents and must ignore floating-point or locale currency formatting entirely. This story does not implement operation validation, ledger parsing, final ledger publication, COBOL runner orchestration, API endpoints, UI display, or benchmark reporting. It depends on the processor result counters and ordered ledger state being available from the modern batch core. The observable result is a small isolated module that makes summary parity easy to test and prevents formatting logic from being duplicated across CLI, test, or future demo surfaces.
| Field | Value |
|---|---|
| Story Points | 2 |
| Hours | 20h |
| Priority | P0 |
| Labels | epic:EPIC-002, modernization, summary-formatting, fixed-width, complexity:low |
Acceptance Criteria
Depends on: WO-011
Implement a LedgerPublisher that writes the final account ledger through a same-directory temporary file and then replaces accounts.dat so operators never see a partially written final ledger. The change belongs in the new modern_bank/publisher.py module, with tests under tests/test_publisher.py and fixture data under tests/fixtures/publisher. Today the legacy COBOL batch in bank.cob rewrites accounts.dat through accounts.tmp for every accepted operation, which increases the mutation window and makes interrupted runs harder to reason about. The target behavior is one end-of-batch publication primitive that accepts already-processed ledger rows, writes them to a temporary file located beside the target ledger, flushes and closes that file, and performs the final replacement only after the write step succeeds. When this story is done, a developer can run the publisher against a temporary workspace and observe that the temp file is created in the same directory as accounts.dat and that the final file changes only after the publish call reaches its replacement phase. Failed writes must leave the original accounts.dat bytes intact so rollback remains a whole-batch rerun from the original synthetic inputs. This story does not include record-count validation, FixedWidthCodec row validation, CLI orchestration, audit JSONL events, artifact retention metadata, or README rollback documentation. It depends on the modern fixed-width record contract and in-memory ledger processing capabilities being available so the publisher can focus only on safe file publication. The implementation should remain local-file based and must not introduce databases, remote storage, locking services, or production banking infrastructure. The operational intent is to reduce blast radius during ledger publication while keeping the prototype small enough for offline parity testing.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P0 |
| Labels | epic:EPIC-003, component:publisher, reliability, data-integrity, complexity:medium |
Acceptance Criteria
Depends on: WO-007, WO-013
Add record-count and FixedWidthCodec validation to LedgerPublisher before accounts.dat replacement so invalid or incomplete ledger output cannot be promoted as a completed batch result. The change belongs in modern_bank/publisher.py and should use the canonical fixed-width account codec rather than duplicating the bank.cob substring contract. The current safe replacement primitive can protect against partial writes, but without validation it could still publish the wrong number of rows or rows that do not match the IIIIIIII|BBBBBBBBBBBB account format. Stakeholders will recognize this as the data-integrity gate that prevents a numerically plausible but byte-incompatible ledger from entering parity evidence. When the story is done, publication will fail closed before os.replace if the serialized row count differs from the expected account count or any row violates the account record contract. Developers should be able to run targeted pytest cases that prove malformed rows, bad delimiters, short rows, non-numeric balances, and count mismatches preserve the original accounts.dat. This story does not implement the codec itself, change operation processing rules, create audit events, or wire CLI orchestration. It depends on the canonical account record parser and serializer capability and on the safe same-directory publication primitive already existing. The implementation should report safe validation failure details suitable for CLI display without exposing absolute host paths. This preserves the fixed-width contract as an executable publication gate rather than relying on comments in bank.cob.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P0 |
| Labels | epic:EPIC-003, component:publisher, component:codec, data-integrity, complexity:medium |
Acceptance Criteria
Depends on: WO-014
Wire the modern CLI load process so accounts.dat and operations.dat are processed once and the final ledger is published through LedgerPublisher as the only accounts.dat mutation step. The change belongs in modern_bank/cli.py, with orchestration tests under tests/test_cli.py and CLI fixture workspaces under tests/fixtures/cli. The legacy bank.cob entry point mixes operation reading, validation, per-operation rewrites, final total calculation, and stdout reporting inside one procedural program. The target CLI should coordinate the already-built ledger loading, operation processing, summary reporting, and validated publication components without reintroducing per-operation file writes. When complete, running the CLI against a fixture workspace will read accounts.dat and operations.dat, process operations sequentially in memory, call LedgerPublisher once after processing, and print or return the summary labels PROCESSED, REJECTED, and TOTAL_CENTS. File-level failures such as missing accounts.dat, unreadable operations.dat, or publication validation failure must return a non-zero process exit and leave the original ledger intact. This story does not implement the processor, codec, publisher validation, audit writer, artifact store, web UI, parity runner, or benchmark runner. It depends on the fixed-width codec, ordered ledger processing, summary formatting, and validated safe publisher capabilities being available. The CLI must remain an offline local prototype surface and must not accept arbitrary remote inputs or imply production banking operation. This story establishes the operational control path that later audit and artifact stories can observe.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P0 |
| Labels | epic:EPIC-003, component:cli, component:publisher, operability, complexity:medium |
Acceptance Criteria
Depends on: WO-006, WO-012, WO-013, WO-015
Implement append-only JSONL audit events for fixture selection, ledger generation, and run completion so every prototype ledger publication has a minimal operational trail. The change belongs in modern_bank/audit.py and should be called from modern_bank/cli.py after the load orchestration path is available. The current legacy batch in bank.cob prints only aggregate counters to stdout and leaves no structured record of which synthetic fixture was selected or when the final ledger was generated. Stakeholders need this traceability to review prototype evidence, diagnose failed runs, and satisfy the local one-year audit-artifact expectation without deploying a production audit platform. When the story is done, running the CLI against a fixture workspace will append JSON lines containing event_type, run_id, timestamp, actor, resource, and synthetic metadata for the required lifecycle points. Audit writes must be append-only, newline-delimited, parseable by Python json.loads, and safe to display without stack traces, secrets, or host paths. This story does not implement artifact storage metadata, benchmark events, parity comparison events, web UI display, centralized log shipping, or production SIEM integration. It depends on the CLI load orchestration and validated ledger publication path so audit events can represent real run lifecycle boundaries. The implementation should classify the audit content as Internal synthetic prototype evidence and avoid storing raw absolute fixture paths. This adds observability and recoverability without changing ledger processing behavior.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P1 |
| Labels | epic:EPIC-003, component:audit, observability, governance, complexity:medium |
Acceptance Criteria
Depends on: WO-016
Update README.md with the bank.cob fixed-width migration map and accounts.tmp rollback procedure so operators can run, verify, and recover the prototype safely. The change belongs in the existing README.md file at the repository root. The current README.md is only seven lines and names accounts.dat, operations.dat, the deliberate scan/rewrite bottleneck, and the modernization objective without detailed operational runbook guidance. Stakeholders need the documentation to explain exactly how COBOL substring offsets map to the modern fixed-width codec and why the Python publisher uses one final same-directory temporary ledger before replacement. When this story is done, a reviewer can inspect README.md and find the account row layout, operation row layout, bank.cob offset references, modern module ownership, safe publish sequence, and rollback procedure. The rollback procedure must cover retaining original inputs, comparing modern output with the COBOL baseline, discarding generated modern output, restoring or rerunning from original accounts.dat and operations.dat, and rerunning the legacy baseline when needed. This story does not change bank.cob behavior, implement Python code, create fixtures, or add audit/artifact modules. It depends on the CLI and validated publisher behavior being available so the documented runbook matches the implemented flow. The document must reinforce that all data is synthetic, local, and not production banking evidence. The goal is operational clarity that reduces mean time to recovery during failed demo or parity runs.
| Field | Value |
|---|---|
| Story Points | 2 |
| Hours | 20h |
| Priority | P1 |
| Labels | epic:EPIC-003, component:documentation, runbook, operability, complexity:low |
Acceptance Criteria
Depends on: WO-016
Implement a RunArtifactStore for Internal synthetic outputs and one-year audit retention metadata so CLI runs produce reviewable operational evidence without a production storage platform. The change belongs in modern_bank/artifacts.py and should integrate with modern_bank/cli.py after audit events are available. The current repository has only bank.cob and README.md, so generated ledgers, summaries, audit JSONL files, and run metadata have no structured local home. Stakeholders need artifact metadata to understand what was generated, how it is classified, and how long evidence should be retained for prototype governance review. When the story is done, a run workspace will contain a metadata JSON document that references generated accounts.dat output, summary output, and audit JSONL using sanitized artifact names and Internal data classification. The metadata must include retention_until or retention_days indicating at least one year of retention for audit evidence and generated outputs. This story does not implement automated purge enforcement, cloud object storage, artifact signing, parity comparison, benchmark reporting, or a web download endpoint. It depends on audit JSONL event generation and CLI run orchestration so artifacts can share a consistent run_id and lifecycle. The implementation must avoid recording absolute host paths and must not imply production compliance certification. This makes the prototype more operable by giving SRE and QA reviewers deterministic files to inspect after a batch run.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P1 |
| Labels | epic:EPIC-003, component:artifacts, governance, operability, complexity:medium |
Acceptance Criteria
Depends on: WO-017
Add pytest unit coverage for the modern fixed-width account and operation record parser so modernization engineers can prove the Python record contract preserves the legacy ledger interface before broader parity runs. The tests belong beside the planned modern record contract module at modern_bank/records.py, with developer-facing run instructions added to README.md in this repository. The current COBOL baseline in bank.cob parses account IDs from bank-row positions 1 through 8, balances from positions 10 through 21, operation kind from ops-row position 1, source ID from positions 3 through 10, destination ID from positions 12 through 19, and amount text from positions 21 through 32. Stakeholders need this parser-level evidence because a single offset drift can create byte-identical-looking but financially incorrect fixture results later in the parity pipeline. When this story is complete, a developer can run a targeted pytest command and see assertions for exact field widths, delimiter placement, integer-cent conversion, malformed row rejection, and serialization round trips. The scope is limited to unit tests around record parsing and formatting; it does not create the full golden fixture catalog, execute COBOL side by side, or benchmark runtime. This depends on the modern record contract capability already existing with public parsing and serialization APIs for accounts.dat and operations.dat. The implementation must keep bank.cob as the behavioral reference and must not modify legacy COBOL behavior while adding these tests.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P0 |
| Labels | epic:golden-file-parity, type:test, complexity:medium, runtime:python, contract:fixed-width |
Acceptance Criteria
Depends on: WO-003
Create committed golden fixture inputs for the 13 required parity categories so QA and platform automation can validate behavior drift using repeatable synthetic data instead of one-off local files. The fixture catalog should live under tests/fixtures with README.md updated to describe how the categories map back to the legacy logic in bank.cob. The current repository only documents accounts.dat and operations.dat shapes in README.md and bank.cob comments, but it does not include any committed sample ledgers, operation feeds, expected outputs, or fixture inventory. This matters to stakeholders because missing fixture categories block sign-off even when existing tests happen to pass, and parity evidence must become an executable specification of the fixed-width ledger contract. When this story is complete, every required category has an accounts.dat and operations.dat input, plus expected summary metadata or expected final accounts output where the fixture design can state it unambiguously. The scope is limited to deterministic synthetic fixture data and inventory validation; it does not implement side-by-side execution, byte comparison tests, or benchmark timing. This depends on the modern record contract and core batch behavior being available so fixture expectations can align with the Python implementation while still treating COBOL as the final oracle. The fixture data must remain synthetic, avoid real customer records, and preserve exactly the fixed-width formats used by bank.cob.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P0 |
| Labels | epic:golden-file-parity, type:fixture, complexity:medium, data:synthetic, contract:fixed-width |
Acceptance Criteria
Depends on: WO-002, WO-005
Implement a side-by-side parity runner that executes the COBOL baseline and modern Python batch against the same fixture workspace so approval evidence can be generated reproducibly. The orchestration should be implemented in tests/parity_runner.py, with legacy execution delegated to scripts/run_legacy.sh and modern execution delegated to scripts/run_modern.py, while README.md documents the operational command sequence. The current legacy behavior in bank.cob requires accounts.dat and operations.dat in the process working directory, rewrites accounts.dat, and prints PROCESSED, REJECTED, and TOTAL_CENTS to stdout, but the repository has no scripts or runner to isolate those mutations. This story matters because parity cannot be trusted if legacy and modern runs share a mutable directory, reuse stale accounts.tmp, or capture different inputs. When complete, a developer can invoke the parity runner for one fixture category and receive separate legacy and modern output directories containing final accounts.dat, stdout capture, stderr capture, exit code metadata, and a copy of the exact input files. The scope is orchestration and artifact capture only; strict byte comparison assertions and benchmark measurement are handled by later stories. This depends on a runnable modern batch capability, a COBOL baseline execution path, and the committed golden fixture catalog. The runner must avoid unsafe shell interpolation and must treat fixture IDs or paths as allow-listed local artifacts rather than arbitrary operator-controlled commands.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P0 |
| Labels | epic:golden-file-parity, type:integration, complexity:medium, operability:artifact-capture, security:subprocess-safety |
Acceptance Criteria
Depends on: WO-002, WO-016, WO-009
Implement strict parity tests that compare legacy and modern final ledger bytes and summary counters so modernization approval is blocked on any observable behavior drift. The test module should be tests/test_parity.py and it should use tests/parity_runner.py to execute each committed golden fixture against bank.cob and the modern Python batch. The current COBOL baseline in bank.cob prints PROCESSED, REJECTED, and TOTAL_CENTS after mutating accounts.dat, but the repository has no automated test that compares those outputs with the modern path. Stakeholders recognize this as the primary release gate because a numerically plausible ledger is not enough if field widths, byte ordering, or rejection counts differ from the baseline. When this story is complete, running the parity pytest module iterates the fixture catalog, creates side-by-side artifacts, and fails with a diagnostic that identifies whether accounts.dat bytes, processed count, rejected count, or total cents diverged. The scope does not include creating the fixture catalog, writing the side-by-side runner, or measuring performance; it consumes those capabilities. This depends on reproducible legacy and modern execution and on committed golden fixtures covering the required categories. The test output must retain enough artifact references for operational debugging while avoiding absolute host paths in failure messages.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P0 |
| Labels | epic:golden-file-parity, type:parity-gate, complexity:medium, quality:blocking, operability:evidence |
Acceptance Criteria
Depends on: WO-019
Implement a benchmark timing harness for the required 1200 accounts by 400 operations and 5000 accounts by 500 operations fixture sizes so performance evidence is repeatable after parity is established. The harness should be implemented in benchmarks/runner.py, with README.md documenting the benchmark command and artifact location. The current bank.cob source explicitly documents the O(m x n) scan and rewrite bottleneck, but the repository has no benchmark runner, benchmark fixture generator, or timing artifact format. This matters because stakeholders need raw timing evidence for the legacy and modern paths before accepting claims that indexed lookups and one final write reduce file-system work. When complete, a developer can run a single command that generates or validates deterministic benchmark fixtures, executes both implementations through the parity runner path, records elapsed milliseconds, and writes a machine-readable benchmark result. The scope is timing measurement and artifact generation only; it does not format stakeholder-facing speedup labels or independently certify benchmark results. This depends on the side-by-side runner capability and should treat parity status as a prerequisite signal in the benchmark output. The harness must be automation-friendly, avoid uncontrolled shell execution, and record enough metadata for SRE-style reproducibility without implying production banking readiness.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P1 |
| Labels | epic:golden-file-parity, type:benchmark, complexity:medium, operability:timing, evidence:performance |
Acceptance Criteria
Depends on: WO-019
Implement benchmark report generation that presents measured timing results and qualifies the preliminary 28.6x and 128.1x prototype speedups with the required governance-safe language. The reporting code should live in benchmarks/report.py, with README.md documenting how to convert benchmarks/runner.py JSON output into a human-readable report. The current repository has only the short README.md and bank.cob comments, so there is no controlled place to present benchmark evidence or prevent overstated performance claims. This matters because stakeholders want performance evidence, but the project must not imply independent validation, production readiness, or use with real banking records. When this story is complete, a developer can feed the benchmark results JSON into the report command and receive a Markdown or JSON report that includes raw timings, computed speedups, parity status, fixture sizes, and exact qualification text for the local prototype values. The scope is report formatting and labeling only; it does not rerun benchmarks, implement the timing harness, or change parity checks. This depends on the benchmark runner emitting a stable results.json artifact for the required sizes. The report must be automation-friendly for CI artifact publishing while preserving the synthetic offline prototype boundary.
| Field | Value |
|---|---|
| Story Points | 2 |
| Hours | 20h |
| Priority | P1 |
| Labels | epic:golden-file-parity, type:reporting, complexity:low, governance:benchmark-labeling, evidence:performance |
Acceptance Criteria
Depends on: WO-023
Add a minimal Vite React Tailwind frontend scaffold so demo operators have a local dashboard foundation for reviewing synthetic batch evidence. This work belongs in web/package.json and supporting new files under web/, while README.md should document how to start the local dashboard. The current repository has no web directory, package manifest, build tool, or frontend entry point, so this story creates the operator UI substrate without implementing the full run-status dashboard content. Stakeholders need the scaffold because the one-day prototype requires a lightweight local web UI, but it must remain separate from the COBOL batch and not imply a production banking portal. When complete, npm install and npm run dev from web should start a Vite React app, and npm run build should produce a static production bundle for local review. The story does not implement API data fetching, parity rendering, audit event rendering, or accessibility refinements beyond a basic scaffold. It depends on the repository modernization foundation being ready for additive frontend files. The observable result is a committed frontend package with pinned scripts, Tailwind styling entry point, React mounting code, and a placeholder synthetic prototype page.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P2 |
| Labels | epic:local-prototype-api-dashboard, frontend, vite, react, tailwind, complexity:medium |
Acceptance Criteria
Depends on: WO-001
Create a FastAPI localhost API with fixture listing and run creation endpoints so demo operators can start synthetic batch evidence runs without invoking the COBOL baseline or Python CLI by hand. This work belongs in the new ModernBank API module at modern_bank/api.py, with README.md updated to document the local-only operator command and endpoint purpose. The current repository has bank.cob and README.md only, so the target state is an additive Python API layer that does not change the legacy COBOL program or the fixed-width ledger contract. Stakeholders should be able to call GET /api/v1/fixtures and receive synthetic fixture metadata, then call POST /api/v1/runs with a fixture identifier and mode to receive a run identifier, status, summary counters, parity state, duration fields, and artifact references produced by the completed batch services. The API must be explicit that it is a prototype orchestration surface, not a banking transaction API, and it must not expose account onboarding, payment authorization, identity integration, or real customer data handling. The story does not include the dashboard implementation, structured error sanitization beyond basic HTTP validation, or the final allow-list enforcement hardening that is handled separately. It depends on the completed modern batch engine, fixture catalog capability, run orchestration capability, audit artifact writer, and parity or benchmark result contracts. When complete, the observable behavior is that a developer can run the API locally, inspect the OpenAPI route list, and exercise both endpoints with committed synthetic fixture data using automated tests.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P1 |
| Labels | epic:local-prototype-api-dashboard, backend, fastapi, prototype, complexity:medium |
Acceptance Criteria
Depends on: WO-005, WO-017, WO-019
Add a structured API error module so local demo users receive actionable JSON failures without stack traces, secrets, or host filesystem paths. This work belongs in the new ModernBank API errors module at modern_bank/api_errors.py and must be wired into the existing FastAPI app in modern_bank/api.py. The current API layer is expected to expose fixture and run endpoints, but without a dedicated sanitizer any raised exception could leak implementation details from the local workspace. Stakeholders need safe errors because failed fixture selection, malformed JSON, unknown runs, and internal batch failures are expected during demos and should be diagnosable without exposing host details. When the story is complete, invalid requests return stable JSON fields such as errorCode, message, correlationId, and statusCode with appropriate HTTP status codes. The story does not add new API business endpoints, dashboard screens, authentication, or production observability infrastructure. It depends on the local FastAPI endpoint capability already existing and on completed run services surfacing typed domain errors or catchable exceptions. The implementation should make failures operationally useful for local triage while keeping the blast radius of unexpected exceptions contained.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P1 |
| Labels | epic:local-prototype-api-dashboard, backend, security, error-handling, complexity:medium |
Acceptance Criteria
Depends on: WO-024
Enforce FixtureCatalog allow-listed fixture identifiers in the API so operators can select only committed synthetic inputs and cannot submit raw filesystem paths. This work belongs in modern_bank/api.py, integrating the completed fixture catalog capability that resolves fixture IDs to approved account and operation files. The legacy bank.cob program trusts accounts.dat and operations.dat in the current working directory, so the API must add a safer boundary around demo fixture selection without changing the COBOL baseline. Stakeholders need this control to prevent accidental use of real records, path traversal, or arbitrary local file access during prototype demos. When complete, POST /api/v1/runs accepts a fixture_id from the catalog and rejects path-like, unknown, or malformed fixture identifiers before any run workspace is created. The story does not create new fixture categories, implement the run engine, or change dashboard rendering. It depends on a completed fixture catalog that owns synthetic fixture metadata and on the local FastAPI run endpoint already existing. The observable result is that developers can run targeted API tests proving allowed fixture IDs are accepted and path input is rejected with safe structured JSON.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P1 |
| Labels | epic:local-prototype-api-dashboard, backend, security, input-validation, complexity:medium |
Acceptance Criteria
Depends on: WO-005, WO-024
Implement the React dashboard so demo operators can see synthetic run status, parity outcome, rejection summary, timing, and audit events in one local review surface. This work belongs in web/src/App.jsx and consumes the already available localhost API endpoints from modern_bank/api.py. The current frontend scaffold only renders a placeholder, while the legacy bank.cob output is limited to three stdout summary lines that are not enough for stakeholder visibility. Stakeholders need a readable dashboard to review whether the modern run preserved processed count, rejected count, total cents, parity evidence, and benchmark timing before approving the prototype demonstration. When complete, the page loads fixture metadata from GET /api/v1/fixtures, lets an operator start a run through POST /api/v1/runs, and renders the returned status fields and audit event list without exposing host paths. The story does not add new backend endpoints, change fixture allow-listing, implement production authentication, or certify benchmarks as independently reviewed. It depends on the local API endpoints, structured safe errors, allow-listed fixture selection, completed run evidence contract, and the frontend scaffold. The observable result is that a developer can run the API and Vite app locally, start a synthetic fixture run, and verify dashboard text for status, parity, rejection counts, duration, and audit entries.
| Field | Value |
|---|---|
| Story Points | 8 |
| Hours | 80h |
| Priority | P2 |
| Labels | epic:local-prototype-api-dashboard, frontend, dashboard, observability, complexity:high |
Acceptance Criteria
Depends on: WO-026, WO-027, WO-028, WO-004
Add explicit synthetic prototype labels and WCAG-conscious keyboard focus states so the local dashboard is safe to present and usable without a mouse. This work belongs in web/src/App.jsx, with supporting style updates in the existing web Tailwind entry file created by the scaffold. The current dashboard renders run evidence, but it needs final governance and accessibility refinements to avoid implying production banking operation and to support keyboard-only review. Stakeholders need this because the prototype handles banking-style synthetic data and must be visually clear that it is educational evidence, not a production bank portal. When complete, every major dashboard region includes synthetic prototype wording, interactive controls have visible focus indicators, and keyboard users can navigate fixture selection, run action, error details, and audit events in a predictable order. The story does not add new run metrics, new API calls, authentication, or full internationalization. It depends on the completed dashboard rendering run status, parity, rejection summary, timing, and audit events. The observable result is that automated tests and file inspection verify labels, accessible names, and focus class names on the controls used during the local demo.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P2 |
| Labels | epic:local-prototype-api-dashboard, frontend, accessibility, governance, complexity:medium |
Acceptance Criteria
Depends on: WO-030
Add a Forge Shipping pipeline configuration so the modernization prototype has repeatable Python build, Docker build, secret-scan, and dependency-scan automation before evidence is promoted for stakeholder review. The change belongs beside the legacy batch baseline in .forge/shipping.yml, with README.md updated only enough to point operators from the existing BBS SG Bank overview to the new shipping entry point. Today the repository contains only bank.cob and README.md, so every build and scan action is manual, unaudited, and easy to skip during the one-day prototype. Stakeholders need a reliable pipeline because parity and benchmark evidence is only credible if it is generated after a known build and clean scan posture. When this story is complete, a developer can inspect .forge/shipping.yml and see named build:python, build:docker, secret-scan, and dependency-scan steps with deterministic commands and no production deployment step. The pipeline should treat bank.cob as the retained COBOL baseline and should invoke the Python modernization assets created by earlier work without altering the legacy fixed-width file contract. This story does not add parity gating, benchmark capture, artifact packaging, rollout approval, or changes to COBOL transaction semantics. It depends on an existing modern Python batch build surface, a Docker build definition, and dependency metadata being available from earlier modernization work. It must keep the execution model local, offline, and synthetic-only so a failed scan blocks release evidence without implying any live banking deployment. The implementation should favor explicit step names and log-safe commands so SREs can quickly identify whether a failure came from build, container packaging, secret detection, or dependency analysis.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P1 |
| Labels | platform, ci-cd, security-scan, forge-shipping, complexity:medium |
Acceptance Criteria
Depends on: WO-001, WO-002, WO-016
Add a Forge Shipping parity gate that blocks release evidence unless tests/test_parity.py reports a full P0 fixture pass, because behavioral drift in ledger bytes or summary counters invalidates the modernization prototype. The change is made in .forge/shipping.yml and must reference the parity test module tests/test_parity.py that exercises the bank.cob baseline against the modern Python engine. The current shipping configuration only builds and scans once the base pipeline exists, so it cannot yet stop promotion when deposits, withdrawals, transfers, malformed rows, or rejection cases diverge from the COBOL behavior. Stakeholders recognize this as the hard sign-off control that keeps performance improvements from masking incorrect balances. When complete, a pipeline run should execute the parity test command after successful build and scan steps, publish the parity result as a gate decision, and stop later evidence or packaging steps on any P0 failure. The observable behavior is that changing a golden expected final accounts.dat or summary count causes the parity gate to return a non-zero status before any rollout sign-off can proceed. This story does not create the parity fixture categories, rewrite the COBOL baseline, implement the Python engine, or add benchmark reporting. It depends on a working golden-file parity harness, shared fixtures, and a modern batch implementation that can run side by side with legacy-bank. The gate must compare what stakeholders care about: byte-identical final ledger output, processed count, rejected count, and total cents for required P0 fixtures. The implementation should keep logs diagnostic but safe, retaining diff artifact paths without exposing host-specific absolute paths or pretending the prototype is a production banking release.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P1 |
| Labels | platform, ci-cd, parity-gate, quality-gate, complexity:medium |
Acceptance Criteria
Depends on: WO-022, WO-020
Add Forge Shipping benchmark artifact capture for benchmarks/runner.py reports so performance evidence is retained alongside parity evidence for operational review. The change belongs in .forge/shipping.yml and must call the benchmark runner module at benchmarks/runner.py that measures the required fixed-width ledger fixture sizes. At present, the base pipeline can build, scan, and later gate parity, but it does not persist the runtime measurements stakeholders need to evaluate whether the indexed modern batch reduced the O(m × n) file I/O bottleneck. The business value is reliable, reviewable performance evidence that shows raw timings without overstating local prototype speedups as independently validated results. When the story is complete, a shipping run should execute the benchmark command after parity succeeds and upload or retain report files from the benchmark output directory as named artifacts. The observable behavior is that reports for 1,200 accounts by 400 operations and 5,000 accounts by 500 operations are present in the configured artifact location after the benchmark stage finishes. This story does not implement the benchmark runner, generate new benchmark fixtures, change the performance threshold, or modify bank.cob transaction processing. It depends on a benchmark runner that already emits machine-readable and human-readable reports, plus a parity gate that prevents benchmark publication for behaviorally invalid runs. The benchmark capture must preserve the required caveat that preliminary 28.6x and 128.1x values are local prototype results on one host pending independent review. From a platform perspective, the step must be diagnosable by artifact name, fixture size, command, and exit code so failed performance evidence does not turn into ambiguous release risk.
| Field | Value |
|---|---|
| Story Points | 3 |
| Hours | 30h |
| Priority | P1 |
| Labels | platform, ci-cd, benchmarking, artifact-capture, complexity:medium |
Acceptance Criteria
Depends on: WO-026, WO-020
Add scripts/package_artifacts.sh to create a deterministic archive containing fixtures, ledgers, audit JSONL, parity diffs, and benchmark reports so reviewers can download one complete modernization evidence bundle. The new script belongs at scripts/package_artifacts.sh, with README.md receiving only a minimal operator pointer if needed because README.md is the existing documentation surface in the repository. Currently the repository has no packaging script and evidence from parity, benchmark, audit, and run workspaces can remain scattered across local directories after a Forge Shipping run. Stakeholders need a single reproducible archive to support offline side-by-side sign-off, rollback review, and SRE incident-style diagnosis when a gate fails. When complete, a developer can run the script with an input artifact root and output path, then inspect the archive and find fixture inputs, final ledgers, audit JSONL files, parity diffs, benchmark reports, and a manifest. The script should preserve relative paths, avoid absolute host paths, and exclude secrets or unrelated local files from the package. This story does not create the fixtures, generate parity diffs, run benchmarks, decide sign-off, or upload the archive to a remote artifact store. It depends on stable artifact directories produced by parity and benchmark automation, plus append-only local audit evidence from the prototype runtime. The packaging workflow must be safe for shell execution by using strict mode, validating allow-listed directories, and failing closed when required evidence categories are absent. Operationally, the archive becomes the handoff artifact for rollback analysis: retain original inputs, compare outputs, discard generated modern output if needed, and rerun the COBOL baseline.
| Field | Value |
|---|---|
| Story Points | 5 |
| Hours | 50h |
| Priority | P2 |
| Labels | platform, artifact-packaging, audit-evidence, shell-script, complexity:medium |
Acceptance Criteria
Depends on: WO-021, WO-025, WO-029
Update README.md with an operational rollout runbook covering Docker execution, parity gates, benchmark interpretation, rollback, and synthetic-only sign-off so DevOps and SRE reviewers can run the prototype without relying on tribal knowledge. The change belongs in README.md, the only existing documentation module for the bbs-sg legacy batch, and it should reference bank.cob as the retained COBOL baseline. Today README.md is only a seven-line overview, so it does not explain the Forge Shipping pipeline, the parity gate, benchmark artifact capture, the packaging script, or how to recover by discarding modern output and rerunning legacy-bank. Stakeholders need this runbook because the prototype is intentionally offline and evidence-driven, and approval must be blocked by parity failure rather than operator judgment. When complete, a developer can follow README.md from a clean checkout through Docker build, Forge Shipping validation, parity execution, benchmark capture, evidence packaging, rollback, and sign-off boundaries. The observable behavior is documentation that names the specific commands and artifacts operators should use, including .forge/shipping.yml, tests/test_parity.py, benchmarks/runner.py, and scripts/package_artifacts.sh. This story does not change pipeline behavior, implement Docker files, alter test code, generate benchmarks, or modify the COBOL batch logic. It depends on working build and scan automation, parity gating, benchmark capture, and deterministic evidence packaging being available. The runbook must explicitly state that only synthetic fixtures are allowed, preliminary speedups are local single-host prototype results pending independent review, and no production banking readiness is implied. It should be written in operational language with clear rollback triggers, expected artifacts, and failure handling so mean-time-to-recovery for a failed prototype run is a rerun from retained inputs rather than manual reconstruction.
| Field | Value |
|---|---|
| Story Points | 2 |
| Hours | 20h |
| Priority | P2 |
| Labels | documentation, runbook, rollout, rollback, complexity:low |
Acceptance Criteria
Depends on: WO-018, WO-031