Skip to content

Prepare bounded FTW beta shadow collection and release packages - #36

Merged
frahlg merged 13 commits into
mainfrom
agent/ftwdb-beta-readiness
Sep 7, 2026
Merged

Prepare bounded FTW beta shadow collection and release packages#36
frahlg merged 13 commits into
mainfrom
agent/ftwdb-beta-readiness

Conversation

@frahlg

@frahlg frahlg commented Sep 7, 2026

Copy link
Copy Markdown
Member

FTW's beta needs a bounded copy of live history while SQLite/Parquet keep their current role. This prepares FTWDB 0.1.0-alpha.2 as an opt-in shadow collector with a separate process, a fixed protocol, resource limits, and usable release packages.

Paired Core integration: srcfl/ftw#1096. Core owns the bounded history queue, loss/status reporting and opt-in Compose overlay. Core head f305fce493f346c39c7a212676517c9c7be87adf pins FTWDB 7bbae63532f695b10aca548bf4ee58c6d7ebb3a8 in both Compose and CI; its Go-to-Rust contract check passes.

Changes

  • Keep source/sequence/commit identity with each atomic write. Exact retries survive restart; changed retries conflict. Add bounded Unix ingress, peer UID checks, durable watermarks, clean shutdown, and offline reconciliation.
  • Harden torn-write recovery, corruption checks, manifest and segment validation, receipt bytes after reclaim, catalog references, and backup/restore/salvage. The new writer reads published alpha.1 stores and unsealed shadow data; the old alpha cannot read the new ingress/reclaim formats.
  • Bound reconciliation before block reads and count filtered-out entries against its scan budget. Visit matches without collecting the whole query. Bind new sealed raw files to manifest v3 by file CRC32, exact time bounds and point count; verify on open, check and salvage. This adds streaming reads of sealed bytes at startup. Unpublished v2 stores with sealed raw files lack this binding and require a pre-seal snapshot or a fresh shadow store; they fail without falling back to an older manifest.
  • Stop new sidecar writes before the store exceeds 512 MiB or available disk drops below its 512 MiB reserve. Return Overloaded and degraded health while continuing to serve exact stored receipts. Disable automatic rollups/sealing/retention on this bounded collection path. Add process tests for both limits, invalid settings, conflicts, restart, and recovery after changing the budget.
  • Package all three tools for Linux AMD64, Linux ARM64, and macOS. Linux builds use a pinned Debian 12 baseline. Each archive contains source identity, binary checksums, service examples, and recovery docs; the package check runs the extracted binaries. Add a container for UID 100/GID 101, private paths, and a Unix socket. Core owns the opt-in Compose overlay.
  • Run native ARM64, container/archive, dependency, process-crash, and ext4/NBD fault checks in CI. The filesystem gate keeps the healthy card cache/power-loss model and full workload but removes artificial SD latency; timing experiments retain the original profile. Remove Postcard's unused heapless feature and its archived atomic-polyfill dependency.

Validation

  • The final debug and optimized release suites each pass 284 tests, plus benchmark targets. Format, Clippy, doctests and clean Cargo package verification pass. Property tests use 512 cases.
  • 512 SIGKILL iterations across seeds 20260907 and 20260908: no lost acknowledged batch, partial batch, or ordering failure. These are process-crash results, not physical SD-card evidence.
  • SD-emulator tests (14), Python adapter tests (9), and package verification pass.
  • Both lockfiles pass cargo audit --deny warnings; no ignored advisories.
  • Final source 7bbae63532f695b10aca548bf4ee58c6d7ebb3a8 passes all eight CI jobs: https://github.com/srcfl/ftwdb/actions/runs/34130603839. Native tests and all three package builds pass on Linux AMD64, Linux ARM64 and macOS. The downloaded push-run archives identify this exact clean source; all archive/binary SHA-256 values and ELF/Mach-O architectures match. Local Linux ARM64 container start/stop and native macOS archive checks also pass.
  • Final ext4/NBD evidence preserves all 889,978 acknowledged smoke-test points and all 110,000 acknowledged points from an interrupted write run. ENOSPC recovery retains 790,000 complete points and reports the torn final payload. Backup, restore and salvage checks pass. These reports identify the final source; the test profile keeps the original healthy-card cache and power-loss model.
  • Alpha.1 upgrade/rollback drill: the candidate reads a 2,550-point alpha.1 store, seals it, and retains all points. Alpha.1 rejects that upgraded store. Restoring the pre-upgrade snapshot with the new tool gives identical snapshot CRCs and a store that alpha.1 can read again. Repeated after manifest v3: all 2,550 points survive; snapshot rollback still works. A sealed development v2 store fails without changing any source file. A two-point store without rollups also rejects the old reader after sealing.

