Repository source: docs/plans/high_traffic_post_refresh/high_traffic_post_refresh_step3_development_plan.md
Debug mode: enabled
Effort study: railspike-effort / v3/high_traffic_post_refresh; host ledger. Standing P2 enrollment.
Extended estimates: enabled
Cycle estimate: 0.30
Concepts touched: static publication, changed in Stage 3.
Completion Contract
Normal entry: with high-traffic mode on, a member or an agent posts a thread or a reply.
End-to-end outcome: the thread page is rendered fresh and swapped in before the poster's response returns. The first load after posting shows the post, in any browser.
Recovery: if the render cannot run, the post still saves. The route is queued, and the next cron run renders it even if the cached file looks fresh.
./v3 high-traffic refresh /threads/<id>/stays the manual fix.Deployment check: on zenmemes.com with the mode on, an agent reply through
frm.pyshows on the maintainer's phone without turning the mode off.Release condition: merged, deployed, and the deployment check passed.
Key Risks
Slower posting. One render is added to each post while the mode is on. Early validation: Stage 3 times a long-thread render on the production host with
./v3 high-traffic refresh. Mitigation: if too slow, move the render after the response is sent; the queue still covers it.An older render wins the race. A cron render that started before the post can swap in the old page afterward. Early validation: a Stage 1 test holds the page lock during a write. Mitigation: a busy page lock queues the route, and the queued entry records the write time, so cron renders again.
Hint queue drops the route.
HighTrafficRefresh::hintandhints()skip and delete routes whose file is under 60 seconds old, which is exactly the case after a stale render. Early validation: Stage 1 test. Mitigation: a hint from a write counts as due until the page file is newer than the write.A refresh error fails a saved post. Mitigation: the refresh runs after the write lock is released and catches every error; the post result is already final.
Stage 1
Estimate: 0.10
Goal: one call refreshes a thread page after a write, or queues it.
Dependencies: none.
Expected changes: add
HighTrafficRefresh::afterPost(string $threadId): string, returningrefreshed,queued,skippedorinactive. It does nothing when the mode is off or the page is not cached; a missing page is generated by its first reader as today. Otherwise it callsHighTrafficCache::generatewith force. A refusal or error queues the route. Changehintto accept a write-time stamp that bypasses the freshness check, and changehints()to keep such an entry until the page file is newer than the stamp.Verification approach: new
HighTrafficTestcases: a cached page is replaced and the old file served until the swap; a held page lock givesqueuedand leaves a write-stamped hint; cron keeps that hint while the page is under 60 seconds old but older than the stamp; mode off givesinactiveand touches nothing.Estimate details (extended mode only): driver: hint semantics shared with the browser's 60-second hint; uncertainty: whether
generatewith force can run cleanly from a web request outside cron.Risks or open questions:
Impact: a changed
hints()could re-render routes endlessly.Early warning / validation: test that a hint is dropped once the page is newer than its stamp.
Mitigation: browser hints keep today's behavior; only write-stamped hints use the new rule.
Canonical components/API contracts touched:
HighTrafficCache::generate(reused unchanged),HighTrafficRefresh::hintandhints(extended),HighTrafficRoute::canonical(reused).
Stage 2
Estimate: 0.10
Goal: every post write refreshes its thread page.
Dependencies: Stage 1.
Expected changes:
LocalWriteService::withTimedWriteLockgains a refresh step after the lock is released, beside the offline snapshot queue. It runs only when the write's result asks for it.createThreadForAuthoringMode,createReply(including agent replies),createPreparedPost,createSignedPostandcreatePreparedPostFormatset that request with their thread ID. Tags, likes andsetThreadSubjectIfEmpty(the media-preview subject fill) do not. The step's time goes into the result'stimings; any error goes to the error log.Verification approach: a
LocalWriteServicetest with the mode on in a temporary site: a reply replaces the cached thread page; a tag write leaves it alone; a forced render failure still returns a saved post and leaves a queued hint. Run with the smoke set:./v3 test --smoke HighTrafficTest HighTrafficPublicationTest AgentPostingApiTest.Estimate details (extended mode only): driver: five write entry points and the already-posted early returns; uncertainty: whether the test harness can enable the mode without a real access log.
Risks or open questions:
Impact: a write path missed here keeps today's stale page.
Early warning / validation: test each entry point through its public method.
Mitigation: the request is set where each path builds its success result, so a new post path is easy to spot in review.
Canonical components/API contracts touched:
LocalWriteService::withTimedWriteLock(extended), the post write methods named above (extended),HighTrafficSafety::beforeWriteand thedirtymarker (unchanged).
Stage 3
Estimate: 0.05
Goal: document the behavior and confirm the render cost.
Dependencies: Stage 2.
Expected changes: one line in the static publication concept; a paragraph in the high-traffic section of
docs/reference/v3_cli.mdon post refresh, the queue fallback and the manual command; this cycle's ledger entry. Ask the maintainer to time./v3 high-traffic refreshon the longest thread on vps22365.Verification approach: links resolve;
git diff --check; the timing is recorded in the Step 4 summary.Estimate details (extended mode only): driver: production timing depends on the maintainer; uncertainty: the render time itself.
Risks or open questions:
Impact: a slow render makes posting feel stuck.
Early warning / validation: the production timing.
Mitigation: if over about two seconds, move the render after the response, as Key Risks describe, before the PR.
Canonical components/API contracts touched: concept and CLI reference docs only.
Stage 4
Estimate: 0.05
Goal: replay the reported failure on zenmemes.com.
Dependencies: Stage 3, then the maintainer's merge and deploy.
Expected changes: none in code. Record the result in the Step 4 summary.
Verification approach: with the mode on, the maintainer posts a thread; Claude replies through
frm.py; the maintainer reloads on his phone and sees the reply. The thread's cached file time is after the reply. If it fails, the queue should still show the reply within one cron run; record which happened.Estimate details (extended mode only): driver: coordination with deploy; uncertainty: production cron and log setup.
Risks or open questions: none beyond Key Risks.
Canonical components/API contracts touched: none.
Study Checkpoint
2026-11-09T22:56:44Z — Step 3 handoff. Scope v1 (Step 2 approved, no new scope); starting revision a2bcc64d; R1/P2, hashes not re-verified. Whole-cycle projection 0.30 reaffirmed; independently judged, not the stage sum. Stage work 0.10/0.10/0.05/0.05, non-additive. New understanding: the hint queue needs a write-stamped entry, absorbed within Stage 1. Single exposed Claude rater. No approval to advance.
Step 2 approved on 2026-11-09 ("approved step 2").
Status: awaiting Approved Step 3. Planning uncommitted.
— Claude · 2026-11-09 UTC · Model: claude-opus-5-5