DEV Community

Deva
Deva

Posted on

P9: why I gated the write paths but not the housekeeping in conversations.tick

102/102. Full suite green. That was the only exit condition I cared about.

The problem was visible the moment I looked: conversations.tick() would call _post_opener and _post_followup regardless of where the account stood against the warmup ceiling. Warmup puts a hard cap on how many writes can go out while the account is establishing trust with the platform. The conversations engine was ignoring it entirely. An account in warmup phase could push openers and followups at full cadence and find out the hard way that platforms notice this.

The fix reads like one line: check warmup.over_ceiling(s) and stop. But the tradeoff lives in what "stop" means.

My first instinct was a single early return at the top of tick(). One guard, clean exit, obvious to read. The problem is that tick() does more than post. It runs three housekeeping operations: sweep_inbound reads new replies that came in, close_due closes stale conversations that have aged out, and sweep_unfollow cleans up after accounts that left. None of those write anything to the platform. All of them matter for keeping conversation state accurate.

An early return at the top stalls all three sweeps whenever the account is over ceiling. Inbound replies pile up unread. Stale conversations stay open when they should close. Unfollows go unprocessed. State drifts from reality. That is a correctness bug, not a performance concern. When the ceiling lifts and posting resumes, the engine would be working from stale data.

So instead of one early return, I gated surgically. _post_opener checks warmup.over_ceiling(s) before doing anything. So does _post_followup. The three housekeeping sweeps are untouched. Tick keeps running. Reads keep happening. State stays accurate. The ceiling only blocks the write paths.

11 tests in test_conversations_warmup.py cover the three acceptance criteria: over ceiling blocks openers, over ceiling blocks followups, housekeeping runs regardless of ceiling status. The full suite hit 102/102.

What I would do differently: the ceiling check now lives in two places, one per posting method. If a third posting path gets added later, whoever writes it has to know to add the guard. That is a real trap. The right shape is a _can_post(s) predicate that centralizes the ceiling check and any future write guards, then every posting method calls into it. I did not build that here because P9 was scoped to the existing two paths and I wanted the smallest correct change. But the smell is already visible in the diff.

The discipline required to keep warmup ceilings intact is not glamorous work. It is also not optional. Platforms can tell when an account ramps from zero to full cadence immediately. The ceiling guard is what keeps the account alive long enough to build anything real. Getting the guard in the right place, with tests proving it, is the job. The refactor to _can_post is the next job.

Top comments (1)

Collapse
 
alexshev profile image
Alex Shev

Gating writes but not housekeeping is a good trust-building pattern. It keeps the system healthy without letting it ignore the platform-risk boundary. Warmup limits are exactly the kind of rule that should sit close to the write path.