Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ See [docs/architecture.md](docs/architecture.md) for the full architecture overv

## Domain Expertise

OTAIP agents encode real industry logic: ATPCO fare rules (Categories 1-33), NUC/ROE fare construction with HIP/BHC/CTM checks, BSP HOT file reconciliation, ADM prevention (9 pre-ticketing checks), NDC/EDIFACT normalization, IRROPS rebooking with EU261 and US DOT compliance, void window enforcement, married segment integrity, and payment-to-ticketing state machines with BSP finality rules.
OTAIP agents encode real industry logic: ATPCO fare rules (Categories 1-33), NUC/ROE fare construction with HIP/BHC/CTM checks, BSP HOT file reconciliation, ADM prevention (10 pre-ticketing checks), NDC/EDIFACT normalization, IRROPS rebooking with EU261 and US DOT compliance, void window enforcement, married segment integrity, and payment-to-ticketing state machines with BSP finality rules.

---

Expand Down
2 changes: 1 addition & 1 deletion agents.graph.json
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@
"id": "6.2",
"name": "ADM Prevention",
"stage": "settlement",
"version": "0.1.0",
"version": "0.2.0",
"contract_status": "active",
"has_contract": false,
"source_path": "packages/agents/settlement/src/adm-prevention/index.ts"
Expand Down
2 changes: 1 addition & 1 deletion agents.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5357,7 +5357,7 @@
"id": "6.2",
"name": "ADM Prevention",
"stage": "settlement",
"version": "0.1.0",
"version": "0.2.0",
"contract_status": "active",
"has_contract": false,
"source_path": "packages/agents/settlement/src/adm-prevention/index.ts"
Expand Down
2 changes: 1 addition & 1 deletion docs/agent-map.html

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
| ID | Class | Name | Description | Contract |
|----|-------|------|-------------|----------|
| 6.1 | `RefundProcessing` | Refund Processing | ATPCO Category 33 refund processing: penalty application, commission recall, BSP/ARC reporting, conjunction ticket handling | -- |
| 6.2 | `ADMPrevention` | ADM Prevention | Pre-ticketing audit: 9 checks covering fare integrity, segment validity, and compliance to prevent Agency Debit Memos | -- |
| 6.2 | `ADMPrevention` | ADM Prevention | Pre-ticketing audit: 10 checks covering fare integrity, passive/UC/churn (history-required), married integrity, TTL, and compliance to prevent Agency Debit Memos | -- |
| 6.3 | `ADMACMProcessingAgent` | ADM/ACM Processing | Agency Debit Memo receipt, assessment, dispute, and Agency Credit Memo application workflows | -- |
| 6.4 | `CustomerCommunication` | Customer Communication | Multi-channel customer notification generation for flight disruptions, refunds, and operational changes. 8 notification types x 4 channels | -- |
| 6.5 | `FeedbackComplaintAgent` | Feedback & Complaint | Complaint submission, EU261/US DOT compensation calculation, case management, and regulatory DOT record generation | -- |
Expand Down
24 changes: 21 additions & 3 deletions docs/agents/stage-6-settlement.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Refund processing, ADM prevention, ADM/ACM dispute management, customer communic
ATPCO Category 33 refund processing: penalty application, commission recall, BSP/ARC reporting fields, conjunction ticket handling. Supports full, partial, and tax-only refunds.

**Input (`RefundProcessingInput`):**

- `ticket_number`, `conjunction_tickets?`
- `issuing_carrier`, `passenger_name`, `record_locator`
- `base_fare`, `base_fare_currency`, `taxes`, `commission?`
Expand All @@ -25,6 +26,7 @@ ATPCO Category 33 refund processing: penalty application, commission recall, BSP
- `settlement_system` -- `'BSP' | 'ARC'`

**Output (`RefundProcessingOutput`):**

- `refund` -- penalty applied, base fare refund, tax refund, tax breakdown, commission recalled, net refund, BSP/ARC reporting fields, audit trail
- `net_refund_amount`, `commission_recalled`

Expand All @@ -36,17 +38,25 @@ ATPCO Category 33 refund processing: penalty application, commission recall, BSP
**Class:** `ADMPrevention`
**Status:** Implemented

Pre-ticketing audit with 9 checks: duplicate booking, fare/class mismatch, passive segment, married segment integrity, TTL expiry, commission rate, endorsement box, tour code format, net remit validation.
Pre-ticketing audit with 10 checks: duplicate booking, fare/class mismatch, passive/unable/risky status (core HX/UC/UN/NO/TK + **per-host** maps — HN/PK/GK/YK are not universalized), churning (history-required), married segment integrity, TTL expiry (timezone / deadline-day), commission rate (caller-supplied only), endorsement box, tour code format, net remit validation.

**Domain KB:** `docs/knowledge-base/adm-prevention.md` — IATA Reso 850m covers ADM memo windows/dispute (Agent 6.3); passive/UC/churn come from carrier booking policy + host statuses. Travelport: those statuses do not need a ticketing field. No carrier-secret commission tables.

**Input (`ADMPreventionInput`):**

- `booking` -- record locator, passenger name, segments (with status, class, married group), base fare
- `fare_basis`, `booked_class`
- `commission_rate?`, `carrier_contracted_rate?`
- `commission_rate?`, `carrier_contracted_rate?` -- both caller-supplied; no embedded carrier tables
- `endorsement?`, `tour_code?`
- `is_net_remit?`, `net_contracted_amount?`
- `ttl_deadline?`, `duplicate_check_pnrs?`, `current_datetime?`
- `ttl_deadline?`, `ttl_timezone?`, `ttl_source?`, `current_datetime?`
- `duplicate_check_pnrs?`
- `segment_history?` -- required for churning; current status alone is insufficient
- `gds?` -- `SABRE` | `AMADEUS` | `TRAVELPORT` | `UNKNOWN` (Travelport DX marriage break)
- `churn_cycle_threshold?`, `churn_window_hours?`

**Output (`ADMPreventionOutput`):**

- `result` -- all check results, overall pass/fail, blocking/warning counts

---
Expand All @@ -60,10 +70,12 @@ Pre-ticketing audit with 9 checks: duplicate booking, fare/class mismatch, passi
Agency Debit Memo receipt, assessment, dispute, and Agency Credit Memo application workflows. Tracks dispute deadlines (15-day window), supports dispute grounds, and manages status transitions.

**Input (`ADMACMProcessingInput`):**

- `operation` -- `'receiveADM' | 'receiveACM' | 'assessADM' | 'disputeADM' | 'acceptADM' | 'escalateADM' | 'applyACM' | 'getADM' | 'getPendingWithDeadlines'`
- Operation-specific fields: ticket number, airline, amount, reason code, dispute ground/evidence, ADM/ACM IDs

**Output (`ADMACMProcessingOutput`):**

- `adm?` -- ADM record with status history
- `acm?` -- ACM record
- `assessment?` -- days remaining, window expired, recommended action
Expand All @@ -81,13 +93,15 @@ Agency Debit Memo receipt, assessment, dispute, and Agency Credit Memo applicati
Multi-channel customer notification generation. 8 notification types (flight cancelled, delayed, gate change, rebooking confirmed, refund processed, schedule change, waitlist cleared, ADM received) x 4 channels (Email HTML, Email text, SMS, WhatsApp).

**Input (`CustomerCommunicationInput`):**

- `operation` -- `'generateNotification' | 'generateBatch' | 'getTemplate'`
- `notificationType?` -- notification type
- `channel?` -- delivery channel
- `variables?` -- template variables (passenger name, flight info, amounts, etc.)
- `batchRequests?` -- for batch generation

**Output (`CustomerCommunicationOutput`):**

