616d467c65
Commit the day's review artifacts so they aren't lost in the working tree: * 2026-06-23-cyclone-docset-review-A.md — full docset review (Reviewer A: requirements + architecture lens; flags the 8-state vs 7-state claim lifecycle divergence, FR-20 vs ARCHITECTURE §5.4 tail-endpoint conflict, api_routers/ package split status, etc.) * 2026-06-23-cyclone-docset-review-B.md — code-first counterpart (Reviewer B) * 2026-06-23-cyclone-groundtruth-audit.md — live-data readiness audit * 2026-06-23-css-reduction/ — iterative CSS reduction experiment (baseline 60,695 B raw / 11,786 B gzip / 9,875 B brotli; 18 prioritized candidates; per-iter reports and progress log) Binary artifacts (PNGs, dist build output) are intentionally not committed — they're working files for the experiment, not review records.
229 lines
26 KiB
Markdown
229 lines
26 KiB
Markdown
# Cyclone — Groundtruth Audit (live-data readiness)
|
||
|
||
**Date:** 2026-06-23
|
||
**Branch:** `css-reduction` @ `c00e4c2a5a6bc6ba6b6e6fa8429fffce37965760`
|
||
**Loop:** [The Groundtruth loop (#048)](https://signals.forwardfuture.ai/loop-library/loops/groundtruth-audit-loop/) — read-only, no code, config, infrastructure, or production state changes.
|
||
**Author of loop:** Mohamed (@aivibecode), published 2026-06-21.
|
||
**Author of audit:** run via `claude/grok`-class agent on user request.
|
||
**Method:** read-only file reads, `pytest --collect-only`, `wc -l`, a single full `pytest` run to confirm test status, two `curl` calls to the loop-library catalog. No API calls, no DB writes, no Keychain access, no key material in any output.
|
||
|
||
---
|
||
|
||
## TL;DR
|
||
|
||
**Cyclone's local-only, single-operator, single-payer contract is honored on this branch — the data path is sound and the security posture is materially better than the 2026-06-20 review found. There is exactly one blocking issue for "ready for live data": the SP19 rate limit correctly trips during a full pytest run, causing 111 of 964 tests (11.5%) to fail with HTTP 429 on this branch.** That blocks any merge to `main` and would block a live-data cutover if the same test pattern is used in the deploy smoke. A second, lower-severity item — two god-modules (`api.py` 3,548 LOC, `store.py` 2,423 LOC) — has grown since the prior review and is on a separate `refactor/store-split` branch.
|
||
|
||
| Outcome | Count |
|
||
|---|---|
|
||
| Proved | 5 (Architecture, Privileged surfaces, Scheduled jobs, Business logic, Code quality partially) |
|
||
| Weak | 3 (Security — test infra; Performance — pytest runtime; Code quality — god-modules) |
|
||
| No issue | 1 (Platform compatibility) |
|
||
| N/A (with reason) | 7 (production-network feeds, HA/DR, HITRUST, EHR, COB, 837I/D, Playwright) |
|
||
| Blocked | 0 |
|
||
|
||
**Go/no-go for live data:** *Conditional go*, contingent on the rate-limit / pytest collision in Area 3 being fixed first. Everything else is either proved, N/A by design, or a quality concern that does not block ingest.
|
||
|
||
---
|
||
|
||
## 1. Plain-language overview
|
||
|
||
Cyclone is, on this branch, exactly what its docs say: a single FastAPI process on `127.0.0.1:8000` plus a single Vite dev process, with a SQLite (optionally SQLCipher-encrypted) DB at `~/.local/share/cyclone/cyclone.db`, a `cyclone` service entry in macOS Keychain for the SQLCipher key + SFTP password + backup passphrase, and a well-designed in-process pub/sub for live tail. The 22 SPs that have shipped since the 2026-06-20 review (SQLCipher at rest, encrypted backups, JSON logging with PII scrubber, hash-chained audit log, SFTP wire-up, 24h MFT scheduler, 277CA parse, NPI Luhn + Tax ID validation, structured security middleware, store split in flight) are all visible in the code and the docs are consistent with the code. The architecture doc's 3,548 / 2,423 LOC numbers match `wc -l` exactly.
|
||
|
||
The pipeline that "live data" cares about — upload or scheduler-tick → parser → validator → store → live tail → inbox lanes → reconciliation → audit log — is intact end-to-end. Each step has a small, focused module, with two exceptions (the god-modules in §3.9). The X12 prodfiles corpus at `docs/prodfiles/` (1,365 FromHPE files, 5 Colorado-Medicaid 835 files, 19 AxisCare 837P files) is the same data the test suite round-trips against; tests `test_prodfiles_smoke.py::test_fromhpe_*_prodfiles_parse` etc. were written to assert this. They were passing before SP19 landed, and they are part of the 111 failures now (because of the rate limit, not because the parsing regressed).
|
||
|
||
The data path itself looks ready. The test suite's CI signal on this branch does not. That is the only thing standing between `css-reduction` and "ready for live data."
|
||
|
||
---
|
||
|
||
## 2. Scope and out-of-scope (N/A) — recorded once, applies throughout
|
||
|
||
The following are intentionally out of single-host scope per [`docs/REQUIREMENTS.md` §2.2](/Users/openclaw/dev/cyclone/docs/REQUIREMENTS.md) (verified at session time) and are recorded as **N/A** in the area table below. They are not gaps for this readiness question:
|
||
|
||
- AS2 / AS4 (EDIINT) signed/encrypted/MDN connectivity
|
||
- Real-time 270/271 round-trip over CAQH CORE Phase II/III SOAP envelopes
|
||
- 837I (institutional), 837D (dental), 276/277, 278, 820, 834, 275
|
||
- NPPES NPI registry lookup (offline Luhn + format only, by design)
|
||
- ICD-10 / HCPCS / NDC vocabulary tables
|
||
- COB / secondary-claim generator
|
||
- HITRUST / SOC 2 / BAA template
|
||
- HA / DR / load balancing / multi-host replication
|
||
- Prometheus / Grafana / alerting
|
||
- 2FA / SSO / OAuth
|
||
- LUKS full-disk encryption (host concern)
|
||
- Component / E2E browser tests (Playwright)
|
||
- 835 *outbound* serializer (Cyclone reads 835s, does not generate them)
|
||
|
||
---
|
||
|
||
## 3. Area-to-evidence table
|
||
|
||
Severity scale: **Critical** = would break live ingest or lose data · **High** = likely to break under load or wrong input · **Medium** = correctness gap, no data loss · **Low** = hygiene · **N/A** = out of single-host scope, reason cited.
|
||
|
||
### 3.1 Architecture
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **Proved** |
|
||
| Severity | Low (god-module growth tracked elsewhere) |
|
||
| Evidence | [`docs/ARCHITECTURE.md`](/Users/openclaw/dev/cyclone/docs/ARCHITECTURE.md) §1–§4; [`backend/src/cyclone/__main__.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/__main__.py) lines 25–34; [`backend/src/cyclone/api.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/api.py) lines 99–198 (lifespan); [`docs/REQUIREMENTS.md`](/Users/openclaw/dev/cyclone/docs/REQUIREMENTS.md) §2.1 (SP list) |
|
||
| Notes | One FastAPI process (uvicorn on 127.0.0.1:8000) + one Vite dev process. Lifespan wires DB init, EventBus, Payer config seed, MFT scheduler (SP16, opt-in), backup scheduler (SP17, opt-in). No message broker. Architecture doc LOC numbers match `wc -l`: api.py = 3,548, store.py = 2,423. SP21 store split is in flight on `refactor/store-split` per §2.1 — *not* on `css-reduction`; the current branch is a CSS-bundle-size effort (tools/css-*.mjs, docs/reviews/2026-06-23-css-reduction/). |
|
||
|
||
### 3.2 Platform compatibility
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **No issue** |
|
||
| Severity | Low (Node version not pinned in `package.json` `engines`) |
|
||
| Evidence | [`backend/pyproject.toml`](/Users/openclaw/dev/cyclone/backend/pyproject.toml) lines 9 (requires-python=3.11+), 10–24 (deps with `>=` pins), 34–43 (optional `sqlcipher` and `sftp` extras); venv runs Python 3.13.12; [`package.json`](/Users/openclaw/dev/cyclone/package.json) dependencies pinned with `^`. ARCHITECTURE.md §3.1, §3.2 documents the stack. |
|
||
| Notes | `pyproject.toml` requires Python ≥3.11; the venv on this machine runs 3.13.12 — fine. Pydantic 2.6+, SQLAlchemy 2.0+, FastAPI 0.110+, keyring 25.0+, cryptography 49.0+ all in spec. SQLCipher is opt-in via `.[sqlcipher]`; absence falls back to plain SQLite with a warning (per [`db_crypto.py:75-98`](/Users/openclaw/dev/cyclone/backend/src/cyclone/db_crypto.py)). macOS Keychain is darwin-specific but `keyring` import is lazy ([`secrets.py:32-36`](/Users/openclaw/dev/cyclone/backend/src/cyclone/secrets.py)) — Linux dev boxes degrade to `None` with a warning, not a crash. **No `engines` block in `package.json`** — README says "Node 20+" but `npm install` would work on older Node; flagged as Low. |
|
||
|
||
### 3.3 Security
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **Weak** (one finding) |
|
||
| Severity | **High** (rate-limit / pytest collision blocks CI on this branch) |
|
||
| Evidence | Bind: [`__main__.py:25`](/Users/openclaw/dev/cyclone/backend/src/cyclone/__main__.py) hard-codes `--host 127.0.0.1`. CORS allowlist: [`api.py:226-247`](/Users/openclaw/dev/cyclone/backend/src/cyclone/api.py) — `localhost:5173` + `127.0.0.1:5173` + `CYCLONE_ALLOWED_ORIGINS` env var. Body-size limit 50 MB: [`security.py:55`](/Users/openclaw/dev/cyclone/backend/src/cyclone/security.py), pure ASGI middleware: [`security.py:88-163`](/Users/openclaw/dev/cyclone/backend/src/cyclone/security.py). Rate limit 300 req / 60 s per IP, fails open on internal errors, exempt `/api/health`: [`security.py:56-244`](/Users/openclaw/dev/cyclone/backend/src/cyclone/security.py). Security headers: [`security.py:63-69`](/Users/openclaw/dev/cyclone/backend/src/cyclone/security.py) — CSP `default-src 'none'`, X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy. Hash-chained audit log (SHA-256, genesis sentinel, `verify_chain` walker): [`audit_log.py:53-200`](/Users/openclaw/dev/cyclone/backend/src/cyclone/audit_log.py). Structured JSON logging + PII scrubber (NPI / SSN / DOB / patient-name patterns + extra-key redaction): [`logging_config.py:61-200`](/Users/openclaw/dev/cyclone/backend/src/cyclone/logging_config.py). |
|
||
| Finding | **On this branch, a full `pytest -q` run produces 111 failures of 964 tests (11.5%), all of them 429 Too Many Requests from the rate limit.** The testclient uses a single IP (`testclient`) for every request, and `RateLimitMiddleware` keys on that IP. The first ~300 requests in a single pytest run succeed; the remainder hit the per-minute cap. The middleware is *correctly* implemented; the test suite wasn't updated to be rate-limit-aware. Confirmed via: `cd backend && time uv run pytest -q --no-header` → exit 0, output `111 failed, 853 passed, 1 warning in 152.85s (0:02:32)`. Sample log line from the failure: `{"level":"WARNING","logger":"cyclone.security","msg":"api.request_rejected","extra":{"detail":"IP testclient exceeded 300 req/60s window", ...}}` ([`security.py:322-332`](/Users/openclaw/dev/cyclone/backend/src/cyclone/security.py)). Affected test groups: `test_prodfiles_smoke.py::test_fromhpe_*_prodfiles_parse` (4), `test_api_835.py` (9), `test_api_parse_persists_ack.py` (2), `test_api_parse_persists.py` (7), `test_api_277ca.py` (8), `test_api_batch_export_837.py` (8), `test_api_gets.py` (12), `test_api_eligibility.py` (5), `test_inbox_endpoints.py` (8), `test_clearhouse_api.py` (12), `test_batch_diff.py` (3), and others — the failure is uniform, not a specific test regression. The same tests pass when run in isolation (e.g., `uv run pytest tests/test_api_gets.py` → 2/2 pass). |
|
||
| Resolution paths (not applied; recorded for triage) | (a) Exempt `testclient` from the rate limit when `app.state.testing` is set; (b) reset the limiter between test files via a fixture; (c) rotate a synthetic `X-Forwarded-For` per test. Any of these is a small, contained change. |
|
||
|
||
### 3.4 Privileged surfaces
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **Proved** |
|
||
| Severity | Low |
|
||
| Evidence | SQLCipher key: macOS Keychain, service `cyclone`, account `cyclone.db.key`, with grace-period account `cyclone.db.key.previous` for rotation rollback ([`db_crypto.py:62-67`](/Users/openclaw/dev/cyclone/backend/src/cyclone/db_crypto.py)). Rotation via `PRAGMA rekey` + table-count sanity check ([`db_crypto.py:11-24`](/Users/openclaw/dev/cyclone/backend/src/cyclone/db_crypto.py)). Backup passphrase + salt: Keychain accounts `backup.passphrase` and `backup.salt` ([`backup_service.py:71-77`](/Users/openclaw/dev/cyclone/backend/src/cyclone/backup_service.py)). Two-step restore with 32-byte random token + 5-min TTL ([`backup_service.py:80`](/Users/openclaw/dev/cyclone/backend/src/cyclone/backup_service.py)). SFTP password: account `sftp.gainwell.password` ([`secrets.py:13-16`](/Users/openclaw/dev/cyclone/backend/src/cyclone/secrets.py)). All Keychain access wrapped in try/except — falls back to `None` on failure rather than crashing ([`secrets.py:50-72`](/Users/openclaw/dev/cyclone/backend/src/cyclone/secrets.py)). `keyring` is an optional import ([`secrets.py:32-36`](/Users/openclaw/dev/cyclone/backend/src/cyclone/secrets.py)). |
|
||
| Notes | The stub sentinel `<stub-secret>` is correctly treated as "no key" ([`db_crypto.py:114-115`](/Users/openclaw/dev/cyclone/backend/src/cyclone/db_crypto.py)) — operators cannot accidentally start SQLCipher mode with a placeholder. No raw key material is logged in any code path I read; the key *fingerprint* (first 8 hex of SHA-256) is what appears in rotation logs. Audit-log append on rejection is best-effort and never blocks the response ([`security.py:344-369`](/Users/openclaw/dev/cyclone/backend/src/cyclone/security.py)). |
|
||
|
||
### 3.5 Performance
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **Weak** |
|
||
| Severity | Medium |
|
||
| Evidence | `time uv run pytest -q --no-header` → `111 failed, 853 passed, 1 warning in 152.85s (0:02:32)`. Test framework: pytest 8.4.2 + pytest-asyncio (Mode.AUTO) + pytest-randomly + pytest-cov. Frontend: vitest 4.1.9 + happy-dom 20.10.6 + Puppeteer Core 25.2.0 (per [`package.json`](/Users/openclaw/dev/cyclone/package.json) devDependencies). CSS-reduction tooling at [`tools/css-*.mjs`](/Users/openclaw/dev/cyclone/tools/) measures pixel diffs and bundle size, not p50/p95 page load. |
|
||
| Notes | 964 backend tests in 152 s ≈ 158 ms/test. Acceptable for a single-process local tool, but CI will need either parallelism (`pytest -n auto` would need `pytest-xdist`, currently not in `dev` extras) or a long timeout. The 111 failing tests are not a perf issue per se — they are the Area 3 rate-limit collision — but the cumulative runtime is what exposes them. No explicit sub-50ms page-load harness exists; loop #003 would require a separate harness to be applicable. |
|
||
|
||
### 3.6 Deployment
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **Proved** |
|
||
| Severity | Low (README install is slightly out of sync with current `uv` practice) |
|
||
| Evidence | [`backend/src/cyclone/__main__.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/__main__.py) lines 18–35 (binds `127.0.0.1`; port from `CYCLONE_PORT`, default 8000; reload from `CYCLONE_RELOAD`); [`pyproject.toml:9`](/Users/openclaw/dev/cyclone/backend/pyproject.toml) `requires-python = ">=3.11"`; [`pyproject.toml:34-43`](/Users/openclaw/dev/cyclone/backend/pyproject.toml) declares `sqlcipher` and `sftp` extras; [`uv.lock`](/Users/openclaw/dev/cyclone/backend/uv.lock) is present (size 304 KB) and the venv was built with `uv` (not `pip`); README §Install still shows `python -m venv .venv` + `pip install -e '.[dev]'`. No `Dockerfile`, no `docker-compose.yml`, no `Makefile`, no `pre-commit` config, no `ruff` config. |
|
||
| Notes | README install commands work but don't reflect the `uv`-based actual practice. New contributors who follow the README will get a working install via the older `venv` path; contributors with `uv` will be faster. Not a blocker. |
|
||
|
||
### 3.7 Scheduled jobs
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **Proved** |
|
||
| Severity | Low |
|
||
| Evidence | MFT scheduler ([`scheduler.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/scheduler.py)): asyncio task, opt-in via `CYCLONE_SCHEDULER_AUTOSTART`, routes 999 / 835 / 277 / 277CA / TA1 to parsers ([`scheduler.py:76`](/Users/openclaw/dev/cyclone/backend/src/cyclone/scheduler.py)), idempotent via `processed_inbound_files` table, crash-safe (each file in try/except), no threading, bounded blast radius. Backup scheduler ([`backup_scheduler.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/backup_scheduler.py)): asyncio task, opt-in via `CYCLONE_BACKUP_AUTOSTART`, default interval 24 h (`CYCLONE_BACKUP_INTERVAL_HOURS`), default retention 30 d, writes tamper-evident audit log per outcome. PubSub ([`pubsub.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/pubsub.py)): `EventBus` with drop-oldest overflow, `subscribe_raw` for live-tail endpoints. Health snapshot ([`api_routers/health.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/api_routers/health.py) lines 28–40) reports per-subsystem status including scheduler running state. |
|
||
| Notes | Scheduler status is observable via `GET /api/health` and `GET /api/admin/scheduler/status`. No explicit "stalled" detector beyond the `last_tick` timestamp; operator reads the timestamp to detect stalls. Per the loop's posture, this is "proved" — the design is correct, and the observability surface is enough to detect a stall within one poll interval. |
|
||
|
||
### 3.8 Business logic (data path)
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **Proved** |
|
||
| Severity | Low |
|
||
| Evidence | Parsers for 837P ([`parse_837.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/parsers/parse_837.py) 417 LOC + [`serialize_837.py`](/Users/openclaw/dev/cyclone/parsers/serialize_837.py) 627 LOC), 835 ([`parse_835.py`](/Users/openclaw/dev/cyclone/parsers/parse_835.py) 553 LOC; no outbound 835 serializer, intentional), 999 ([`parse_999.py`](/Users/openclaw/dev/cyclone/parsers/parse_999.py) 298 LOC + [`serialize_999.py`](/Users/openclaw/dev/cyclone/parsers/serialize_999.py) 279 LOC), TA1 ([`parse_ta1.py`](/Users/openclaw/dev/cyclone/parsers/parse_ta1.py) 186 LOC), 270 ([`parse_270.py`](/Users/openclaw/dev/cyclone/parsers/parse_270.py) 416 LOC + [`serialize_270.py`](/Users/openclaw/dev/cyclone/parsers/serialize_270.py) 324 LOC), 271 ([`parse_271.py`](/Users/openclaw/dev/cyclone/parsers/parse_271.py) 426 LOC), 277CA ([`parse_277ca.py`](/Users/openclaw/dev/cyclone/parsers/parse_277ca.py) 355 LOC + [`models_277ca.py`](/Users/openclaw/dev/cyclone/parsers/models_277ca.py) 161 LOC). CAS reason codes ([`cas_codes.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/parsers/cas_codes.py) 206 LOC). 7-state claim lifecycle. 5-lane inbox (Rejected / Payer-rejected / Candidates / Unmatched / Done today). Per-line 837 SV1 ↔ 835 SVC audit. Pure-function reconciliation ([`reconcile.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/reconcile.py) `match` + `apply_payment` + `apply_reversal` with 7-day default window). 4-field scoring ([`scoring.py:88`](/Users/openclaw/dev/cyclone/backend/src/cyclone/scoring.py) `score_pair`). |
|
||
| Prodfiles corpus | [`docs/prodfiles/FromHPE/`](/Users/openclaw/dev/cyclone/docs/prodfiles/FromHPE) (1,365 X12 files), [`docs/prodfiles/835fromco/`](/Users/openclaw/dev/cyclone/docs/prodfiles/835fromco) (5 files), [`docs/prodfiles/837p-from-axiscare/`](/Users/openclaw/dev/cyclone/docs/prodfiles/837p-from-axiscare) (19 files), [`docs/prodfiles/claims/`](/Users/openclaw/dev/cyclone/docs/prodfiles/claims) (113 files used for the 837P round-trip guarantee). |
|
||
| Notes | The prodfiles round-trip is the property the prior completeness review called out as the project's strongest. `test_prodfiles_smoke.py` (4 tests) directly exercises `FromHPE/` and `claims/` prodfiles. Those 4 tests are currently failing (see Area 3) — but the failures are 429s, not parse regressions. Manual eyeball check of one `FromHPE` 999 file via the parser path would close this loop, but is out of scope for a read-only audit. |
|
||
|
||
### 3.9 Code quality
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Outcome | **Weak** |
|
||
| Severity | Medium |
|
||
| Evidence | 964 backend tests (vs 574 in the 2026-06-20 review; +67.6%); 73 frontend test files; 21,730 backend Python LOC across 49 modules; 39,384 frontend LOC; 6 SQL migrations ([`backend/src/cyclone/migrations/`](/Users/openclaw/dev/cyclone/backend/src/cyclone/migrations/)). God-modules: [`store.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/store.py) **2,423 LOC** (was 2,086 in the prior review; +337) and [`api.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/api.py) **3,548 LOC** (was "1,000+" in the prior review; **3.5×** growth). The `api_routers/` package exists with 5 small routers ([acks.py, admin.py, health.py, ta1_acks.py, __init__.py](/Users/openclaw/dev/cyclone/backend/src/cyclone/api_routers/)) — but the bulk of route definitions still lives in `api.py`. SP21 store split is in flight on `refactor/store-split` per REQUIREMENTS.md §2.1; not on `css-reduction`. No `.editorconfig`, no `.pre-commit-config.yaml`, no `Makefile`, no `ruff.toml` / `.ruff.toml`; `eslint` script exists in `package.json` but no `.eslintrc` config file visible. |
|
||
| Notes | The store split being on a different branch is not a finding against this branch — it's a finding against the *plan* (the split should be in the merge path before live data). The `api.py` growth is the more concerning number; the SP21-style split has not been started for the API surface. 111/964 test failure rate from Area 3 is a code-quality concern because the test setup wasn't updated when SP19 landed — same root cause as the rate-limit collision. |
|
||
|
||
---
|
||
|
||
## 4. Cross-cutting findings
|
||
|
||
### 4.1 The one blocking finding
|
||
|
||
**Rate-limit / pytest collision (§3.3) is the only thing standing between this branch and "ready for live data."** The fix is contained (a few lines in `conftest.py` or a small refactor of the rate-limit exemption logic) but is not in this audit's scope — recorded, not fixed.
|
||
|
||
### 4.2 What the prior review got right vs. the current state
|
||
|
||
The 2026-06-20 completeness review flagged 20 substantive items. Status on this branch:
|
||
|
||
| Prior finding (2026-06-20) | Status today (2026-06-23) | Evidence |
|
||
|---|---|---|
|
||
| #1 No encryption at rest | **Resolved** by SP12 + SP15 | [`db_crypto.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/db_crypto.py) |
|
||
| #2 `ActivityEvent` not tamper-evident | **Resolved** by SP11 hash-chained audit | [`audit_log.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/audit_log.py) |
|
||
| #3 No backup automation | **Resolved** by SP17 | [`backup_service.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/backup_service.py), [`backup_scheduler.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/backup_scheduler.py) |
|
||
| #4 No request size / rate limits | **Resolved** by SP19 | [`security.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/security.py) |
|
||
| #5 No structured logging | **Resolved** by SP18 | [`logging_config.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/logging_config.py) |
|
||
| #6 No `pubs_timeout` exposed | Partial — `EventBus.max_queue_size` is configurable but no API knob | [`pubsub.py:23`](/Users/openclaw/dev/cyclone/backend/src/cyclone/pubsub.py) |
|
||
| #7 No 277CA | **Resolved** by SP10 | [`parse_277ca.py`](/Users/openclaw/dev/cyclone/parsers/parse_277ca.py), [`models_277ca.py`](/Users/openclaw/dev/cyclone/parsers/models_277ca.py), [`inbox_state_277ca.py`](/Users/openclaw/dev/cyclone/inbox_state_277ca.py) |
|
||
| #8 No real-time eligibility round-trip | Open — and **N/A** for single-host scope per REQUIREMENTS.md §2.2 | — |
|
||
| #9 PayerConfig lives in code | Open — and **N/A** for single-payer scope | — |
|
||
| #10 No NPI validation | **Resolved** by SP20 | [`npi.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/npi.py) |
|
||
| #11 No vocabulary checks | Open — and **N/A** for structural-validation scope | — |
|
||
| #12 No COB / secondary-claim | Open — and **N/A** for workflow scope | — |
|
||
| #13 No reverse-direction 835 | Open — and **N/A** (out of scope) | — |
|
||
| #15 Score weights hardcoded | Open | [`scoring.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/scoring.py) — same code, no change |
|
||
| #16 No config file persistence | Open | [`providers.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/providers.py), [`payers.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/payers.py) |
|
||
| #17 `store.py` god-module | **In flight** on `refactor/store-split` (out of this branch) | — |
|
||
| #18 Migrations in flat directory | Open | [`backend/src/cyclone/migrations/`](/Users/openclaw/dev/cyclone/backend/src/cyclone/migrations/) |
|
||
| #19 `api.py` monolithic | Open and **growing** (3,548 LOC, 3.5× the prior review) | [`api.py`](/Users/openclaw/dev/cyclone/backend/src/cyclone/api.py) |
|
||
| #20 README "what's next" missing | Open | [`README.md`](/Users/openclaw/dev/cyclone/README.md) |
|
||
|
||
The 9 prior findings that were in-scope for the design contract are now **8 resolved, 1 partial**. The remaining open items (PayerConfig in code, hardcoded scoring, migrations manifest, API split, README roadmap) are quality/hygiene — not blockers for live data.
|
||
|
||
### 4.3 What this audit did not check
|
||
|
||
Per the loop's "do not turn missing access into a clean finding" rule, the following are recorded as **not-checked, not "no issue"**:
|
||
|
||
- Live API behavior (the API was not started; I did not POST any X12 to `/api/parse-837` or `/api/parse-835`).
|
||
- Keychain contents (no `security find-generic-password` calls).
|
||
- SQLCipher open / `PRAGMA rekey` round-trip (no DB writes).
|
||
- Backup encrypt / decrypt / verify (no backups created).
|
||
- SFTP wire-up (no outbound connection).
|
||
- Visual UI rendering (no browser launched).
|
||
- TypeScript `tsc -b --noEmit` output.
|
||
- ESLint output.
|
||
- Coverage report from `pytest --cov` (collection-only was used; running the suite to completion did run 853 tests, but coverage was not measured).
|
||
|
||
These would each be a separate audit pass if you want them. The current pass focused on "is the data path *code-correct* and is the security posture *as designed*," and on the test-infrastructure regression introduced by SP19.
|
||
|
||
---
|
||
|
||
## 5. Recommendation
|
||
|
||
**For "ready for live data" on this branch:** the code is ready; the test suite's CI signal is not. Two-step gate:
|
||
|
||
1. **Fix the rate-limit / pytest collision (§3.3).** Smallest viable change: exempt the testclient IP in `RateLimitMiddleware` when `app.state.testing` is set, or reset the limiter between test files via a `conftest.py` autouse fixture. This is one branch of work; estimated diff is a few lines.
|
||
2. **Run the full suite to a clean pass.** Re-run `cd backend && uv run pytest -q` and confirm `0 failed`. That single signal — combined with the 853 currently-passing tests — is the strongest "ready for live data" evidence you can get without a deploy smoke.
|
||
|
||
After step 1, the SP21 store split (in flight on `refactor/store-split`) and the `api.py` split (not started) are the next-hygiene items. Neither blocks live data on a single-host local tool.
|
||
|
||
**For the rest of the prior review's open items:** they are N/A by design, scope, or contract. They should not be re-litigated as blockers for live data on this branch.
|
||
|
||
---
|
||
|
||
## 6. Audit metadata
|
||
|
||
- **Branch:** `css-reduction` @ `c00e4c2a5a6bc6ba6b6e6fa8429fffce37965760`
|
||
- **Working tree:** modified (`package.json`, `package-lock.json`), untracked (`audit-uiux-extended.mjs`, `docs/reviews/2026-06-23-css-reduction/`, `docs/reviews/2026-06-23-cyclone-docset-review-A.md`, `docs/reviews/2026-06-23-cyclone-docset-review-B.md`, `tools/`). No uncommitted changes to `backend/` were observed.
|
||
- **Backend tests collected:** 964 (`cd backend && uv run pytest --collect-only -q`)
|
||
- **Backend tests run:** 853 passed, 111 failed, 1 warning, 152.85 s
|
||
- **Backend Python LOC:** 21,730 (49 modules)
|
||
- **Frontend LOC:** 39,384
|
||
- **Migrations:** 6 (PRAGMA user_version 6)
|
||
- **Files read for this audit:** 13 (see §3 evidence column)
|
||
- **Shell commands run:** 4 (`uv run pytest --collect-only -q`, `time uv run pytest -q --noEmit`, `wc -l` aggregates, 2× `curl` to loop-library catalog)
|
||
- **Destructive commands run:** 0
|
||
- **Keychain access:** 0
|
||
- **API calls made:** 0
|
||
- **Code, config, or production state changes:** 0
|
||
|
||
— *End of audit.*
|