Documentation

Adopt with log-only

Ship the integration without blocking anyone: emit verdicts as observations first, review the numbers, then turn enforcement on.

Every verdict reports enforcementMode: enforce (gate traffic) or log_only (observe only). During a rollout, your server opts in per request with context.logOnly: true and traffic is never blocked or challenged: deny and challenge verdicts become observations you review before flipping the switch.

Same verdict either way

Verify always produces a full verdict. enforcementMode only controls whether your integration observes that verdict or gates on it:

                    ┌─ log_only → observe
verify → verdict ───┤
                    └─ enforce  → challenge / deny / allow

Opt in per request

Set the flag in your integration (middleware, route handler, Worker), not from the browser or agent payload. Roll out one funnel action at a time:

// Server integration only: never copy this from req.body / query.
const v = await chitmark.verify({
  action: "signup",
  session: sessId,
  context: { logOnly: true },
});

// Response: v.enforcementMode === "log_only"
// decisions are observations only: nothing is blocked

Run the observation window

Persist eventId, decision, and enforcementMode on the account row as usual, and keep sending feedback for outcomes. The weekly Agent Farming Ledger joins each historical verdict to its later label so you can compare what enforce would have gated on that request versus what actually happened while you were observing.

Keep the observation period auditable. For each event, retain at least: decision, enforcementMode, eventId, and the eventual outcome. Chitmark stores the same join keys on the event ledger (plus a schema eventVersion on the verify row). If you tune context.decisionCosts or other local policy knobs during rollout, snapshot those beside the account row so you can answer "which boundary produced this verdict?" without re-running history.

Treat decisionCosts as relative, dimensionless weights (not dollars, not score thresholds). falseAllow = abusive traffic allowed; falseChallenge = legitimate traffic challenged when allow would have been fine; falseDeny = legitimate traffic denied. Raise falseDeny when incorrectly blocking real buyers hurts more; raise falseAllow when letting abuse through hurts more; raise falseChallenge when over-frictioning legitimate users hurts more. Revisit after enough labeled traffic to make the error patterns meaningful (false denies on real buyers, allows that later burn or charge back), not just after a fixed number of days. A few weeks is a practical starting point on a live funnel; a quiet week with dozens of signups is not the same window as a week with millions.

Flip to enforce

Stop setting context.logOnly on the server path you have validated and watch the funnel.