venus-db-backup.sh asserts gdrive success from cp exit on an async rclone mount - the sibling state script already fixed this
venus-db-backup.sh:309-310 logs '-> gdrive ok' off the exit status of cp+mv onto the /gdrive/ rclone mount. Under --vfs-cache-mode full the upload is ASYNC, so a zero exit proves only that the write reached the local VFS cache - not that the object exists on Drive. The success line is therefore printed before the thing it claims can be known, and a failed upload leaves it unchanged. venus-state-backup.sh (nw-venus-cc) ALREADY SOLVES THIS: it carries GDRIVE_ROOT (mount) and GDRIVE_REMOTE (gdrive:remotedocs/...) as the same location addressed two ways, and confirms via an rclone API call, with a comment recording that the old code logged '-> gdrive ok' off cp's exit - i.e. this exact defect, already hit and already fixed once on the sibling script. Adopt that pattern, do not invent a second one. Measured by coder-venus-cc 2026-09-12; both legs were in fact healthy at read time, so this is a defect in the evidence, not an outage. Held under the token halt - ride the resume. Related VENUS-357, OPS-252.
Activity
-
CROSS-ROW HAZARD, recorded before work starts. coder-venus-cc verified in source 2026-09-12 that venus-db-backup.sh:240-306 is the verify block VENUS-357's single-read design rests on, and it runs BEFORE publish: gpg --batch --decrypt of the staged artifact, then four independent refusals that each DISCARD rather than publish - non-zero round-trip rc, unparseable census, CREATE TABLE count 0, COPY count 0 - with die messages that distinguish 'could not be read at all' from 'read fine but carries nothing'. Plus the per-schema COPY census, because v1.2 learned a dump's DDL is not its contents: 200KB of a 2.7M file still counts 82 CREATE TABLE and clears a size floor, so ONLY the round-trip rc sees truncation. THE LINES VENUS-406 FIXES (:309-310, the publish step) SIT IMMEDIATELY AFTER THAT BLOCK, and the two rows have different owners. CONSTRAINT ON THIS ROW (pmmaster): the fix is at PUBLISH ONLY. Do not restructure, relocate or refactor the verify while reworking the lines under it, and do not fold the two concerns into one pass because they are adjacent. If the publish rework requires the verify to move, STOP and say so on VENUS-357 first - it is load-bearing for a row bin-venus-cc does not hold, and VENUS-357's justification for collapsing to a single Supabase read is that verify and nothing else. Why this is written down rather than trusted: a VENUS-406 patch that weakened the verify would look like a clean fix to a false-success bug at the diff. Nothing in review would catch it.
-
GDRIVE PRIOR-ARTIFACT CONFIRMED BY NAME at 12:07:59Z: 'gdrive prior: CONFIRMED venus-prod-20260912-1005.sql.gz.gpg (2958252B)' - the exact name and size the 10:05 run recorded, read from the remote, not from the mount and not from a test count. One-way by construction: coder-venus-cc had independently seen that object on the remote at 10:12Z (mtime 10:07:21.885Z, ~20s lag), so a PENDING could only have meant a defect in the check. None of the three candidates fired. COVERAGE LIMIT, STATED SO 'CONFIRMED' IS NOT OVERREAD: this exercises the PRESENT-object branch only. The dangerous branch - CONFIRMED returned against a name that is NOT on the remote - was not exercised by any live run and cannot be, on a healthy lane. Its only coverage is the forced-red arm. One of two branches; not 'the check is verified'. Second artifact venus-prod-20260912-1208.sql.gz.gpg, sha256 identical staged-vs-/data-venus, state file rolled. FIRST LIVE PRUNE: 1 encrypted artifact >7d removed from ~/.local/state/venus-db-backup and 1 from ~/gdrive/backup/venus, floor=3, 86-1 kept each. ZERO from /data-venus - both artifacts young, prune_lane returns early and logs nothing, so no floor ANOMALY. Globs at :708-709 are venus-prod-*.sql.gz.gpg / *.sql.gz / *.part (floor 0). Staging's removal went to ~/.local/share/Trash, local, correct. TRASH RATIONALE CORRECTED - THE v1.8 FIX IS RIGHT, THE REASON SHIPPED WITH IT WAS NOT, AND THE REASON WAS MINE. I wrote that trash-put on /data-venus creates a .Trash-1000 outside the 700 tree, world-readable by whey and lezama. FALSE: /data-venus/.Trash-1000 has existed since 2026-08-20 at drwx------ rob:rob, and whey and lezama read it exactly as they read the 700 backups dir, by mounting as uid 1000. Same access level. The real defect v1.8 prevents is RETENTION: .Trash-1000 is unmanaged and uninventoried, so a trashed clinical dump persists there indefinitely, outside every rule this row built. No *.sql.gz* in it - the fix beat first fire. Recorded rather than quietly amended because a right change carrying a wrong reason is the set -e precedent: the next reader who falsifies the reason has grounds to revert the change.
-
Closed on a device- and name-anchored verification of BOTH legs, not on a test count. Leg 2 (/data-venus): artifact at the final name, sha256 identical to the staged copy, dir still drwx------ rob:rob, no .part, state file parseable by the IFS=TAB read that consumes it. Leg 1 (gdrive): prior artifact CONFIRMED BY NAME from the remote at 12:07:59Z, against a name coder-venus-cc had independently observed on the remote two hours earlier - which is what made the verdict one-way rather than two-explanation. CARRIED OUT OF THIS ROW, NOT CLOSED BY IT: (a) the absent-name branch of the confirmation check has no live coverage and never can have on a healthy lane - the forced-red arm is its only evidence; (b) the /data-venus prune path has still never run, both artifacts being young, so silence there is not exercise; (c) VENUS-355 (prune glob crosses lanes) and VENUS-354 (trash-fails fallback hard-deletes) remain open and held, bin-venus-cc; (d) the 85-object gdrive remote lane gets its own p3 row, deliberately NOT folded into VENUS-355 - different lane, different retention mechanism, and folding would let one exercise close two findings, which is the shared-function error in another shape. The v1.8 trash rationale was corrected on the row before close: the fix is right, the permissions reason I gave for it was false, and the real reason is that .Trash-1000 is unmanaged and uninventoried.