* feat(inbox): promote a single prominent amount into the editable total
Follow-up to #2048 after founder review: the Belopp row was load-bearing
for matching but read-only, so a misread amount could not be corrected,
and an empty TOTALT still read as "extraction failed".
- promoteSingleProminentAmount (extraction post-step, all intake paths):
documentKind other/government_letter with no total and exactly one
distinct nonzero prominent amount gets it copied into totals.total,
stamped totalSource: 'prominent'. Multi-amount documents are left
alone: picking one silently would invent a total.
- provenance keeps the safety rails: matching demotes a promoted total
back through the prominent-amounts fallback (0.85 discount, date guard,
amountSource tag), so the nightly receipt-hunt still excludes these
documents and confidence never presents as certainty.
- the fields-PATCH route clears totalSource when a human edits TOTALT:
a user-set amount is a verified total at full weight.
- the read-only Belopp row now renders only for multi-amount documents,
and filters zero amounts ("Totalt manadspris: 0 kr" noise).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm9QgdyNAFaWiz6Ww7pgb
* fix(inbox): review pass: concurrency-safe fields PATCH, zero-amount predicate
CodeRabbit findings on #2073:
- the fields-PATCH read-merge-write could let a racing autosave restore a
stale extracted_data blob (including a totalSource stamp a concurrent
TOTALT edit had just cleared). The update is now conditional on the
trigger-maintained updated_at; zero rows matched returns 409 and the
client's next debounced save re-reads.
- hasAnyExtractedField now uses the same meaningful-amount predicate as
the Belopp render filter, so a zero-only prominentAmounts list no longer
suppresses the retry / upgrade affordances.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hqm9QgdyNAFaWiz6Ww7pgb
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
PATCH /items/:id/fields rebuilt extracted_data from a hand-written list of
six keys. Everything outside that list was destroyed the first time somebody
corrected a single field by hand: documentKind, merchantCategory, legibility,
purchaseTime, payment and suggestedTemplateId.
Nothing surfaced the loss. The row kept working, the edit landed, and the
classification simply stopped being there. It is not recoverable afterwards
without re-running extraction, so rows edited before this fix have already
lost it.
The comment above the merge names the three fields it does preserve, which
reads as though the list were exhaustive. It never was: those six arrived on
InvoiceExtractionResult later and nobody came back here. Spreading `current`
first fixes the six and, more usefully, means the next field added survives
by default rather than waiting to be noticed missing.
The tests pin the merge rather than the six names. One walks every key that
was on the row and asserts it is still there, so a field added tomorrow is
covered without anyone editing the test. Removing the spread fails two of
them with "`documentKind` was dropped by the merge".
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>