Visa Eligibility Is a Decision System, Not a Database
Before a customer purchases a visa application on Atlys, we need to know exactly what to sell them. The naive approach: build a lookup table. We did that. It worked until it did not, and when it failed, it failed silently. A customer at a border, not a system throwing an error.
Visa eligibility looks like a data problem. It is actually a knowledge representation problem. We solved it by:
Storing derivations instead of conclusions
Making dependencies explicit so updates have bounded blast radius
Adding a confidence model that decays with freshness and source agreement
Why Visa Eligibility Is Not a Lookup Problem
Visa eligibility depends on three primary variables: destination, nationality, and residence. That combination alone creates over 500,000 permutations across 150+ countries. But the real problem is the conditional nature of secondary variables.
Take an Indian national applying to enter the UAE. By default, a visa is required. But if that applicant holds a valid US visa that has been used at least once and has not expired, they qualify for visa on arrival. The eligibility outcome changed not because of who they are, but because of what they carry.
The headline “visa free for Indians” is a lossy compression of the actual policy. The sub-conditions are not footnotes. They are the rule.
A conclusion store materializes outputs and discards the derivation graph. Even when the conclusion is correct, the system cannot tell you why it is correct or what upstream facts it depends on.
The Table That Broke
We built the matrix. Rows were nationality and residence combinations. Columns were destinations. Cells held one of four values: visa required, visa on arrival, visa free, evisa.
The failures were structural, not incidental:
Qatar/Bali case: Our table said visa free for Indian nationals. Qatar had a separate bilateral arrangement that modified the answer for Indians residing there. Both facts were true. The table had no way to hold both simultaneously.
Kenya/Ireland case: The rule for UK visa holders entering Ireland was stored as a static yes. The table could not express the precondition that the UK visa must have been used at least once.
A matrix has no dependency model. If the rule governing a cell depends on five facts and one changes, the matrix gives you no way to know which cells to review.
The deeper problem: a matrix is optimized for confidence. No cell can express “this answer is conditional on something I have not verified recently.” For a domain where conditions change at any time without notification, that is not a missing feature. It is the failure mode.
Data Freshness and Source Divergence
Policy updates arrive through three asynchronous channels:
Asynchronous source updates – embassy websites, government advisories, and third-party aggregators update on independent timelines
Source divergence during rollouts – during a policy transition, two official sources may simultaneously carry different answers, each technically correct at a different point in the rollout
Unclear effective dates – announced changes often lack a precise activation timestamp, creating a window where neither the old nor new answer is safe to serve
A system that cannot represent uncertainty will always resolve it by picking one answer and presenting it as fact. The system needs to know not just what the current answer is, but how confident it is in that answer, derived from source agreement, source recency, and proximity to known change windows.
Representation: Typed Predicates and Dependency Graph
Storing Derivations Instead of Conclusions
The shift that changed everything was moving from storing conclusions to storing the rules that produce them.
Conclusion: Indian nationals residing in India do not need a visa for Thailand.
Rule: IF nationality = IN AND residence_country = IN AND entry_type IN {air, sea} AND stay_duration <= 60 AND overstay_history = false THEN result = visa_not_required
When a threshold changes (e.g., 30 to 60 days), we update one leaf parameter and every dependent rule re-evaluates without touching each cell.
Node Types
Node Type What It Holds Change Frequency Leaf nodes Atomic facts: stay duration thresholds, qualifying visa types, eligible residence permit countries Changes with every policy update Internal nodes Logic: AND, OR, NOT, threshold comparisons, set membership Almost never changes Result nodes Outputs: eligibility determination, product to display, document checklist Derived from above
Some rules reference other rules. The Irish entry condition for UK visa holders references the UK visa validity rule as a precondition. These are explicit edges in a directed dependency graph. When a qualifying permit type list changes, the system traverses the graph and surfaces every rule that references it. That traversal is the review list before the update goes live.
Temporal Rules and Confidence Decay
Each rule carries a source URL, a verification timestamp, an expiry date if known, and a computed confidence score. Confidence is a live property, not a static label.
confidence = f(source_agreement, verification_recency, expiry_distance, destination_volatility)
High confidence: Full eligibility determination
Medium confidence: Determination plus advisory to verify with the embassy
Below minimum floor: No confident determination – customer is told to verify directly
The Hard Problems
Conflicting Official Sources
When sources diverge, the system requires agreement across at least two independent sources for a high confidence answer. Conflicts are flagged for human review with both sources surfaced side by side. This adds latency to policy updates but eliminates the risk of automated propagation of a wrong answer at scale.
Rules That Cannot Be Encoded
Consulate-level discretion is real and undocumented. A condition tree cannot express that a consulate officer reviewing a sparse travel history may request additional documentation not listed in any official source. These rules are marked in metadata and surface in the product as a specific advisory, not a confident eligibility determination.
Announced but Not Yet Effective
These are encoded as time-gated rules in a pending state. The current rule remains active until the effective date. The new rule is encoded with an activation timestamp and activates automatically. Where the effective date is unspecified, an explicit advisory recommends direct verification with the embassy.
Evaluation and Regression
Golden set of edge case corridors – high-stakes nationality and destination pairs with known conditional rules, maintained as ground truth fixtures
Regression suite on every rule and leaf update – any change triggers a full pass against the golden set before going live
Backtesting on historical policy changes – past rule states replayed against known outcomes
Coverage metric – percentage of queries served above the confidence threshold (primary health indicator)
Time to detect divergence – how quickly the monitoring pipeline surfaces a new source conflict
Time to restore high confidence – elapsed time from a divergence flag to a human-reviewed resolution
Incident rate – confirmed wrong answers served to customers, tracked per destination tier
The Actual Takeaway
Visa rules look like a data problem because the question seems simple: what visa do I need? The complexity is invisible until you ask: how do you know, and how do you know that you know?
The failure mode of a lookup table is not inaccuracy. It is misplaced confidence, delivered silently. The failure mode of a rules engine without a confidence layer is the same problem at a higher level of abstraction.
The matrix would have been faster to build. It also would have continued to fail silently. The system we built fails loudly. It surfaces uncertainty, flags degraded confidence, and tells you when it does not know.
This is what decision systems look like when the domain changes without a changelog: explicit derivations, explicit dependencies, and calibrated confidence as a first-class output.
Note: Eligibility in this piece refers to whether a visa is required and what type. Approval likelihood, processing time, and document requirements are handled by separate systems.