> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vort-sourcing.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Certification checklist

> The 22-item go-live checklist. Production keys are issued only after every item passes in the sandbox.

Production keys are issued only after every item below passes in the **sandbox**. Each item is a test with a defined procedure and pass criterion. Vort runs the tests together with your team on a screen share (or from a recording you supply), using sandbox data. RFC 2119 keywords apply.

<Info>
  The fixtures, test codes and test webhooks these items use are described on [Certification fixtures](/certification-fixtures) and [Sandbox](/sandbox).
</Info>

## Checklist

| # | Item | Procedure | Pass criterion |
| - | - | - | - |
| C-01 | Connect flow | Admin pastes the sandbox activation code in your Connect screen. Repeat with the expired and the already-redeemed codes. | Connected state shows `organization_name`. Expired/redeemed codes show the API `message` under the input. No token is visible anywhere in the UI. |
| C-02 | No secrets in the browser | (a) Build your production frontend bundle and search all emitted files for `vpk_` and `vot_`. (b) Record a browser HAR of the full flow C-01 to C-12 and search it (URLs, headers, bodies, cookies, local/session storage dumps) for `vpk_` and `vot_`. | Zero occurrences of either string in the bundle and in the HAR. The HAR contains no request to the Vort API host: all calls originate from your server. |
| C-03 | Users | Two recruiters use the flow. | Each is registered via `POST /users`; their `acting_user_external_id` values appear on the runs, reveals and decisions they made (verified in Vort's request log). |
| C-04 | Must cap before submit | In the editor, set 3 musts, try to set a 4th. | The 4th must cannot be set; the counter and the fixed must-cap label are visible before submit. No `POST /runs` with more than 3 musts is sent. |
| C-05 | Rejected requirements shown | Submit the provided requirement set that triggers every rejection code. | For each rejected item, the API message and (when not null) suggestion appear verbatim under the requirement at its `index`. The recruiter can edit and resubmit. |
| C-06 | Warnings shown, not blocking | Submit the provided set that triggers every warning code (with no rejections). | The run starts (`202`). Each warning is shown under its requirement, verbatim. |
| C-07 | Run id visible | Start any run. Open the results screen, and reload it. | The `run_id` is visible without interaction, with the fixed label and a copy action, both during and after the run, and in the error shown for `cert-failed`. |
| C-08 | Progress shown | Run `cert-slow` and watch the results screen. | `confirmed / target` is shown as numbers and a determinate bar and visibly updates at least every 10 s. A spinner alone fails this item. On completion the final count replaces the progress indicator. |
| C-09 | Every catalogue notice | Run `cert-notices-all`. | Every notice appears in its slot with its severity styling, `title` and `body` verbatim (Vort compares text against the payload). `warning` and `blocking` notices are visible without interaction and have no dismiss control. |
| C-10 | Invented notice renders generically | Run `cert-notice-unknown`. | Each `zz_certification_probe` notice renders from `title` + `body` in its slot with its severity styling. The unknown-slot notice renders in `above_list`; the unknown-severity notice renders as `warning`. Nothing crashes, and nothing is silently dropped. |
| C-11 | Empty and failed runs | Run `cert-empty` and `cert-failed`. | The `empty_state` notices replace the list; no "0 results" text of your own is added. The failed run stops the progress indicator and shows its notice and the `run_id`. |
| C-12 | Candidate card | Inspect candidates from `cert-notices-all`. | Verdict uses the fixed label and color; one row per requirement in `index` order with met icon, fixed kind label, text and evidence verbatim; null evidence shows the fixed met label. API order of candidates is kept. No extra scores or percentages. |
| C-13 | Reveal price from payload | Vort changes the sandbox reveal price between two runs. Reveal a candidate in each. | The price shown before each click equals that run's `reveal_price_credits`. After the reveal, `credits_charged` and `wallet_balance_after` are shown as returned; a null phone or e-mail shows "not found". |
| C-14 | Insufficient credits | Attempt a reveal with header `x-vort-sandbox-simulate: insufficient_credits` (a sandbox reveal never charges, so it never refuses on its own). | The API `message`, `balance` and `required` are shown; no automatic retry. |
| C-15 | Decisions round-trip | A recruiter shortlists one candidate, rejects one with each of the 7 reasons (one with a note, one with no reason and a note), and marks contacted, interviewing and hired. | Vort's side shows every decision with the right `decision`, `reject_reason`, `note`, `occurred_at` and acting user, within 5 minutes. Reject menu shows exactly the seven fixed labels. |
| C-16 | `notices_shown` round-trip | After C-09 and C-10, check Vort's side. | Every code rendered in those runs, including `zz_certification_probe`, is recorded for that run. A run viewed without any decision still reports its codes (`decisions: []`). |
| C-17 | Unknown fields ignored | Run `cert-extra-fields` through the whole flow. | No error, no visible change. |
| C-18 | Webhook signature verified | Vort sends each event with a valid signature, then one with a bad signature. | Valid deliveries get `2xx`. The bad-signature delivery gets `401` (or another non-`2xx`) and is **not** processed (show Vort your log line or a missing side effect). Verification is on the raw body with a constant-time comparison (code review of the handler). |
| C-19 | Webhook de-duplication | Vort re-sends one valid event (same `event_id`), then sends two `candidate_revealed` events for different candidates of the same run, then an event with an unknown `event` name. | The re-sent event is processed once (de-duplicated on `event_id`). Both `candidate_revealed` events are processed. The unknown event gets `2xx` and is ignored. |
| C-20 | Rate limit and no auto-retry of runs | Vort forces a `429` with `Retry-After: 30` on a `GET /runs`, then a `503` on a `POST /runs`. | The `GET` is retried only after 30 s. The `POST /runs` is not retried automatically; the recruiter sees an error with a manual retry. |
| C-21 | Right-to-left | Repeat C-07 to C-12 with `x-vort-lang: he` and your UI in Hebrew. | Every screen is mirrored; Hebrew notices and evidence render right-to-left; mixed Hebrew/English text is not scrambled. |
| C-22 | Customization within bounds | Vort reviews the screens against the [UI specification](/ui-specification). | Only colors and fonts differ from the spec. Contrast meets WCAG 2.1 AA; severity and verdict states carry icons or labels, not color alone. |

## Re-certification

You MUST re-certify (the affected items, at minimum) before releasing to production any **significant UI change** to the Vort screens, which includes:

* changing the layout, order or presence of any element in the [UI specification](/ui-specification);
* changing how notices, validation messages, evidence, prices or decisions are rendered or sent;
* changing your reject-reason menu, decision mapping, or pipeline-stage mapping;
* changing how and where Vort credentials are stored, or your webhook handler;
* moving the integration to a new frontend framework or a new backend.

Color and font changes alone do not require re-certification, provided C-22 still holds. Vort MAY also request re-certification after a new notice severity, slot or field is introduced in `v1`; you will be notified in advance.

<Warning>
  Vort monitors production for certification drift (for example, runs with no `notices_shown` reported, or no decisions for runs with revealed candidates) and may suspend a partner key (`403 partner_disabled`) until a failing item is fixed.
</Warning>
