Skip to main content
← Back to list
01Issue
FeatureShippedSwamp CLI
Assigneesstack72

Port bundle_freshness (content-fingerprint cache invalidation) to reports / drivers / datastores / vaults loaders

Opened by stack72 · 4/17/2026· Shipped 4/20/2026

Problem

PR systeminit/swamp#1188 closes issue #125 by replacing mtime-based bundle-cache freshness with sha-256 content fingerprinting in the models loader. The fix lives in a shared helper at src/domain/extensions/bundle_freshness.ts (pure findStaleFiles + computeSourceFingerprint).

The four sibling user-extension loaders — reports, drivers, datastores, vaults — still carry a verbatim copy of the old mtime-based findStaleFiles / bundleWithCache logic. They are therefore latent-vulnerable to the same bug under the same triggers (atomic-rename saves, mtime-preserving sync tools, sub-second second edits). No user has reported a stale-cache symptom on those loaders yet, but the root cause is identical.

Users affected — anyone iterating on a custom vault / driver / datastore / report extension whose editor or workflow produces a save that does not strictly advance source mtime past the cached bundle mtime. Same failure mode as #125 — method runs, validation or output fails because the executed bundle is stale.

Proposed solution

Port each of the four loaders onto the shared helper that already exists in extensions/bundle_freshness.ts —

  1. Replace each loader's private findStaleFiles with a thin wrapper delegating to findStaleFilesShared.
  2. Replace each loader's bundleWithCache mtime fast-path with the same content-fingerprint-aware shape introduced in PR #1188 (remove the freshness check from bundleWithCache, add the isExpectedBundleFailure pre-check for pulled extensions).
  3. In each loader's rebundleAndUpdateCatalog and populateCatalogFromDir — compute and persist source_fingerprint alongside source_mtime (already optional on ExtensionTypeRow, so this is additive).
  4. Add one regression test per loader mirroring the models-loader regression added in #1188 — Deno.utime restores the source mtime after an atomic-rename-style content swap, buildIndex must rebundle.

The catalog schema and migration are already in place (source_fingerprint column with PRAGMA-guarded ALTER TABLE), so this is purely loader-side work.

Alternatives considered

  • Do nothing and wait for a user to hit the bug on one of the four. Not worth the slip — the helper is one line away for each loader and the symptom is confusing for users ("my extension code change isn't taking effect").
  • Extract the full loader lifecycle into a generic user-extension loader. Too large; the five loaders have enough idiosyncratic behavior that a full unification is a separate refactor.

Context

  • Related PR — systeminit/swamp#1188
  • Related issue — #125
  • Shared helper — src/domain/extensions/bundle_freshness.ts
  • Catalog schema — src/infrastructure/persistence/extension_catalog_store.ts (column already present, migration already in place)

Acceptance criteria

  • Each of reports / drivers / datastores / vaults loaders delegates freshness to bundle_freshness.findStaleFiles and persists source_fingerprint on every catalog write.
  • Each loader has a regression test mirroring user_model_loader_test.ts "findStaleFiles detects content change when source mtime is preserved".
  • deno check / lint / fmt / test / compile clean.
  • swamp-uat full suite passes against the recompiled binary.
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPEDTRIAGE+ 7 MOREREVIEW+ 3 MOREPR_MERGEDSHIPPED

Shipped

4/20/2026, 3:31:11 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack724/17/2026, 11:50:54 PM

Sign in to post a ripple.