Spec #135: owner data-correction actions — Latest Chapter, series_url, Cover, orphan removal (#156)

Implements spec #135 (spec 2 of 4, derived from wayfinder map #114; decisions settled in #120/#121/#125/#131). Blocked-by #134 is merged, so this lands on `main`.

Four owner actions the dashboard can now perform, one ticket each:

- **#149** — Latest Chapter correction: one numeric input, overwritten by the next machine write.
- **#151** — Series URL repair: owner-typed, gated by the poller's own fetch gate.
- **#150 / #153 / #154** — Cover replacement: addresses derived from bytes (`#150`), a Forced Poll replaces the Cover while an ordinary pass still only fills a blank one (`#153`), and byte reclamation is one guarded helper, file first / covers row last (`#154`).
- **#155** — Orphan removal: one Series at a time, with the foreign key as the guard.

Plus **#152** — Latest Chapter provenance: one derived line naming the actor class, so an owner can tell a hand-edited number from a machine read.

- Migration `0015_latest_correction.sql` adds the correction/provenance columns; `0009` now derives cover addresses from bytes.
- ADR `0014-cover-addresses-from-bytes.md` records the address scheme.

Backend tests cover the store, poller, admin handlers, and web routes (`go test ./...`, needs Docker).

Reviewed-on: #156
Co-authored-by: Sulthan Zaki <sultankiki05@gmail.com>
Co-committed-by: Sulthan Zaki <sultankiki05@gmail.com>
This commit was merged in pull request #156.
This commit is contained in:
2026-08-22 12:10:40 +07:00
committed by sulthan
parent 889f0f3f38
commit 4aaf1d4f91
25 changed files with 2327 additions and 130 deletions
+28
View File
@@ -653,6 +653,13 @@
margin-left: auto;
}
.admin-sheet .tbl.series .row-msg {
grid-column: 1 / -1;
margin-top: 6px;
color: var(--danger-soft);
font: 400 13px/1.4 var(--font-body);
}
.admin-sheet .detail-back {
display: inline-block;
margin: 18px 0 0;
@@ -720,6 +727,27 @@
margin-top: 8px;
}
.admin-sheet .dform input {
min-width: 0;
padding: 8px 10px;
border: 1px solid var(--field-line);
background: var(--ink);
color: var(--paper);
font: 500 14px var(--font-mono);
outline: none;
}
/* Focus follows the chapter form's idiom — paper, not heat: a red border on
a valid number field reads as "invalid". */
.admin-sheet .dform input:focus {
border-color: var(--paper);
}
.admin-sheet .dform .hint {
margin: 0;
color: var(--mute-2);
font: 500 12px/1.4 var(--font-mono);
letter-spacing: .04em;
}
.admin-sheet .pausebar {
display: flex;
align-items: center;