Appearance
Plausibility and velocity
The problem, stated without euphemism
Merchants and issuers limit what one account may plausibly do. One account redeeming forty gift cards a week, or shipping to forty addresses, does not look like a customer. It gets closed.
The naive response is evasion: rotate fingerprints and randomise everything so each account looks like nobody in particular. That is the wrong model. It optimises against detection instead of what detection measures.
The actual defence is decomposition
The real constraint is per-account volume, so spread demand across accounts, each behaving like one ordinary person, instead of disguising one account behaving like forty.
- Evasion hides abnormal volume. It breaks as soon as the detector gets better.
- Decomposition makes each account's volume really normal, so there is nothing to find, however good the detector gets.
What consistency means concretely
- A stable fingerprint per account. Rotation is the anomaly, because people do not change device every session.
- Geography that matches the account's home, with explicit vacation windows, because real people travel and refusing every out-of-metro order would turn away legitimate demand.
- Human-shaped timing. Jitter with a plausible distribution, because uniform-random delays are as identifiable as none.
- Isolation between accounts. Two accounts sharing a fingerprint is worse than either looking odd alone, because it links them.
Velocity limits
Per-account velocity is the primary control, measured over a rolling window instead of a lifetime total. The window has to actually roll. The project's most instructive bug lived here:
The velocity window was inert for most of the project's life
velocityWindowDays was declared and read by nothing. Usage only climbed (filled volume incremented it, repayment deliberately did not decrement it) until every LP hit velocity_exhausted permanently.
Per-LP velocity limits had been the primary issuer-risk mitigation since Phase 3. Both later caps were per-window and inherited from it. So it was the floor under three mitigations and did nothing.
The fix that mattered is where the roll happens: at the point the window is read, with no scheduled sweep to remember. Rolled on read, it cannot go stale, because reading it is the only way it matters.
That failure is why the build now fails when an exported function is reachable only from tests. See Read this first.
Load spreading
Given multiple plausible accounts, demand is routed to the one that can take it without becoming implausible: enough headroom, inside its velocity window, geographically consistent, not on vacation.
Refusing to fill is a legitimate outcome. Forcing an implausible order through would damage the account carrying it.
Status
Built, not proven, and largely unwired. The consistency layer, the plausibility engine and the multi-account router are implemented and tested. None of them has a production caller, because seller accounts have no persistence, so there are no accounts to spread across. They are annotated as future-use, not active.
The velocity window is the exception: it is wired, and a test that advances the real wall clock across the boundary shows it rolls.