---
module: agent.activeteller
title: Active Teller (IAT) — teller-session, core-banking & Check21 monitoring for Nautilus Hyosung ITMs
tab: Claude
order: 40
audience: dev
---

> **Internal · agent reference.** Terse. Confirmed against `hiveops-module-activeteller` source 2026-07-01.

## Identity
- Maven artifact: **`hiveops-module-activeteller`** (`com.hiveops`, version `1.0.0`, packaged as a standalone `jar`, parent `hiveops-agent-parent` `4.4.3`).
- Agent module id (`getName()`, and the string to use in **`modules.disabled`**): **`activeteller`**. Module `getVersion()` = `1.0.0`.
- Entry class: `com.hiveops.activeteller.ActiveTellerModule`, registered via `META-INF/services/com.hiveops.core.module.AgentModule`.
- Log package (`getLogPackage()`): `com.hiveops.activeteller`.
- Activation gate: `device.type` must equal `NH_IAT`; any other value → module inert, `isEnabled()` returns `false`.
- Classes: `ActiveTellerModule`, `TellerSessionMonitor`, `SymXchangeMonitor`, `CheckProcessingMonitor`, `RollingLogTailer`, `IatEventEmitter`.

## Config properties (exact keys)
| Key | Default | Required | Notes |
|---|---|---|---|
| `device.type` | *(none)* | **yes** | must be `NH_IAT` |
| `activeteller.log.dir` | *(none)* | **yes** | base folder holding `yyyyMMdd/` daily subfolders; must exist & be a dir or module disables (warn, no crash) |
| `activeteller.poll.interval.sec` | `30` | no | **applied** in `start()` |
| `activeteller.heartbeat.interval.sec` | `900` | no | rollup heartbeat cadence |
| `activeteller.answer.timeout.sec` | `180` | no | request→assignment deadline |
| `activeteller.video.timeout.sec` | `60` | no | session→video deadline |
| `activeteller.server.failure.threshold` | `3` | no | consecutive REST fails → `IAT_SERVER_UNREACHABLE` |
| `activeteller.core.failure.threshold` | `3` | no | consecutive SymXchange conn errors → `IAT_CORE_UNREACHABLE` |
| `activeteller.check.invalidity.threshold` | `50` | no | Check21 invalidity flag threshold |
| `activeteller.check.amount.mismatch.cents` | `500` | no | CAR/LAR gap (cents) that flags a check |

Shared (not module-specific): `agent.endpoint` / `incident.endpoint` (prefix = `agent` if `agent.endpoint` set, else `incident`), resolved via `HttpClientHelper.loadSettingsFromProperties(props, prefix)` — same bearer-token / institution-key chain as every other event module. No IAT-specific auth keys.

## Event types emitted (exact strings)
| Event type | `eventSource` | Trigger |
|---|---|---|
| `IAT_TELLER_UNANSWERED` | `IAT_ACTIVETELLER` | teller requested, no session assigned within `answer.timeout.sec` |
| `IAT_VIDEO_SESSION_FAIL` | `IAT_ACTIVETELLER` | session assigned but no video/remote-control within `video.timeout.sec`, or session ended with no video |
| `IAT_SERVER_ERROR` | `IAT_ACTIVETELLER` | Active Teller REST call returned non-2xx |
| `IAT_SERVER_UNREACHABLE` | `IAT_ACTIVETELLER` | `server.failure.threshold` consecutive REST failures |
| `IAT_SERVER_RECOVERED` | `IAT_ACTIVETELLER` | first REST success after an `IAT_SERVER_UNREACHABLE` (→ incident auto-close) |
| `IAT_MODE_CHANGE` | `IAT_ACTIVETELLER` | `"ModeType"` payload, `ModeName` changed (not first observation) |
| `IAT_CORE_TXN_FAIL` | `IAT_SYMXCHANGE` | SOAP fault / error line in SymXchange log (once per header block) |
| `IAT_CORE_UNREACHABLE` | `IAT_SYMXCHANGE` | `core.failure.threshold` consecutive connection errors |
| `IAT_CORE_RECOVERED` | `IAT_SYMXCHANGE` | next SymXchange message after an `IAT_CORE_UNREACHABLE` (→ incident auto-close) |
| `IAT_CHECK_IMAGE_QUALITY` | `IAT_CHECK21` | Check21 status≠Processed, invalidity>threshold, or CAR/LAR gap≥threshold |
| `IAT_HEARTBEAT` | `IAT_ACTIVETELLER` | every `heartbeat.interval.sec`, only if a monitor saw a line today |

- `eventType` is a free-form `String` on `CreateJournalEventRequest` (`hiveops-agent-journal` DTO) — **not validated client-side**. These `IAT_*` strings are custom (not in any agent enum) — recognition is hiveops-incident's DB-backed `event_type` table.
- `CreateJournalEventRequest` fields set: `agentAtmId`, `eventType`, `eventDetails`, `eventSource`, `eventTime` (ISO_LOCAL_DATE_TIME, or null). No cassette/card fields set.
- Transport: `POST {endpoint}/api/journal-events` via `IncidentEventClient.sendEvent()` — same client/endpoint as `journal-events`.

## Files monitored (under `{activeteller.log.dir}/{yyyyMMdd}/`)
- `ActiveTellerAgent_*.log` — newest-matching (session-stamped); `TellerSessionMonitor`, tag `agent`.
- `SymXchange{yyyyMMdd}.log` — fixed daily name; `SymXchangeMonitor`, tag `symx`.
- `CheckProcessingResults{yyyyMMdd}.log` — fixed daily name; `CheckProcessingMonitor`, tag `check`.
- All via `RollingLogTailer`: tail-by-offset (`RandomAccessFile` + `fileOffset`), reset on new-day/new-file or truncation; lines re-decoded ISO-8859-1 → UTF-8.

## Behavior facts
- Answer/video timers use the **log clock** (timestamp of last processed line), not wall-clock — backlog replay won't raise false timeouts.
- Dedup guards: `IAT_VIDEO_SESSION_FAIL`, `IAT_SERVER_UNREACHABLE`, `IAT_CORE_UNREACHABLE`, and per-block `IAT_CORE_TXN_FAIL` each fire once until state resets. When an `*_UNREACHABLE` state resets (first REST success / next SymXchange message), the matching `IAT_SERVER_RECOVERED` / `IAT_CORE_RECOVERED` is emitted.
- REST "success" whitelist: `OK, Created, Accepted, NoContent, NotModified, ResetContent`.
- SymXchange fault/conn regexes are conservative heuristics — may need tuning against a real failure sample.

## Deployment
- Delivered fleet-wide via **`INSTALL_MODULE`** fleet task (drops JAR into agent `modules/` dir, restarts agent — `ProcessInstallModule` in `hiveops-file-collection`).
- Disable without uninstalling: add `activeteller` to `modules.disabled`, push `CONFIG_UPDATE`.
- Register the eleven `IAT_*` event types in hiveops-incident → Settings → Event Types (DB `event_type` table) for correct labeling.

## Do NOT
- Do NOT expect the module to run on any `device.type` other than `NH_IAT` — inert by design elsewhere, not a bug.
- Do NOT expect retry/queueing on send failure — a failed `sendEvent()` is logged (`activeteller: failed to send ...`) and dropped.
- Do NOT assume the `IAT_*` strings exist in an agent `EventType` enum — they don't; the incident DB `event_type` table is what gates recognition.
- Do NOT point `activeteller.log.dir` at the daily `yyyyMMdd` subfolder — it must be the **base** folder; the tailer appends `{yyyyMMdd}/` itself.
- Do NOT assume `IAT_HEARTBEAT` fires on an idle/offline machine — it's suppressed unless a monitor saw a line today.
- Do NOT treat the SymXchange fault detection as authoritative — the markers are heuristics tuned without a real fault sample.
