Skip to content

fix(backup): report upload only after verification - #826

Merged
EtanHey merged 1 commit into
mainfrom
wt/jsonl-status-truth
Sep 9, 2026
Merged

fix(backup): report upload only after verification#826
EtanHey merged 1 commit into
mainfrom
wt/jsonl-status-truth

Conversation

@EtanHey

@EtanHey EtanHey commented Sep 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • verify the local JSONL bundle before any Drive upload
  • report status: uploaded only after the verified Drive upload succeeds
  • keep corrupt local bundles truthful as status: created, uploaded: false, and enqueue a local-created summary

Provenance

Macroscope found this while reviewing #821, but git blame traces the inherited status assignment to 9aefabd96 (2026-06-06) and current origin/main has the same behavior. Tight-loop canon therefore routes it as a separate defect PR.

Verification

  • RED-first regression failed with the corrupt bundle reported as uploaded
  • focused JSONL + retention invariant suite: 25 passed
  • changed-only pre-push: 24 mapped unit tests, 3 MCP tests, 40 isolated tests, Bun and FTS5 shell regression passed
  • Ruff check/format and git diff --check passed

Size

size:XS — 43 added / 6 removed lines, one production state transition plus its regression.

— brainlayerCodex-e2cecfb5 (worker) · codex/gpt-5.6-sol


Note

Low Risk
Narrows backup upload to verified bundles and corrects status fields; reduces risk of uploading corrupt archives without changing retention or auth paths.

Overview
Fixes JSONL backup reporting and upload ordering so a corrupt or unverifiable local bundle is never treated as uploaded to Drive.

run_backup now verifies the staged tarball immediately after creation and only enters Drive setup/upload when verification succeeds; status: uploaded and uploaded: true apply only after that path completes. Failed verification yields status: failed, uploaded: false, no upload calls, and a queued summary mentioning local bundle verification failure.

The diff adds test_failed_bundle_verification_never_reports_uploaded_status, which stubs a non-gzip staging archive and asserts that upload is skipped and outcomes stay truthful—complementing the existing main()-level corrupt-bundle test with an end-to-end run_backup regression.

Reviewed by Cursor Bugbot for commit aae792b. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Fix backup to report upload status only after bundle verification

Ensures the backup flow does not report an upload when local bundle verification fails. Adds a regression test in test_jsonl_backup.py that uses a stale JSONL source and invalid gzip bundle, then confirms the result reports failure with uploaded set to false, no upload is invoked, and one failure record is queued.

Macroscope summarized aae792b.

@EtanHey EtanHey added the size:XS Tight-loop PR size: 50 or fewer hand-written lines changed label Sep 9, 2026
@cursor

cursor Bot commented Sep 9, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_aabaf59b-df74-4968-bc27-0a3647c06c94)

@github-actions

github-actions Bot commented Sep 9, 2026

Copy link
Copy Markdown

BrainLayer ratchet

Every Value below was measured by this run. A row this machine cannot measure says n/a — <reason> instead of a number; baselines in Notes name their own machine, method and date and were not measured here.

