Maestro task 008c0a8a-2242-429b-a1fd-69346bc1d414 — "Release corrections round 4", from the independent release review of release/2026-10-07c (PR #123, APPROVED at fd225b9).
Documentation only: the diff is exactly deploy/RUNBOOK.md and docs/ARCHITECTURE.md.
Findings fixed
R01 (MEDIUM), deploy/RUNBOOK.md "Routine deploy and rollback": the deploy steps did not require checking a current, restorable Litestream point before the restart applied migrations 0013 and 0014. Because an older SHA refuses the upgraded schema, the only rollback is a restore to a point before the restart — so an operator could restart production on an unverified backup. The Deploy sequence now has a discrete step 2, before sudo systemctl restart mealquest, that checks Litestream is replicating, restores the replica to a scratch file beside the live database (the documented restore command writing elsewhere, so the live files are untouched), compares integrity and counts with the existing Count check script, records the pre-deploy restore point as a UTC timestamp next to the previous SHA, and says plainly "If any check fails, do not restart". The Rollback section now uses that recorded -timestamp instead of describing a separate exercise. No script was added and deploy/compose.yaml is unchanged.
R02 (LOW), docs/ARCHITECTURE.md: the prose said the rotation_check schedule calls MarkTried, but this release has no production caller for MarkTried — the scheduler is Feature 20, so nothing opens a Rotation check automatically. The prose now says the schedule "is to call" MarkTried and states that this release provides only the MarkTried method and the rotation review read/decide APIs.
Notes for review
The developer deliberately gave only one remedy when the backup check fails (restore replication and repeat the step) rather than also offering a manual-backup path, per the house rule of one way to do a thing; the cost is that a deploy stays blocked while the NAS holding the replica is unreachable.
A brief mismatch between the restored copy and the live copy can come from copying a running database's WAL file, which the runbook already notes elsewhere; the step therefore says to re-run the comparison rather than fail immediately.
The developer left the scheduler table row for rotation_check (around line 600) unlabelled, keeping scope to the prose the finding named. This document's header states it describes the planned application; flag it if the table row is still misleading.
gofmt -l . — empty; CGO_ENABLED=0 go build ./... — ok; working tree clean
Developer-reported: go vet ./... pass, go test -race -count=1 ./... all packages ok, and cd web && npm run typecheck && npm test && npm run build clean with 45 files / 764 tests
## Task
Maestro task `008c0a8a-2242-429b-a1fd-69346bc1d414` — "Release corrections round 4", from the independent release review of `release/2026-10-07c` (PR #123, APPROVED at `fd225b9`).
Documentation only: the diff is exactly `deploy/RUNBOOK.md` and `docs/ARCHITECTURE.md`.
## Findings fixed
- **R01 (MEDIUM), `deploy/RUNBOOK.md` "Routine deploy and rollback":** the deploy steps did not require checking a current, restorable Litestream point before the restart applied migrations 0013 and 0014. Because an older SHA refuses the upgraded schema, the only rollback is a restore to a point before the restart — so an operator could restart production on an unverified backup. The Deploy sequence now has a discrete step 2, before `sudo systemctl restart mealquest`, that checks Litestream is replicating, restores the replica to a scratch file beside the live database (the documented restore command writing elsewhere, so the live files are untouched), compares integrity and counts with the existing Count check script, records the pre-deploy restore point as a UTC timestamp next to the previous SHA, and says plainly "If any check fails, do not restart". The Rollback section now uses that recorded `-timestamp` instead of describing a separate exercise. No script was added and `deploy/compose.yaml` is unchanged.
- **R02 (LOW), `docs/ARCHITECTURE.md`:** the prose said the `rotation_check` schedule calls `MarkTried`, but this release has no production caller for `MarkTried` — the scheduler is Feature 20, so nothing opens a Rotation check automatically. The prose now says the schedule "is to call" `MarkTried` and states that this release provides only the `MarkTried` method and the rotation review read/decide APIs.
## Notes for review
- The developer deliberately gave only one remedy when the backup check fails (restore replication and repeat the step) rather than also offering a manual-backup path, per the house rule of one way to do a thing; the cost is that a deploy stays blocked while the NAS holding the replica is unreachable.
- A brief mismatch between the restored copy and the live copy can come from copying a running database's WAL file, which the runbook already notes elsewhere; the step therefore says to re-run the comparison rather than fail immediately.
- The developer left the scheduler table row for `rotation_check` (around line 600) unlabelled, keeping scope to the prose the finding named. This document's header states it describes the planned application; flag it if the table row is still misleading.
## Evidence (orchestrator-run gate at 614c4febfa601bd049b6b81aef94fc0efbed9c4c)
- `gofmt -l .` — empty; `CGO_ENABLED=0 go build ./...` — ok; working tree clean
- Developer-reported: `go vet ./...` pass, `go test -race -count=1 ./...` all packages ok, and `cd web && npm run typecheck && npm test && npm run build` clean with 45 files / 764 tests
RUNBOOK: the deploy steps now verify, before the restart that applies
migrations, that Litestream replication is current and its replica
restores to the live data, and record the pre-deploy restore point; if
not, do not restart. The rollback section restores to that recorded point.
ARCHITECTURE: the rotation_check schedule that calls MarkTried is planned
(Feature 20); this release ships MarkTried and the rotation review read and
decide APIs only.
Task: 008c0a8a-2242-429b-a1fd-69346bc1d414
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Write /tmp/mqcount.py from the Count check section with one heredoc
command, and give rollbacks that cross a migration an ordered
restore-then-start procedure separate from the plain restart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rollback check diffed all of migrations/, so a change to the sqlc
queries in migrations/queries/ sent the operator down the restore path and
discarded household changes made since the pre-deploy point. Compare the
versions in the live database's schema_migrations with the top-level *.sql
files at the previous SHA instead, the rule internal/store/migrate.go
enforces at start-up.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Run the check in a set -eu subshell so a failed cd, copy, git ls-tree
or comparison stops it before any verdict is printed, and remove the
scratch directory from an EXIT trap that preserves the check's status.
Spell out the reading rule: none, listed versions, or stop on error.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The pre-deploy verification and the rollback migration check copied the
live mealquest.db and its WAL as separate files while the app and
Litestream ran, so a checkpoint between the copies could leave an older,
readable state: the rollback check could print "none" while the live
database held a migration the older SHA does not know.
Both now read the live database through /tmp/mqsnap.py, written once in
"Count check": SQLite's online backup API from a read-only connection,
then PRAGMA integrity_check, exiting nonzero unless it is ok. The
pre-deploy verification runs as one fail-fast subshell (set -eu, an EXIT
trap that cleans /tmp/mqcheck and the scratch restore while keeping the
status), diffs the replica and live count checks, and prints the restore
point only after every step has passed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Capture the docker compose ps status before testing its output, and
scan the Litestream log with grep's status read explicitly: 0 is a
logged error, 1 is no match, anything else fails the verification.
- Run both clean-ups on exit whatever happens, keep any failure, and
print the pre-deploy restore point only after every check and both
clean-ups succeeded.
- State that the live snapshot expects the existing -wal and -shm, list
their ownership after the snapshot, and say to stop and check the
service state if a root-owned sidecar appears.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The rollback check's trap now attempts its clean-up whatever happens,
keeps a failed clean-up as a nonzero status and prints "check FAILED" on
every nonzero exit. Both checks install their trap before the first
command that can fail. Deploy step 1, both rollback paths and the
script-writing block now chain with && so a failed checkout, fetch, build
or write stops the block with its status, instead of a later command
restarting the wrong release or masking the failure.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deploy step 3 printed `git rev-parse HEAD` as "the deployed SHA" even
after a failed restart; the Count check copy block could read a stale
/tmp/mqcheck copy and report integrity ok. Apply the established
pattern (subshell with set -eu, trap registered first, clean-up that
keeps a nonzero status, success line only after everything passed) to
Deploy step 3, the no-migration rollback, Restore the database steps
1-3 and 5, the Count check copy block and Restore photos (media). The
volume listings, service states, health codes and file counts that the
operator previously read by eye are now checked in the block.
Task: 008c0a8a-2242-429b-a1fd-69346bc1d414
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The media restore copied with rsync -a and checked file counts only, so a
local photo with the NAS size and mtime but other bytes could survive and
still print "media restored". Take a SHA-256 manifest of the NAS before the
copy, copy with --checksum, require every manifest entry to be present
locally with the same bytes, and require the NAS to still match the
manifest. On failure, the message now reads the timer's real state instead
of assuming it is stopped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Task
Maestro task
008c0a8a-2242-429b-a1fd-69346bc1d414— "Release corrections round 4", from the independent release review ofrelease/2026-10-07c(PR #123, APPROVED atfd225b9).Documentation only: the diff is exactly
deploy/RUNBOOK.mdanddocs/ARCHITECTURE.md.Findings fixed
deploy/RUNBOOK.md"Routine deploy and rollback": the deploy steps did not require checking a current, restorable Litestream point before the restart applied migrations 0013 and 0014. Because an older SHA refuses the upgraded schema, the only rollback is a restore to a point before the restart — so an operator could restart production on an unverified backup. The Deploy sequence now has a discrete step 2, beforesudo systemctl restart mealquest, that checks Litestream is replicating, restores the replica to a scratch file beside the live database (the documented restore command writing elsewhere, so the live files are untouched), compares integrity and counts with the existing Count check script, records the pre-deploy restore point as a UTC timestamp next to the previous SHA, and says plainly "If any check fails, do not restart". The Rollback section now uses that recorded-timestampinstead of describing a separate exercise. No script was added anddeploy/compose.yamlis unchanged.docs/ARCHITECTURE.md: the prose said therotation_checkschedule callsMarkTried, but this release has no production caller forMarkTried— the scheduler is Feature 20, so nothing opens a Rotation check automatically. The prose now says the schedule "is to call"MarkTriedand states that this release provides only theMarkTriedmethod and the rotation review read/decide APIs.Notes for review
rotation_check(around line 600) unlabelled, keeping scope to the prose the finding named. This document's header states it describes the planned application; flag it if the table row is still misleading.Evidence (orchestrator-run gate at
614c4febfa)gofmt -l .— empty;CGO_ENABLED=0 go build ./...— ok; working tree cleango vet ./...pass,go test -race -count=1 ./...all packages ok, andcd web && npm run typecheck && npm test && npm run buildclean with 45 files / 764 testsIndependent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: CHANGES_REQUIRED for this exact commit.
Independent Codex gpt-6-sol review: APPROVED for this exact commit.