Skip to content

feat: client-side --prune-dead-weight flag on rescue (no contract change) #51

Description

@sanity

Problem

When a contract's mirror mode flips (snapshot → history or vice versa), bundles published under the old mode become dead-weight: no current ref points at their tip, no clone can be served from them, but they stay in object_index forever because the contract is append-only by design.

After the flip, auto-detect reads the new mode and turns off the dead-weight filter for the bundle class that's now legitimate. Rescue then iterates all bundles — including the old-mode orphans — every cron cycle. Rescue cost grows monotonically with mode-flip count over the contract's lifetime.

Filed as a refinement that avoids the contract-migration risk of #47 (now closed in favour of this).

Approach

Add a client-side --prune-dead-weight flag to freenet-git rescue that computes the dead-weight set from local state alone and SKIPS rescuing those bundles — same rescue-cost effect as a real object_index prune, without touching the contract.

The dead-weight check builds on reachable_bundle_ids (already implemented for --only-current-tips). The difference:

  • --only-current-tips says "rescue ONLY bundles whose tip is in refs." Correct for snapshot mode; wrong for history mode (would skip ancestor commits reachable via parent chain).
  • --prune-dead-weight says "rescue everything EXCEPT bundles whose tip is NOT in refs AND NOT in any reachable ancestor path." Correct for history mode after a mode-flip cleanup.

The second predicate needs a way to identify "ancestor commits of current refs" — which requires walking the commit graph. Two implementations:

  1. Local-clone-assisted (--prune-dead-weight --from <git-dir>): operator points the helper at a local clone. Helper does git merge-base --is-ancestor checks. Cheap but requires operator to have a clone.
  2. Network-walked: helper fetches the branch tip's bundle, parses commits, walks parents using bundle-tip extensions to identify which old bundles are still ancestor-reachable. Slow and complex but works without local clone.

Option 1 is cleaner; Option 2 is similar in shape to walk_unresolved_parents from PR #33. Start with Option 1.

Constraints

  • No contract change. object_index stays as-is; rescue just skips work.
  • Bundles still occupy contract bytes. Acceptable cost; the rescue-iteration savings is the real win.
  • Other rescuers without the flag still pay the full cost. Document this — the flag is opt-in cleanup, not a contract-wide fix.

Related

[AI-assisted - Claude]

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions