Skip to content

fix(publish): prune site snapshots no active page version references - #652

Open
ngocht wants to merge 1 commit into
CoreBunch:mainfrom
ngocht:fix/prune-unreferenced-site-snapshots
Open

ngocht wants to merge 1 commit into
CoreBunch:mainfrom
ngocht:fix/prune-unreferenced-site-snapshots

Conversation

@ngocht

@ngocht ngocht commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #651.

Every full publish stores a complete copy of the published SiteDocument in site_snapshots, and nothing ever deleted one. Readers only reach a snapshot through data_rows.active_version_id, and version history (listDataRowVersions / getDataRowVersion) reads data_row_versions alone. That leaves superseded snapshots as dead weight. On one production site the table held 293 snapshots / 439 MB, and only 7 of them backed an active version.

Changes:

  • persistSitePublish calls pruneUnreferencedSiteSnapshots at the end of its transaction. The function deletes every snapshot that no page row's active version references, and always keeps the snapshot it just wrote.
    • Pages whose active version came from an earlier publish keep that snapshot.
    • Superseded version rows stay, so the history list is unchanged. on delete set null (both dialects; SQLite runs with foreign_keys = ON) clears their site_snapshot_id.
  • Migration 032_data_row_versions_site_snapshot_idx indexes data_row_versions.site_snapshot_id. Without it, the set-null on each deleted snapshot scans the whole versions table (14k rows on that site).
  • Docs: content-storage.md and publisher.md.

Before merging, please decide one thing. The docs call the reassembled PublishedPageSnapshot "the canonical audit record". After this PR, that record exists for the active version only; older versions keep their row (title/slug/publisher/time) but not the full site document. There is no rollback today, so nothing reads it. If you'd rather keep site-level history for a future rollback, the predicate can also keep the newest N snapshots.

The first publish after upgrading deletes the whole backlog. A dry run of the predicate on that production Postgres, inside a read-only transaction, counted 287 snapshots / 415 MB. Operators reclaim the space with VACUUM FULL site_snapshots (Postgres) or VACUUM (SQLite).

Independent of #647, which prunes published_runtime_assets. Both touch persistSitePublish, but they merge cleanly in either order. I checked by merging both branches and running bun test src/__tests__/server/: 1117 pass.

Verification

  • bun run build — ran tsc -p tsconfig.app.json and tsc -p tsconfig.node.json (clean)
  • bun test — ran bun test src/__tests__/server src/__tests__/db: 1141 pass. New publishSiteSnapshotRetention.test.ts (real SQLite via createTestDb) covers two cases: (1) after three publishes only the last snapshot remains, all six version rows remain with superseded links nulled, and the page still resolves by slug; (2) a snapshot still serving a page that a later publish skipped is kept. Both fail with the prune call removed. The cmsPublish fake DB handles the new delete.
  • bun run lint — eslint on the changed files (clean)
  • Docker/deployment check, if relevant

Checklist

  • Tests cover behavior changes.
  • Docs were updated when behavior, config, deployment, or public surfaces changed.
  • No compatibility shim was added for old pre-release behavior.
  • No secrets, local databases, uploads, or generated artifacts are included.

🤖 Generated with Claude Code

Every full publish stored a full copy of the site in site_snapshots and
nothing deleted one. Readers only reach a snapshot through a page row's
active version, and version history reads data_row_versions alone, so
superseded snapshots were dead weight (439 MB, 7 of 293 in use, on one
production site).

persistSitePublish now deletes the snapshots no active version references,
keeping the one it just wrote. Superseded version rows stay; on delete set
null clears their site_snapshot_id. Migration 032 indexes
data_row_versions.site_snapshot_id so that set-null does not scan the
versions table per deleted snapshot.

Closes CoreBunch#651

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ngocht
ngocht marked this pull request as ready for review October 15, 2026 08:05

This branch has not been deployed

No deployments
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.

[Feature]: Prune site_snapshots no active page version references

1 participant