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

#209 Schema-invalid extensions loop in rebundle path: catalog row never updates after first failed validation

Opened by stack72 · 5/1/2026· Shipped 5/1/2026

Description

Discovered while implementing the fix for #208 (broken transitive deps). Same regression shape, different trigger: an extension that previously bundled cleanly can be permanently stuck in the rebundle loop if its source becomes schema-invalid.

Mechanism

In each loader's `rebundleAndUpdateCatalog` (models, vaults, drivers, datastores, reports), the sequence is:

  1. `bundleWithCache` — succeeds (or falls back to cached bundle on failure)
  2. `importBundle` — succeeds
  3. `computeSourceFingerprint` — succeeds (after #208 fix)
  4. `UserXSchema.safeParse(module.x)` — throws if schema-invalid
  5. `catalog.upsert` — never reached

If the user edits an extension and the new source doesn't pass schema validation (e.g. removes a required field, types it wrong, etc.), the source fingerprint changes (so `findStaleFiles` keeps marking it stale) but the catalog row's stored fingerprint never advances past the last-good state. Every `buildIndex` pass repeats the cycle: stale → rebundle → schema throws → row not updated → stale again.

User-visible effects:

  • `Failed to load user X` warning on every read-only command (`model type search`, `vault type search`, etc.)
  • One extra deno bundle spawn per affected file per invocation (~1s each on real-world bundles with deps)
  • `swamp model type search` exhibits the same kind of latency the #208 fix removed, just with a different warning class

Steps to reproduce

  1. Create a healthy extension that bundles and validates — `swamp model type search` to populate the catalog.
  2. Edit the source to remove a required schema field (e.g. delete the `methods` block from a model, or the `name` field from a vault).
  3. Run `swamp model type search` (or the equivalent for the kind you're testing) repeatedly.
  4. Observe: each run emits the schema-validation warning and the catalog row's `source_fingerprint` never advances past the original.

``` $ sqlite3 .swamp/_extension_catalog.db "SELECT type_normalized, substr(source_fingerprint,1,16) FROM bundle_types" @local/echo|f238dacf7cd4ded2 <-- never updates after schema breaks ```

Expected

Either:

  • (a) Treat schema-invalid extensions like #208 treats unreadable deps: capture the failure into the catalog row (negative-cache marker, sentinel-bearing fingerprint, or a `failed` column) so subsequent passes skip retry until the source content actually changes.
  • (b) Always upsert the catalog row with the new fingerprint after a successful bundle+import, even when schema validation fails. The schema warning still fires once per content edit, but subsequent passes are stable.

(b) is the lighter fix. (a) is more thorough — gives a place to surface a sticky "this extension is broken" UI marker without spawning every command.

Why filed separately from #208

#208 narrowed the throw inside `computeSourceFingerprint`. This bug lives one level up — the throw happens after fingerprint computation, before catalog upsert. Different mechanism, different fix, separate review surface.

Environment

  • swamp: `20260501.150516.0-sha.acc85d5a` (also reproduces on #208 fix branch)
  • Affected loaders: all five (models, vaults, drivers, datastores, reports) since they share the same rebundleAndUpdateCatalog pattern
02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 3 MOREPR_MERGEDSHIPPED

Shipped

5/1/2026, 11:33:34 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack725/1/2026, 9:49:37 PM

Sign in to post a ripple.