From 7cb0278be0aebbba7161ede32e4e98e42fb3a267 Mon Sep 17 00:00:00 2001 From: Nora Date: Tue, 7 Jul 2026 12:02:33 -0600 Subject: [PATCH] docs(sp37): document canonical submit-batch flow RUNBOOK gets a 'Submitting claims (canonical)' section with both CLI and HTTP examples, the shared cyclone.submission.submit_file helper, and a 'submit-batch vs resubmit-rejected-claims' decision rule. CLAUDE.md gets a pointer to cyclone/submission/ in the 'Backend at a glance' subpackage list. --- CLAUDE.md | 2 +- docs/RUNBOOK.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 8dfdba6..8c7cb9e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -125,7 +125,7 @@ Frontend triplet for any live page: `use(params)` (initial fetch) + `useTailS ## Backend at a glance -`backend/src/cyclone/` is a single namespace. The two largest files are `api.py` (~3,548 LOC, the only large file) and `store.py` (~2,423 LOC, the `CycloneStore` facade — SP21 is in flight to split it into a `cyclone/store/` subpackage; the public API stays unchanged). Subpackages: `api_routers/` (acks, admin, health, ta1_acks), `clearhouse/` (Clearhouse + SftpClient), `edi/` (filenames), `parsers/` (X12 transaction parsers + models + validators + serializers), `workflow/` (placeholder for future sub-project 6). +`backend/src/cyclone/` is a single namespace. The two largest files are `api.py` (~3,548 LOC, the only large file) and `store.py` (~2,423 LOC, the `CycloneStore` facade — SP21 is in flight to split it into a `cyclone/store/` subpackage; the public API stays unchanged). Subpackages: `api_routers/` (acks, admin, health, ta1_acks), `clearhouse/` (Clearhouse + SftpClient), `edi/` (filenames), `parsers/` (X12 transaction parsers + models + validators + serializers), `submission/` (SP37 — canonical `submit_file` helper shared by `cyclone submit-batch` CLI + `POST /api/submit-batch` HTTP endpoint; owns parse → DB-write → SFTP-upload → audit per file), `workflow/` (placeholder for future sub-project 6). The store is the only read/write surface for the database; every mutating endpoint goes through it. All persistence flows through SQLAlchemy sessions via `db.SessionLocal()()`. SQLAlchemy ORM models live in `db.py`; 12 SQL migrations under `migrations/` (0001_initial through 0012_backups) are walked in order by `db_migrate.py`. diff --git a/docs/RUNBOOK.md b/docs/RUNBOOK.md index 1271f43..cd241db 100644 --- a/docs/RUNBOOK.md +++ b/docs/RUNBOOK.md @@ -187,6 +187,52 @@ absent.) `processed_inbound_files` are skipped automatically — to re-process, delete the row first (`DELETE FROM processed_inbound_files WHERE name = ...`). +### Submitting claims (canonical — SP37) + +For 837P files generated upstream (dzinesco) that you want cyclone to +**track in the DB** before uploading, use the canonical submit path. +This is the preferred outbound path going forward — it captures the +batch's `transaction_set_control_number` (the ST02 control number that +999 acks reference in AK201) so future 999 ack links resolve instead +of becoming orphans. + +```bash +cd /home/tyler/dev/cyclone/backend + +# 1. Lay out files in batch-*-claims subdirs under your ingest dir: +# ingest/batch-2026-07-08-claims/claim-001.x12 +# ingest/batch-2026-07-08-claims/claim-002.x12 +# ... + +# 2. CLI — walks ingest/, parses, writes to DB, then SFTP-uploads. +.venv/bin/python -m cyclone submit-batch \ + --ingest-dir /home/tyler/dev/cyclone/ingest \ + --actor cli-submit-batch + +# Or via HTTP (auth-gated by matrix_gate): +curl -s -X POST http://localhost:8000/api/submit-batch \ + -H 'Content-Type: application/json' \ + -d '{"ingest_dir": "/home/tyler/dev/cyclone/ingest", "actor": "api-submit-batch"}' +``` + +Both surfaces share `cyclone.submission.submit_file` for the +parse → DB-write → SFTP-upload chain (DB-first, upload-second +invariant). The walker pattern is identical: `batch-*-claims/*.x12`, +sorted, with `._*` AppleDouble files skipped. + +**When to use `submit-batch` vs `resubmit-rejected-claims`:** +- `submit-batch` — canonical path for fresh 837s from dzinesco (or any + source) that should be tracked in the DB before upload. Default choice. +- `resubmit-rejected-claims` — one-off path for cases where you do NOT + want a DB row (e.g., dzinesco-generated fixes not ready for canonical + tracking). Legacy, retained for backward compat. + +**Status codes / exit codes:** +- HTTP 200 on completed runs (per-file failures live in the JSON body); + 401 unauthenticated; 404 no clearhouse; 409 stub mode; 422 validation. +- CLI exit 0 on completed runs (per-file failures counted, not bumped); + 2 on config-level failures (no clearhouse / stub mode / missing dir). + ### Note on per-file parse CLIs `parse-837` and `parse-835` exist as CLIs but only emit JSON files to