- `notification?` -- generated notification with body, subject, SMS segments, used/missing variables
- `notifications?` -- batch results
- `template?` -- template info with required variables
Expand All @@ -103,12 +117,14 @@ Multi-channel customer notification generation. 8 notification types (flight can
Complaint submission, EU261/US DOT compensation calculation, case management with status tracking, and DOT regulatory record generation.

**Input (`FeedbackComplaintInput`):**

- `operation` -- `'submitComplaint' | 'updateStatus' | 'getCase' | 'listCases' | 'calculateCompensation' | 'generateDOTRecord'`
- Complaint fields: type, passenger, booking reference, airline, flight, description
- Compensation fields: regulation, distance, delay, alternative offered, fare paid, cabin class
- Case management: case ID, status transitions

**Output (`FeedbackComplaintOutput`):**

- `complaintCase?` -- full case record with status history, compensation result
- `cases?` -- filtered case list
- `compensation?` -- EU261/US DOT calculation (eligibility, base/final amount, reduction, notes)
Expand All @@ -125,13 +141,15 @@ Complaint submission, EU261/US DOT compensation calculation, case management wit
Mileage accrual calculation, redemption eligibility checking, status benefits lookup, and cross-airline status matching.

**Input (`LoyaltyMileageInput`):**

- `operation` -- `'calculateAccrual' | 'checkRedemptionEligibility' | 'getStatusBenefits' | 'matchStatus'`
- Accrual: operating/crediting carrier, booking class, distance, loyalty status
- Redemption: distance, cabin, partner flag, current balance
- Benefits: airline, status tier
- Match: source/target airline, source status

**Output (`LoyaltyMileageOutput`):**

- `accrual?` -- base miles, bonus miles, total, earn rate, partner flag
- `redemption?` -- eligibility, miles required, remaining balance
- `statusBenefits?` -- benefit list by tier
Expand Down
123 changes: 123 additions & 0 deletions docs/knowledge-base/adm-prevention.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# ADM Prevention — Domain Knowledge (Agent 6.2)

Authoritative input for `@otaip/agents-settlement` ADM Prevention. Sources: IATA Resolution 850m (ADM process), public GDS status/advice tables (Amadeus Service Hub; Travelport Universal API PNR Status Codes), and mid-office practice for carrier booking-policy ADMs. Anything missing is an open `DOMAIN_QUESTION` — never invent carrier-secret fee or commission tables.

## Scope split (do not conflate)

| Concern | Authority | What Agent 6.2 uses it for |
| -------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| ADM **memo** lifecycle — issuance windows, BSP processing limits, agent dispute period | **IATA Resolution 850m** | Context only for Agent 6.3 (dispute deadlines). 850m does **not** define passive/UC/churn rules. |
| Passive / UC / unable / schedule-change / churning ADMs | **Carrier booking & ticketing policies** + **GDS host segment status codes** | Pre-ticketing checks in Agent 6.2 |

Typical 850m process facts used elsewhere in OTAIP (Agent 6.3): agent review/dispute window **15 days** before BSP submission; airline dispute handling expected in a timely manner (commonly up to **60 days** in carrier policies that cite 850m); BSP processing generally within **nine months** of final travel (or refund) date. Carrier policies may add market-specific overlays — do not hardcode carrier dispute SLAs here.

## Host statuses that block ticketing (core set)

Carrier booking policies and host queues treat these **advice / status** codes as must-clear before issue. Detection is from the **segment status on the PNR**, not from inventing a parallel “ticketing field.”

| Code | Typical meaning (public GDS tables) | ADM / mid-office risk |
| ------ | ------------------------------------------------------- | --------------------------------------------------------------- |
| **HX** | Holding canceled / cancel confirm hold | Dead or rejected space — remove before ticketing |
| **UC** | Unable to confirm (often flight closed, not waitlisted) | No confirmed inventory — remove / rebook |
| **UN** | Unable — flight does not operate / no flight | Schedule or sell failure — remove / reprotect |
| **NO** | No action taken (common airline reject of passive) | Passive/claim rejected — delete NO segments |
| **TK** | Schedule change — advise passenger of new times | Uncleared schedule change — passenger not advised / times stale |

**Travelport note:** On Travelport hosts, the statuses above are sufficient for detection — they do **not** require an additional ticketing-specific field on the segment. Status alone drives the passive/unable/schedule-change queue action.

### Per-host extended codes (NOT one IATA meaning)

**Do not globalize** HN / PK / GK / YK (or other extended codes) as a single industry-wide meaning. The same two-letter string can mean different things on Sabre vs Amadeus vs Travelport. Agent 6.2 applies these **only when `gds` is set** to that host. If `gds` is omitted / `UNKNOWN`, only the core set above applies.

| Host | Codes treated as blocking (public host tables / ops) | Notes |
| -------------- | ---------------------------------------------------------- | ------------------------------------------------------------------ |
| **Amadeus** | HN, PK, PL, GK, GL, GN, UU, US, XX | PK/PL = passive sell; GK/GL/GN = ghost — Amadeus semantics |
| **Sabre** | YK, GK, HN, XX | YK = Sabre administrative/itinerary passive; GK ≠ Amadeus ghost |
| **Travelport** | HN, AK, AL, AN, BK, BL, DX, MK, PS, ZK, LK, UU, US, XX, XK | DX = broken marriage / marriage-integrity signal (Travelport-only) |

```
// TODO: DOMAIN_QUESTION: Confirm Sabre vs Amadeus GK semantics in each adapter's
// normalized status before treating GK as interchangeable across hosts.
// TODO: DOMAIN_QUESTION: When gds is UNKNOWN, host-specific codes are ignored
// (core only). Should UNKNOWN emit a warning instead of silent skip?
```

Active / ticketable examples (not exhaustive): **HK**, **KK**, **KL**, **RR**, **HS** (context-dependent). Do not treat “looks confirmed now” as proof the PNR was never churned — see churning.

## Churning (requires history)

**Definition (ops):** Repeated book → cancel → rebook of the same (or equivalent) air space to circumvent TTL, hold inventory, or game GDS productivity — without intent to ticket the intermediate holds.

**Hard rule:** Churning **cannot** be detected from **current** segment status alone. A PNR that is all `HK` today can still be a churn case if the history shows multiple cancel/rebook cycles on the same carrier/flight/date (or same O&D class) inside a short window.

Minimum history signals Agent 6.2 expects (when provided):

1. Ordered segment history events: `BOOKED` | `CANCELLED` | `REBOOKED` (ISO timestamps).
2. Flight identity: carrier + flight number + departure date (and optionally origin/destination).
3. Default detection heuristic (conservative, not carrier-secret): **≥ 3 cancel→rebook cycles** on the same flight identity within **72 hours** → blocking `CHURNING` failure.

If history is omitted, churning is **skipped** (not assumed clear). Callers that need churn coverage must supply history — skipping is an explicit ADM exposure.

```
// TODO: DOMAIN_QUESTION: Carrier-specific churn thresholds (cycle count / window hours)
// vary by airline booking policy. Do not hardcode a global carrier table; keep the
// default heuristic overridable once policy feeds exist.
```

## Married segments (GDS-specific)

Married segments are **host constructs**, not “segments that happen to be in the same PNR.”

| GDS | What mid-office looks for | Break risk |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| **Sabre** | Married Segment Indicator (MSI) / marriage linkage on connecting sells | Partial cancel or class change on one leg of a marriage → married-segment ADM under many carrier policies |
| **Amadeus** | Married connection / marriage control on Air Sell; status must stay consistent across the married set | Splitting or mixed advice codes across the marriage |
| **Travelport** | Marriage grouping on the air segment; status **DX** can mean _broken marriage_ (passive) or authorized partial cancel within marriage | Seeing **DX** (or mixed HK + cancel advice inside one marriage group) is a red flag for integrity review |

Agent 6.2 minimum check: every `married_group` must have identical statuses and at least two segments. When `gds` is `TRAVELPORT` and any segment status is `DX`, treat as married-integrity failure even if a group id is missing.

```
// TODO: DOMAIN_QUESTION: Exact Sabre MSI field names in OTAIP normalized PNR
// vs cryptic *IA display — confirm adapter mapping before relying on MSI alone.
```

## TTL edge cases (timezone / deadline day)

Carriers set TTL at booking, fare quote, or by departure rules — interpretation is carrier-specific. Agent 6.2 applies these operational guards when inputs are present:

1. Compare `current_datetime` to `ttl_deadline` in absolute UTC instants when both are full ISO-8601 timestamps.
2. If `ttl_timezone` is provided (IANA name), also evaluate **calendar deadline-day** in that zone: ticketing **on the same local calendar date as the deadline** is ADM-prone even when a few hours remain in UTC (carriers often ADM same-day-of-deadline issuance).
3. Distinguish `ttl_source`: `BOOKING` vs `FARE_QUOTE` vs `CARRIER_RULE` in messages — do not silently assume one source.
4. Keep a pre-issue buffer (currently 30 minutes) so the PNR cannot expire mid-transaction.

```
// TODO: DOMAIN_QUESTION: Default agency timezone vs airport-of-origin vs BSP
// market clock when ttl_timezone is absent — Agent 8.3 mid-office may share this policy.
```

## Commission

Commission validation remains **input-driven**: compare supplied `commission_rate` to caller-supplied `carrier_contracted_rate`.

**Do not** paste or hardcode carrier-secret commission tables, override grids, or net-remit contract schedules into this repository.

## Fixtures (scariest false negatives)

See `packages/agents/settlement/src/adm-prevention/__tests__/fixtures/`:

| Fixture | Why it is scary |
| ----------------------------- | --------------------------------------------------------------------------- |
| `churn-all-hk-now.json` | Current statuses all HK — HX/UN/NO-only scanners pass; history proves churn |
| `uncleared-tk.json` | TK schedule-change left on PNR — not in classic HX/UN/NO set |
| `uc-hn-passive-pk.json` | Amadeus UC + HN + PK — host-specific HN/PK, not a universal IATA meaning |
| `travelport-dx-marriage.json` | Travelport DX / broken marriage without needing a ticketing field |
| `ttl-deadline-day-tz.json` | UTC still “has time” but local deadline day has begun |

## Open DOMAIN_QUESTIONs

1. Per-carrier churn cycle/window overrides (policy feed shape).
2. Sabre MSI normalized field mapping across adapters.
3. Default timezone when `ttl_timezone` omitted (agency vs origin airport vs BSP market).
4. Whether legitimate passive-for-ticketing (host claim / airline-held PNR) should warn instead of block when an airline record locator claim is present — needs claim-flow design, not a guess.
5. Confirm Sabre vs Amadeus **GK** semantics in each adapter's normalized status before treating GK as interchangeable across hosts.
6. When `gds` is UNKNOWN, host-specific codes are ignored (core only) — should UNKNOWN emit a warning instead of silent skip?
Loading
Loading