Sifting by Example
Four domains. Same mechanism. Each example: a problem, a pattern, a graph, and a result you can run in the playground.
Quick DSL guide: stage e1 { ... } defines an event slot. e1.type = "login" matches an edge with that label and value. e1.user -> ?user binds the target to a variable. ?user in a later stage creates a join (same entity). @3 means time 3. unless between e1 e2 { ... } means "these events must NOT occur between stages e1 and e2."
| Time | ~10 minutes |
| Prerequisites | What is Sifting? |
1. Narrative: Broken promise
Problem: A character promises something, then breaks that promise, with no fulfillment between.
Result: 1 match — Macbeth promised Duncan and then betrayed him. Banquo also promised and later betrayed Macbeth, but fulfilled the promise first (time 4), so the negation kills that match.
What to notice: The variable ?char joins the actor across both stages. The unless between clause requires the same actor and recipient to have fulfilled the promise — a random fulfillment by someone else doesn't count.
2. Observability: Cascade failure
Problem: Service A calls B, B calls C, and C times out. No recovery event (successful retry) follows.
Result: 1 match — the api_gateway → auth_service → user_db chain timed out with no recovery. The cache_service → redis chain also timed out, but redis recovered at time 8, so unless after kills that match.
What to notice: The variable chain ?svc_a → ?svc_b → ?svc_c traces the call path through shared bindings. The unless after negation is open-ended — it checks from the timeout forward, not between two fixed events.
3. Compliance: Four-eyes violation
Problem: The same person both initiates and approves a transaction — violating the four-eyes principle (dual control).
Result: 1 match — Alice both initiated and approved txn_100. Bob initiated txn_200 but Carol approved it (different people), so no violation.
What to notice: This pattern has no negation — the match itself is the violation. The join on ?person is what makes it work: the same actor in both stages means dual control failed. No negation needed because there is no "exception" here — the pattern completing IS the problem.
4. Process mining: Stuck order
Problem: An order was placed and shipped, but never confirmed as delivered — with no cancellation between.
Result: 1 match — order_500 was placed and shipped but never delivered. order_501 was delivered (time 6), so unless after kills that match. order_502 was cancelled before shipping, so unless between prevents stage 2 from being reached.
What to notice: Two negation windows working together. unless between e1 e2 catches cancellations during processing. unless after e2 catches the missing delivery. The variable ?order threads through everything, ensuring each negation checks the same order.
The pattern across all four examples
Every example uses the same three primitives:
| Primitive | Narrative | Observability | Compliance | Process Mining |
|---|---|---|---|---|
| Stages | promise → betray | call → call → timeout | initiate → approve | placed → shipped |
| Variable joins | same actor, same target | call chain via caller/callee | same person, same transaction | same order |
| Negation | no fulfillment between | no recovery after | (none needed) | no delivery after, no cancel between |
The mechanism is identical. The domain vocabulary differs.
Where to go next
- Getting Started — Build this in Rust, from
cargo newto working code. - Pattern Cookbook — More pattern recipes with matching and non-matching graphs.
- Pattern Playground — Full playground with 12 presets to explore.