Skip to content

feat(retention): [retention] manifest section + verisimiser gc subcommand#87

Merged
hyperpolymath merged 1 commit into
mainfrom
feat/retention-and-gc
May 14, 2026
Merged

feat(retention): [retention] manifest section + verisimiser gc subcommand#87
hyperpolymath merged 1 commit into
mainfrom
feat/retention-and-gc

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Per V-L2-P1: sidecar tables grew unboundedly. Adds retention bounds + a purge subcommand.

  • New [retention] section in manifest with provenance-days / temporal-days / lineage-days (0 = forever, default).
  • init template emits the section with the same Default-driven approach as the rest of V-L2-O1.
  • New src/gc.rs module: run_gc(&Manifest, dry_run) -> Result<GcReport>. Opens SQLite sidecar via rusqlite, DELETEs rows older than now - retention_days per dimension. Crucially, temporal purge is scoped to valid_to IS NOT NULL so the current version is never deleted regardless of age.
  • Non-SQLite backends fail loudly (typed error) rather than silently no-op.
  • New CLI: verisimiser gc [--manifest <path>] [--dry-run] [--json].
  • New dep: rusqlite = { version = "0.32", features = ["bundled"] }. Bundled SQLite avoids system-library dependency at the cost of ~1MB binary size.

Closes

Test plan

  • cargo clippy --all-targets -- -D warnings clean on Linux CI (local Windows build blocked by AppControl/WDAC on libsqlite3-sys build script — Windows-specific local issue)
  • 4 new tests in gc::tests:
    • gc_dry_run_counts_but_does_not_delete
    • gc_apply_deletes_old_rows (verifies current temporal version survives)
    • gc_retention_zero_is_forever
    • gc_rejects_non_sqlite_backend

Note on local build

Windows Application Control policy is blocking the freshly-compiled libsqlite3-sys build script on my dev box (os error 4551). Linux CI builds and tests should be unaffected; please flag if CI reports the same.

…ommand

Closes #50.

Sidecar tables grew unboundedly. README mentioned retention; the
data model didn't.

Manifest:

  - New `[retention]` section with three `*-days` fields
    (`provenance-days`, `temporal-days`, `lineage-days`). `0` means
    "keep forever" — the default. Modelled as `RetentionConfig`
    with serde renames so the TOML field names stay kebab-case.
  - `init` template emits the section with explanatory comments,
    pulling defaults from `RetentionConfig::default()` (continues
    the V-L2-O1 "no string drift between code defaults and template"
    invariant).

New module `src/gc.rs`:

  - `run_gc(&Manifest, dry_run: bool) -> Result<GcReport>` opens the
    SQLite sidecar via rusqlite and DELETEs rows whose timestamp is
    older than `now - retention_days` per dimension.
  - `dry_run = true` only counts candidates (no writes), so users can
    audit before applying.
  - `temporal_versions` purge is scoped to `valid_to IS NOT NULL` so
    the *current* version is never deleted regardless of age.
  - Non-SQLite sidecar backends fail loudly with a typed error
    ("only supports the SQLite sidecar backend") rather than silently
    no-op'ing.
  - `GcReport` is `Serialize` so `--json` can emit a structured
    report (sidecar path, dry-run flag, per-dimension counts, total).

New CLI: `verisimiser gc [--manifest <path>] [--dry-run] [--json]`.

New dep: `rusqlite = { version = "0.32", features = ["bundled"] }`.
The `bundled` feature compiles SQLite from source so users don't need
a system libsqlite3 install. Adds ~1MB to the binary; outweighed by
deployment simplicity.

Tests in `gc::tests` (require rusqlite at compile time but use only
in-tempdir SQLite files):

  - `gc_dry_run_counts_but_does_not_delete` — dry-run reports
    correct counts; row count in DB is unchanged.
  - `gc_apply_deletes_old_rows` — real purge deletes the right rows;
    crucially, the current (`valid_to IS NULL`) temporal version
    survives even though its `valid_from` is old.
  - `gc_retention_zero_is_forever` — every retention=0 means total=0
    deletions.
  - `gc_rejects_non_sqlite_backend` — non-SQLite storage returns the
    typed error.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@hyperpolymath hyperpolymath merged commit 0436bfe into main May 14, 2026
16 of 18 checks passed
@hyperpolymath hyperpolymath deleted the feat/retention-and-gc branch May 14, 2026 15:40
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.

V-L2-P1: [retention] manifest section + verisimiser gc subcommand

1 participant