{"slug": "mullet-of-log-processing-determinism-in-the-front-ai-at-the-back-expanso-jev", "title": "Mullet of Log Processing: Determinism in the Front, AI at the Back (Expanso/Jev)", "summary": "Expanso and TypeSafe published a GitHub demo showing that Jev, TypeSafe's AI judgment model, classified an INFO-level log line reading \"config reload requested by unknown actor\" as a warning with a severity confidence score of 0.74 and an actionability score of 0.72, routing it to NOTIFY where a severity-only baseline would have sent it to ARCHIVE. The demo runs in three stages on Expanso Cloud and Expanso Edge, giving Jev context including a ten-minute occurrence counter, time since first occurrence, and prior routing decisions, while a level/service/raw-message allowlist bypasses the model for known benign records such as \"GET /health 200 2ms\". The authors state the scores are not calibrated probabilities or a claim of detection accuracy, only a record of how a particular answer produced a particular route.", "body_md": "The log line says `INFO`:\n\n```\nconfig reload requested by unknown actor\n```\n\nWould you archive it and move on?\n\nIn our Expanso and Jev demo, a severity-only rule would do exactly that. It maps `ERROR` to page, `WARN` to notify, and `INFO` to archive. But when Jev evaluated this record with the context assembled by the pipeline, it returned a warning classification and an actionability score that sent the record to **NOTIFY**.\n\nThat is a useful disagreement to inspect. It does not establish that someone attacked the service, or that the model is always right. It shows why the log level alone can be an incomplete basis for deciding what deserves attention.\n\nWe built this demo to make that decision visible, down to the input record, the model’s answer, the routing rule, and the destination file. The [source and setup instructions are available on GitHub](https://github.com/expanso-io/demo-expanso-jev).\n\n## Start with a baseline you can compare\n\nThe demo moves through three stages. First, synthetic logs arrive and are kept as written. Next, an Expanso pipeline structures and archives them. Finally, we deploy a version of that pipeline that adds contextual judgment through [Jev by TypeSafe](https://typesafe.ai/).\n\nExpanso Cloud manages the pipeline deployment; Expanso Edge executes it on the connected node. The presenter’s board runs locally and displays the records written by the pipeline.\n\nEach record carries the result of the same simple baseline: where would severity-only routing have sent this exact input? That lets us compare the baseline with the model-assisted decision one record at a time.\n\nFor the configuration-reload example, the saved receipt shows a warning classification, a severity confidence score of 0.74, and an actionability score of 0.72. The pipeline’s configured gates selected NOTIFY. The baseline selected ARCHIVE.\n\nThese are the scores from that recorded run, with its accumulated context. They are not calibrated probabilities or a claim of detection accuracy. Their value here is that you can inspect how a particular answer produced a particular route.\n\n## Give the model the context you can compute\n\nA repeated event can deserve a different response from an isolated one. A restart after a deployment and repeated restarts within a few minutes may have the same message text, but the on-call engineer needs to know about the pattern.\n\nThe pipeline prepares that context before asking Jev for a judgment. It shapes the record, computes a fingerprint, and calls a small counter service that tracks occurrences in a ten-minute window. The request to Jev includes the original level, service, and message, along with the occurrence count, time since the first occurrence, and previous routing decisions.\n\nJev answers constrained questions about actionability, severity, likely owning team, and how much the recurrence pattern increases concern. The pipeline then applies explicit rules to those answers.\n\nThis division keeps the mechanics inspectable. Counting occurrences does not require inference. Deciding whether a pattern deserves attention may benefit from it. You can change the context or the routing thresholds and examine the effect without handing the entire processing workflow to a model.\n\nThe counter in this example keeps its state in memory. A production implementation would need a deliberate choice about where that state lives, how long it persists, and what happens when a node restarts.\n\n## Skip inference when a precise rule is enough\n\nThe demo does not send every log to Jev. A small allowlist identifies known benign records and archives them without a model call.\n\nOne entry is an `INFO` message from the API service:\n\n```\nGET /health 200 2ms\n```\n\nChange the response code:\n\n```\nGET /health 500 2ms\n```\n\nNow it no longer matches, so the pipeline asks Jev to judge it.\n\nThe implementation detail matters: the bypass matches the **level, service, and raw message**, exactly. It does not use the normalized fingerprint. The fingerprint removes numbers to group recurring patterns, which would make it a poor safety boundary for a rule that needs to distinguish a 200 response from a 500.\n\nNovel `INFO` messages also reach Jev, as do the demo’s `WARN` and `ERROR` records. Bypassed records still go to the archive; bypassing inference does not mean dropping data.\n\nOn a real log stream, an exact-string allowlist would need maintenance. Bounded rules such as a successful health check below a specified latency may be more useful. Start with records you understand well, write the rule narrowly, and test changed values before broadening it. The share of traffic that avoids inference will depend on that rule set and the actual input mix.\n\n## Make the routing policy explicit\n\nThe demo has four final destinations: PAGE, NOTIFY, REVIEW, and ARCHIVE. They are local JSONL files with those names, so you can inspect what the pipeline wrote.\n\nThe model supplies judgments; the pipeline selects the destination. For example, a critical classification with severity confidence of at least 0.85 selects PAGE. An actionability score of at least 0.7 with severity confidence of at least 0.5 selects NOTIFY. Other gates catch uncertainty and scores near decision thresholds for REVIEW.\n\nThose thresholds are example policy, not universal on-call advice. A team adopting this pattern should test them against labeled incidents and routine traffic, and inspect both missed events and unnecessary escalations. A plausible explanation from a model is not sufficient evidence that a routing decision was useful.\n\nThe configuration-reload example is a good place to start that review. You can see the original `INFO` label, the contextual answer, and the rule that changed the route. That is more actionable than a dashboard that shows only an aggregate count of “AI detections.”\n\n## Exercise the failure path, too\n\nThe walkthrough deliberately breaks the connection to Jev using a local fault-injection gate that returns a simulated 503 response. The failed requests exercise the pipeline’s configured handling for an unavailable model.\n\nRecords waiting for a judgment enter a hold-and-retry path. Retries wait between two and four seconds, with jitter, and stop at a configured limit. Records still unanswered at that limit go to REVIEW. Known benign traffic can continue through the bypass without waiting for a model response. Restoring the link lets held records be evaluated again.\n\nThis is an important part of the example because a model dependency can fail independently of the data source. You need to decide what happens to incoming work before that failure occurs.\n\nThe demonstration uses an in-memory buffer and local files. It does not establish durable delivery, exactly-once processing, or zero loss across a crash. It also does not prove that an external paging or messaging service received anything. Those require separate output integrations and end-to-end failure testing.\n\n## Try the decision on your own records\n\nThe [log-triage README](https://github.com/expanso-io/demo-expanso-jev/tree/main/demos/01-log-triage) describes the setup, Cloud-managed deployment, synthetic source, and controls. The [pipeline configuration](https://github.com/expanso-io/demo-expanso-jev/blob/main/demos/01-log-triage/pipeline-recurrence.yaml) contains the bypass, model questions, routing gates, and retry path.\n\nFor a first evaluation, choose a small set of records with outcomes your team can explain. Include a routine health check, a changed response code, a concerning message logged at `INFO`, and a repeated event. Write down where each should go, then compare those expectations with the pipeline’s receipts.\n\nKeep the baseline visible. Inspect the disagreements. Test what happens when the model does not answer. That gives you something concrete to improve before you let a new decision process influence an on-call workflow.", "url": "https://wpnews.pro/news/mullet-of-log-processing-determinism-in-the-front-ai-at-the-back-expanso-jev", "canonical_source": "https://expanso.io/blog/log-triage-expanso-jev/", "published_at": "2026-09-21 18:35:55+00:00", "updated_at": "2026-09-21 18:54:01.485661+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "mlops", "developer-tools"], "entities": ["Expanso", "Jev", "TypeSafe", "Expanso Cloud", "Expanso Edge", "GitHub"], "alternates": {"html": "https://wpnews.pro/news/mullet-of-log-processing-determinism-in-the-front-ai-at-the-back-expanso-jev", "markdown": "https://wpnews.pro/news/mullet-of-log-processing-determinism-in-the-front-ai-at-the-back-expanso-jev.md", "text": "https://wpnews.pro/news/mullet-of-log-processing-determinism-in-the-front-ai-at-the-back-expanso-jev.txt", "jsonld": "https://wpnews.pro/news/mullet-of-log-processing-determinism-in-the-front-ai-at-the-back-expanso-jev.jsonld"}}