| 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. | 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. |