# Verification record — zw/immigration/evisa-application@1.0.0

## Candidate selection

GOV-4481 (child of GOV-4476, "GovSchema Standard Research"). Opens Zimbabwe's Visa vertical (3 of 6), following the zw/zimra Taxes (GOV-4470) and Business Formation (GOV-4478) schemas.

## Reaching the live source

The issue delegating this work disclosed that `evisa.gov.zw`'s field schema is not behind login: the entire compiled Angular client ships on a plain unauthenticated GET before any auth. Independently re-fetched fresh rather than trusting the delegating issue's own disclosed hash: `https://www.evisa.gov.zw/app/main.baa2096ea7e0d09e.js`, HTTP 200, `Content-Type` JavaScript, 7,376,521 bytes — byte-for-byte matching the delegating issue's own disclosed size, confirming the specimen is unchanged. `https://www.evisa.gov.zw/app/index.html#/start` returns HTTP 200, 50,568 bytes, and redirects an unauthenticated visitor to `#/sign-in` (confirmed via a real Playwright/Chromium session, realistic desktop UA, `LD_LIBRARY_PATH`/`FONTCONFIG_FILE` sandboxed-launch fix applied per this registry's own established recipe). The sign-in screen's own "No account yet?" link reaches a sign-up form requiring e-mail verification to proceed — not completable without a real inbox, and not attempted, since GovSchema does not create accounts on government portals it documents. This confirms, first-hand, the delegating issue's own caution that live-browser rendering of the actual multi-step wizard is not the reliable path for this specimen (the issue additionally reported a prior SIGABRT crash on an unrelated MRZ/passport-scanner WASM asset); all field-level modelling below is instead drawn from static re-extraction of the compiled bundle's own source code, which is authoritative for what the client actually submits regardless of account access.

## Extraction method

The bundle is minified but not obfuscated: every Angular reactive-form field configuration survives as a literal JavaScript object (e.g. `{name:e.Wd.PURPOSE_OF_VISIT,type:"select",validators:[n.kI.required],...}`), and the field-name enum (`Wd`) and section-name enum (`mP`) both survive as literal `U.SOME_KEY="someValue"` assignment chains. Located and bracket-matched (respecting string/escape state) four distinct product field-configuration objects, each keyed by section name (`[e.mP.PERSONAL_DETAILS]`, etc.); the one beginning with `PERSONAL_DETAILS`+`EMERGENCY_CONTACT`+`TRAVEL_INFORMATION`+`DOCUMENT` sections and containing passport issue/expiry dates, arrival/departure dates, and funds-available fields is the one modelled here as the ordinary `zwevisa` product — distinguished from a second, adjacent configuration (personal details + travel information with vehicle/mode-of-travel numbers, an existing-entry-reference field, and a residence-permit-number field, but no advance passport-issue/expiry or arrival/departure dates) that is far more plausibly the physical border-crossing `zweentry` form, and from a third (attestant/extension-reason fields) that is plainly one of the `zwevisaextc`/`zwevisaextab` extension forms. Cross-referenced every field's translation key (`form.*`, 241 keys confirmed, matching the delegating issue's own disclosed count) against the bundle's own embedded, per-language translation object literals (no separate `assets/i18n/*.json` file exists; translations are inlined directly in `main.js`) to recover human-readable labels, taking the first English-language occurrence per key after confirming several samples resolved to genuine English text rather than a stray cross-reference.

The applicant's document-type (`passportType`) and nationality are set on a separate, shared "passport-type" screen (component class confirmed by name) reused across every product, not part of the four-section field-configuration object; its selectable document types are a subset of a shared `PassportType` enum (`ordinary`, `diplomatic`, `marine`, `service`, `laissez-passer`, `identity-card`, `resident-permit`, `refugee`, `permanent-resident-permit`) which are exposed to the applicant, only 5 of which (`ordinary`, `diplomatic`, `service`, `refugee`, `marine`) carry a confirmed English translation anywhere in the bundle — the remaining 4 (`identity-card`, `resident-permit`, `permanent-resident-permit`, `laissez-passer`) have no translation and no other reference in the bundle, and are excluded here as unconfirmed for this product rather than fabricated. Similarly, the applicant's planned port of entry (`plannedEntry`) is set on a dedicated "travel-name" screen whose own component code fetches its selectable options at runtime from a separate live API call (`this.api.schema("zweentry")`, reading `properties.ProvisionnalEntryPort.enum`) rather than embedding them statically in this bundle; that live endpoint was not called (it plausibly requires the same account session as the wizard itself, and calling an unfamiliar authenticated-looking endpoint speculatively was judged out of scope for a static bundle re-extraction), so `plannedEntry` is modelled as an open string rather than a fabricated closed enum.

## Disclosed findings

