A migration policy is the set of regression budgets the hosted app enforces on a project. It is the server’s source of truth for whether a run blocks — and unlike the verdict baked into a bundle at push time, it is editable and re-applied to past runs.
thresholds block in your evalshift.yaml. Thresholds travel with the run and are overwritten by evalshift push; the governed policy lives only in the project and survives pushes. Settings shows your config thresholds read-only, for context.## The six budgets
These mirror the CLI policy field-for-field. Ratio fields are decimal fractions (0.20 = 20%). An empty policy still enforces these defaults, so a project is never ungoverned by accident.
| Budget | Default | Meaning |
|---|---|---|
max_overall_regression_rate | 0.03 | Max share of examples allowed to regress (3%). |
max_critical_regressions | 0 | Max count of critical-severity regressions. An integer, not a ratio. |
min_equivalence_rate | 0.95 | Min share of examples the target must hold equivalent to the source (95%). |
max_tool_argument_drift | 0.01 | Max share of tool calls whose arguments may drift (1%). |
max_cost_increase | 0.20 | Max allowed cost increase as a fraction (20%). |
max_latency_increase | 0.30 | Max allowed latency increase as a fraction (30%). |
Per-slice overrides are supported via a slices map: each slice may override any of the six budgets, inheriting the top-level value where it doesn’t.
## Editing the policy
Open the Settings tab on a project. Owners get an editable six-budget form (number inputs, per-field validation, and a Reset to defaults action); members see the same values read-only. Saving validates every field and rejects unknown keys.
## Re-evaluation, not re-scoring
Editing the policy re-decides past runs. The server never re-scores examples — it only re-compares the run’s stored aggregate metrics against the new budgets. Tightening max_cost_increase, for instance, can flip a previously-passing run to FAIL the moment you save, with no re-run required.
A run’s detail page shows an enforcement strip: a binary status (PASS / FAIL / INCONCLUSIVE), the reason, and a table of each budget’s result against the current policy. The gate is binary even though the badge is four-valued — see Verdicts & gating.
## Per-PR enforcement
The Pull Requests tab folds every run that was pushed with a pr_number (e.g. from the GitHub Action) into one row per PR, showing its latest verdict and policy status. PRs whose latest run fails the current policy get a Blocked marker. Each row links to the run history filtered to that PR.
- +Enforcement re-evaluates against the project’s current policy, so editing the policy re-decides which PRs are blocked.
- +The GitHub Action keeps its own local diff gate; this view is the server’s record for the web UI and non-GitHub CI.