All posts

Observation layer as a runtime

Why system logs break agents — and how Mesh treats the observation layer as a runtime: bounded on the way in, lossless underneath, searchable on demand, and signal-aware before the planner takes its first step.

System logs are one of the hardest inputs for an agent to handle well — not because they’re semantically deep the way source code is, but because they are structurally hostile to context windows.

Mesh log observation pipeline

A single incident easily produces 10k–100k lines: pod logs, event streams, Kubernetes object dumps, controller output, scheduler traces, raw tool responses. The root cause is rarely spread evenly through that volume. It’s usually one line — an OOMKilled, a failed readiness probe, a bad port assignment, an image-pull failure, a permission error, one pod stuck in a state that appears exactly once inside a long listing. And the agent doesn’t control where that line lands: top, bottom, or 40k lines deep in otherwise healthy output.

Giving the model “more context” doesn’t fix it. A 100k-line log can be ~1.5M tokens; even with a huge window, you’ve now asked the model to find a sparse causal signal in a long, repetitive, noisy sequence — attention cost grows as n², and retrieval turns positional, overweighting what’s easy to see (the ends) over what’s causally important (often the middle). That’s the measured “lost in the middle” effect: a >30% accuracy drop, not a rounding error. Model attention cost increases as n², where n is the number of tokens in the context, and most current agent memory systems and harnesses are built to mitigate that.

So the real question for a systems agent isn’t how much context the model can hold. It’s what reaches the model, and how the signal gets surfaced before the agent even knows what to search for — in short, it’s about tuning the signal-to-noise ratio that reaches the agent.

How we think about it at Cerebral

Mesh observation layer as a runtime

Mesh treats the observation layer as a runtime, not storage — context is something you engineer on the way in, not a clipboard you dump output onto.

At a high level, two things happen to every tool observation:

  • a signal-aware digest is pushed into the model’s context — shaped to surface likely failure signals before the model knows what to look for;
  • the full, lossless output stays pulled-on-demand — searchable, with exact lines available for verification and citation.

Push answers the cold-start problem (the agent sees candidate anomalies without first naming a query). Pull answers verification (it can still inspect the exact surrounding lines). Truncation gives you neither; pull-only gives you only the second.

Shaping the digest comes down to trusting the right signals in the right order — severity, rarity, and position — where position is the one that lies. Small outputs pass through untouched. Repetitive structure is compacted so the rhythm collapses and rare lines surface themselves. High-severity and rare lines are preserved explicitly, wherever they sit. Positional truncation is the last resort, never the default — because in infrastructure, position is often uncorrelated with cause. kubectl output is sorted by name or namespace, so where the failing pod lands is decided by its name, not the fault. In a sorted listing, position is noise.

One principle underneath all of it: preserve structure before you bound anything. Every signal heuristic — splitting lines, compacting repetition, scanning severity, counting rarity — presupposes structure. Lose it early and they all silently no-op while the pipeline still emits an observation that looks fine.

One of the key differences between proactive and reactive systems is when the issue becomes legible. If you already know “Instagram OAuth is down,” it is straightforward to regex through logs and confirm it. The hard part is noticing that failure signal in the first place as it arrives inside a high-volume, mostly healthy stream. That cold-start detection problem is what we focus on with Mesh.

The landscape

There are three common answers today, and each was built for a different problem.

Truncation (head/tail). Keep the ends, drop the middle. Cheap and universal — and exactly backwards for logs, where the ends are boilerplate (startup, steady state) and the middle is the incident. Its worst trait is silence: the agent doesn’t announce “I lost the important line.” It anchors on a plausible surviving line and builds a confident, coherent, wrong diagnosis.

Pull-based discovery (e.g. Cursor’s Dynamic Context Discovery). Don’t truncate — write the large output to a file and let the agent inspect it incrementally with tail/grep/targeted reads. Lossless and elegant, and a great fit for code, where there’s almost always a handle to chase: a stack trace names a file, a test names a function. But logs rarely hand you a handle. Pull has a cold-start blindness — it assumes a query, and the agent’s first step has none. You can’t grep for an anomaly you can’t yet name.

Template mining (LogPAI / Drain). Parse the stream into templates and collapse repetition — Received block <*> size <*> ×1000. This is powerful because it makes rarity computable: once the background rhythm collapses, a line that fired once stands out against ten thousand that didn’t, with no labels required. But template mining is a parsing technique, not a context strategy — it tells you how to compress structure, not what should reach the model or how to keep the raw evidence reachable afterward.

Each is a piece. None is the whole answer for an agent debugging live infrastructure.

What we found

Three findings from our log-heavy SRE / Infrastructure Engineering benchmarks made this concrete.

Loghub benchmark results

Our Loghub benchmark dataset corpus comes from arxiv.org/abs/2008.06448: “Jieming Zhu, Shilin He, Pinjia He, Jinyang Liu, Michael R. Lyu. Loghub: A Large Collection of System Log Datasets for AI-driven Log Analytics. IEEE International Symposium on Software Reliability Engineering (ISSRE), 2023. arXiv:2008.06448.”

The middle really does get lost. In one task the real fault sat around line ~4000; a positional view surfaced an earlier anomaly-looking line instead, and the model produced a fluent diagnosis with almost no overlap with the actual root cause.

Observation quality is not the same as model quality — and it’s easy to confuse them. We once had the observation layer receive a tool result in a nested shape it didn’t unpack; the output collapsed into an unstructured blob, signal-preservation had nothing to work on, and the failing component fell out of view. Same logs, same model — different observation handling, a different answer. The model was never the problem.

The dangerous failure is the confident one. A lossy observation layer doesn’t make the model abstain; it makes it anchor on whatever salient line survived and rationalize around it. Across our runs, nearly every wrong case still produced a specific, confident diagnosis — and the outcomes were bimodal: the model either nailed it or scored zero, with little in between. That bimodality is itself a tell — a U-shaped result distribution is usually an observation problem wearing a reasoning problem’s clothes. Coherence is not correctness, and with a lossy observation layer, coherence is actively misleading.

The principle

For code agents, the repository supplies the navigational structure — test → trace → file → symbol — so pull-based discovery works because the handle usually exists. For systems agents, the observation layer has to create the handle first: surface likely anomalies, compact the background rhythm, and keep the raw evidence searchable.

That’s the difference between an agent that reads logs and one that merely receives them. Receiving means pasting or truncating tool output and hoping the model notices the important part. Reading means an observation layer that understands the shape of infrastructure output — repetition, rarity, severity, position, structure, and the need for exact evidence on demand.

Logs break agents when context is treated as storage. They become tractable when context is treated as a runtime: bounded on the way in, lossless underneath, searchable on demand, and signal-aware before the planner takes its first step.