Pattern 01 · Facts
Every change to a case reaches AIOL, in order, exactly once
AIOL has to know what ADR knows: who the parties are, which documents were filed, where the procedure stands. Not by polling, and not by a hook on every route — by observing the database itself.
01What you see
# the operator's view of the same thing $ flask aiol status integration: ON -> https://aiol.local LIT-304 seq=2 active pending=2
Live output from a demonstration instance. One line per case: where its sequence stands, whether it is active, paused or closed, and how much is still in flight.
02How it is used
Nobody uses it. That is the point: there is no “send to AIOL” button, no export, no nightly job a clerk has to remember. A party files a document, the Secretariat admits a case, an arbitrator signs an award — and AIOL knows.
What a human does touch is the operator surface, when something is wrong:
- flask aiol status — where every case stands.
- flask aiol retry — put a paused case back in the queue once the cause is fixed.
- flask aiol resync <case> — start that case over from a fresh snapshot.
- flask aiol drain — send what is pending now instead of waiting for the next tick.
03Technically
- Observed at the flush.The outbox listens to SQLAlchemy's session flush, so a case change is noticed wherever it happens. There are no per-route hooks to forget.
- Ordered per case. Sequence numbers are allocated under a row lock; a later event can never overtake an earlier one.
- Signed and fresh. Every request carries a timestamp, a nonce and an HMAC over the exact bytes sent. AIOL tolerates ±5 minutes and never accepts a nonce twice.
- Failure is not silence. 5xx, 429 and network errors retry with exponential backoff; a 409 gap re-sends from where AIOL is; a 404 starts over; a 400 or 401 is a defect and pauses the case for an operator instead of hammering it.
- It can never break the case. If the listener itself fails, the change still commits — the event is recoverable with
resync.
the signature, both directions
X-ADR-Timestamp: 1760441700 X-ADR-Nonce: "9f3c…" (16–128 chars, single use) X-ADR-Signature: HMAC-SHA256( secret, "<timestamp>.<nonce>." + body )
what travels — and what never does
| sent | stable ids (LIT-…, usr-…, doc-…), parties, the merits of the case, PDF/DOCX only |
| never sent | identity papers, powers of attorney, payment receipts, CVs, pictures, phone numbers, addresses |
A single worker is not a tuning choice: the scheduler runs in-process, so a second worker would send everything twice.