#4869·gastown

gt compact is a no-op across all wisp categories while gt compact report counts tens of thousands as active

Author: BBerabiCreated Sep 15, 2026Updated Sep 15, 2026
Labelsstatus/needs-triage

Summary

gt compact evaluates zero wisps for TTL compaction, while gt compact report — the same command family, same invocation — reports 22,582+ active wisps. Two queries over the same data disagree completely. The result is unbounded wisp growth.

This appears to be the root cause of Dolt wisp-table bloat (we hit an 11,491-wisp threshold breach, alert threshold is 800) and of repeated manual reaper dispatches to clear a backlog that continuous compaction should have prevented.

Reproduction

$ gt compact --dry-run --json
{
  "promoted": null,
  "deleted": null,
  "skipped": 0,
  "orphaned_wisp_deps": 0
}

$ gt compact report --dry-run
## Wisp Compaction: 2026-09-15

### Summary
| Category | Deleted | Promoted | Active |
|----------|---------|----------|--------|
| Patrols  | 0       | 0        | 444    |
| Errors   | 0       | 0        | 10     |
| Untyped  | 0       | 0        | 22582  |

Reproduced from multiple directories and rig scopes. A separate agent on the same town independently observed 27,553 active Untyped wisps with the same 0/0 result.

Why skipped: 0 is the key signal

gt compact --help documents TTLs for every category, including default (untyped): 24h and patrol: 24h. So with 444 patrol wisps and 22,582 untyped wisps present, compaction should either act on them or skip them.

skipped: 0 means zero wisps entered the evaluation at all — it is not scanning 22k and finding none past TTL, it is scanning an empty set. Meanwhile the report path sees 22,582. That points at a scope/filter mismatch between the two code paths rather than a TTL-comparison bug: candidate selection for compaction returns nothing, while the counting query returns everything.

Note on scope — this is broader than one category

It was initially diagnosed as "TTL not applied to the Untyped category". Our repro suggests that framing is too narrow: Patrols (444, 24h TTL) and Errors (10, 7d TTL) are also 0/0. Compaction appears to be a no-op across all categories, not just untyped. Worth checking the shared candidate-selection query rather than per-category TTL handling.

Impact

  • Unbounded wisp accumulation; Dolt table growth with no automatic reclamation.
  • Threshold alerts fire (11,491 vs 800) and get triaged as their own incidents, with manual reaper dispatches repeatedly summoned to clear a backlog that should never accumulate.
  • Because the report path reports plausible-looking numbers, the failure is silent: a digest shows 'Active: 22582' without signalling that nothing is ever being compacted.

Suggested direction

Compare the candidate-selection predicate used by the compaction pass against the counting predicate used by compact report. The report path clearly resolves the wisp set correctly; the compaction path does not. Likely a differing rig scope, status filter, type predicate, or data source (wisp JSON files vs the Dolt table) between the two.

Environment: gt binary 2026-09-11, town at ~/gt, daemon uptime 41d.