GC probe cap defers popular-parent sweeps indefinitely; stale one-level-per-pass comments #460
Labels
No labels
actions
bug
cli
duplicate
enhancement
fork
forum
git storage
help wanted
insights
invalid
issues
moderation
oidc
ownership transfer
packages
pr/merge protection rules
projects
pull requests
question
releases
sponsorships
tags
webhooks
wiki
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#460
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Child of #449 (audit finding F7 Low, comment 4563). forknet.go:31,82-145: maxForkNetworkProbes=64 at two probes per child means ~32 direct children exhaust the cap; exhaustion aborts the sweep (compact.go:132-134, fail-closed correct) so a parent with a large fork fan-out never compacts — superseded packs accumulate with only a log line. Also stale 'one level per pass' comments. Fix: raise/page the probe budget for wide fan-outs (bounded), and refresh the stale comments.
Fix ready for review: PR #471 (#471) — raises the probe cap 64→512, keeps fail-closed on exhaustion, refreshes the stale one-level-per-pass comments, regression tests green (-race, coverage 95.5%).
Review of PR #471 (fix/issue-460) — verified in scratch worktree at
532ca95(removed afterward; main worktree untouched, still clean apart from pre-existing untracked .opencode/).Cap raise sound (64->512): YES. Two probes/child (manifest + own index, forknet.go:128-137) so old cap died at ~32 children; 40-child sweep now compacts with measured 81 GETs (1 parent index + 2x40), pinned exactly by TestForkNetworkGCWideFanout. Linear cost confirmed. Law 6: walk runs only on background leased compact unit (TryLock-or-defer, exact-key GETs, never LIST, never push hot path) — 512 GETs/pass is bounded maintain-path cost. No browser check needed (no browser-facing change) — noted explicitly.
Fail-closed preserved: YES. Cap exhaustion returns error before any deletion (forkNetworkLive runs before the delete loop in gcSuperseded); TestForkNetworkGCCapExceeded (300 children, 600 probes needed) asserts err contains 'probe cap', removed==0, AND gone-old.pack survives — nothing deleted, next pass retries from scratch.
Residual bound honest: YES. ~256-child limit stated in forknet.go const comment + header, and docs/features/03_pull_requests.md Decisions entry; durable paged cursor named as follow-up requiring bucket-side cursor state (schema decision per law 4) — correctly scoped out.
Stale 'one level per pass' comments: corrected accurately. The walk is a queue-based BFS extending within the same loop (forknet.go:100-145) — cap, not depth, bounds it. Fixed in all three places: forknet.go header + inline, pulls/model.go:139, features/03 §7.
Child-index error comment fix: correct. Old text claimed child path skips on error; code returns fmt.Errorf on child index read failure (fail closed), skipping only on absent index (nil,nil leaf). New readForkIndex comment matches implementation at both parent and child levels.
No behavior change besides cap: confirmed. Only the const value + comments changed in non-test code; GC decisions identical under the old cap (same abort/skip/delete rules, same lock protocol).
Hygiene: maintain suite -race green, coverage 95.5% (>=95% gate), targeted WideFanout + CapExceeded pass -race, pulls package green, go build ./... clean, go vet + gofmt clean, no new deps, law 12 docs updated in same change (03 Decisions + code comments).
MERGE RECOMMENDATION: ready to merge. No fixes pushed (nothing to fix).
Fixed by PR #471 (review clean — all 7 points pass, fail-closed preserved, residual honestly bounded), merged. Closing.