Repository navigation
fix(edi): report what ingest_events stored in the response status - #3819
PetrefiedThunder wants to merge 1 commit into
Conversation
Both EDI routes returned status "accepted" by default, so a document whose events were all rejected answered 201 accepted with ingestion_result.accepted == 0. A partly stored document looked the same as a fully stored one. status is now derived from the ingest result: accepted, partial, or rejected. The field has no default, so a new return path must state its outcome. HTTP 201 is unchanged. The new tests post through the routes into the real ingest_events and _validate_event_kdes. The existing EDI tests stub ingest_events, which is why this went unseen. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
PR Blocker ChecklistHead SHA: Status: Ready
|
Problem
Both EDI routes (
POST /api/v1/ingest/ediand/document) reported success wheningest_eventsstored nothing.EDIIngestResponse.statusdefaulted to"accepted", so a document with every event rejected returned 201 withstatus: "accepted"andingestion_result.accepted == 0. A partly stored document looked identical to a fully stored one. #3781 fixes the KDE names and listed this as out of scope.Contract change
statusis now derived from the ingest result. All three values arrive with HTTP 201.statusacceptedpartial(new)ingestion_result.events[],statusanderrorsper eventrejectedingestion_result.events[], orrejectionfor?strict=falseacceptedwithaccepted: 0now saysrejected. A partly stored one now sayspartial, a value partners have not seen before.rejectedis reused from the existing advisory path, which already returns 201 withstatus: "rejected". Its two shapes stay mutually exclusive:ingestion_resultmeans the document reached ingest, andrejectionmeans it was stopped before ingest.statushas no default and is typed as aLiteral, so a new return path fails loudly instead of claiming success.rejected, and the body carries everything a 4xx would. Partners that check only the HTTP code stay misled and must readstatus, whichTRACEABILITY_FILE_INTAKE.mdnow says.Consumers checked
frontend/srcmentions EDI only as a source-type label and a capability flag.EDIIngestResponse.status, and all three constructors are inroutes.py.status="accepted"matches are per-eventEventResultstubs.status.partialis new to them.Tests
test_edi_ingest_status.pyposts through the routes into the realingest_eventsand real_validate_event_kdes, faking only auth, rate limit, database, canonical store and graph sync. The existing EDI tests stubingest_events, which is why this went unseen./documentwhere one set has noN1*ST, so only that event fails KDE validation./document.acceptedandpartialcases stubingest_events, because no real 856 passes KDE validation until fix(ingestion): give EDI events the shipping KDEs validation requires #3781 lands.Verification
services/ingestion/tests: 6,243 tests, 0 failures, 0 errors, 63 skipped (live Postgres tests).statusis forced back to alwaysaccepted.201 rejected, 0 accepted, 1 rejected.201 accepted, 2 accepted.201 partial, 1 accepted, 1 rejected.fsma.cte_events, none from the rejected 856s._record_edi_rejectionwith or without this PR.Not in this PR
rejecteddocument still burns its ISA13, so a corrected resend gets a 409. fix(edi): release the ISA13 claim when an interchange is not stored #3782 readsingestion_result.accepted, notstatus, so the two are independent. After fix(edi): release the ISA13 claim when an interchange is not stored #3782, apartialdocument keeps its claim, so a partner resending the failed lines needs a new ISA13.rejecteddocuments in the new shape have norejection_id. Per-event errors are in the response.accepted.ingest_eventscounts it that way, and the data is stored.data_gap_write_failed ... error_type=ProgrammingErrorafter commit. It is fail-open and this PR does not touch it.Jev sidecar was off:
TYPESAFE_API_KEYis not set in this session.🤖 Generated with Claude Code
Note
Medium Risk
This is an external API contract change (
partialis new; zero-store documents flip fromacceptedtorejected) while HTTP 201 is unchanged, so integrations that ignore body fields may mis-handle failures.Overview
Fixes a misleading EDI API contract where
EDIIngestResponse.statusalways defaulted to"accepted"even wheningest_eventsstored nothing or only some lines.Both
POST /api/v1/ingest/ediand/documentnow setstatusfromingest_status(ingestion_result):acceptedwhen every event persisted,partial(new) when some did,rejectedwhenaccepted == 0. HTTP 201 is unchanged; partners must readstatusandingestion_result, not the status code alone.statusis a requiredLiteralwith no default so new return paths cannot silently claim success.TRACEABILITY_FILE_INTAKE.mddocuments the three outcomes and where errors live (ingestion_result.events[]vs advisoryrejection).test_edi_ingest_status.pyexercises the realingest_events/ KDE validation path (existing EDI tests stub ingest and missed this).Reviewed by Cursor Bugbot for commit d140073. Bugbot is set up for automated code reviews on this repo. Configure here.