Skip to content

fix(upload): ISO-only date inference; an all-failed upload is an error (#123) - #124

Merged
amar-python merged 1 commit into
mainfrom
fix/123-failed-uploads
Oct 27, 2026
Merged

amar-python merged 1 commit into
mainfrom
fix/123-failed-uploads

Conversation

@amar-python

Copy link
Copy Markdown
Owner

Fixes #123. Relates to BR-34. Built on the product owner's go-ahead on 27 Oct 2026.

Root cause

Transactions (3).csv has dates like "27 Oct 26" in Date and Processed On.

  • The browser's inferCell marked a value as timestamptz whenever new Date() could parse it, so it sent timestamptz for both columns.
  • The API's cast_value accepts only ISO dates, so it rejected the Date value in every row: 171 of 171 failed.
  • The upload was then registered as migrated, with 0 rows.

What changes

Part Change
Type inference (csv-preview.ts) date and timestamptz are inferred only for ISO values the API accepts. Impossible dates such as 2026-02-30 are no longer inferred as dates. "27 Oct 26" now imports as text.
Every row fails (dynamic_loader.py) The upload returns status: "error" with the first problem in the message, for example None of the 171 rows could be imported, so nothing was saved. First problem: row 1, column "date": …, and the row errors. Nothing is saved: the new table and the registry row are rolled back, and an overwrite leaves the previous upload in place.
Some rows fail The toast is now a warning ("Import complete with failed rows"). The Migrated files list and the Preview dialog show "N of M rows failed".

Correction to the issue text

#123 says nothing on the page reported the failures. The upload's own job card did show "0 of 171 rows imported · 171 failed", and its error report could be downloaded from Import history. But it came with a success toast, and the Migrated files list showed nothing. Both are fixed here.

Decision for the product owner

Keeping row errors on the server isn't in this PR. The row errors are kept in the browser's Import history, where the error report can be downloaded, but not in the database. Storing them server-side needs a migration and somewhere to show them. Recommendation: leave it until a user needs it from another browser. #123's "Done when" doesn't depend on it.

Checks

  • Local CI replica: 311 passed, 0 failed, 0 skipped (it was 308). Evals 26/26.

  • New tests in tests/test_failed_uploads.py:

    • every row failing returns an error, with nothing registered;
    • a failed overwrite keeps the previous upload and its table;
    • a partly failed upload still imports, and its counts are persisted.
  • Frontend: vitest 131 passed (it was 126). The tests cover "27 Oct 26" staying text, ISO timestamps still inferred, impossible dates not inferred, the partial-failure warning, and failedRowsNote.

  • Mutation checks:

    Change removed Result
    the all-failed branch 2 tests failed
    the loose timestamp rule put back 1 failed
    the impossible-date check 1 failed
    the partial-failure warning 1 failed
    the explicit conn.rollback() no test failed

    The last result is expected: the connection pool already rolls back an uncommitted transaction. The explicit rollback is kept as a guard and to state the intent.

  • Also: tsc exit 0, production build OK, make lint exit 0.

Done when


Generated by Claude Code

#123)

- Root cause: the browser inferred timestamptz for anything new Date()
  parses (e.g. "27 Oct 26"); the API accepts only ISO, so every row
  failed. inferCell now infers date/timestamptz only for real ISO values.
- When every row fails, the upload is an error: the transaction is
  rolled back (no table, no registry row, an overwrite is undone).
- Partial failures: warning toast, and the Migrated files list and
  Preview show "N of M rows failed".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019YPoXzBSj89ZHgw7nfTmbB

Copy link
Copy Markdown
Owner Author

Product owner decision, 27 Oct 2026: keeping row errors on the server is moved to ART M3 (#107, scope comment added there). It isn't part of this PR.


Generated by Claude Code

@amar-python
amar-python merged commit 443ed9a into main Oct 27, 2026
3 checks passed
@amar-python
amar-python deleted the fix/123-failed-uploads branch October 27, 2026 08:35
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.

Upload with every row rejected is shown as migrated (171 of 171 rows failed, no warning)

2 participants