You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Update docs/translation-rules.md with the patterns that surfaced repeatedly during the INQCUST POC auto-review (PR #4, 6 rounds). The companion code-side issue is #5.
Goal: every subsequent program PR should converge in ≤2 review rounds because the rulebook is now explicit on these points.
Patterns to codify
Single 500 JSON schema via ProblemDetail end-to-end. Successful responses are domain DTOs; every error response (4xx/5xx) is ProblemDetail (RFC 7807). No per-program legacy result-record leaks to the wire on the error path. @RestControllerAdvice builds the body; controllers do not handcraft error JSON.
Defensive null-checks at service-method boundaries. Every public service method begins with Objects.requireNonNull(arg, "arg must not be null") for each parameter. Every constructor of an immutable result record (e.g. …Result.success(record)) null-checks its arguments before assigning fields.
@Valid on controller request bodies. Any controller method that accepts a @RequestBody DTO must mark the parameter @Valid. Validation annotations on DTO classes that are never @Valid-bound are dead code and must be removed or wired up.
Deterministic randomness via injected source / clock. Services must not call ThreadLocalRandom, Math.random, Random.next*, or Instant.now() directly. Inject a small interface (e.g. RandomCustomerNumberGenerator, Clock) and provide a deterministic test double. Integration tests must not depend on probabilistic outcomes.
Retry off-by-one: random-exhaustion vs not-found. When a bounded retry loop in random-pick mode exhausts without finding a target, the response is a distinct "retry exhausted" outcome (fail code "R" → HTTP 503), not a generic backend abend. "Exact key not found" remains fail code "1" → HTTP 404.
Control-baseline preservation on writes and in tests. The control table holds Flyway-seeded invariants (sortcode, last_*_number, *_count). Production code must UPDATE rather than DELETE+insert; integration-test cleanup must either skip control entirely (preferred) or re-insert the canonical baseline row after deleting. The canonical baseline row is sortcode 987654, all counters/last-numbers 0.
Empty-table → 404, not 500. For read paths, an empty target table is semantically "not found", matching the COBOL behavior where an empty file produces the same fail code as a missing record. Map empty-table outcomes to the regular not-found fail code, not the backend-failure code.
Acceptance
docs/translation-rules.md has new sections covering each of the seven patterns above, with a brief rationale and a code-shape example for each.
Update
docs/translation-rules.mdwith the patterns that surfaced repeatedly during the INQCUST POC auto-review (PR #4, 6 rounds). The companion code-side issue is #5.Goal: every subsequent program PR should converge in ≤2 review rounds because the rulebook is now explicit on these points.
Patterns to codify
Single 500 JSON schema via
ProblemDetailend-to-end. Successful responses are domain DTOs; every error response (4xx/5xx) isProblemDetail(RFC 7807). No per-program legacy result-record leaks to the wire on the error path.@RestControllerAdvicebuilds the body; controllers do not handcraft error JSON.Defensive null-checks at service-method boundaries. Every public service method begins with
Objects.requireNonNull(arg, "arg must not be null")for each parameter. Every constructor of an immutable result record (e.g.…Result.success(record)) null-checks its arguments before assigning fields.@Validon controller request bodies. Any controller method that accepts a@RequestBodyDTO must mark the parameter@Valid. Validation annotations on DTO classes that are never@Valid-bound are dead code and must be removed or wired up.Deterministic randomness via injected source / clock. Services must not call
ThreadLocalRandom,Math.random,Random.next*, orInstant.now()directly. Inject a small interface (e.g.RandomCustomerNumberGenerator,Clock) and provide a deterministic test double. Integration tests must not depend on probabilistic outcomes.Retry off-by-one: random-exhaustion vs not-found. When a bounded retry loop in random-pick mode exhausts without finding a target, the response is a distinct "retry exhausted" outcome (fail code
"R"→ HTTP 503), not a generic backend abend. "Exact key not found" remains fail code"1"→ HTTP 404.Control-baseline preservation on writes and in tests. The
controltable holds Flyway-seeded invariants (sortcode, last_*_number, *_count). Production code mustUPDATErather thanDELETE+insert; integration-test cleanup must either skipcontrolentirely (preferred) or re-insert the canonical baseline row after deleting. The canonical baseline row is sortcode987654, all counters/last-numbers0.Empty-table → 404, not 500. For read paths, an empty target table is semantically "not found", matching the COBOL behavior where an empty file produces the same fail code as a missing record. Map empty-table outcomes to the regular not-found fail code, not the backend-failure code.
Acceptance
docs/translation-rules.mdhas new sections covering each of the seven patterns above, with a brief rationale and a code-shape example for each.