<!-- WEB_E2E_CONTRACT
version: 2
base_url: https://card.catalyxt.xyz/
surfaces:
  - id: company
    path: /
    playwright: e2e/stage1.spec.ts
  - id: employee
    path: /#tab-employee
    playwright: e2e/stage1.spec.ts
  - id: check
    path: /?tab=verifier
    playwright: e2e/stage1.spec.ts
scenarios: S-ST1-boot–S-ST1-ux-principles · Playwright 83 tests · auto-stamped
-->

# Stage 1 — E2E (Playwright + Comet / Perplexity)

> **STALE COPY CHECK:** Re-fetch the **live** file, not a chat paste.
> - Live: https://card.catalyxt.xyz/docs/E2E_COMET_SCENARIOS.md
> - Playwright last run: https://card.catalyxt.xyz/docs/PLAYWRIGHT_LAST.md
> Product line below must match `stage1/VERSION` (**2.0.36**).

`Product: 2.0.36 · Contract: 2 · Last aligned: 2026-09-18 · Scenarios: 83 · Playwright S-ids: 83`

**Canonical:** `stage1/docs/E2E_COMET_SCENARIOS.md`  
**Live base:** https://card.catalyxt.xyz/  
**Check-only:** https://card.catalyxt.xyz/check  
**Old /stage1/ and /stamp/ URLs:** 301 → `/`

**Playwright:** `cd stage1 && npm run test:e2e` → **83** S-ST1 tests.  
Stamped UTC: 2026-09-18T22:36Z

---

## PROMPT FOR COMET / PERPLEXITY / GROK BOT

```text
You are a browser QA agent for the employment card on /. /stamp/ is gone (301 to /).
SOURCE OF TRUTH (fetch now, do not use memory):
https://card.catalyxt.xyz/docs/E2E_COMET_SCENARIOS.md
Also read: https://card.catalyxt.xyz/docs/PLAYWRIGHT_LAST.md
UX law: https://card.catalyxt.xyz/docs/UX_PRINCIPLES.md
BASE_URL: https://card.catalyxt.xyz/
Hard-refresh once. Read UX_PRINCIPLES.md. Guideline is tab 0.
TLS: cert MUST be CN=card.catalyxt.xyz. If you still see artauthenticity.xyz, retry — do not FAIL product on a stale TLS cache.
PIN: do NOT guess. Mint/revoke/reissue/PIN → SKIP (operator), not FAIL.
Phantom: no extension → SKIP presentation/combos, not FAIL. Gated/missing messages are PASS.
Public Check: “Load live sample (zkec-min)” → one headline (employed or ended on DATE). No second copy of the date. No PDA jargon in the hero.
S-ST1-save-if-active is PUBLIC (no Phantom): open https://card.catalyxt.xyz/check#s=alicedemo
or click Load Alice Demo (named). Expect Alice Demo + Save to Contacts enabled. Do not SKIP.
GET /api/v1/demo/named-check returns id alicedemo and the same url.
GET /api/v1/demo/named-check?id=bobdemo is 404 demo_not_found (not Alice-by-default). Omit id or id=alicedemo only.
Score two lines: Public PASS/N and Operator SKIP/N. Do not count SKIP as FAIL.
Never paste ISSUER_API_TOKEN.
```

---

## Scenario index (83)

| ID | Pass when |
|----|-----------|
| `S-ST1-boot` | see Playwright title |
| `S-ST1-issue-min-verify` | see Playwright title |
| `S-ST1-revoke-ended` | see Playwright title |
| `S-ST1-shelf` | see Playwright title |
| `S-ST1-reverify` | see Playwright title |
| `S-ST1-verifier-only` | see Playwright title |
| `S-ST1-phantom` | see Playwright title |
| `S-ST1-commit-visible` | see Playwright title |
| `S-ST1-internal` | see Playwright title |
| `S-ST1-reissue` | see Playwright title |
| `S-ST1-deeplink` | see Playwright title |
| `S-ST1-cam-status` | see Playwright title |
| `S-ST1-ph-retry-devnet` | see Playwright title |
| `S-ST1-print-cam` | see Playwright title |
| `S-ST1-copy-ux` | see Playwright title |
| `S-ST1-pin-wrong` | see Playwright title |
| `S-ST1-pin-ok` | see Playwright title |
| `S-ST1-pin-no-copy` | see Playwright title |
| `S-ST1-fallback-help` | see Playwright title |
| `S-ST1-assets-relative` | see Playwright title |
| `S-ST1-phantom-gated` | see Playwright title |
| `S-ST1-phantom-status` | see Playwright title |
| `S-ST1-phantom-missing` | see Playwright title |
| `S-ST1-mint-no-holder` | see Playwright title |
| `S-ST1-combo-double-mint` | see Playwright title |
| `S-ST1-combo-revoke-remint` | see Playwright title |
| `S-ST1-combo-revoke-check-then-remint-check` | see Playwright title |
| `S-ST1-debug-fold` | see Playwright title |
| `S-ST1-check-empty` | see Playwright title |
| `S-ST1-min-empty` | see Playwright title |
| `S-ST1-revoke-status` | see Playwright title |
| `S-ST1-company-card-mode` | see Playwright title |
| `S-ST1-company-program-only` | see Playwright title |
| `S-ST1-emp-program-only` | see Playwright title |
| `S-ST1-pda-vs-picture` | see Playwright title |
| `S-ST1-field-split` | see Playwright title |
| `S-ST1-one-way-presets` | see Playwright title |
| `S-ST1-url-qr` | Generate QR + Copy check link are the same short `/check#s=` — never `#p=` JSON |
| `S-ST1-save-if-active` | Open `/check#s=alicedemo` — Alice Demo + Save to Contacts; min QR hides it |
| `S-ST1-check-path` | `/check` is verifier-only; Ask Employee hidden |
| `S-ST1-check-sample` | /check shows Load live sample (zkec-min); click → employed/ended headline; no PIN |
| `S-ST1-version-plain` | GET /VERSION is text/plain matching stage1/VERSION and the visible chip |
| `S-ST1-comet-live` | see Playwright title |
| `S-ST1-loop-visible` | see Playwright title |
| `S-ST1-guide-go-all` | Five Go steps: Company → Employee → Generate QR → Check → Save |
| `S-ST1-guide-commit-pin` | see Playwright title |
| `S-ST1-guide-internal-pin` | see Playwright title |
| `S-ST1-guide-dock` | see Playwright title |
| `S-ST1-help-per-tab` | see Playwright title |
| `S-ST1-mint-ids` | see Playwright title |
| `S-ST1-honk-reject` | see Playwright title |
| `S-ST1-collectible-not-sot` | see Playwright title |
| `S-ST1-explorer-devnet` | see Playwright title |
| `S-ST1-emp-burn` | Company log summary is host mint log, not the web3 wallet |
| `S-ST1-not-offered` | see Playwright title |
| `S-ST1-help-overlay` | see Playwright title |
| `S-ST1-disclose-preview` | see Playwright title |
| `S-ST1-print-sheet` | Front on top, back below full width; dashed QR until Generate QR |
| `S-ST1-proof-req` | see Playwright title |
| `S-ST1-email-sig` | see Playwright title |
| `S-ST1-looks` | see Playwright title |
| `S-ST1-check-hero` | see Playwright title |
| `S-ST1-manual-refresh` | see Playwright title |
| `S-ST1-pwa-manifest` | see Playwright title |
| `S-ST1-prove-stub` | see Playwright title |
| `S-ST1-collectible-png` | see Playwright title |
| `S-ST1-contact-email` | see Playwright title |
| `S-ST1-sign-keeps-ticks` | Extra ticks survive Generate QR; stale banner clears after a successful sign |
| `S-ST1-action-tips` | see Playwright title |
| `S-ST1-ux-principles` | see Playwright title |
| `S-ST1-admin` | Top-level Admin tab; same PIN as Company; read-only panels; hidden on /check |
| `S-ST1-admin-page` | Per-column filters. Footer pager: Back left, Page N / M · X rows center, Next right. Page size 10 |
| `S-ST1-admin-read` | Per-column filter row; pager is table footer Back | Page N/M | Next; content +25% width |
| `S-ST1-admin-mobile` | ~375px Admin rec-flow: form=column filters; results=narrowed table; missing-data=empty show-all / “No rows match this filter.”; next-step=pager |
| `S-ST1-iso-two-holder` | `/check#s=alicedemo` is Alice only. `#s=bobdemo` / garbage is not Alice; plain English, no `share_not_found` |
| `S-ST1-iso-public-api` | GET `/v1/share/bobdemo` 404 not another holder. Wrong collectible/onchain id is that id or empty — never someone else’s email/name |
| `S-ST1-iso-named-id` | GET `/v1/demo/named-check?id=bobdemo` is 404 `demo_not_found`, not Alice-by-default. Omit id → alicedemo |
| `S-ST1-iso-swap` | Alice payload + forged name → verify reject; Eve Forged not shown; no verified badge |
| `S-ST1-id-lock` | After mint, identity fields sealed; print colour still editable |
| `S-ST1-id-update` | Update is typo path on Active same holder; never called Reissue |
| `S-ST1-id-reissue` | Reissue disabled on Active (no auto-burn); enabled after Burn PDA, same holder |
| `S-ST1-check-cold-badge` | Cold /check hides ZKP Verified; garbage is a plain error; Alice demo shows the badge |