Review follow-up

The two scan-limit and segment-binding findings now have regressions that exercise the failure before reading a block, filtered points, limits across seals/live data, valid replacement files, and refusal of unsafe restore/salvage. The flush comment does not reproduce: Database::flush already calls mark_ingress_durable after a successful sync. Existing storage and multi-source runtime tests verify both source watermarks; grouped append sync also advances prior sources.

The final Cursor Security Agent check passed. The final Bugbot rerun hit the account usage limit and returned a neutral error, so it supplies no new review.

Rollout limits

This PR does not publish a release or switch an authoritative read path. The Core integration must pin this FTWDB source and share the frozen v1 fixtures. Collection can have gaps after restart, overload, or outage; it does not claim complete replication or backfill.

A standalone FTWDB beta still needs target-box soak, physical SD-card power cuts, resource/write-volume measurements, and an off-card backup/restore drill. Process and NBD tests cannot substitute for those checks. The new exact-retry receipt index retains payload bytes; long-term space/replay budgets still need measurement before any read promotion.

Rollback: stop the source copy and sidecar, retain the new shadow store, then use a pre-upgrade snapshot or a fresh empty shadow store. Keep SQLite/Parquet in place. Filesystem free-space checks cannot reserve blocks against other processes, so keep host disk alerts and the service/container memory and CPU limits.

frahlg and others added 10 commits August 6, 2026 13:54
…ery, and range-query performance.

Co-authored-by: Cursor <cursoragent@cursor.com>
…d skip unchanged series during maintain.

Co-authored-by: Cursor <cursoragent@cursor.com>
Prod-beta cannot keep every historical point in RAM: after seal, queries
merge immutable segments with the unsealed tail, open replays only that
tail, and dirty maintain materializes a window instead of scanning all time.

Co-authored-by: Cursor <cursoragent@cursor.com>
…pen without dropping historical points.

Co-authored-by: Cursor <cursoragent@cursor.com>
…lvage.

Query methods return Result instead of panicking on corrupt blocks; integrity
checks verify block payloads, salvage can drop orphan segments, and the CLI
and shadow sidecar gain seal/maintain operations with periodic background upkeep.

Co-authored-by: Cursor <cursoragent@cursor.com>
…tes.

Smoke only cut after sync; this records a durable ACK watermark during Always ingest, verifies recovery against that watermark, rebuilds rollups after salvage, and exposes health/service-log ops fields plus a snapshot backup runbook.

Co-authored-by: Cursor <cursoragent@cursor.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4927c1c. Configure here.

Comment thread src/storage.rs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4927c1cda8

ℹ️ 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".

Comment thread src/shadow_reconcile.rs Outdated
Comment on lines +498 to +501
let series_points = database.query_history(series_id, span.start, span.end)?;
report.scanned_points = report
.scanned_points
.checked_add(series_points.len())

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce the scan limit while reading points

For a reconciliation window that overlaps a large sealed segment, query_history fully decompresses matching blocks and materializes the complete filtered result before max_scanned_points is checked. Moreover, series_points.len() counts only points surviving timestamp filtering, not all entries visited, so many wide overlapping blocks can consume unbounded time and memory while the reported scan count remains below the limit. Apply the limit during block/index traversal or expose a bounded query iterator.

Useful? React with 👍 / 👎.

Comment thread src/store.rs Outdated
Comment on lines +1305 to +1313
if segment.stats().points != descriptor.points {
return Err(Error::Corruption {
offset: 0,
reason: format!(
"raw segment {} point count does not match the manifest",
descriptor.file
),
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Bind sealed segment contents to their manifest descriptor

When a referenced .wseg is replaced or mixed up with another internally valid segment having the same point count, this check accepts it and the store subsequently serves the replacement history as valid. The manifest records minimum and maximum timestamps but those fields are never compared anywhere, and it stores no content digest, so check_integrity cannot detect the substitution either. Store and verify a segment checksum or otherwise bind all relevant segment contents to the descriptor.

Useful? React with 👍 / 👎.

@cursor
cursor Bot requested review from Leitet and davmoz September 7, 2026 13:32

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Left a non-blocking comment: Cursor Bugbot reported 1 unresolved durability-watermark finding, so this PR is not approved. Human review is needed; reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@chatgpt-codex-connector

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-07T13:32:14.223595Z 4927c1c PR opened
ℹ️ 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.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved: Cursor Bugbot completed successfully and the prior durability-watermark finding is resolved, with no unresolved Bugbot issues needing human review. No additional reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@cursor

cursor Bot commented Sep 7, 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_968c336c-f424-4635-b5c8-20725d5bddba)

@frahlg
frahlg merged commit 6486961 into main Sep 7, 2026
18 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant