mech.app

The mech.app newsletter

Agentic AI, minus the noise.

Get practical field notes on AI agents, automation, developer tools and security delivered to your inbox.

No spam. Unsubscribe anytime.

Financial

Gate Check: How a Power Bank Agent Exposes the Plumbing of Multi-Source Regulatory Reconciliation

A travel compliance agent reveals infrastructure patterns for handling conflicting authoritative sources, versioned regulations, and disagreement surfac...

Source: dev.to
Gate Check: How a Power Bank Agent Exposes the Plumbing of Multi-Source Regulatory Reconciliation

Gate Check is a working agent that answers whether your power bank can board a specific flight. The implementation is less interesting than the problem it solves: reconciling conflicting authoritative sources without hallucinating consensus.

On 27 March 2026, ICAO limited power banks to two per passenger and banned in-flight recharging. Hong Kong applied the rule the next day. Korea followed on 20 April, Japan on 24 April. Emirates already allowed only one power bank. IATA’s 2026 guidance lists 100-160 Wh batteries as forbidden, while ICAO’s addendum still permits them with airline approval. A 2025 Korean government page says you may bring five. Incheon Airport’s press release converts 100 Wh to 20,000 mAh at 5 V, while the ministry and airlines use 3.7 V (about 27,000 mAh).

This is not a search problem. It is a reconciliation problem with versioned regulations, overlapping jurisdictions, and no single source of truth.

The Reconciliation Flow

Gate Check separates deterministic logic from agent reasoning:

  1. Conversion layer: mAh to watt-hours using manufacturer voltage (3.7 V default).
  2. Rule retrieval: fetch airline policy, departure country regulation, and ICAO baseline from Sanity CMS.
  3. Band placement: slot the battery into each rule’s watt-hour bands (0-100, 100-160, >160).
  4. Strictest-wins resolution: apply the most restrictive count limit across all sources.
  5. Agent explanation: a Sanity Knowledge Base-backed agent surfaces which sources agree, which conflict, and why.

The agent does not decide the answer. The code does. The agent explains the decision and exposes disagreements.

Data Model for Versioned Regulations

Each regulation is a document in Sanity with:

  • Effective date: when the rule applies.
  • Jurisdiction: airline, country, or international body.
  • Watt-hour bands: array of { min, max, allowedCount, requiresApproval }.
  • Source URL: link to the official page.
  • Supersedes: reference to the previous version.

A query for Korean Air departing Seoul on 25 April 2026 retrieves:

  • Korean Air policy (effective 20 April 2026).
  • Korea Ministry of Land policy (effective 20 April 2026).
  • ICAO baseline (effective 27 March 2026).

The system does not merge these into a single rule. It keeps them separate and applies the strictest band for each watt-hour range.

interface RegulationBand {
  min: number;
  max: number;
  allowedCount: number;
  requiresApproval: boolean;
}

interface Regulation {
  jurisdiction: string;
  effectiveDate: string;
  bands: RegulationBand[];
  sourceUrl: string;
  supersedes?: string;
}

function resolveStrictest(
  batteryWh: number,
  regulations: Regulation[]
): { allowed: number; approval: boolean; sources: string[] } {
  const applicable = regulations
    .flatMap(reg =>
      reg.bands
        .filter(b => batteryWh >= b.min && batteryWh < b.max)
        .map(b => ({ ...b, source: reg.jurisdiction, url: reg.sourceUrl }))
    );

  const strictest = applicable.reduce((acc, band) =>
    band.allowedCount < acc.allowedCount ? band : acc
  );

  return {
    allowed: strictest.allowedCount,
    approval: applicable.some(b => b.requiresApproval),
    sources: applicable.map(b => `${b.source}: ${b.url}`)
  };
}

Agent Boundary: Explanation, Not Decision

The agent receives:

  • Battery capacity (Wh).
  • Resolved answer (allowed count, approval requirement).
  • List of sources and their individual answers.

It does not query regulations directly. It queries a Sanity Knowledge Base that indexes the same regulation documents, then generates natural language that:

  • States the answer.
  • Lists which sources agree.
  • Highlights disagreements (e.g., IATA forbids 100-160 Wh, ICAO allows with approval).
  • Links to each source.

This prevents the agent from inventing a middle ground or picking a rule based on token probability.

Failure Modes and Observability

Failure ModeDetectionMitigation
Stale regulation in CMSEffective date checkDaily sync job compares CMS dates to known airline update schedules
Agent hallucinates a ruleSource link validationEvery claim must map to a sourceUrl in the resolution payload
Voltage assumption wrongUser overrideUI exposes voltage field; logs flag non-3.7V inputs for review
Conflicting band definitionsBand overlap detectorPre-publish hook rejects regulations with overlapping min/max ranges
Agent ignores strictest ruleDeterministic test suiteEvery query logs resolved answer + agent output; diff alerts on mismatch

Observability hooks:

  • Query logs: battery Wh, flight details, resolved answer, agent output, sources cited.
  • Disagreement metrics: count of queries where sources conflict, grouped by jurisdiction pair.
  • Staleness alerts: regulations older than 90 days without a superseding version.

Deployment Shape

Gate Check runs as:

  • Sanity Studio: editors update regulations, preview band logic.
  • Next.js API route: receives query, runs resolution logic, calls agent.
  • Sanity Knowledge Base: agent queries indexed regulations for explanation.
  • Vercel Edge Function: serves UI, caches resolved answers by flight + battery hash.

The resolution logic is deterministic and cacheable. The agent explanation is not, but it is idempotent given the same resolution payload.

When Regulations Disagree

Gate Check does not hide disagreement. A query for a 111 Wh battery on Asiana from Seoul returns:

Needs airline approval. This battery is over 100 Wh and up to 160 Wh. Korea Ministry of Land allows two with approval. Asiana policy matches. IATA 2026 guidance forbids batteries in this range, but ICAO Addendum 1 permits them with airline approval. The strictest rule requires approval.

The agent surfaces the IATA/ICAO conflict because both are in the resolution payload. It does not pick one or synthesize a compromise.

Security Boundaries

  • No user-supplied regulation URLs: all sources are CMS-managed.
  • Agent cannot write to CMS: read-only Knowledge Base access.
  • Rate limiting: 10 queries per IP per minute.
  • Input validation: battery capacity clamped to 0-300 Wh, voltage to 3.0-5.0 V.

The agent cannot be prompt-injected into citing a fake regulation because it only queries pre-indexed CMS content.

Technical Verdict

Use this pattern when:

  • You have multiple authoritative sources that frequently conflict (tax codes, insurance policies, compliance frameworks).
  • The cost of a wrong answer is high (financial penalty, safety risk, contract breach).
  • Users need to understand why sources disagree, not just get a single answer.

Avoid this pattern when:

  • Sources rarely conflict and a single source of truth exists.
  • Deterministic resolution logic is too complex to maintain (hundreds of overlapping rules).
  • Users expect instant answers and cannot tolerate explanation overhead.

Gate Check proves that agents can handle regulatory reconciliation without hallucinating consensus. The key is separating deterministic resolution (code) from explanation (agent), versioning every source, and surfacing disagreement instead of hiding it.


Tags

agentic-ai orchestration infrastructure

Primary Source

dev.to ↗