1. **The "Application reference" field (`BatchId`/`travelName`, called out in the delegating issue's own field list) is excluded from `fields[]` entirely.** Its own component code (found and read in full) shows it is not applicant-supplied: `this.form.controls.travelName.patchValue(this.cart.currentApplication.travelName||this.cart.getUniqueReference(this.existingTravelNames))` immediately followed by `this.form.controls.travelName.disable()` — the client itself generates a unique reference and disables the control before the applicant ever sees it. It carries a `Validators.required` only because the system always supplies a value, not because a human must type one; modelled here the same way this registry excludes other system/office-assigned identifiers (e.g. ZIMRA's own pre-issuance office box).
2. **`lastName`, `firstName`, and `otherName` are modelled `required: false`, matching the source's own configuration exactly, despite this being surprising for a visa applicant's own name.** The extracted field objects for these three carry only a name-shape `pattern` validator (`^[A-Za-z\s\-]+$`) and no `Validators.required` — confirmed by direct, repeated reading of the raw configuration text, not a parsing artifact. The most plausible explanation (not itself confirmed, disclosed as inference only) is that these fields are ordinarily auto-populated from the passport-scan upload's OCR/MRZ pipeline earlier in the same product family, making a client-side required check redundant in the reference implementation; this schema models the confirmed validator set as-is rather than adding a required flag the source does not carry.
3. **No field in the Supporting Documents section carries a `Validators.required` (or any `validators` array at all) in the extracted configuration**, unlike every other section, where required fields are explicit. All 14 modelled `documents[]` entries are therefore `required: false`, disclosing this as a genuine, confirmed absence rather than an assumption; the government's own officer-review workflow (found separately in the same bundle) manually inspects and can reject an application short on supporting evidence, rather than the client blocking submission.
4. **Five generic "Extra document" upload slots (`ExtraDocument1`–`ExtraDocument5`) and one further upload field explicitly marked `hidden: true` in its own source configuration (`PreviousVisa`) are excluded from `documents[]`.** The five extra slots carry no semantic label distinguishing one from another (each only progressively reveals the next via `ifFormControlHasValue` chaining) and the sixth is explicitly hidden from the applicant by the source's own flag; none represents a distinct, nameable document requirement.
5. **`gender`, `maritalStatus`, `fundsAvailableCurrency`, `passportType`, and `modeOfTravel` enum values are modelled using the exact lower-case (and, for `passportType`, hyphenated) string literals the compiled client itself submits** (e.g. `"male"`, `"married"`, `"USD"`, `"ordinary"`, `"flight"`), rather than this registry's more common upper-cased convention for enums inferred from a printed paper form — because these values were read directly from the live client's own JavaScript enum definitions, not inferred from rendered text, source fidelity is best served by preserving the exact wire values.
6. **`purposeOfVisit`'s 9-value enum (`business_visa`, `holiday_visa`, `conferencing_visa`, `transit_visa`, `student_visa`, `sports_visa`, `arts_visa`, `live_here`, `other_visa`) includes `live_here` ("Long-term Resident"), an option that reads oddly for an advance single-entry tourist/business e-visa product.** Modelled as-is because it is the confirmed, complete set of values referenced by this exact product's own field-configuration object (`durationOfStayDays`'s own `requiredWhen` explicitly exempts this value), not a value borrowed from a different product.
7. **`durationOfStayDays` is `requiredWhen` the applicant's purpose is anything other than `live_here`** (`{"not":{"field":"purposeOfVisit","equals":"live_here"}}`), matching the source's own `ifFormControlHasNotValue` condition exactly.
8. **The source's own relative-date rules that require date arithmetic beyond simple field-to-field comparison (e.g. a passport must remain valid at least 6 months beyond the arrival date; the applicant must be at least old enough that their passport's issue date follows their birth date) are disclosed in the relevant fields' own `description`, not encoded as `crossFieldValidation`,** since GSP-0013's `fieldCompare` grammar supports only direct value comparison between two fields, not comparison against another field plus a duration offset. The two relationships that do map cleanly to direct comparison (`dateOfIssue` on/after `dateOfBirth`; `departureDate` on/after `arrivalDate`) are modelled as `crossFieldValidation` rules.

## Conformance

3 valid mock scenarios — `valid-holiday-single-applicant` (an unmarried holiday visitor travelling by air, no spouse/companions/prior convictions); `valid-business-visa-with-spouse-and-convictions-disclosed` (a married business applicant travelling with their spouse, declaring a disclosed prior conviction in Zimbabwe, funds in EUR); and `valid-long-term-resident-by-road` (a `live_here` applicant entering by car, exercising `carNumber` and the `durationOfStayDays` exemption) — plus mutation-control fixtures (one missing-required-field fixture for each statically required field, an invalid-enum fixture, and an unknown-field-rejected fixture), committed under `conformance/zw/immigration/evisa-application/1.0.0/`. An ephemeral, from-scratch conformance checker (deriving required/requiredWhen rules directly from this schema's own `fields[]`, discarded after use, not committed) ran all fixtures: all 3 valid scenarios at 0 errors, all mutation controls each raising exactly 1 error, and the unknown-field fixture correctly rejected. Validated clean with `node tools/validate.mjs` and `node tools/validate-ajv.mjs`, individually and as part of the full registry run. `registry-index.json` regenerated via `npm run build-index` in `tools/govschema-client/`.
