Skip to content

fix(edi): store an interchange completely or not at all - #3833

Open
PetrefiedThunder wants to merge 2 commits into
claude/edi-isa13-false-409from
claude/edi-atomic-interchange
Open

PetrefiedThunder wants to merge 2 commits into
claude/edi-isa13-false-409from
claude/edi-atomic-interchange

Conversation

@PetrefiedThunder

@PetrefiedThunder PetrefiedThunder commented Nov 6, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

If one line of an EDI interchange failed during ingest, the other lines stayed stored and the ISA13 claim stayed held. A resend got a 409 for seven days, so the failed lines were never stored. Codex flagged this as P1 while reviewing #3818.

#3811 explains why releasing the claim is unsafe: event keys carry line numbers, so a corrected resend would store surviving lines twice.

Fix

An interchange now stores completely or not at all, so the key problem never arises.

  • ingest_events gains all_or_nothing, default off. Both EDI routes turn it on.
  • Any rejected event rolls the batch back in both stores, through one savepoint around the event loop.
  • The response reports every event as rejected. Events that had been accepted get the error Not stored: another event in this batch was rejected.
  • Accepted-event gap closures are dropped, and graph sync waits for the commit, because a publish can't be recalled.
  • accepted is 0, so the claim is released and the corrected document can reuse its ISA13.
  • The savepoint opens after the receipt, so the ingestion run and any retained file stay as the record of the attempt.

Other ingest_events callers keep per-event acceptance.

Merge order

Based on #3811 (claude/edi-isa13-false-409). Retarget to main once it lands.

Verification

  • test_edi_atomic_interchange.py runs the real ingest_events and gate, against a journal that savepoints actually undo.
  • Ingestion suite: 6293 passed, 58 skipped, 6 xfailed, 0 failed.
  • Production image with real Postgres, forcing a storage failure on the second event:
    • accepted: 0, rejected: 2, with nothing in fsma.cte_events or fsma.traceability_events, and no graph publish.
    • The ingestion run stayed, recording 0 accepted and 2 rejected.
    • A corrected batch then stored both events in both stores, and graph sync ran after commit.
  • That run called ingest_events directly. The route-level path needs fix(edi): store valid 856s through the required-KDE gate #3818 to store an 856, so it hasn't been driven end to end on this branch.

🤖 Generated with Claude Code


Note

Medium Risk
Changes core EDI ingest persistence and ISA13 dedup semantics for multi-line interchanges, but behavior is scoped to EDI routes with savepoint rollback and dedicated test coverage.

Overview
EDI interchanges are now atomic at persistence: if any event in the batch fails validation or storage, the whole interchange rolls back in CTE and canonical stores, the API reports every line as rejected (including a "Not stored: another event in this batch was rejected" message for lines that looked accepted mid-flight), and ISA13 is released so partners can resend the corrected document under the same control number.

Both POST /api/v1/ingest/edi and /document pass all_or_nothing=True into ingest_events. That helper gains an opt-in all_or_nothing flag (default off for other callers): a nested savepoint wraps the event loop, graph sync is deferred until after DB commit, and a post-commit graph failure is logged without failing the request.

Docs in TRACEABILITY_FILE_INTAKE.md now describe this all-or-nothing interchange rule instead of partly stored interchanges holding a duplicate 409. New tests in test_edi_atomic_interchange.py exercise rollback, successful commit + sync, default per-event behavior, and graph outage tolerance; existing EDI test stubs accept the new keyword.

Reviewed by Cursor Bugbot for commit 738f368. Bugbot is set up for automated code reviews on this repo. Configure here.

If one line of an interchange failed during ingest, the others stayed stored
and the claim stayed held, so a resend got a 409 for seven days and the failed
lines were never stored. Releasing the claim is not safe: event keys carry line
numbers, so a corrected resend would store surviving lines twice.

Add all_or_nothing to ingest_events and use it on both EDI routes. Any rejected
event undoes the batch in both stores, nothing reaches graph sync, and the
claim is released because nothing was stored. The ingestion run stays as the
record of the attempt. Other callers keep per-event acceptance.

Found by a Codex review of #3818.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
regengine Ready Ready Preview Nov 6, 2026 4:01am UTC

Request Review

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-06T03:57:02.166457Z a0075a3 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review: 1

  • main

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

@github-actions

github-actions Bot commented Nov 6, 2026 •

Copy link
Copy Markdown
Contributor

PR Blocker Checklist

Head SHA: 738f3688f23917a3e0ff404562a69743aeb665c8

Status: Ready

  • All review threads resolved
  • No reviews requesting changes
  • No blocked review engines

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a0075a3266

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

The deferred graph publish ran after the commit, so a Redis error escaped
ingest_events and the route released the claim on stored events. A resend
could then store them again. Log the failure and return the stored result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — 738f3688 Deployed Nov 6, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants