[omp blocking] Overflow drain marks seq complete without completing it #152
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 project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
crueber/walhub#152
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?
[omp blocking] Overflow drain marks seq complete without completing it
internal/notify/tasks.go:331-335,:353-391,:484-487:fanoutOnereturns "event existed", not "recipients done" — 5sFanoutBudgettimeout (:354) strands goroutines at thefctxprecheck (:369-377), per-recipientcreateFailedswallowed (:384-386), yetmarkFanoutDonestill writes the completion marker so the #77 redrain sweep skips the seq forever.Fix
Report completion honestly: count
createFailed, log, skip the marker on incomplete (re-drain is idempotent, so a retry converges). Deterministic regression test (fault-injected recipient failure / expired budget → no marker, redrain recovers). Coverage gate holds; doc Decisions entry (law 12).Acceptance criteria
-race -count=20.Fix is up: #158 (branch fix/issue-152). fanoutOne returns (existed, complete); incomplete drains skip the done marker and the redrain converges idempotently. Regression tests verified FAILING pre-fix, green -race -count=20; coverage 96.2%. Not merging per instructions.
Review PR #158 (fix/issue-152, honest drain completion) — APPROVE.
(existed, complete) mapping (internal/notify/tasks.go:364-424) — all correct:
Counter mutex (375-383): increment-only fail() closure, never held across store calls (createOne:408, publish:417 outside lock); single unnested mutex so no lock-order issue (AGENTS.md law 3 / 13 S2). Read of failed at 419 after wg.Wait is race-safe (writes happen-before Done, -race clean x10 below).
Honest marker + exactly-once redrain: drain skips marker on !complete (336-339); sweep re-drives via fanoutDone==false + FanoutPending (tasks.go:507+); retry idempotent via deterministic NotificationID + PutCreate-412 + index dedup + orphan-delete (emit.go:526-571). Test asserts amy stays 1, zed converges 0->1 (redrain_test.go:358-396). No double delivery.
Shortfall log (420-421): repo/seq/recipients/failed only; no principals/titles/actors. Uses parent ctx (live), not expired fctx. Clean.
Negative controls genuine: pre-fix drain (main: if fanoutOne single-bool { markFanoutDone }) marked faulted drains, so TestFanoutDrainSkipsDoneMarkerOnIncomplete fails pre-fix at the fanoutDone==true assertion for the right reason (marker on partial drain). TestFanoutOneExpiredBudgetIsIncomplete pins (true,false)->(true,true) convergence (redrain_test.go:398-430); pre-fix single-bool could not distinguish stranded from done (would mark-and-lose).
Checks (scratch /tmp/pr158 @
e9cdb66): go test -race ./internal/notify/... PASS; new tests -count=10 PASS; coverage 96.2% (>=95%); gofmt clean; go vet clean. No new non-stdlib imports (tasks.go: none; redrain_test.go adds stdlib strings only).Doc (docs/features/06_notifications.md:493-508) accurate: tuple semantics, dedup-complete rationale, idempotent retry, budget/createFailed incomplete, regression names. Nit (non-blocking): 'No new locks (one counter mutex...)' reads contradictory — suggest 'One new mutex (counter-only...)'.
No fix pushed (nothing structural/broken). MERGE RECOMMENDATION: ready to merge.
Fixed by PR #158 (review: completion mapping + mutex scope + negative controls verified; 96.2% coverage), merged. Closing.