Code-quality audit remediation (2026-06-28)
## Summary
Tracking epic for the **2026-06-28 automated code-quality audit** of the CRAIG workspace (236K LOC / 51 crates),
reviewed through a safety-critical Rust lens (DRY/YAGNI/KISS/SOLID, idiomatic Rust, safety, security,
readability, god functions/files/services, concurrency, error-handling, dependency hygiene).
**Method:** multi-agent review (god-object metrics + 16 component deep-dives + 7 cross-cutting sweeps), then
adversarial verification of every finding, then reconciliation against the full GitLab backlog (open + closed +
epics). 104 findings verified; 1 already tracked (#699); 103 filed here.
**Severity:** 7 high · 25 medium · 71 low. Highest-risk cluster: statutory-decision & money correctness that
fails *silently* (foster-care day-count, FFP staleness, AFCARS/NCANDS report integrity, placement occupancy,
exchange retry). See child issues. Many low items belong with existing epics &23 (authz/PII), &29 (DRY),
&34 (partner schemas), &41 (decomposition); cross-referenced per issue.
Child task list added below as issues are created.
## Children
### High (7)
- [ ] #757 fix(exchange): redact partner auth_config; wire or defer outbound auth (weight: 5)
- [ ] #758 fix(exchange): retry endpoint must restage a send-job, not just flip st… (weight: 5)
- [ ] #759 fix(financial): recompute ffp_amount when an adjustment is approved (weight: 5)
- [ ] #760 fix(financial): unify inclusive day-count across persist and /calculate (weight: 5)
- [ ] #761 fix(placement): track occupancy + recheck capacity on planned->active (weight: 5)
- [ ] #762 fix(reporting): stop stamping zero-record AFCARS files "validated" (weight: 5)
- [ ] #763 fix(web): add CSRF protection to cookie-authed state mutations (weight: 5)
### Medium (25)
- [ ] #764 chore(deps): re-audit RUSTSEC-2023-0071 ignore (reachable via JWT) (weight: 3)
- [ ] #765 chore(reference): add counties generator + drift gate (or fix doc) (weight: 3)
- [ ] #766 fix(api): make rate-limit client-IP source proxy-aware (TRUSTED_PROXIES) (weight: 3)
- [ ] #767 fix(cases): fail-closed on concurrent non-superseding dispositions (weight: 3)
- [ ] #768 fix(cases): make state-transition writes atomic (guarded WHERE/FOR UPDA… (weight: 3)
- [ ] #769 fix(cli): handle bare-array list responses in table output (weight: 3)
- [ ] #770 fix(cli): write cached token file with 0600 permissions (weight: 3)
- [ ] #771 fix(common): harden outbound HTTP client (redirect/https/body cap) (weight: 3)
- [ ] #772 fix(exchange): add SSRF allowlist for partner endpoint_url (weight: 3)
- [ ] #773 fix(financial): apply explicit 2dp rounding to monetary products (weight: 3)
- [ ] #774 fix(financial): carry FFP rate/amounts as decimal strings, not f64 (weight: 3)
- [ ] #775 fix(financial): validate financial inputs (sign, magnitude, period/age… (weight: 3)
- [ ] #776 fix(financial): void all placement payments on placement.ended (weight: 3)
- [ ] #777 fix(mq): lock inbox row during idempotent claim/handle/stamp (weight: 3)
- [ ] #778 fix(mq): stop inline-sleeping inbox retries in the consume loop (weight: 3)
- [ ] #779 fix(partner): enforce garde DTO validation on the live dispatch path (weight: 3)
- [ ] #780 fix(placement): single atomic conditional-increment for capacity admit (weight: 3)
- [ ] #781 fix(reference): derive total_admin_unit_count from data + real test (weight: 3)
- [ ] #782 fix(reporting): block NCANDS auto-validate when validation_errors>0 (weight: 3)
- [ ] #783 fix(rules): bound/parallelize single-thread rule evaluation (weight: 3)
- [x] #784 fix(rules): implement the documented evaluate() timeout (weight: 3)
- [ ] #785 fix(rules): propagate eval serialization errors instead of Null-coercing (weight: 3)
- [x] #786 fix(security): narrow authz fail-open to PolicyMissing only (weight: 3)
- [ ] #787 fix(web): URL-encode BFF list filter/search params (weight: 3)
- [ ] #788 refactor(partner): extract shared adapter scaffold + error enum (weight: 3)
### Low (71)
- [ ] #789 chore(auth): security-critical EC signing/base64 crates hardcode versio… (weight: 2)
- [ ] #790 chore(crypto): craig-crypto and craig-mock-server hardcode package meta… (weight: 2)
- [ ] #791 chore(deps): sha2 centralized in the workspace but redeclared locally i… (weight: 2)
- [ ] #792 chore(deps): sqlx pulls unused mysql+sqlite drivers because default-fea… (weight: 2)
- [ ] #793 chore(docker): build stage installs openssl dev/static libs, contradict… (weight: 2)
- [ ] #794 chore(seed): seed payment amounts use a hardcoded GA rate literal, igno… (weight: 2)
- [ ] #795 fix(api): admin event-replay re-stages ALL rows in the window, includin… (weight: 2)
- [ ] #796 fix(api): rate-limit middleware doc comment is stale on both API names… (weight: 2)
- [ ] #797 fix(auth): inbound JWT/JWS validation hard-pins RS256, excluding ES256/… (weight: 2)
- [ ] #798 fix(auth): oAuth client secrets and an intermediate JWK string are not… (weight: 2)
- [ ] #799 fix(cases): auto-link referral creation and audit fan-out commit in sep… (weight: 2)
- [ ] #800 fix(cli): password accepted as a CLI flag, exposing it to ps / shell hi… (weight: 2)
- [ ] #801 fix(composition): rFC 6902 override layers applied with no op-count/dep… (weight: 2)
- [ ] #802 fix(composition-engine): composition content version truncates SHA-256… (weight: 2)
- [ ] #803 fix(composition-engine): grid row index type diverges between engine (u… (weight: 2)
- [ ] #804 fix(exchange): inbox case-assignment reassignment runs three UPDATEs ou… (weight: 2)
- [ ] #805 fix(financial): ffp_amount recompute is split across two uncoordinated… (weight: 2)
- [ ] #806 fix(financial): workspace-wide arithmetic_side_effects allow blankets c… (weight: 2)
- [ ] #807 fix(intake): stale authz-skip comment overstates a since-closed partner… (weight: 2)
- [ ] #808 fix(intake-keyring): standalone keyring performs blocking fsync under a… (weight: 2)
- [ ] #809 fix(rules): no per-evaluation resource ceiling on untrusted JDM input b… (weight: 2)
- [ ] #810 fix(rules): rule-set name has no validation; flows into RabbitMQ routin… (weight: 2)
- [ ] #811 fix(store): attachmentScanner and idempotency cleanup workers cannot be… (weight: 2)
- [ ] #812 fix(web): bFF write-authorization is template display logic only (with… (weight: 2)
- [ ] #813 fix(web): oAuth login flow omits a nonce and never verifies id/access-t… (weight: 2)
- [ ] #814 fix(web): role-gate middleware authorizes on JWT claims decoded without… (weight: 2)
- [ ] #815 fix(xtask): crate-wide arithmetic_side_effects allow masks step-counter… (weight: 2)
- [ ] #816 refactor(api): cORS origin parsing silently drops unparseable entries i… (weight: 2)
- [ ] #817 refactor(api): idempotency response cache silently drops non-ASCII head… (weight: 2)
- [ ] #818 refactor(cases): case-number entropy derived from UUID v7 low bytes rat… (weight: 2)
- [ ] #819 refactor(cases): concurrent report conversion surfaces a 500 instead of… (weight: 2)
- [ ] #820 refactor(cases): direct-to-DB integration-test connection-URL helper du… (weight: 2)
- [ ] #821 refactor(cases): inconsistent domain-event emission across mutating han… (weight: 2)
- [ ] #822 refactor(cases): pagination offset/limit/clamp arithmetic repeated acro… (weight: 2)
- [ ] #823 refactor(cli): 32 byte-identical CLI client wrappers — ~2,220 LOC of pu… (weight: 2)
- [ ] #824 refactor(cli): some delete/revoke commands succeed silently — inconsist… (weight: 2)
- [ ] #825 refactor(common): from<anyhow::Error> for ApiError is a typed-boundary… (weight: 2)
- [ ] #826 refactor(composition): o(items x plugins) export-slug resolution reimpl… (weight: 2)
- [ ] #827 refactor(composition): rEALM_ROLES hardcoded role set duplicated from c… (weight: 2)
- [ ] #828 refactor(crypto): shared library crates (craig-crypto, craig-rules-clie… (weight: 2)
- [ ] #829 refactor(docker): per-service runtime stages duplicate apk add curl and… (weight: 2)
- [ ] #830 refactor(intake): prepare_submission's load-bearing step ordering is do… (weight: 2)
- [ ] #831 refactor(matching): dob_year_match compares years via string formatting… (weight: 2)
- [ ] #832 refactor(mq): stringly-typed envelope-serialization error mapped to sql… (weight: 2)
- [ ] #833 refactor(partner-audit): 10 audit codecs are near-identical clones (orp… (weight: 2)
- [ ] #834 refactor(partner-caps): audit() projects partner ack UTC date as a prox… (weight: 2)
- [ ] #835 refactor(partner-cprs): clippy allow-block preamble pasted into many in… (weight: 2)
- [ ] #836 refactor(partner-cprs): partner adapter test scaffolding (round_trip.rs… (weight: 2)
- [ ] #837 refactor(placement): matching GET stages an outbox event and reuses chi… (weight: 2)
- [ ] #838 refactor(reference): admin_unit_by_name uses allocating to_lowercase()… (weight: 2)
- [ ] #839 refactor(reference): workspace-wide validate_* helpers return Result<()… (weight: 2)
- [ ] #840 refactor(reference): ~45 carried-over 'countyies' typos in counties.rs… (weight: 2)
- [ ] #841 refactor(reporting): eligibility-derived quality issues are mislabeled… (weight: 2)
- [ ] #842 refactor(reporting): inbound data-quality event handlers duplicate a ne… (weight: 2)
- [ ] #843 refactor(reporting): list handlers return untyped serde_json::Value env… (weight: 2)
- [ ] #844 refactor(reporting): submission status is stringly-typed end-to-end des… (weight: 2)
- [ ] #845 refactor(security): uUIDv4-pair API keys provide 244 bits of entropy, n… (weight: 2)
- [ ] #846 refactor(seed): hand-maintained COLUMNS must stay in lockstep with writ… (weight: 2)
- [ ] #847 refactor(state-bundle): five registry from_bundles impls are near-ident… (weight: 2)
- [ ] #848 refactor(test-lib): 98 near-identical client-factory methods in harness… (weight: 2)
- [ ] #849 refactor(test-lib): testHarness::new() documents a failure-on-unreachab… (weight: 2)
- [ ] #850 refactor(web): bFF tolerant-upload conflates an errored/truncated uploa… (weight: 2)
- [ ] #851 refactor(web): created-resource IDs silently swallowed to empty string,… (weight: 2)
- [ ] #852 refactor(web): hTTP status round-tripped through formatted error string… (weight: 2)
- [ ] #853 refactor(web): render_plugin is a long but cohesive request pipeline (b… (weight: 2)
- [ ] #854 refactor(xtask): hardcoded [N/13] step-numbering in validate.rs has ove… (weight: 2)
- [ ] #855 refactor(xtask): long-function budget silently scores unparseable files… (weight: 2)
- [ ] #856 refactor(xtask): near-duplicate compose* wrapper family in docker.rs (weight: 2)
- [ ] #857 refactor(xtask): three divergent workspace_root() implementations with… (weight: 2)
- [ ] #858 test(partner-caps): untrusted partner-response parse has a fuzz/proptes… (weight: 2)
- [ ] #859 test(test-lib): evil-corpus ExpectedRejection::ProblemType ignores the… (weight: 2)
### Already tracked (not re-filed)
- #699 chore(docker): migrate sibling service images to non-root runtime (audit finding `docker-services-run-as-root`)
## Follow-up audit-coverage gaps filed (completeness critic)
- [ ] #894 fix(store): legitimate OOXML uploads (docx/xlsx/pptx) may be silently rejected by the MIME sniff
- [ ] #895 feat(cases): confirm + enforce O.C.G.A. investigation-response deadlines server-side
- [ ] #896 test(security): full PII-in-logs sweep of mutating handlers (cases/financial/placement)
- [ ] #897 chore(db): audit existing migrations for FK ON DELETE / NOT NULL / CHECK / soft-delete coverage
- [ ] #898 chore(db): set max_lifetime on the Postgres pool for failover hygiene
## Preserve-as-invariant (audit strengths — do NOT refactor away or weaken)
The audit verified these subsystems as load-bearing and correctly built. Recording here so the remediation work does not mistake them for over-engineering or regress them:
- **Composition content version truncates SHA-256 to 8 bytes — cache discriminator only** — `crates/craig-composition-engine/src/hash.rs:41`
- **CONFIRMED-GOOD: single-impl DI traits and the single-consumer craig-crypto crate are justified, not YAGNI** — `crates/craig-auth/src/introspection.rs:461; crates/craig-auth/src/actor_verifier.rs:59`
- **CONFIRMED-GOOD: untrusted-ingress security pipeline (JWS-before-parse, uniform-401, replay, cross-partner binding, redaction)** — `services/craig-intake/src/backend/shines/signed_submit.rs:114-199; services/craig-intake/src/api/jws.rs:75-284`
- **CONFIRMED-GOOD: SHINES mapper is a pure, total, hash-pinned, property-tested translation with no silent defaults** — `services/craig-intake/src/backend/shines/mapper.rs:327-613; services/craig-intake/src/backend/shines/mapper.rs:1248-1287`
- **CONFIRMED-GOOD: transport abstraction, registry/bundle orchestration, and send-worker idempotency** — `crates/craig-exchange-transport/src/transport.rs:62-106; services/craig-exchange/src/bundle_orchestrator.rs:236-294`
- **CONFIRMED-GOOD: plugin macro hygiene, manifest validation, and the compile-time loading seam** — `crates/craig-plugin-macros/src/lib.rs:143; crates/craig-plugin-contracts/src/manifest.rs:357`
- **CONFIRMED-GOOD: clippy panic-gate is effective — unwrap/expect/panic test-only, no runtime todo!/unimplemented!, no product unsafe; casts/indexing bounded** — `crates/craig-crypto/src/lib.rs:37; crates/craig-composition-engine/src/defaults.rs:21-39`
- **CONFIRMED-GOOD: complete JWT/JWS validation and redacted error responses across auth and error layers** — `crates/craig-auth/src/jwks.rs:288-381; crates/craig-auth/src/actor_verifier.rs:199-279`
- **CONFIRMED-GOOD: centralized plumbing that is correctly DRY (ApiError/IntoResponse, env-prefixed config, erased-adapter macro, StubTransport)** — `crates/craig-common/src/error.rs:91-351; crates/craig-bootstrap/src/authz_source.rs:59`
- **CONFIRMED-GOOD: craig-security is the widest bounded context but is cleanly decomposed** — `services/craig-security/src/api/; services/craig-security/src/api/mod.rs:602`
- **CONFIRMED-GOOD: headline 'large' files are inflated by in-file tests / generated data / flat DTOs, not cohesion defects** — `crates/craig-reference/src/counties.rs:1; services/craig-composition/src/loader.rs:865`
_From the 2026-06-28 audit's 'Confirmed-good' theme; not actionable, context for the dev team._
epic