Skip to content

feat: per-wrapper compactionPolicy hint + Repo-level compaction interval #122

Description

@AlexJeffcott

Summary

Heartbeat-style $meshState documents (lease renewals, health pings, presence) accumulate Automerge history unboundedly. Today every consumer rolls its own change-count threshold plus compaction call plus per-key cooldown loop. A declarative per-wrapper policy hint, paired with a Repo-level interval that drives it, would let consumers state intent once instead of rebuilding the loop.

Spun out of #115 (Q5). The owner's position there: worth doing, but wanted to see one more consumer of the pattern before committing to the option shape.

Proposed shape

A compactionPolicy option on each $mesh* primitive:

type CompactionPolicy = {
  kind: "heartbeat" | "tombstone-filter" | "manual";
  threshold?: number;   // change-count trigger (uses the changeCount getter from #115)
  cooldownMs?: number;  // minimum gap between compactions of the same key
};
  • heartbeat — snapshot the wrapper's current materialised state into a fresh doc (no history). For docs where only the current state matters.
  • tombstone-filter — entries-map filter (the mesh:devices shape).
  • manual — opt out; no automatic compaction.

Plus a Repo-level interval that, on each tick, fires the appropriate primitive against every wrapper that declared a non-manual policy whose changeCount exceeds threshold and whose last compaction is older than cooldownMs.

The per-key cooldown and best-effort (failures log, never crash the tick) shape is the one fairfox already runs in its relay heartbeat.

Dependencies

Open design questions

  • Who is allowed to compact (signing / access)? Heartbeat snapshots reseed a doc — the policy needs an eligibility answer.
  • Option shape: confirm against the second real consumer before locking the CompactionPolicy type.
  • Whether tombstone-filter needs a consumer-supplied predicate or can be expressed declaratively.

Acceptance criteria

  • compactionPolicy option accepted on $meshState / $meshText / $meshCounter / $meshList.
  • Repo-level interval fires the matching primitive for non-manual policies past threshold, respecting cooldownMs.
  • Compaction failures log and never crash the interval tick.
  • manual (and the absence of the option) means no automatic compaction.
  • Unit coverage for threshold trigger, cooldown suppression, and best-effort failure handling.

Tracking

Follow-up to #115. Depends on the design questions above being settled — owner wants a second concrete consumer of the pattern first.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions