POST /api/libraries/:id/issues/:issueId/retry (admin, family-lens gated
via the existing gateIssue) re-runs the work that produced an open issue
— deliberately NOT a library-wide rescan. Two shapes mirror the two
ledger entry kinds:
- item-backed issues rescan their media item through the book-detail
RescanMediaItem mechanism (self-resolving folders, multi-file
audiobook routing, write-after-success guards) and then close the
issue (RetryMediaItemIssue);
- row-less import_failed issues re-import the single file through the
watcher's standalone processMediaFile path (RetryFailedImport: folders
resolved RescanMediaItem-style so paths stay library-root-relative),
whose create-path self-heal plus an explicit path resolve closes the
issue even when the content was already imported by a prior attempt.
Failures return the REAL underlying error so the UI can show why the
issue still exists; a vanished file is a 409 (ErrRetryFileMissing);
already-resolved issues reject re-retry.
Docs + bruno mirrors regenerated for the new route (the generator's seq
renumbering touches three unrelated bruno files as fallout; openapi
gains the path and the date bump), and the docs schema registry gains
the retry entry so TestDocsMatchRoutes passes.
The generator moves into the Go toolchain per repo preference:
internal/docs/bruno_gen.go emits the OpenCollection mirrors (same output
contract — gate-verified example-request bodies, env-var params,
device-token headers, login/register/refresh token-capture scripts) and
TestBrunoMirrorsDocs grows a -update flag: verification by default,
regeneration on demand:
go test ./internal/docs -run TestBrunoMirrorsDocs -update
Generator and checker are now the same code — they cannot drift apart.
scripts/gen_bruno_from_docs.py deleted; opencollection.yml README points
at the go-test command.
Also fixed vs the Python pass: mirror placement follows the docs tree
folder (RelPath), not the area frontmatter (several docs — highlights,
notes, ratings, users, progress — carry a different area); docs blocks
emit the collection's mapping form (content + type), not a bare scalar;
JSON body sanity is checked at generation time.
Idempotent: back-to-back -update runs are byte-identical.
make test green (9 pkgs).
WO4. The old collection was the drifted artifact AGENTS.md warned about:
bodies pre-truncated at their first {{var}}, routes renamed server-side
but not here (/api/notes/:media_id, /api/book-matching/search,
/api/collections/:id/rules/test), an orphan universal-progress suite for
routes that no longer exist.
scripts/gen_bruno_from_docs.py emits one OpenCollection request per
frontmatter'd endpoint doc (191 requests): gate-verified example-request
JSON as body, {{env}} params per the environment file, device-token
routes get an explicit Bearer {{device_token}} header, login/register/
refresh keep the token-capture after-response scripts that chain the
collection. Old 1:1 mirrors deleted (128); hand-authored NewDevDBSetup,
environments, and edge-case suites kept. 30 scenario files with
truncated bodies (the documented corruption) deleted — they could not
run.
internal/docs/drift_test.go gains TestBrunoMirrorsDocs: every
frontmatter'd doc must have a Bruno request with matching method+URL
shape — the collection can never silently drift from the docs again.
opencollection.yml README block replaced with the real run instructions.
make test green (9 pkgs, parity test included in internal/docs).