How lumnik breathes — from frozen rows to decisions
What happens when something changes in the source, and who is told.
The moment this page is about
A commande slips into EN LITIGE in the 02:00 batch. The row lands, a declared rule turns it into a decision seconds later, and your webhook pings the team's phone at 02:01 — before the client calls at 9:04.
The chain, end to end
The chain in one picture:
flowchart LR
erp[("legacy source")] -->|"your ingestion cron"| row["a row lands<br/>in the hub"]
row --> ev["an event"]
ev -->|"≤ 5 s"| proc["your declared rule<br/>when: statut=EN LITIGE"]
proc --> dec["decision.litige"]
dec --> inbox["Décisions tab<br/>lm inbox"]
dec -->|"≤ 5 s, retried"| hook["your webhook →<br/>the tool that pings phones"]
sweep["dormancy sweep<br/>every 15 min"] -->|"a document that STOPPED moving"| dec2["decision.dormant.*"]
dec2 --> inbox
dec2 --> hook
inbox -->|"✓ Traiter · lm inbox ack"| ack["acked — an event,<br/>timestamped, with who"]
- A new row emits. So does a row changed at the source, when its table has a key. A REST
table always has one (
unique_key). - A row read again unchanged emits nothing.
- A table emits only once something listens to it: a rule, a webhook or an email rule. The rows that landed before stay silent.
- jdbc, CSV, kafka and REST connectors emit. A REST, GraphQL or SOAP endpoint lands in the
table its manifest names (usually
ext.*). A rule names that table. - Every rule emits
decision.<your-name>. The apply refuses any other prefix.
| Clock | Value |
|---|---|
| rule, webhook and email consumers | every 5 s |
| webhook and email retry sweeps | every 30 s, 3 attempts in total. Journals: lm outputs list, lm notify deliveries |
| dormancy and due-date sweeps | every 15 min |
| your ingestion | the connector's own spec.schedule — the slow clock |
Where a human meets it — the channels
| Channel | What it does | Mode |
|---|---|---|
| Décisions tab (PWA, phone & desktop) | the pile, newest first, with a badge counting what waits. ✓ Traiter treats one; it stays visible, dimmed, marked ✓ traité | pull — it waits for you to open it |
lm inbox / TUI :inbox |
the same pile for keyboard people. Untreated only, unless --all |
same pull |
| Your webhook (n8n, Make, your own endpoint) | every subscribed event, in seconds. Retried, journaled, replayable — the road to a Teams message or an SMS | push. lm integration add. Forwards from registration onward, never retroactively |
Email (lm notify add) |
one mail per matching event, through a template. Retried, journaled in lm notify deliveries |
live once the deploy sets the SMTP knobs (Email notifications) |
The inbox is per scope, not per person.
- Everyone holding a scope sees all of its decisions.
- A user with no
scope:*role sees every decision. - There is no assignment, escalation or out-of-office.
$ lm inbox
ID WHEN PROCESS MESSAGE ENTITY_KEY
8 10min lyon-client-arrive Nouveau client Camille Roux à Lyon ff1027320a1acbe2646ce1b2d1e4a42111868a75bb30825dc4609d785e6aaa7f
$ lm inbox ack 8
acked.
$ lm inbox
ID WHEN PROCESS MESSAGE ENTITY_KEY
The gesture: what ✓ Traiter is, and is not
✓ Traiter in the PWA and lm inbox ack ID are the same gesture.
- It clears the decision from everyone's untreated pile.
- It is an event,
annotation.decision.acked, timestamped, carrying who acked. A webhook can forward it. - It never writes to your source system (Reversibility). The correction itself is made in the legacy screen.
Silence also emits
Rules catch what happens. The dormancy sweep
catches what stopped happening. A watched workflow follows every document. One that stays in a
non-terminal state past its threshold becomes decision.dormant.<workflow>.
- The threshold counts from lumnik's first observation of the document, not from the source's history.
lm workflow applynames every status value your manifest missed, with its row count. An undeclared status is watched too.- A workflow can also declare a deadline column. A document still in one of the states you list
when its date passes becomes
decision.overdue.<workflow>: Due date.
$ lm observations stats
WORKFLOW WATCHED DORMANT MEDIAN_DETECTION_S
commande-lifecycle 7 5 900
MEDIAN_DETECTION_S is the median time, in seconds, from a document's observed last move to its alert.
What remains, three months later
Events — decisions and acks — are kept 30 days by default (LUMNIK_EVENTS_RETENTION_DAYS).
Three things outlive that window:
| What | Where to look |
|---|---|
| the observation tape: every watched document — first seen, in its state since, alerted when | lm observations list (--workflow NAME for one); per workflow: lm observations stats |
your webhook target: forward decision.* and annotation.* to the tool that keeps your proof |
your tool, on your retention |
| the ingested tables themselves | lm entity get, lm view |
Wire the webhook on day one
It forwards from registration onward, never retroactively. If an auditor may ask "prove this alert was handled", register it the day you deploy.
Named limits, in one place
- No push to user surfaces. The tab and the CLI are pull. The webhook is the road to tools that push. Integrators also have a live event stream on the platform API.
- The inbox is per scope, time-ordered, without assignment or severity.
- ✓ Traiter never writes to the source.
- Webhooks forward from registration onward, never retroactively.
- A Process does not evaluate rows that existed before it was applied. Only later inserts and source changes can trigger it.
- Declared status aliases (encours/EC…) serve the dormancy watch and the chat's background knowledge. The chat's SQL and the view filters match the literal values in the column.
- Email stays mocked until the deploy sets the SMTP knobs.
- No usage dashboard. The only proxy is the operational metrics at
/q/metrics, per endpoint, if your ops scrape them.
See also
Outputs — the roads out — the wiring manual for every channel on this page · Processes — react · Inbox — decide · Workflows — declare · The PWA · The WOW, step by step — Act 2 runs this whole chain on the demo dataset, EN LITIGE included.