From 1fef52dcc2b720e1844387d841176f125bf87324 Mon Sep 17 00:00:00 2001 From: Bretton Date: Mon, 10 Aug 2026 04:21:22 +0000 Subject: [PATCH] docs(posts): correct two review-flagged comment inaccuracies The consumer-vs-service error-disposition comment claimed the rev gate stops a redrive from reaching the sweep; in fact the consumer reconsiders the sweep on every redelivery whose row is already tombstoned — so its swallow is a genuine choice, which is what makes the service's surface-instead the real departure. The wiring comment claimed the shared writer means a shared clock/retry budget; the writer is stateless per call, so it is shared configuration, not budget. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01QDvRJ45k6E5KrBARDHUtiM --- cmd/server/wiring.go | 6 ++++-- internal/core/posts/service.go | 18 +++++++++++------- 2 file(s) changed, 15 insertion(s)(+), 9 deletion(s)(-) diff --git a/cmd/server/wiring.go b/cmd/server/wiring.go --- a/cmd/server/wiring.go +++ b/cmd/server/wiring.go @@ -391,8 +391,10 @@ posts.NewAuthorRepoFactory(a.oauthClient.ClientApp, aggregators.DefaultSessionID)), posts.WithSyncAcceptance(a.admissionRepo, acceptanceEngine), // The SAME writer the engine accepts through, so both ends of an // acceptance's life — the write the fast path makes and the withdrawal - // the author's delete makes (§5.3) — share one writer's clock and swap - // retry budget. buildAcceptanceEngine above is what populated it. + // the author's delete makes (§5.3) — go through one configured writer + // (same repo factory and clock func). The writer is stateless per call, + // so this is shared configuration, not shared runtime budget. + // buildAcceptanceEngine above is what populated it. posts.WithAcceptanceWithdrawal(a.communityWriter), posts.WithAdmissionPolicy(posts.AdmissionPolicy{ Ledger: postgresRepo.NewSubmissionLedger(a.db), diff --git a/internal/core/posts/service.go b/internal/core/posts/service.go --- a/internal/core/posts/service.go +++ b/internal/core/posts/service.go @@ -1820,13 +1820,17 @@ // §5.2 CAS refuses a rev that does not win), so doing the work twice is a // no-op while doing it zero times is the failure above. // // A FAILURE IS RETURNED, and that is the one place this deliberately departs -// from the consumer, which logs and swallows. The consumer must: an error -// there dead-letters an event whose local half already committed, and the rev -// gate would refuse the redrive, so the retry could never reach the sweep -// again. Here the CLIENT is the retry loop — the author's record is already -// gone, every step below is idempotent, and surfacing the failure is what gets -// the remaining work done. Reporting success over a half-finished compensation -// reproduces the exact silence this path exists to end. +// from the consumer, which logs and swallows. The consumer can afford to: its +// sweep is reconsidered on every redelivery whose row is already tombstoned +// (authorpost.go withdrawAcceptance is gated on the POST's state, not the +// event's), so a transient withdrawal failure there gets another firehose +// attempt for free, and returning an error would only dead-letter an event +// whose local half already committed. Here the firehose is exactly the thing +// that may never arrive — the CLIENT is the only retry loop, the author's +// record is already gone, and every step below is idempotent — so surfacing the +// failure is what gets the remaining work done. Reporting success over a +// half-finished compensation reproduces the exact silence this path exists to +// end. func (s *postService) compensateAuthorDelete(ctx context.Context, uri string) error { // THE LOCAL TRUTH LANDS FIRST, in the consumer's order and for its reason: // the author asked for their post to be gone, and a community PDS that -- tangled.sh