# The compliance plan

> The ordered, machine-readable list of changes that makes a site compliant — each task with the law, the place, the exact change and how it is verified — and the verify loop around it.

The compliance plan turns findings into work. It is built on demand from the site's latest evaluation and stays stable
as you work: task ids survive recomputation, and each task says exactly what to change and how Checkbox will confirm it.
[The agent loop](https://checkbox.site/docs/agent-loop#plan) shows where it fits.

## Read the plan {#read}

```bash
checkbox plan --json
```

The CLI picks the site from `--site`, `$CHECKBOX_SITE`, the site `checkbox init` saved for the directory, or your only
site. The API call is [`retrieveCompliancePlan`](https://checkbox.site/docs/api/compliance-plans#retrieveCompliancePlan)
(`GET /v1/sites/{site}/plan`).

## Tasks {#tasks}

Tasks group the checks one change fixes. Every machine check belongs to exactly one task:

| Task | Checks | Where | Verified by |
|---|---|---|---|
| `terms_cancellation`, `terms_renewal`, `terms_refund` | `terms.*` | Policy page (the offending clause is quoted) | Re-fetching the policy, decided at once |
| `online_cancellation` | `cancel.*` | Code: account-page link or the hosted cancellation page | A scan |
| `billing_portal_cancel` | `config.portal_cancel_enabled` | Stripe `billing_portal.configuration` params | Billing-platform sync |
| `signup_disclosure` | `signup.*` | Code patch, Checkout Session or Payment Link params, or a Shopify block | Page fetch or Stripe params now, then a scan |
| `acknowledgment_email`, `trial_reminder`, `renewal_reminder`, `annual_terms_notice`, `charge_notice`, `price_change_notice` | `confirmation.*`, `reminder.*`, `config.trial_reminder_enabled` | Email template, or Checkbox Notices | The next real email at the inbound address |
| `attest_ny_notice_channel`, `attest_ny_price_increase` | New York attestations | A question for the human | `answerTask` |

Ordering: severity first, then fixes of observed failures before tasks that only let Checkbox observe something, then
lifecycle stage (policies, cancellation, sign-up, emails). A change another one depends on comes first — for example the
sign-up disclosure states the cancellation URL, so a broken online cancellation is fixed before it.

## Patches {#patches}

For code tasks, `change.content` is a unified-diff template anchored to the elements Checkbox observed
(`@@ insert directly above the purchase button "Start now" (#subscribe-button) @@`), plus machine-applicable `edits`
(`insert_before`, `remove_attribute`, `replace_text`…). `checkbox fix <task> --file <path>` applies the edits to your
file in memory and prints a diff you can `git apply`; anything it cannot find is reported as unmatched, never guessed.

```bash
checkbox fix task_8c1d2e3f4a5b6c7d8e9f0a1b2c3d4e5f --file app/checkout/page.tsx --out fix.diff && git apply fix.diff
```

## Verify {#verify}

`POST /v1/tasks/{task}/verify` (`checkbox verify <task> --wait`) runs the fastest re-check now and queues the
authoritative one:

| Method | Immediate re-check | Confirmed by |
|---|---|---|
| `page_fetch` | Static fetch of the live checkout, or the `html` you send before deploying | The scan it queues |
| `stripe_params` | The `stripe_checkout_session` params you send | The scan it queues |
| `policy_refetch` | — | Re-fetching the policy and re-evaluating at once |
| `email_copy` | The `email` you send (optional) | The next real email at the inbound address |
| `platform_sync` | — | The billing-platform sync it queues |
| `evaluation` | — | A scan, or an immediate re-evaluation |

A failing immediate check fails the verification at once, with a diff. Otherwise it stays `pending` until the
confirming observation arrives (`?wait=30` long-polls). Pending verifications expire after 1 hour for scans and 24 hours
for emails, with a `reverify` next action. The `task.verified`, `plan.updated` and `site.compliant`
[webhooks](https://checkbox.site/docs/webhooks) fire without polling.

## Decisions and answers {#decisions}

- `updateTask { status: "in_progress" }` claims a task; `{ status: "wont_fix", reason }` declines it. A declined
  critical or high task keeps the plan `blocked`.
- Manual tasks carry a `question`. Ask the human, then record their answer with `answerTask` (CLI:
  `checkbox answer <task> <answer> --note "…"`). Answers that assert a legal fact — `yes` to an attestation,
  `confirmed` for an undecided check — are stored as a **proposal**: the response's `next_action.type` is
  `ask_human_to_confirm` with a link the human opens while signed in to Checkbox. Only their confirmation writes the
  attestation, sets the site fact and re-evaluates; an API key alone can never attest. `no` / `needs_change` turn the
  task into a change for the agent at once. A confirmation holds only while the checks keep the status it was given for.
- Steps only a person can do in the dashboard (connecting the billing platform) come as `next_action.type:
  "connect_billing_in_dashboard"` with the URL; answer `done` afterwards so Checkbox re-reads it.
- Human confirmations are attestations, not observations: the plan can reach `compliant` while the underlying checks
  stay `needs_review` in the evaluation, and the plan summary says how many items rest on a confirmation.

## What the plan says, and what it does not {#coverage}

- Each task has **one stable title**. When Checkbox cannot give the exact change yet, `blocked_on` says why
  (`observation`: it has not seen the page or email; `facts`: it needs the plan, price, cancel URL or merchant name) and
  `change.type` is `config` or `needs_facts`: `change.content` is the request body of `change.operation_id`
  (`updateSite`, `updateSetupSession`), validated against that operation. Checkbox never returns a patch with
  `{price}`-style tokens, `[placeholders]` or a cancel link it made up.
- Registered Stripe Checkout params (`createStripeCheckoutConfig`, `checkbox init`) that fail the preflight become a
  `stripe_checkout_params` task with the engine-corrected params.
- Done tasks keep the title and priority they had, and `closed_reason` says why they closed: `verified` (their checks
  pass), `no_longer_applicable` (nothing was observed passing; the checks stopped applying), `declined`.
- `coverage` lists the lifecycle stages Checkbox observed and the ones it did not, the items resting on a human
  confirmation, and whether a billing platform is connected. `status: "compliant"` means every applicable check
  Checkbox could observe passes — an automated assessment, not a legal determination. When the plan is done, tell the
  human what was not observed; never tell them the site "is compliant". The `insurable` flag is a preview of what the
  planned warranty will key on; no warranty or insurance is offered yet.
