Skip to content

simplify(maintenance): unify storage-report sizing on a bounded, coverage-aware filesystem walk #4303

Closed

Description

@ScriptedAlchemy

Priority / scope

P2 · medium effort · medium reporting-compatibility risk. Static audit of master 064973de6e32bb2f31475d65bac9d184094fa470 (2026-10-18). This is a read-only reporting simplification and resource-bound fix, not a change to retention eligibility or a request to delete profile data.

Concrete source evidence

Confirmed from control flow: daemon page size does not cap nested metadata work, and the two sizing paths have different error accounting. No wall-time, CPU, or production-outage attribution is claimed.

Exact implementation instructions

  1. Use the existing footprint metadata walker for both registered and unregistered storage-report sizing. Remove the report's use of the unbounded dir_size_bytes convenience path; do not delete the age/mtime semantics needed by actual retention callers.
  2. Pass one request-owned entry budget across every subtree sampled in a daemon call. Do not reset a full budget for each of up to 64 projects. Thread the caller's existing cancellation/deadline checks into this traversal rather than creating another scheduler, generic executor, or persistent census cache.
  3. Return measured bytes together with explicit complete/partial/unavailable accounting. Preserve unavailable-entry counts and a distinct truncation/budget reason. Propagate this through per-store records, unregistered totals, profile_total_size, and CLI/dashboard rendering. Partial bytes must be presented as a lower bound, never as an exact complete size or a fabricated zero.
  4. Keep the current opaque top-level directory cursor implementation. Do not replace it with repeated full-directory sorting. Distinguish 'more projects remain' from 'this subtree was only partially sampled'; never mint an outer cursor that falsely claims the unsampled subtree was fully covered. A documented partial sample is sufficient for the bounded daemon route—do not add a durable recursive traversal engine just for exact totals.
  5. Keep the explicit full-profile CLI census a separate deliberate operation. Its existing truncation state and unavailable evidence must survive aggregation; do not silently relabel it complete or promise exact full totals after hitting its ceiling.
  6. In append_project_report, check a known unavailable retention-protection result before enumerating generation files for the digest-size preflight. Still emit the same named unavailable reason, and do not plan or collect against an empty guessed protection set. Any remaining daemon generation-directory scan needs an entry/work bound as well as the byte threshold; many zero-byte files must not evade the budget.
  7. Preserve metadata-only sampling, read-only free-page probes, source-directory side-effect rules, no-follow behavior, and the existing registry snapshot/lease ownership. This issue does not permit copying every graph database to calculate sizes or changing retention decisions.

Required behavioral tests

  • A single project containing more entries than a small injected budget yields bounded visits and explicit partial coverage even when outer page size is one.
  • Several projects share one call budget; later projects cannot restart unlimited work.
  • Deep trees, zero-byte files, unreadable entries and symlinks produce honest totals/coverage without recursive stack growth or following another store.
  • Cancellation/deadline checkpoints stop further traversal, including work running on the blocking pool; dropping only the awaiting future is not sufficient evidence.
  • Full and partial totals survive serialization and the existing report aggregation/rendering paths.
  • Missing retention protection performs no generation digest-size preflight and reports the original unavailable reason.
  • Use deterministic visit counters and small isolated temporary trees, not flaky elapsed-time thresholds or a real operator profile.

Acceptance

  • Both storage-report sizing paths use one bounded accounting implementation.
  • Nested filesystem work is bounded per daemon call, not merely per top-level page.
  • Read failures and truncation cannot disappear into apparently exact totals.
  • Existing cursor semantics and retention protection remain intact.
  • Obsolete report-specific traversal is deleted rather than wrapped by a new framework.

Run the affected maintenance and storage-report integration tests through their existing Bazel targets; no zero-test/compile-only acceptance. Related to #4099 observability, but distinct from its profile-growth/retention investigation: this ticket owns the report's traversal and accounting path. No Rust tests were executed during this audit.

Activity

  1. ScriptedAlchemy commented on Oct 19, 2026

    @ScriptedAlchemy
    OwnerAuthor

    Full-backlog workstream: implement #4303 and the directly related observability/retention gaps in #4099, coordinating #4152 temp-spill investigation and active transaction PR #4321. Read their current comments, merged work and source before modifying anything. First replace both report-specific unbounded traversals with the existing footprint walker and one per-call entry/cancellation budget. Propagate partial/unavailable lower-bound totals and skip generation scanning when protection is already unavailable. Then make per-store/WAL/payload/temp-spill growth observable via the actual daemon maintenance/reporting authority, adding deterministic isolated growth/retention regressions for remaining gaps. No direct deletion of operator data, no database reset, no fake zero/complete measurements, no second census engine, and no attribution of memory corruption to an unproven allocator suspect. Keep unsafe allocator remediation separate and evidence-backed. The 24-hour real-profile acceptance is not satisfied by unit tests; report it explicitly if not performed. Preserve active storage/native-runtime changes. Existing Bazel tests, nonzero counts, commit headers <=72; no timeout increases or skipped coverage. Produce real implementation PR(s), not another plan-only audit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions