Batch import without guessing: "unconfirmed" is an outcome, and recovery is a rerun
Language: English | 简体中文
FLH’s capture CLI imported one learning_capture_v1 file at a time. I added a batch mode for up to 100 files and a preview that sends nothing. Most of the design is about one question: when a response never arrives, what should the report say?
My engineering contribution: defining the outcome categories and exit statuses, choosing a rerun over automatic retry, and setting the privacy rule for reports.
Published: 2026-11-08
Reuse the single-file path
-batch FILE... plans the files (1–100, byte-wise path order, refusing a file listed twice by path or identity), then calls the unchanged single-file Import once per file. No route, schema, migration or frontend changed. Single-file and stdin output stay byte-identical, with one deliberate exception: stray positional arguments without -batch used to be silently ignored, and are now refused with exit 2.
-batch -preview runs only local checks. The acceptance run confirmed 0 requests through the logging proxy.
Name what you do not know
Each file gets exactly one outcome:
| Answer | Outcome |
|---|---|
201 |
created |
200 |
replayed |
409 |
conflict: the stored capture is unchanged |
400, 422, or a bad local file |
invalid |
| lost or unreadable response, timeout, interruption | unconfirmed: may or may not be stored |
| connection failed, or the batch stopped | not_attempted |
The key category is unconfirmed. The client cannot know whether the server committed, so the report does not pretend. After three files in a row with no server response, or an interruption, the rest are not_attempted instead of piling up more unknowns.
Exit 0 means every file is created or replayed. Exit 1 means a conflict or invalid file. Exit 3 means rerun the same files.
Recovery is a rerun, never a retry
The CLI never retries on its own. The server already keeps a fingerprinted receipt per capture_id, so rerunning the same files lets the server decide: a committed file replays, and a new one is created.
The acceptance run put a proxy in front of the real server binary and dropped one response after the server returned 201. The first batch exited 3 with that file unconfirmed. The rerun reported it replayed, and the database still held 4 entries, no duplicate. A real SIGINT mid-batch and an unreachable server both exited 3 and left the entries unchanged. Overall: 46 PASS, 0 FAIL.
Reports contain identifiers only
Reports list paths, a capture_id label when it is a portable identifier, HTTP statuses and entry IDs. They never contain learner text or request bodies, and a server message that echoes request content is withheld. The acceptance run searched every report for synthetic learner-text markers and found none.
Limits
- A file edited between preview and the real run is not detected by the CLI. For an already stored
capture_id, the server’s fingerprint turns it into aconflict. - Batches above 100 files must be split by hand.
make verifywas not run in the scratch copy because no frontend file changed; the Go half ran in full.
Implementation used Claude Code and Codex under my direction, task definitions and review.
- Title: Batch import without guessing: "unconfirmed" is an outcome, and recovery is a rerun
- Author: Sirui Liu
- Created at : 2026-11-08 13:00:00
- Updated at : 2026-11-08 13:00:00
- Link: https://vanquisher.world/2026/11/08/flh-capture-batch-import/
- License: This work is licensed under CC BY-NC-SA 4.0.