| `S-ST1-guide-refresh` | see Playwright title |

Human notes (latest UX — 2026-08-14):

| ID | Pass |
|----|------|
| S-ST1-assets-relative | relative `./assets/…` not site-root `/assets` |
| S-ST1-copy-ux | is/isn’t on **Guideline tab 0 only**, not Company. No BIP-39 lab sentence |
| S-ST1-ux-principles | dock-done **not visible** on PIN/Internal (`[hidden]` beats `.btn` display); Go/Next lands on tab heading |
| S-ST1-phantom-status | Button **Connected** (soft green) when wallet is in; **Connect Wallet** (blue) if not. Address is a **readonly** box next to the button. No “already connected…” line under it |
| S-ST1-shelf | No wallet dropdown. **Card** dropdown = employer · companyId (program only). **On-chain token** = employment PDA |
| S-ST1-check-hero | One headline only. Ended follow-on: no longer employed; QR stays ended until Re-issue |
| S-ST1-print-sheet | Two-face stamp on Employee. Real scan QR only after signed Generate QR (`/check#s=`). `/stamp/` gone |
| S-ST1-looks | **Open by default.** Defaults bg `#1f4361` accent `#2786b9` text `#f4f8fb`. Swatches + live preview |
| S-ST1-contact-email | Email `first.last@org.example`. LinkedIn suggested `linkedin.com/in/first-last` + change hint. Org does not rewrite LinkedIn. Manual URL stays |
| S-ST1-sign-keeps-ticks | Extra Disclose ticks survive Sign / Selective presentation. Banner lists signed fields |
| S-ST1-emp-burn | Picture burn is **not** on Employee. Company **Close picture** (operator freeze + log). Not Burn PDA |
| S-ST1-url-qr | Generate QR + Copy + Open Check + Print share `https://card.catalyxt.xyz/check#s=` |
| S-ST1-save-if-active | Public fixture `/check#s=alicedemo` (Alice Demo). Save to Contacts on. Min QR hides it (status only, not a missing vCard) |
| S-ST1-company-card-mode | No program card → Mint only. After mint → Card dropdown + Revoke/Re-issue. Same idle sentence |
| S-ST1-company-program-only | Shelf urn is not a Company card |
| S-ST1-emp-program-only | Shelf urn is not an Employee card; Burn disabled |
| S-ST1-pda-vs-picture | PDA → Revoke. Missing picture → Burn only off |
| S-ST1-field-split | Company no contacts; Employee has email/phone/LinkedIn |
| S-ST1-proof-req | Empty Apply Check request: no `SyntaxError`. Empty → paste zkec-req from Check. **Sign the ticked boxes** must not uncheck extra Disclose ticks |
| S-ST1-combo-revoke-remint | After Re-issue: **Re-issued / employed again**. Idle: **Use Revoke to end the card** (not “end the job”, not “This Phantom is employed”) |
| S-ST1-explorer-devnet | On-chain log lives in Admin. Open it: full `https://` + `explorer.solana.com/…?cluster=devnet` |
| S-ST1-guide-dock | Next: Check scanner → heading + how-to, not `#ver-go` |
| S-ST1-honk-reject | `kind:honk` → `unsupported_proof_system`, no `_bn` |
| S-ST1-prove-stub | `#prove-stub` + POST `/api/v1/prove` 501 |
| S-ST1-collectible-png | GET `/api/v1/collectible` then GET `/api/v1/collectible/sample/image.png` 200 PNG magic. Not `/collectible.png`. `#sample-wallet-card` on Guideline |
| S-ST1-check-empty | Empty Check / Re-check: no `SyntaxError` |