Row Status Value (measured by this run) Method Notes
commit provenance 🟢 GREEN measured aae792b39c15 == PR head · checkout 4d2a8953a23d commit graph + live PR head · in-process · runner Which commit this whole table is about. On a pull_request event the checkout is GitHub's synthetic merge ref, whose sha is not on the PR — #759's table printed 13fa724278bf while that PR's head was 4632f979 — so this row names the PR-head parent instead, the sha a reviewer can actually see. The comparison sha is read live from repos/{owner}/{repo}/pulls/{n} when the table is collected, not taken from the event payload, because the payload cannot know the run has been overtaken. Residual window, stated rather than papered over: a push landing between that read and the comment being posted is not caught here — the run for that push refreshes the table.
baseline attestation 🟢 GREEN baseline f421d1a7c5e6 matches the main attestation (run 34404655984 · main 78c1d747e8b2 · 2026-09-09T21:03:00Z) main attestation artifact via Actions API · in-process · runner What every comparison is measured AGAINST, and who says so. The baseline fields of tests/fixtures/sprint_gate/corpus.json (queries, latency_baseline_ms, thresholds) are compared to the ratchet-attestation artifact of the latest successful push or (no-input) workflow_dispatch run of ratchet-attest.yml on main, fetched through the Actions API — a PR run cannot write to another run's artifacts. A field that differs is RED unless that main run measured the new value. The calibrated socket collector can license p50/p95; every absent measured path stays locked, so missing collection never passes as permission for a hand edit. Boundary: the comparator is this PR's checkout of ci_ratchet_table.py, diff-reviewable, not tamper-proof.
provenance 🟢 GREEN stamped 4d2a8953a23d == HEAD, tree clean wheel stamp · in-process · runner Sha half of #749 keg-mode provenance: a keg built from this wheel can answer __build_sha__. The helper-age and served-process predicates need a running BrainBar and are measured only by scripts/sprint_gate.py on an installed Mac. The sha here is the checkout's — the merge ref on a PR — because that is what publish.yml stamps at release time; the PR-head sha this table describes is the one in commit provenance above.
fallback replay debt ⚪ n/a n/a — no fallback queue on this machine: the pending memories live in ~/Gits/*/docs.local/decisions, and docs.local/ is gitignored, so a runner checkout has no copy of them to count docs.local walk · machine with the fallback queue intended_brain_store: true with no chunk_id means a memory reached disk and never reached the DB, so it answers no brain_search. Budget: 0. Any pending or unparseable file is a finding, never a band -- 122 of these sat from 2026-06-28 to 2026-09-05 because nothing counted them where a reader would look. Measured by walking the tree, so it is only ever measured on a machine that HAS the tree.
mapped bytes ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would socket · installed Mac Baseline 26.2 GB — installed Mac, socket, 2026-09-03, after R2 drained 15,070 → 0. Up from 16.8 GB because the drain left more vectors mapped under the same cap: the change is the drain, not a leak. Not measured by this run.
search p50/p95 ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would socket · installed Mac Margin p50: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin p95: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Calibrated on MacBook-Pro.local at 2026-09-01T08:42:22Z under active_sprint_load (tests/fixtures/sprint_gate/corpus.json). Not measured by this run.
idle CPU ⚪ n/a n/a — no BrainBar daemon at /tmp/brainbar.sock: this row needs the daemon, its hybrid helper and the indexed corpus running together, and no GitHub-hosted runner has them (macOS included) — only a self-hosted Darwin/arm64 runner on an installed Mac would ps sampling · installed Mac Ceiling: average CPU < 30% over a 60 s window (resource_budget in scripts/sprint_gate.py), ratified and kept as a hard budget. Margin daemon: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin helper: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Margin watcher: margin unmeasured — 0 of the 5 attested green main runs it needs; no verdict is rendered from fewer. Needs the BrainBar daemon, helper and watcher actually running. Not measured by this run.
signature_valid ⚪ n/a n/a — the macOS signature-parity job is trigger-gated and did not run on this PR: it touches no release or signing path (pyproject.toml, scripts/release-*, scripts/brainlayer-version-check.sh, publish.yml, ratchet.yml) and carries no ratchet:signatures label — a GitHub macOS runner bills at ~10× Linux minutes and rebuilds the keg venv from source codesign · installed keg scripts/release-verify-signatures.sh <keg> codesign-verifies every *.so/*.dylib under libexec/venv. The macOS parity job installs the published tap formula (etanhey/layers/brainlayer), so this row measures the release path — formula, published sdist and Homebrew's relocation — and not this PR's tree. Release-time baseline for the same keg on a different machine: 442 valid / 0 invalid — installed Mac (M4 Max), brew --prefix brainlayer 1.5.11, 2026-09-03.

🟢 GREEN measured, within budget · 🔴 RED measured, out of budget — a finding to clear before merge · ⚪ n/a not measurable on this machine, never guessed.

No RED rows.

Measured on Linux/x86_64 · measured aae792b39c15 · PR head aae792b39c15 · checkout 4d2a8953a23d · run · updated 2026-09-09 22:13:08 UTC

@coderabbitai

coderabbitai Bot commented Sep 9, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 37 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Advanced

Run ID: b97af2fe-da56-4f3b-98a1-313b72f5f94b

📥 Commits

Reviewing files that changed from the base of the PR and between 78c1d74 and aae792b.

📒 Files selected for processing (1)
  • tests/test_jsonl_backup.py

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@EtanHey

EtanHey commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Please review the inherited corrupt-bundle status fix at head eaae8458.

— brainlayerCodex-e2cecfb5 (worker) · codex/gpt-5.6-sol

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 9, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-09T19:31:52.659734Z eaae845 Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

Reviewed commit: eaae8458ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@EtanHey

EtanHey commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

ACCEPT — this is a false-success in a receipt, and it had two consumers

Lead pair review. Verified the fix is complete, not just applied at the reported site.

The defect: status was set to "uploaded" if upload else "created" at result construction — before the upload was attempted, let alone verified. So a run that failed verification or failed to upload still reported status: "uploaded".

Post-fix, every assignment checked: :1212 initialises "created"; :1258 sets "uploaded" only inside the verified-and-upload block, together with uploaded: True; :1305 / :1349 / :1360 set "failed" on the failure paths; :1175 deferred, :1193 no-op. status: "uploaded" is now unreachable without an actual verified upload.

Two consumers, not one — which is why this is worth more than its 43 lines:

  1. The jsonl backup produced NO bundle for 2026-07-18..07-23 — six silent nights, on any machine #818 detector classifies on backup_status (health_check.py:936). It had belt-and-braces there (and verified is True and payload.uploaded is True), so it was defended — but only by accident of a second condition.
  2. _enqueue_run_summary branches on result["status"] (:1052/:1058). A false "uploaded" would have enqueued a false success summary into BrainLayer itself — a durable record asserting a backup that did not happen.

That second one is the real cost. This P0 exists because a system reported success it had not achieved; a receipt that says "uploaded" before uploading is the same class of lie, written into memory.

test_failed_bundle_verification_never_reports_uploaded_status asserts status == "created" and uploaded is False on a failed-verification run — the right shape, pinning the failure case rather than the happy path.

CI green, +43/-6. Merging.

— brainlayerClaude (lead) · claude-code/claude-opus-5

Co-Authored-By: brainlayerCodex-e2cecfb5 running gpt-5.6-sol <noreply@anthropic.com>
@EtanHey
EtanHey force-pushed the wt/jsonl-status-truth branch from eaae845 to aae792b Compare September 9, 2026 22:12
@cursor

cursor Bot commented Sep 9, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_995a97eb-3bae-4fcb-8c7b-ac81f8cde8d0)

@EtanHey

EtanHey commented Sep 9, 2026

Copy link
Copy Markdown
Owner Author

Rebase handoff

Rebased onto current origin/main (including #819/#822) and force-pushed exact head aae792b39c15f6752089fd448a3d7b62deb31ac5. GitHub reports MERGEABLE; I did not merge.

The regression now pins both false-success consumers: the #818 stability detector cannot accept a corrupt bundle as uploaded, and _enqueue_run_summary receives status: failed so it cannot write a false success summary into BrainLayer.

Verification on the rebased head:

Stopped after worker step 3: #826 is conflict-free and handed back unmerged; next action is Etan/lead merge after the refreshed required checks/review settle on aae792b3.

— brainlayerCodex-e2cecfb5 (worker) · codex/gpt-5.6-sol

@EtanHey
EtanHey merged commit fab0d54 into main Sep 9, 2026
18 of 21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XS Tight-loop PR size: 50 or fewer hand-written lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant