Control Arm — measurement report

30 seeds × 400 customers × 45 days · 1,200 revenue-at-risk events per seed · git 9418359

Ground truth is a function of the seed alone, so every arm faces the same customer with the same true failure cause on the same day. Every interval below is a paired bootstrap on the per-seed difference, never three independent CIs on shared populations.

Per arm

armeventsrecovered nrecoveredcontacts/recbreaches
A no intervention1,200189Rs 4,13,029.360.000
B Razorpay default1,200600Rs 12,85,520.333.220
B' volume-matched to C1,200460Rs 9,81,532.631.500
C Control Arm1,200586Rs 12,49,644.731.310
D gate removed1,200783Rs 16,64,478.164.286,371

The headline, per rail

per-rail lift
raillift95% CI on the delta (Rs/seed)seeds favouring Csign test
card_subscription-46.0%[-268,674, -235,741]0/30p=0.0000
emandate+17.8%[+25,201, +45,499]26/30p=0.0001
payment_link+18.5%[+16,781, +28,907]27/30p=0.0000
upi_autopay+37.9%[+141,116, +174,466]30/30p=0.0000
pooled-2.8%[-65,685, -6,950]10/30p=0.0987

The card rail loses because every compliant retry needs its own 24-hour cl.6(a) pre-transaction notice, while Razorpay's documented ladder retries at T+1/T+2/T+3. That is what the framework costs on that rail. This report does not conclude that Razorpay is non-compliant: Arm B encodes documented retry behaviour, and whether it satisfies cl.6(a) is a question about an issuer's notification practice we cannot see.

The price of the gate

money against breaches

Arm D is Arm C with one substituted collaborator: the policy gate replaced by a null gate that always allows. It recovers +33.2% more and breaches encoded policy rules 6,371 times per seed. The count is of MY predicates on a synthetic population, and the extra money is granted by MY response model. It is not a legal finding.

breaches by rule

Where this stops being worth buying

crossover

pooled: there is no separation to lose — C and B are statistically indistinguishable up to an organic rate of 0.22, and C loses above 0.30. A crossover chart with nothing to cross is an artefact of pooling, and saying so is cheaper than pretending otherwise.

upi_autopay: the advantage decays from +60% to +8% across the swept range and does not cross zero at any swept point up to an organic recovery rate of 0.60, which is far above any plausible value.

Most sensitive to, in order: organic_recovery.base_rate_30d (swept above), response_propensity.insufficient_funds_near_payday and action_response.channel_effectiveness. All three are ASSUMPTION in config/calibration.yaml and say so.

What survives the world being wrong

scenariowhat the agent now believes falselyliftseedsinvariant violations
payday shifted 9 daysthe scheduler aligns retries to a payday that is not when money arrives-5.3%4/150
failure-reason mix invertedthe rarest failure cause is now the most common on every rail-3.8%6/150
organic recovery doubledcustomers self-heal twice as often, so far more 'recoveries' were never wins-6.6%1/150
downtime signal removedthe payment.downtime side-channel is gone; ISSUER_DOWN cannot fire-3.8%6/150

15 seeds per scenario. Lift is a property of my failure model and degrades when that model is attacked. The violation column reads zero four times. It is computed by src/eval/verify.py, which re-derives the invariants from the audit log rather than asking the policy engine — a checker that consulted the same predicates would report zero under every attack and prove nothing. Only Arm C is shown: Arm B is not gated by our policy, so counting our predicates against Razorpay's cadence would read as a compliance claim we have no standing to make.

The exception list, uncensored

136 events per seed escalated to a human, carrying Rs 2,92,844.03 of at-risk revenue. That is the AMBIGUOUS bucket: the four reasons Razorpay itself documents as ones where it “may not have access to specific details regarding the failure reason”. The share was pre-registered at 0.18 before the classifier was written.

11 contacts per seed suppressed because the bank was down, not the customer. Small on purpose: the harness takes one decision instant per logical day, so ISSUER_DOWN can only suppress an outage still open at that instant.

Promises: 14.0 per seed, 66% kept.

Cost per recovered rupee: Rs 0.00. Zero tokens were spent. Tier 0 is deterministic, message drafting runs the template path, and this machine has no Anthropic credentials, so fixtures/llm_cache/ is empty. The accounting reads response.usage and would be non-zero the moment a call is recorded; it is never estimated.