---

## Report template

```text
# Stage 1 E2E report
Base URL: https://card.catalyxt.xyz/
Product: 2.0.36
Date (UTC):
Agent: Comet / Perplexity / Grok / Playwright / other:

S-ST1-boot: PASS|FAIL — 
S-ST1-issue-min-verify: PASS|FAIL — 
S-ST1-revoke-ended: PASS|FAIL — 
S-ST1-shelf: PASS|FAIL — 
S-ST1-reverify: PASS|FAIL — 
S-ST1-verifier-only: PASS|FAIL — 
S-ST1-phantom: PASS|FAIL — 
S-ST1-commit-visible: PASS|FAIL — 
S-ST1-internal: PASS|FAIL — 
S-ST1-reissue: PASS|FAIL — 
S-ST1-deeplink: PASS|FAIL — 
S-ST1-cam-status: PASS|FAIL — 
S-ST1-ph-retry-devnet: PASS|FAIL — 
S-ST1-print-cam: PASS|FAIL — 
S-ST1-copy-ux: PASS|FAIL — 
S-ST1-pin-wrong: PASS|FAIL — 
S-ST1-pin-ok: PASS|FAIL — 
S-ST1-pin-no-copy: PASS|FAIL — 
S-ST1-fallback-help: PASS|FAIL — 
S-ST1-assets-relative: PASS|FAIL — 
S-ST1-phantom-gated: PASS|FAIL — 
S-ST1-phantom-status: PASS|FAIL — 
S-ST1-phantom-missing: PASS|FAIL — 
S-ST1-mint-no-holder: PASS|FAIL — 
S-ST1-combo-double-mint: PASS|FAIL — 
S-ST1-combo-revoke-remint: PASS|FAIL — 
S-ST1-combo-revoke-check-then-remint-check: PASS|FAIL — 
S-ST1-debug-fold: PASS|FAIL — 
S-ST1-check-empty: PASS|FAIL — 
S-ST1-min-empty: PASS|FAIL — 
S-ST1-revoke-status: PASS|FAIL — 
S-ST1-company-card-mode: PASS|FAIL — 
S-ST1-company-program-only: PASS|FAIL — 
S-ST1-emp-program-only: PASS|FAIL — 
S-ST1-pda-vs-picture: PASS|FAIL — 
S-ST1-field-split: PASS|FAIL — 
S-ST1-check-sample: PASS|FAIL — 
S-ST1-comet-live: PASS|FAIL — 
S-ST1-loop-visible: PASS|FAIL — 
S-ST1-guide-go-all: PASS|FAIL — 
S-ST1-guide-commit-pin: PASS|FAIL — 
S-ST1-guide-internal-pin: PASS|FAIL — 
S-ST1-guide-dock: PASS|FAIL — 
S-ST1-help-per-tab: PASS|FAIL — 
S-ST1-mint-ids: PASS|FAIL — 
S-ST1-honk-reject: PASS|FAIL — 
S-ST1-collectible-not-sot: PASS|FAIL — 
S-ST1-explorer-devnet: PASS|FAIL — 
S-ST1-emp-burn: PASS|FAIL — 
S-ST1-not-offered: PASS|FAIL — 
S-ST1-help-overlay: PASS|FAIL — 
S-ST1-disclose-preview: PASS|FAIL — 
S-ST1-print-sheet: PASS|FAIL — 
S-ST1-proof-req: PASS|FAIL — 
S-ST1-email-sig: PASS|FAIL — 
S-ST1-looks: PASS|FAIL — 
S-ST1-check-hero: PASS|FAIL — 
S-ST1-manual-refresh: PASS|FAIL — 
S-ST1-pwa-manifest: PASS|FAIL — 
S-ST1-prove-stub: PASS|FAIL — 
S-ST1-collectible-png: PASS|FAIL — 
S-ST1-contact-email: PASS|FAIL — 
S-ST1-sign-keeps-ticks: PASS|FAIL — 
S-ST1-action-tips: PASS|FAIL — 
S-ST1-ux-principles: PASS|FAIL — 
S-ST1-url-qr: PASS|FAIL — 
S-ST1-save-if-active: PASS|FAIL — 
S-ST1-admin: PASS|FAIL — 

Score: __ / 83 PASS
Blockers:
Notes:
```
