Cut core/model, reclaim, json, util comment bloat ~26% (comments only, zero code change)

This commit is contained in:
2026-07-29 20:49:06 -04:00
parent 1f24c4b095
commit 65ca1e1f9d
16 changed files with 400 additions and 681 deletions
+88 -109
View File
@@ -1,45 +1,32 @@
#pragma once
// prune_reconcile — the pure core of Phase R (Reclaim), Wave 1. The safety-critical
// "which files are orphans" decision, computed with NO filesystem I/O and NO REAPER
// types. The mirror of view_mode_model's reconcile(liveGuids), one level DOWN: it
// reconciles FILES ON DISK against REFERENCED FILES (the union across every bank),
// where reconcile reconciled membership entries against live tracks.
//
// PURE MODULE (CLAUDE.md §load-bearing split): NO REAPER types, NO SWELL, NO
// vendor/ includes, NO filesystem calls. Standard library only. Unit-tested outside
// the DAW — this is the safety-critical part (it decides which bytes get deleted in
// R2/R3), so it is hard-tested here before any I/O exists.
//
// -- The one computation ------------------------------------------------------
// prune_reconcile — the safety-critical "which files are orphans" decision, computed
// with NO filesystem I/O and NO REAPER types. Unit-tested outside the DAW before any
// I/O exists — this decides which bytes get deleted.
//
// The one computation:
// orphans = (owned ∩ present) referenced
//
// * present — files enumerated in the resolved current bank folder (R2 shell).
// * present — files enumerated in the resolved current bank folder (shell).
// * referenced — every project-relative path referenced by ANY bank in the book,
// pool included (union across the whole book — see BankBook::
// referencedPaths). A file referenced by any bank — including via a
// COPY into a second bank — is NEVER an orphan (the prune null test).
// * owned — the owned-file manifest: the files the bank system itself created
// (OwnedFileManifest). A present-but-unowned (hand-dropped) file is
// NEVER reclaimed — prune reclaims only the system's own leavings.
// * owned — the owned-file manifest: files the bank system itself created. A
// present-but-unowned (hand-dropped) file is NEVER reclaimed.
//
// The three settled guardrails fall straight out of the set algebra:
// The three guardrails fall straight out of the set algebra:
// * ∩ present — never proposes deleting a file that is not on disk (an owned-
// but-absent manifest entry yields no orphan, no error).
// * ∩ owned — never a hand-dropped file (ownership attribution, fork R-D).
// * ∩ owned — never a hand-dropped file (ownership attribution).
// * referenced — never a file any bank references (union safety, prune null test).
//
// -- Path representation: EXACT-STRING match (safety-critical) -----------------
//
// Every path in the model is a project-relative string compared VERBATIM: Sample.
// relativePath, OwnedFileManifest::contains (p == relativePath), and BankModel all
// use raw std::string equality — no separator normalization, no case-folding, no
// trailing-slash trimming. This core MATCHES that convention exactly: it compares
// the raw strings the shell supplies. Feeding a consistent spelling across the three
// inputs is the R2 shell's contract (it enumerates the folder, unions the book, and
// reads the manifest against the SAME resolved current folder). Diverging from exact
// match here (e.g. case-insensitive compare) would be the unsafe direction — it could
// let one spelling of a referenced file be treated as an orphan under another.
// Path representation: EXACT-STRING match everywhere — Sample.relativePath,
// OwnedFileManifest::contains, BankModel all use raw std::string equality: no
// separator normalization, no case-folding, no trailing-slash trimming. Feeding a
// consistent spelling across the three inputs is the shell's contract (it enumerates
// the folder, unions the book, and reads the manifest against the SAME resolved
// current folder). Diverging from exact match here (e.g. case-insensitive compare)
// would be the unsafe direction — it could let one spelling of a referenced file be
// treated as an orphan under another.
#include <cstdint>
#include <string>
@@ -48,34 +35,28 @@
namespace reasampler::reclaim {
// The dry-run prune result (Phase R, Wave 2 — report only, no deletion). The thin
// prune shell (persist) fills this from pruneOrphans() + a per-file size stat and hands
// it to the report surface; R3 will act on the SAME set behind the confirm guardrail.
// REAPER-free / filesystem-free by design (the shell does the I/O; this is just the
// tallied outcome), so the count/size aggregation is unit-testable outside the DAW.
// The dry-run prune result — report only, no deletion. The shell fills this from
// pruneOrphans() + a per-file size stat; a confirmed delete later acts on the SAME
// set behind the confirm guardrail. Filesystem-free by design (the shell does the
// I/O; this is the tallied outcome), so the aggregation is unit-testable.
//
// * count — number of orphan files (== orphans.size(); the AUTHORITATIVE tally,
// exact even when `orphans` below is a truncated display list).
// * totalBytes — sum of the on-disk sizes of the orphan files, in bytes (reclaimable
// space). A file the stat could not size contributes 0 (never negative).
// * orphans — the orphan file list as project-relative index-spelled paths, in
// folder-enumeration order (deterministic). MAY be truncated for a large
// set (the shell's display cap); `count` stays exact regardless, and
// `truncated` says whether the list was clipped.
// * truncated — true iff `orphans` holds fewer than `count` entries (a large set was
// clipped for display); false when the list is complete.
// * count — number of orphan files (authoritative tally, exact even when
// `orphans` below is a truncated display list).
// * totalBytes — sum of the on-disk sizes of the orphan files, in bytes. A file
// the stat could not size contributes 0 (never negative).
// * orphans — the orphan file list, project-relative, in folder-enumeration
// order (deterministic). MAY be truncated for a large set (the
// shell's display cap); `count` stays exact regardless.
// * truncated — true iff `orphans` holds fewer than `count` entries.
// * abortedUnreadableUsage — true iff the scan found a present-but-unreadable
// rsusage_* instance-usage record (pS-usage fail-safe): the orphan
// computation was NOT performed (count 0, empty list) and the prune
// must HALT — deleting with degraded protection is the data-loss
// direction. Set by the session's scan shell, never by
// buildPruneReport (which stays a pure tally).
// * offendingUsageKeys — the exact "rsusage_<guid>" ext-state key names that
// triggered the abort (non-empty iff abortedUnreadableUsage). Named
// so the action can print them for operator recovery: a corrupt/
// oversized key whose owning instance no longer exists is never
// automatically rewritten, so the abort would be permanent without
// a way to clear it. The operator can clear each key via ReaScript:
// rsusage_* instance-usage record: the orphan computation was NOT
// performed (count 0, empty list) and the prune must HALT —
// deleting with degraded protection is the data-loss direction.
// Set by the scan shell, never by buildPruneReport (which stays a
// pure tally).
// * offendingUsageKeys — the exact "rsusage_<guid>" key names that triggered the
// abort (non-empty iff abortedUnreadableUsage), so the operator
// can clear each key via ReaScript:
// reaper.SetProjExtState(0, "reasampler", "<key>", "")
struct PruneReport {
std::size_t count = 0;
@@ -86,20 +67,18 @@ struct PruneReport {
std::vector<std::string> offendingUsageKeys; // non-empty iff abortedUnreadableUsage
};
// The outcome of an actual prune DELETION (Phase R, Wave 3 — R3). The prune shell fills
// this as it deletes the confirmed orphan set, reporting what it ACTUALLY reclaimed (not
// what it intended to) so a locked/vanished file shows up as a skip, never a false claim.
// REAPER-free / filesystem-free by design (the shell does the deletion; this is the
// tallied outcome), so the count/byte aggregation is unit-testable outside the DAW.
// The outcome of an actual prune DELETION. The shell fills this as it deletes the
// confirmed orphan set, reporting what it ACTUALLY reclaimed (not what it intended)
// so a locked/vanished file shows up as a skip, never a false claim. Filesystem-free
// by design, so the count/byte aggregation is unit-testable.
//
// * reclaimedCount — number of files actually removed from disk BY THIS CALL (trash or
// unlink). Already-absent files are NOT counted here.
// * reclaimedBytes — sum of the on-disk sizes of the files actually removed, in bytes.
// * skippedCount — files that could not be or were not reclaimed: stale entries that
// dropped out of the fresh-orphan intersection, files that vanished
// between the plan and the delete call (already absent), and real
// delete failures (locked, conversion error). Never an error/crash.
// * usedTrash — true iff the deletions were routed to the OS trash/recycle bin
// * reclaimedCount — files actually removed from disk BY THIS CALL (trash or
// unlink). Already-absent files are NOT counted.
// * reclaimedBytes — sum of the on-disk sizes of the files actually removed.
// * skippedCount — files not reclaimed: stale entries dropped from the
// fresh-orphan intersection, files that vanished between plan
// and delete, and real delete failures. Never an error/crash.
// * usedTrash — true iff deletions were routed to the OS trash/recycle bin
// (recoverable); false iff the platform fell back to hard unlink.
struct PruneDeletionResult {
std::size_t reclaimedCount = 0;
@@ -110,11 +89,11 @@ struct PruneDeletionResult {
// Computes the prune orphan set: (owned ∩ present) referenced.
//
// Returns the subset of `present` that is BOTH owned AND unreferenced, in the ORDER
// they appear in `present` (deterministic output — mirror of the insertion-order
// determinism the index / manifest keep; the R2 dry-run reports a stable file list).
// Duplicate spellings within `present` are de-duplicated in the result (a folder
// enumeration yields distinct names, but the core does not rely on that).
// Returns the subset of `present` that is BOTH owned AND unreferenced, in the order
// they appear in `present` (deterministic — mirrors the insertion-order determinism
// the index/manifest keep). Duplicate spellings within `present` are de-duplicated
// in the result (a folder enumeration yields distinct names, but the core does not
// rely on that).
//
// Pure: no I/O, no REAPER, no hidden state. All three inputs are project-relative
// path strings, compared by exact std::string equality (see header note).
@@ -122,56 +101,56 @@ std::vector<std::string> pruneOrphans(const std::vector<std::string>& present,
const std::vector<std::string>& referenced,
const std::vector<std::string>& owned);
// Union two referenced-path sets into one (pS-usage): the bank's own referencedPaths()
// PLUS the paths held by live ReaSampler 9000 instances (sample_usage::usageHeldPaths).
// Unions two referenced-path sets into one: the bank's own referencedPaths() PLUS
// the paths held by live ReaSampler 9000 instances (sample_usage::usageHeldPaths).
// Order-preserving (`primary` first, then the `extra` paths not already present),
// exact-string de-dup — the same comparison convention as everything above, so feeding
// the result to pruneOrphans keeps the ` referenced` guardrail byte-exact. A path held
// ONLY by an instance (e.g. its bank entry was deleted while the instance kept its v10
// ref) is protected exactly like a bank-referenced one.
// exact-string de-dup — the same comparison convention as everything above, so
// feeding the result to pruneOrphans keeps the ` referenced` guardrail byte-exact.
// A path held ONLY by an instance (its bank entry was deleted while the instance
// kept its ref) is protected exactly like a bank-referenced one.
//
// Pure: no I/O, no REAPER. Kept here (not in the shells) so the "instance usage makes a
// file un-prunable" property is provable at the prune layer itself.
// Pure: no I/O, no REAPER. Kept here (not in the shells) so "instance usage makes a
// file un-prunable" is provable at the prune layer itself.
std::vector<std::string> mergeReferenced(const std::vector<std::string>& primary,
const std::vector<std::string>& extra);
// Tallies a dry-run PruneReport from a computed orphan set and a per-path size lookup.
// PURE (no I/O): the shell does the folder stat and passes the sizes in `sizeByPath`;
// this owns the count / byte-sum / display-truncation decision so it is unit-testable.
// Tallies a dry-run PruneReport from a computed orphan set and a per-path size
// lookup. Pure (no I/O): the shell does the folder stat and passes sizes in
// `sizeByPath`; this owns the count/byte-sum/display-truncation decision.
//
// * count == orphans.size() (the authoritative tally, exact regardless of the cap).
// * totalBytes == the sum of sizeByPath[o] over EVERY orphan o (not just the displayed
// ones); a path missing from sizeByPath contributes 0 (an orphan whose
// size could not be stat'd — never negative, never dropped from the sum).
// * count == orphans.size() (authoritative tally, exact regardless of the cap).
// * totalBytes == sum of sizeByPath[o] over EVERY orphan o (not just displayed); a
// path missing from sizeByPath contributes 0 (never negative).
// * orphans == the first `displayCap` orphans in input order (the deterministic
// folder-enumeration order pruneOrphans preserved); the whole set when
// count <= displayCap. displayCap == 0 means "no display cap" (whole set).
// * truncated == count > orphans.size() (a large set was clipped for display).
// order pruneOrphans preserved); the whole set when count <=
// displayCap. displayCap == 0 means "no display cap".
// * truncated == count > orphans.size().
//
// Kept separate from pruneOrphans so the safety-critical set algebra stays a pure function
// of three sets, while the presentation tally (which the R2 dry-run and R3 confirm both
// need) is its own small, testable step.
// Kept separate from pruneOrphans so the safety-critical set algebra stays a pure
// function of three sets, while the presentation tally is its own testable step.
PruneReport buildPruneReport(const std::vector<std::string>& orphans,
const std::unordered_map<std::string, std::uint64_t>& sizeByPath,
std::size_t displayCap);
// Computes the confirm-time delete plan: the intersection of the set the user was SHOWN
// and confirmed (`confirmed`) with a FRESH pure-core orphan output (`freshOrphans`) taken
// at delete time. Returns exactly `confirmed ∩ freshOrphans`, in the order of `confirmed`
// (deterministic — the same order the confirm listed).
// Computes the confirm-time delete plan: the intersection of the set the user was
// SHOWN and confirmed (`confirmed`) with a FRESH pure-core orphan output
// (`freshOrphans`) taken at delete time. Returns exactly `confirmed ∩ freshOrphans`,
// in the order of `confirmed` (deterministic — the same order the confirm listed).
//
// This is the R3 staleness guard, and it protects in BOTH directions so that "what was
// This is the staleness guard, and it protects in BOTH directions so that "what was
// shown is what is deleted" holds no matter what changed between confirm and delete:
// * A confirmed path that is NO LONGER a fresh orphan — a file that vanished (gone from
// `present`), or that some bank now references (gone from ` referenced`), or whose
// ownership changed — is DROPPED (a skip, never an error, never a wrongful delete of a
// now-referenced file). Because `freshOrphans` is itself a pure-core output, the plan
// can never contain a referenced or hand-dropped file: the guard survives recompute.
// * A path that became an orphan AFTER the confirm (in `freshOrphans` but not `confirmed`)
// is NOT deleted — it was never shown, so it is never swept without its own confirm.
// * A confirmed path that is NO LONGER a fresh orphan — vanished (gone from
// `present`), now referenced (gone from ` referenced`), or ownership changed —
// is DROPPED (a skip, never a wrongful delete of a now-referenced file). Because
// `freshOrphans` is itself a pure-core output, the plan can never contain a
// referenced or hand-dropped file: the guard survives recompute.
// * A path that became an orphan AFTER the confirm (in `freshOrphans` but not
// `confirmed`) is NOT deleted — it was never shown, so it's never swept without
// its own confirm.
//
// PURE: no I/O, no REAPER. Duplicate spellings in `confirmed` are de-duplicated in the
// result (mirrors pruneOrphans; a confirmed set from a real scan holds distinct names).
// Pure: no I/O, no REAPER. Duplicate spellings in `confirmed` are de-duplicated in
// the result (mirrors pruneOrphans; a confirmed set from a real scan holds distinct
// names).
std::vector<std::string> pruneDeletePlan(const std::vector<std::string>& confirmed,
const std::vector<std::string>& freshOrphans);