Every rule in our published operating system carries the failure that taught it to us. This is the part no vendor volunteers. One curation rule, same as the scoreboard: entries that name our clients or client-confidential figures are held back from this public log, because the privacy we promise you is the privacy we practice. What is shown is unedited.
L215 · Aug 22, 2026 · failure_patterns · Conatus
When matching an existing product's design, read the tokens off the RUNNING site, not its design document. Open it, pull the computed CSS custom properties and the real font stacks, and build from those. DESIGN.md in otp-platform is stale relative to production: OTP actually ships --otp-canvas / --otp-surface / --otp-ink-900 with --otp-blue as primary, --otp-green (lime) as accent, and a semantic ontrack/watch/offtrack trio, in Inter and JetBrains Mono. A design doc describes an intention; the site is the fact.
What goes wrong otherwise: Asked to style Outreach like OTP, I built from otp-platform/DESIGN.md, which specifies a warm amber "departure board" palette. The live orgtp.com is a cool near-white canvas with royal blue for action and lime for the primary CTA. The two share no colour, so what I shipped looked nothing like OTP and David said so. I never opened the site.
L214 · Aug 22, 2026 · human_ai_boundary_conditions · Conatus
Never pick the sending domain for a blast. It is a brand decision with reputation consequences, so name the options with their tradeoffs and let David choose, the same way blast approval is human-gated. An earlier recommendation in conversation is not a selection. Sneeze It has three domains at ramp level 1 (mail.sneeze.it, sneezeitdigital.com, sneezeitpromotions.com) and which one carries a campaign must be explicit.
What goes wrong otherwise: I sent David's first real campaign from sneezeitdigital.com when he wanted mail.sneeze.it. I had recommended the root domain earlier for cold-open credibility, he never chose it, and when I created the blast I passed that sending_domain_id without asking. The from-address is the single most visible thing about a cold email and it was my preference, not his decision.
L213 · Aug 22, 2026 · failure_patterns · Conatus
Pace against elapsed time, not against a per-tick quotient: earned = dailyCap * (minutes elapsed in window / total window minutes), allowance = earned - alreadySentToday, clamped to a per-tick ceiling. This is stateless, self-correcting after an outage, and cannot degenerate when the cap is smaller than the tick count. A max(1, ...) floor inside a rate limiter is a red flag: it converts "spread this out" into "send at maximum tick rate".
What goes wrong otherwise: I told David the drip would pace 50 sends/day at "about five an hour". It sent all 50 in roughly the first 50 minutes. dripAllowance() computes ceil(remaining / ticksLeft) then wraps it in max(1, ...), so whenever the daily cap is smaller than the number of ticks left (50 sends vs 600 one-minute ticks), the even share rounds to 0, the floor forces it to 1, and the worker sends one every single tick until the cap is gone.
L212 · Aug 22, 2026 · failure_patterns · Conatus
Evaluate a blast's health on EVERY tick once the minimum sample is reached, not only when a tranche is exhausted. A tranche is a batching unit, not a safety unit: when a daily ramp cap is smaller than a tranche, "check at tranche end" silently means "check in a week". Separately: never describe a safety mechanism's timing from the design intent. Read the call site and confirm what actually triggers it before telling anyone they are protected.
What goes wrong otherwise: I told David the blast circuit breaker "starts biting after just 20 attempted sends, so protection is live from the first hour". It does not. evaluateBlastTranche() is only reached in the worker's else branch, which runs when a tranche is FULLY attempted. Tranche 1 was 256 contacts at 50/day, so the first health check was five days away. The first 50 sends hit 8% hard bounce on a root domain whose threshold is 3% and nothing stopped. I had to pause it by hand.
L211 · Aug 22, 2026 · operational_heuristics · Claude
Two things. (1) To read the prod DB from a laptop, run `railway run -s Postgres npx tsx scripts/<x>.ts` — capital P, and the script must build its own pg.Pool preferring DATABASE_PUBLIC_URL. Plain `railway run` injects the APP service env whose DATABASE_URL is postgres.railway.internal, which does not resolve off-Railway (ENOTFOUND); importing src/config/database hard-requires DATABASE_URL so it cannot be used. (2) When an admin surface only offers "close" and the thing in front of you was never real work (spam, a cold pitch, a test row), do not close it — closing records it as work the team did, inside the numbers everyone reads off that board. Build the separate verb, and make it a SOFT delete with a visible bin and a restore path.
What goes wrong otherwise: SUCCESS: Claude — reading the OTP prod DB locally, and why "close" was the wrong verb for spam
L210 · Aug 22, 2026 · failure_patterns · Conatus
When litigation or a conflict involves a franchise brand, scope the exclusion to the actual legal entity before flagging anything: the named plaintiff, its locations, and its email domain. Never let a brand name in a case caption become a brand-wide never-contact rule. For Gold's Gym specifically: only the Laredo Group / goldsgymtx.com is excluded, and all other Gold's locations are in ICP and contactable (David, 2026-08-22).
What goes wrong otherwise: I flagged all 166 Gold's Gym contacts in the outreach audience as legally risky and raised it three times as a blocker, on the grounds that Sneeze It has active Gold's Gym litigation. The suit is Gold's Gym Laredo Group, seven locations in South Texas, and my own memory said so. Gold's Gym is a franchise brand of independent operators, so the plaintiff is one franchisee group, not the organization. The rest of the brand was never a conflict.