Browse Source

feat: skip exact existing transactions in guided imports

master
Codex 2 months ago
parent
commit
f1b2c204de
  1. 12
      docs/superpowers/specs/2026-09-09-guided-local-import-design.md
  2. 4
      ingestion/guided_imports.py
  3. 16
      tests/test_guided_import_workflow.py

12
docs/superpowers/specs/2026-09-09-guided-local-import-design.md

@ -56,17 +56,17 @@ Each scanned file has one of these statuses:
- **Ready:** every candidate can be created without a validation issue or - **Ready:** every candidate can be created without a validation issue or
unresolved duplicate. unresolved duplicate.
- **Already imported:** every source candidate is already attached through - **Already imported:** every candidate is already attached through existing provenance or
existing provenance; the file is skipped without financial writes. exactly matches a persisted transaction signature; the file is skipped without financial writes.
- **Needs attention:** the file has an unsupported/unrecognized profile, - **Needs attention:** the file has an unsupported/unrecognized profile,
malformed or unresolved candidate, missing account mapping, ambiguous malformed or unresolved candidate, missing account mapping, ambiguous
potential duplicate, or missing/invalid statement context. potential duplicate, or missing/invalid statement context.
The import action creates a normal existing preview per ready file. It applies The import action creates a normal existing preview per ready file. It applies
`CREATE` to clean candidates. Exact source reimports receive `CREATE` to clean candidates. Exact source reimports and candidates with an exact persisted
`SKIP` with `ALREADY_IMPORTED`; they produce no transaction and are not an transaction signature receive `SKIP` with `ALREADY_IMPORTED`; they produce no transaction and
exception. Any potential duplicate that is not an exact existing source record are not an exception. Duplicates within the incoming file still require review and prevent that
requires review and prevents that file from committing automatically. file from committing automatically.
An exception in one file does not prevent other ready files from committing. An exception in one file does not prevent other ready files from committing.
Every file retains the import service's atomic commit boundary; a failed file Every file retains the import service's atomic commit boundary; a failed file

4
ingestion/guided_imports.py

@ -374,7 +374,9 @@ def prepare_import(*, discovered: DiscoveredFile, section_mapping: dict[str, str
decisions = [] decisions = []
counts = {"created": 0, "matched": 0, "skipped": 0} counts = {"created": 0, "matched": 0, "skipped": 0}
for item in batch.items.order_by("locator"): for item in batch.items.order_by("locator"):
if item.issues == ["ALREADY_IMPORTED"]: if item.issues == ["ALREADY_IMPORTED"] or (
not item.issues and item.duplicates["existing"] and not item.duplicates["within"]
):
decisions.append({"locator": item.locator, "action": "SKIP", "reason": "ALREADY_IMPORTED"}) decisions.append({"locator": item.locator, "action": "SKIP", "reason": "ALREADY_IMPORTED"})
counts["skipped"] += 1 counts["skipped"] += 1
elif not item.issues and not item.duplicates["existing"] and not item.duplicates["within"]: elif not item.issues and not item.duplicates["existing"] and not item.duplicates["within"]:

16
tests/test_guided_import_workflow.py

@ -83,14 +83,18 @@ def test_exact_second_import_only_skips_and_commit_is_idempotent(source, bank):
assert_no_open_preview() assert_no_open_preview()
def test_ambiguous_existing_duplicate_cancels_whole_file(source, bank): def test_existing_signature_duplicate_skips_without_creating_transactions(source, bank):
commit(prepare(source(), bank)) commit(prepare(source(), bank))
ambiguous = prepare(source(DATA.replace(b",1,", b",3,")), bank)
assert ambiguous.state == "NEEDS_ATTENTION"
assert ambiguous.code == "REVIEW_REQUIRED"
assert Transaction.objects.count() == 2
assert_no_open_preview()
duplicate = prepare(source(DATA.replace(b",1,", b",3,")), bank)
assert duplicate.state == "ALREADY_IMPORTED"
assert duplicate.counts == {"created": 0, "matched": 0, "skipped": 2}
assert all(item.decision == {"action": "SKIP", "reason": "ALREADY_IMPORTED"}
for item in ImportBatch.objects.get(pk=duplicate.batch_id).items.all())
assert commit(duplicate).counts == {"created": 0, "matched": 0, "skipped": 2}
assert Transaction.objects.count() == SourceRecord.objects.count() == 2
assert_no_open_preview()
@pytest.mark.parametrize("data", [ @pytest.mark.parametrize("data", [
(HEADER + ROW + ROW).encode(), (HEADER + ROW + ROW).encode(),

Loading…
Cancel
Save