Update documentation with 11 changed files (#4809) - #4824
Conversation
… frees space before emergency (#4809) Routine disk reclaim previously sourced candidates only from the LLM recipe. When the agent nominated nothing, the executor routed everything to "skip for review" and removed nothing — logging "freed 0 bytes, 0 paths removed, N skipped for review" every cycle while %-used climbed to 100%. Only the under-scoped emergency tier (target/debug only) freed anything, firing repeatedly and losing ground. Fix: - Add src/disk_reclaim/reclaimable.rs: a deterministic Rust enumerator (reclaimable_targets / enumerate_reclaimable) that always proposes the known-safe, regenerable space hogs routine reclaim never touched — idle self-deploy-target / cargo-target / shared-target build-tree contents (guarded by live-PID + idle window) and stale engineer worktrees. Candidates are additive to LLM proposals and still re-vetted by the non-bypassable guard; the enumerator gets no self-trust. - Widen allow_roots with build_tree_roots(state_root) (self-deploy-target leaf only; never bare state_root or $HOME) so build-tree contents pass guard containment. - Wire the floor into run_disk_reclaim (dedup by path) so routine reclaim frees real bytes with zero agent input. - Align disk_health::emergency_cleanup to the same build_tree_roots set via emergency_cleanup_with_pct (injectable pct seam), reclaiming the idle self-deploy-target tree it previously ignored while retaining all prior removals; live-PID guarded. - Env knobs (safe-clamped defaults): SIMARD_DISK_RECLAIM_BUILD_IDLE_DAYS=1, SIMARD_DISK_RECLAIM_WORKTREE_IDLE_DAYS=7. A 0/empty/invalid value clamps to the floor, never "purge now". Snapshot/backup/corrupt retention stays owned by MaintenanceThread — the enumerator never touches live cognitive state or snapshot dirs. Structured tracing only; no println!; no silent fallbacks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ests The three idle-day env-knob tests in src/disk_reclaim/reclaimable.rs mutate BUILD_IDLE_DAYS_ENV / WORKTREE_IDLE_DAYS_ENV via set_var/remove_var. The serial_guard meta-test requires every lib test that mutates a process-global env var to share the `cognitive_memory` serial key so env mutation is never concurrent with a cognitive-memory state-root env read. Append cognitive_memory to the existing disk_reclaim_env serial key on all three tests, matching the established repo convention (e.g. meeting_backend). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
rysweet
left a comment
There was a problem hiding this comment.
Step 17b — Comprehensive Code Review
Verdict: Approve-quality. No blocking defects. The change is well-guarded, well-tested, and its central invariant (every candidate — LLM or deterministic — is re-vetted by the guard, with no "trusted internal" shortcut) is proven by tests. Reviewed the true PR diff (merge-base 7fe267ad1..HEAD); verified all new tests green first-hand (reclaimable 17 passed, emergency_cleanup 2 passed).
Checklist
- Code quality / standards — idiomatic Rust, clear docs, single-source-of-truth
build_tree_rootsshared by routine + emergency tiers. - Test coverage adequate — enumerator classification, guard re-vetting of enumerated candidates (protected-path + outside-allow-root), emergency parity, root→dry-run downgrade, env clamping. Strong seams (
FakeLiveProcessProbe,MapMeasurer,ScriptedDisk,RecordingRemover,Harness). - No TODOs/stubs/swallowed exceptions — none introduced (see minor note #2).
- No unimplemented functions.
- Logic correctness — fail-closed
is_idleand env clamping (0/empty/negative → safe floor, never "purge now"); dedup preserves agent metadata; children (never roots) proposed so guard containment holds. - Edge case handling — live-PID withholding, sub-idle-window withholding, unreadable-dir → empty, mtime-in-future → not idle.
Strengths
- No self-trust for deterministic candidates.
enumerated_candidate_at_a_protected_path_is_still_rejectedand..._outside_allow_roots_is_still_rejectedprove the Rust enumerator cannot widen scope or bypass rails — the key safety property. - Tier convergence. Routine
allow_rootswidening andemergency_cleanupboth consumebuild_tree_roots, structurally eliminating the divergence that let emergency re-delete onlytarget/debug. - Defense-in-depth root downgrade (
effective_apply_mode) at the guarded core, so every caller inherits the apply→dry-run-as-root invariant.
Findings (all non-blocking)
1. [Low] emergency_cleanup_with_pct bypasses vet_candidate/is_safe_to_delete. Section 5 calls std::fs::remove_dir_all(&root) directly on build_tree_roots, guarded only by the live-PID probe — not routed through the guard the routine path uses. This is consistent with the pre-existing emergency pattern (target/debug etc. are also removed directly) and is PID-guarded last-resort at ≥95%, so acceptable here. Recommend a follow-up PR to route emergency removals through the shared guard for a single enforcement path.
2. [Low / silent-failure] Removal error is dropped without a structured log. if std::fs::remove_dir_all(&root).is_ok() { ... } discards the Err on the failure branch — no tracing::warn!. This nicks R7 ("failures surfaced via structured logs"). It mirrors the pre-existing target/debug pattern, but the PR adds a new instance; a warn!(path, error) on the else branch would keep failures observable.
3. [Informational / scope] Named artifacts from the stated requirements are intentionally not enumerated. canary-repro-target/bootstrap-target (Decision 4) and stale cognitive.* snapshot backups (Decision 3/R1a) are absent. I verified canary-repro-target/bootstrap-target are referenced nowhere in src/ and are created by no code — so substituting the real cargo-target/shared-target caches is the correct real-world choice, not a gap. Snapshot backups are deliberately deferred to MaintenanceThread (its own keep-N/age floor) to avoid double-counting/races — a safer design, and live_cognitive_and_snapshot_state_is_never_enumerated locks it in. This diverges from the written Decision 3 but is the sounder call; recommend confirming with the issue owner that MaintenanceThread ownership satisfies the AC, or filing a follow-up if snapshot reclamation is still wanted.
4. [Minor / edge] is_idle keys on the build-root's own mtime before enumerating all children. A directory's mtime refreshes only on direct child add/remove, so deep writes into an existing subtree may not update it. The live-PID probe mitigates the dangerous active-build case (an in-progress build has a live process), so this is acceptable, but worth noting for future tuning.
5. [Nit] PR title is misleading. "Update documentation with 11 changed files (#4809)" is auto-generated; this is a substantive behavior fix (deterministic reclaim floor), not a docs update. Suggest retitling to match the fix(disk-reclaim): ... commit subject.
Recommendation
Mergeable as-is. Items #1–#2 are worthwhile hardening follow-ups; #3 warrants a one-line confirmation from the issue owner on snapshot-reclamation ownership; #4–#5 are informational.
Step 17c — Security ReviewVerdict: No blocking security findings. Approve from a security standpoint. This change adds a deterministic reclaimable-set enumerator (issue #4809) whose central invariant is sound: every candidate it proposes — like every LLM candidate — is re-vetted at the syscall boundary by Security requirements — all met
Sensitive-data handlingNo secrets, credentials, tokens, or PII are read, logged, or transmitted. Telemetry logs only paths and byte counts. No network I/O, no auth/authz surface, no deserialization of untrusted input. Injection vectors (command/path/env): none introduced — removals use Findings (all non-blocking)1. [Low] Emergency tier's direct
2. [Low] Removal 3. [Info] No privilege/UID checks before destructive ops. Strengths
Recommendation: Mergeable from a security standpoint. Finding #1 (emergency symlink-refusal parity) is worth a one-line follow-up hardening PR but is pre-existing and low-risk, not a merge blocker. |
Step 17d — Philosophy Guardian ReviewReviewed the true PR diff ( Compliance checklist
Non-blocking notes (philosophy-adjacent, defer to follow-up)
Confirmation: Philosophy-compliant. No code changes required for merge. The single |
Address review feedback (S2): emergency_cleanup_with_pct previously dropped the remove_dir_all Err via .is_ok(), silently swallowing failures. Replace with a match that logs a warn! on removal failure, satisfying the surface-failures / no-swallowed-errors rule flagged by the Code, Security, and Philosophy reviews. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Step 18b — Review Feedback ImplementedApplied the one unanimous pre-merge suggestion (S2) from the Code, Security, and Philosophy reviews. Commit Addressed
Verified
Not changed (with reasoning)
No blocking issues remained; the trivial high-consensus fix is applied and merge-ready. |
Final-pass consistency fix. The prior commit (b9b3381) surfaced the build-tree removal Err via warn!, but the four sibling remove_dir_all calls (target/debug, llvm-cov-target, worktrees/*/target, state-root cargo dirs) and the backup prune (remove_file) still dropped their Err via .is_ok(). Replace all with match + warn!(path, error, ...) so no removal failure is silently swallowed in emergency_cleanup_with_pct. Behavior is unchanged (best-effort emergency cleanup continues on failure); failures are now visible via structured logs. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Step 20 — Final Cleanup: F1 Consistency FixApplied the one non-blocking follow-up (F1) surfaced by the philosophy review. Commit F1 — Uniform error surfacing in Verification:
Final cleanup audit: no temp/debug artifacts, no forbidden patterns in non-test source, working tree clean, module boundaries intact, no dead code/stubs. PR remains merge-ready. |
Quality-audit fixes (issue #4809): - reclaimable::sorted_children swallowed all read_dir errors silently, which could reproduce the invisible "0 bytes freed" state on EACCES. Now logs non-NotFound errors via tracing::warn (R7: no silent fallbacks); NotFound stays silent (expected "nothing here"). - Correct docs/comments that claimed emergency_cleanup consumes reclaimable_targets; it actually consumes build_tree_roots (the shared build-tree source of truth). Fixed in reclaimable.rs, disk_health.rs test comment, and the deterministic-enumeration reference. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
📊 Coverage Summary
Coverage data from CI run. Test files matching |
|
Auto-closing this superseded auto-generated documentation PR: it is an older duplicate superseded by the canonical open auto-doc PR #4826. Enforcing the single-open auto-doc PR invariant (goal_hygiene). |
Summary
Concise workflow-generated PR for documentation.
Issue
Closes #4809
Changed files
Diff stat
Behavior
Implemented behavior through these branch commits:
371c8b5 test(disk_reclaim): add cognitive_memory serial key to idle-day env tests
27c91d7 fix(disk-reclaim): deterministic reclaimable floor so routine reclaim frees space before emergency (#4809)
Validation
ℹ NODE_OPTIONS=--max-old-space-size=32768 (saved preference). To change: /home/azureuser/.amplihack/config
I'll start by getting the branch name and understanding what changes have been made.
● Recent commit log (shell)
│ cd /home/azureuser/src/Simard-deploy-4049/worktrees/feat/issue-4809-fix-simards-ineffective-disk
│ -reclaim-so-routine-re && git --no-pager log --oneline -10
└ 11 lines…
● Get branch name and git status (shell)
│ cd /home/azureuser/src/Simard-deploy-4049/worktrees/feat/issue-4809-fix-simards-ineffective-disk
│ -reclaim-so-routine-re && git branch --show-current && echo "---STATUS---" && git --no-pager
│ status && echo "---DIFF STAT---" && git --no-pager diff --stat HEAD
Risk
No high-risk subsystem pattern detected from changed paths.
Checklist
This PR was created as a draft for review before merging.
Step 16b: Outside-In Testing Results
Tested from PR branch
feat/issue-4809-fix-simards-ineffective-disk-reclaim-so-routine-reas a consumer of the disk-reclaim subsystem would — through thesimard diskoperator CLI boundary and the crate's public test surface.Detected toolchain: Rust CLI (
Cargo.tomlat root, edition 2024,rustc 1.95.0). Package manager:cargo. Outside-in boundary: thesimard disk report|reclaimoperator subcommand (src/operator_cli/disk.rs) plus the guarded reclaim core.Chosen strategy: Per the qa-team skill's Rust-CLI guidance, use native
cargo testfor the changed modules as the consumer-boundary parity surface, then exercise the builtsimard diskbinary end-to-end as an external operator would. No gadugi framework required.disk reportvets an idle build tree and deletes nothingsimard disk report --path <tmp>/self-deploy-targetdisk reclaim: 95% -> 95% used, freed 0 bytes, 0 paths removed, 1 skipped for review; exit 0; 5 MB artifact still presentdisk reclaim --dry-runproposes but performs zero destructive opssimard disk reclaim --dry-run --path <tmp>/canary-repro-targetcargo test --lib disk_reclaimdeterministic_floor_is_non_empty_under_the_stale_scenario,idle_build_tree_contents_are_proposed_strictly_inside_the_root,live_cognitive_and_snapshot_state_is_never_enumerated)cargo test --lib disk_healthemergency_cleanup_reclaims_idle_self_deploy_target_and_retains_prior_removals)simard diskCLI dispatch / guard refusalscargo test --lib operator_cli::disk::dry_run_performs_zero_destructive_ops,reclaim_refuses_path_outside_allow_roots,reclaim_refuses_protected_main_even_when_named)Safety-constraint checks: No
println!/print!introduced in changed library code (structured tracing + OTel only) — verified via diff scan. Dry-run andreportmodes perform zero deletions. Guard re-vets every deterministic-floor candidate at the syscall boundary; live cognitive/snapshot state is never enumerated.Fix count: 0 — all scenarios passed on the first run; no diagnose/fix/commit iterations were required.