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

Relationships

#2975 findBySpec/findByTag lose a workflow step's output after a version is deleted, pruned or rolled back

Opened by hammz · 10/2/2026· Shipped 10/6/2026

Follow-up to swamp-club#2520 (PR swamp-club/swamp#2800).

Background

The data catalog keeps two latest flags per row (CatalogStore in src/infrastructure/persistence/catalog_store.ts):

  • is_latest: one row per data name, the highest promoted version. Used by data query, data get, data.latest() and readModelData.
  • is_step_latest: each workflow step's latest version of the name. Used only by the CEL helpers data.findBySpec and data.findByTag (via the latestPerStep query option), so every step's output stays visible (swamp-club#1761).

Problem

Paths that remove a version re-promote only the surviving highest version through catalogUpsert / upsertNewVersion. They never restore is_step_latest for another step whose latest was the removed row.

Example: one data name written by two steps.

v1  step s1   is_latest 0  is_step_latest 0   (superseded by s1 v3)
v2  step s2   is_latest 0  is_step_latest 1
v3  step s1   is_latest 1  is_step_latest 1

findBySpec returns v2 and v3. After v3 is removed, v2 is re-promoted, but v1 stays at is_step_latest 0, so findBySpec returns only v2 and step s1's output silently disappears. A full catalog rebuild (computeLatestFlags) would correctly mark v1 as s1's step latest.

Affected removal paths in src/infrastructure/persistence/unified_data_repository.ts:

  • swamp data delete with a version (delete-specific-version, re-promotes newLatest)
  • GC pruning (collectGarbage) and the write-time version cap (pruneExcessVersions)
  • rollbackVersions for deferred writes. Here a lower version of the same step promoted while a higher deferred write of that step was in flight stays at is_step_latest 0, because upsertNewVersion counts the in-flight row as a higher row in scope. If the deferred write is then rolled back, the step has no step latest.

Only the per-step view is affected. is_latest (data query, data get, data.latest, readModelData) is restored correctly by these paths.

The delete case predates #2520: the old per-step is_latest had the same hole. It is documented as a known gap in design/enablers/data-query.md (Step-aware versioning).

Suggested fix

After removing a version, recompute both flags for that one (namespace, type, model, name) group inside the same transaction: load the group's remaining rows, run computeLatestFlags (src/domain/data/data_query_service.ts), and write back changed rows. This is what enforceUniqueLatest already does catalog-wide. Then remove the known-gap note from the design doc.

Tests

  • catalog_store / unified_data_repository tests for delete-version, GC prune, version-cap prune and rollback, each leaving every step with a step latest that matches computeLatestFlags.
  • Extend the fast-check property in src/domain/data/data_query_service_property_test.ts to interleave removals with promotions.
02Bog Flow
✓OPEN✓TRIAGED✓IN PROGRESS✓SHIPPED+ 1 MOREASSIGNED+ 5 MOREREVIEW+ 53 MOREPR_MERGED+ 2 MORESESSION_SUMMARIZED

Shipped

10/6/2026, 3:31:28 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
stack72 assigned stack7210/6/2026, 12:00:10 AM

Sign in to post a ripple.