DEV Community

Cover image for My AI agent got dumber mid-session. I measured the context window before blaming MCP.
Rapls
Rapls

Posted on • Edited on

My AI agent got dumber mid-session. I measured the context window before blaming MCP.

History bloat vs minimal tool overhead

There's a particular way an AI coding agent goes bad. Not a crash, not an error. It just gets duller. Halfway through a long session it forgets a constraint you set early, repeats a question you already answered, or starts giving you shorter, vaguer replies to the same kind of ask it handled well an hour ago. You can feel the quality sag without anything actually breaking.

My first instinct was to blame MCP. I had a few servers connected, I'd read that connected servers eat the context window, so the story wrote itself: too many tools loaded, no room left to think, of course it's drifting. I was about to start disconnecting things. Then I decided to measure first, and the measurement didn't say what I expected.

I read the breakdown instead of guessing

The agent I use can print a breakdown of what's currently filling the context window, by category. So before cutting anything, I looked at where the tokens were actually going. I'll give this in proportions rather than raw numbers, because the absolute figures depend on the model and window size, and the shape is the part that transfers.

Roughly, in a session that had started drifting:

  • Conversation history (the back-and-forth so far): the single biggest slice, around a fifth of the whole window on its own
  • Fixed startup overhead (system prompt, tool framework, memory files): a meaningful chunk, but stable and one-time
  • Connected MCP tool definitions: a small slice. Smaller than the rounding error I'd been worried about

The thing I was about to blame was near the bottom of the list. The thing I hadn't thought about, the plain accumulation of conversation, was the top.

Why the MCP assumption was half right

I want to be careful here, because "MCP doesn't cost anything" would be the wrong lesson, and it's not what I found.

MCP can be heavy. A connected server can load its full tool schema and carry it on every turn, and if your client loads all of that up front, a handful of servers really can take a large bite out of the window before you type a word. That version of the warning is real, and plenty of people have measured it on their own setups. So if you connect many servers and your client front-loads their schemas, the usual advice to disconnect what you don't use is sound.

What I'd add is narrower: it depends on how your client loads tools. Some setups defer the schema and only pull a tool's definition in when it's actually needed. In a setup like that, idle connected servers cost much less than the worst-case number suggests, and on the session I measured, they weren't my bottleneck. The general claim "MCP is expensive" and my specific result "MCP wasn't what filled my window" aren't in conflict. They're about different loading behavior. The honest takeaway isn't "MCP is innocent," it's "don't assume which line item is the problem, because it varies by setup."

What was actually filling it

The slice that grew without me noticing was conversation history. It makes sense once you see it: every exchange stays in the window, and a long exploratory session piles up turn after turn until the early context is competing for space with the part the model needs right now. Nothing dramatic added it. It was just the steady weight of a long conversation, and it was the part I hadn't thought to look at because it didn't feel like a "feature" I'd switched on.

That reframed the drift for me. The agent wasn't getting dumber because of what I'd connected. It was getting dumber because I'd been having one very long conversation, and the room to reason was slowly filling with the transcript of that conversation.

What I do about it now

None of the fixes are clever. They're just the things that follow once you know history is the heavy part.

I don't let one exploratory session run forever. When a thread of work is basically done, I start fresh instead of carrying the whole transcript into the next, unrelated task. When I do need continuity, I have the agent summarize where things stand and carry the summary into a new session, rather than dragging the entire history across. The point is to move the gist, not the full back-and-forth, because the full back-and-forth is exactly the weight I measured.

The mental model that stuck: the context window is a desk, not a filing cabinet. Everything you want the model to use at once has to fit on the desk's surface, and a long conversation slowly covers it with paper until there's no room to work. Clearing the desk is sometimes better than buying a bigger one.

The actual lesson isn't about MCP

If I'd followed my first instinct, I'd have disconnected a few servers, freed up a small slice, watched the drift continue, and learned nothing. The fix would have missed the cause, and I'd have blamed the tool I'd primed myself to blame.

So the thing I'm keeping isn't "history is always the culprit," because on someone else's setup it really might be the connected servers, or the memory files, or something I'm not thinking of. The thing I'm keeping is the order of operations: when the agent starts drifting, read the breakdown before you cut anything. The line item you're sure is the problem and the line item that's actually the problem are often not the same, and the only way to tell them apart is to look.

A note to my next self

When the agent gets dull mid-session, don't reach for the explanation you already have. Measure first. Read where the tokens are actually going, fix the slice that's actually large, and accept that it varies by setup so last time's culprit isn't a rule. For me it was conversation history, so I keep sessions shorter and hand off a summary instead of a transcript. Next time it might be something else, which is the whole reason to look instead of guess.

I build WordPress plugins and write about AI tooling and security at https://raplsworks.com/.

Disclaimer: The experiences and decisions in this post are my own. English isn't my first language, so I use an AI assistant to help draft and edit the writing.

Top comments (85)

Collapse
 
0xdevc profile image
NOVAInetwork

This matches what I hit on a long agentic coding session yesterday. The fix that worked for me is upstream of clearing: I do not let the agent accumulate the reasoning in the first place.

I run consensus-critical work in phases, recon, plan, implement, and force the agent to write each phase out to a markdown artifact, then I review it and it carries forward the artifact, not the full back-and-forth that produced it. The transcript of how it figured something out is the heavy part you measured, and most of it is not load-bearing once the conclusion is written down. So the desk stays clear because the thinking lives on disk, not in the window.

The other thing that helps: re-ground against source each phase instead of trusting earlier context. If the agent re-reads the actual file before editing it, a slightly stale window matters less, because the ground truth is the repo, not the conversation.

Agreed hard on measure-before-cutting though. I almost blamed MCP for a slowdown once too, and it was history.

Collapse
 
rapls profile image
Rapls

"The thinking lives on disk, not in the window" is the upgrade to what I wrote. My post was about clearing accumulated reasoning; you're pointing out the reasoning never had to accumulate in the first place. The transcript of how it reached a conclusion is the heavy part, and you're right that almost none of it is load-bearing once the conclusion is written down. Clearing is paying down a cost; phasing to disk is never taking it on. Same move as the handoff, just done continuously instead of once at the end.

The re-ground-against-source point is the half I'd underweighted, and it changes what "stale context" even means. If the agent re-reads the actual file before editing, the window being slightly out of date stops being dangerous, because the window was never the source of truth, the repo was. That's the quiet failure mode behind a lot of "the agent got dumber" reports: not that the window filled up, but that the agent started trusting its own summary of the file over the file. Re-reading collapses that gap every phase. Artifact for the conclusions, repo for the ground truth, window for neither. Good thread, this is the version of the idea I'll be stealing.

Collapse
 
0xdevc profile image
NOVAInetwork

Clearing is paying down a cost; phasing to disk is never taking it on" is a cleaner framing than I had it. That is the distinction exactly.

On the re-grounding half: the failure I kept hitting is subtler than a stale window. It is the agent trusting its own summary of a file over the file, like you said, but the dangerous version is when the summary is mostly right. A summary that is obviously stale gets caught. One that is 90 percent right is what slips a wrong edit through, because nothing trips an alarm. So I stopped treating re-read as a freshness check and started treating it as mandatory before any edit, every phase, no exceptions, even when the window "should" be current. The window being right most of the time is what makes trusting it dangerous.

The part I am still working: re-reading the file gives you ground truth on the code, but not on the decisions. The repo tells you what the code is, not which approach you already rejected and why. That is the gap a plain re-read does not close, and it is where the decision-state record you and the others in this thread are circling has to carry the weight the repo cannot.

Collapse
 
jugeni profile image
Mike Czerwinski

"The thinking lives on disk, not in the window" — that's the upgrade in one line.

Extending it to the judgment layer: not just thinking, decisions too. A decision with a lifecycle status (proposed → accepted → locked) on disk means the next session doesn't re-litigate it from window memory — it consults state. Same principle as your reply, different artifact. Same reason it works: the window stops being asked to hold what it was never good at holding.

Collapse
 
jugeni profile image
Mike Czerwinski

This is the line that reframes the whole thread. Extending it: the repo holds code truth, but there's a parallel store needed for judgment truth — which architectural calls got made, which got reversed, which are locked. Without it, every session re-litigates the same decisions because the model has no record they were settled.

Your artifact-first pattern carries this implicitly (each phase becomes an inspectable record). Making the decision-state explicit and addressable — separate from code, separate from prose summaries — is the missing layer for me.

Collapse
 
0xdevc profile image
NOVAInetwork

"Parallel store for judgment truth" is the right name for it, and the reason it has to be separate from the repo is that the two stores have different lifecycles. Code truth is overwritten, the latest commit wins and history is archive. Judgment truth is additive, a rejected approach stays relevant precisely because it was rejected, and a future session needs to see the rejection, not just the survivor. A git log does not carry that, it shows what won, not what was ruled out and why.

Where I have landed: the decision record needs the reversed and superseded entries to stay first-class and addressable, not pruned, because the value is in the path not the endpoint. The thing I am still wrestling is keeping it from rotting. A decision store nobody trusts is worse than none, because the model cites a stale "locked" entry with false authority. So the addressability you are after only pays off if the status stays honest, which loops back to the operator-owned-transition point from the other branch of this thread. Same missing layer, and the hard part is not building it, it is keeping it true.

Thread Thread
 
jugeni profile image
Mike Czerwinski

„The value is in the path not the endpoint" — that's the line I'd been missing the framing for. Code truth is overwritable because the latest commit IS the endpoint; judgment truth has to keep the path navigable because rejected branches stay informative. Two stores, two lifecycles, not because someone decided to split them but because they were never the same shape to begin with.

The staleness loop you're naming is the hardest part — agreed. Across this thread it's shown up four times now: Rapls's status field, Scarab's diagnostic criteria, the lifecycle of authored entries themselves, and now your judgment store rotting. Same problem at every level — addressability without an honest status mechanism is just an indexed archive of confident lies. The transition-ownership split (operator owns locks, agent can propose) is the only thing that's held for me, but I won't claim it scales past medium-sized repos yet.

Curious if you've seen the same shape in distributed systems work — persistent decisions about cluster state, validator behavior, consensus reversals. That's a domain where „what got ruled out and why" presumably matters as much as „what's currently winning." Different threat model, same store shape.

Thread Thread
 
0xdevc profile image
NOVAInetwork

Yes, and it is even sharper in consensus work, because there the "rejected branch stays informative" idea is not a metaphor, it is the actual data structure. A block can earn a quorum certificate in one round and then be abandoned by a view change, and the certified-but-abandoned block does not stop mattering. A node that only keeps "what is currently winning" will happily re-adopt the abandoned branch later and fork itself. The whole safety argument depends on remembering what was ruled out and why, not just the current tip.

I hit exactly this recently. A node committed a block that had a valid certificate but had lost a same-height view change, because the path that finalized it only checked "does this have a certificate" and not "is this still on the canonical branch." The fix was, in your terms, making the store keep the path navigable: finality had to walk the descendant chain, so an abandoned branch with no canonical children can never be re-finalized. The endpoint alone was not enough information. The path was the safety property.

So the threat model is different from agent judgment-drift but the store shape is identical: addressability of the losers, with an honest status that says abandoned-but-retained, not deleted. And your staleness point bites here too. A node trusting a stale "locked" view of which branch is canonical is precisely how it diverges. The transition authority in consensus is a quorum rule rather than an operator, which is the one place it does scale past medium repos, because the honesty of the status is enforced by math instead of discipline. That might be the interesting transfer back the other way: agent decision stores are missing the equivalent of a quorum, a way to make a status honest without a human holding the line.

Thread Thread
 
jugeni profile image
Mike Czerwinski

The quorum-as-transition-authority transfer is the strongest move I've seen all thread. Math instead of discipline is exactly the line — operator-owned status flipping doesn't scale because there's only one hand on the lever, but quorum doesn't need a hand at all. Honest status as an emergent property of multiple observers agreeing, not as a discipline anyone has to hold.

The translation back to agent decision stores is non-trivial because we don't have natural quorum participants — one repo, one agent, one operator. But the pattern points at something: multiple weak signals (diagnostic test passing, prompt history not contradicting, external scan agreeing, git log consistent) that together earn enough weight to authorize a transition without operator action. Not a full BFT quorum, but a synthetic one assembled from independent diagnostic surfaces. Different shape than my current setup, where the alarm fires once and either the operator catches it or doesn't.

Your block-with-certificate-but-lost-view-change example is also the cleanest concrete I've seen for why path navigation matters — finality can't just check the endpoint, has to walk the descendants. Going to credit this thread in the next post I'm writing about decision stores if you're OK with that. The math-vs-discipline framing in particular deserves its own line in print.

Thread Thread
 
0xdevc profile image
NOVAInetwork

Credit it, please do, I would be glad to see the math-vs-discipline line in print. One thing to carry with it if you do: the synthetic-quorum idea you just described (diagnostic test, prompt history, external scan, git log as independent observers that together earn a transition) is the actual translation, and it is yours, not mine. I only pointed at the consensus analogy. What you added is the hard part, that the observers have to be genuinely independent or you have not built a quorum, you have built one signal wearing four hats. A real quorum tolerates one liar; four correlated diagnostic surfaces do not. So the open problem for your post is independence: how do you know your four signals are not all downstream of the same stale assumption. That is the thing that decides whether the synthetic quorum is real or theater.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Crediting it. Independence is the right open question, and it's the one I keep landing on too — four signals downstream of the same operator blind spot is one signal in costume. I don't have a clean answer yet; the honest move there is probably treating independence as a property you measure (do these surfaces ever disagree?) rather than one you assume. Going to think about it properly and write back. Thanks for the sharpening.

Thread Thread
 
0xdevc profile image
NOVAInetwork

"Independence as a measured property, not an assumed one" is the right reframe, and it's a higher bar than it sounds: measuring whether surfaces ever disagree only works if they're exposed to inputs that could split them. Two checks that always see the same input will always agree, and you will read that as independence when it's really just shared exposure. So the measurement needs adversarial inputs designed to make them disagree, not just observation of normal traffic. Look forward to what you land on, this is the right thread to keep pulling.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Right, shared exposure is the trap. Two surfaces fed identical input will agree by construction, and reading that as independence is the same category of error as reading high effective confidence as truth. Independence proves itself only when the inputs are designed to split the surfaces, which means the test has the same shape as planted-fault: deliberate construction of cases where divergence is possible, then observation of which surfaces actually diverged.

The wrinkle one floor up: the inputs you can design adversarially are bounded by your own understanding of the failure modes. The dangerous failure modes are the ones the designer did not model, so handcrafted adversarial sets share their designer's blind spots. You can stretch this with randomized generation, perturbation, mutation, property-based fuzz, but at some level you accept that independence verification is bounded by the imagination of whoever specified the adversarial space. Which is honest if you name it, and a different category of failure if you don't.

So independence-as-measured is the right reframe, independence-as-adversarially-tested is the sharper version, and „we ran the tests we knew how to design" is the honest stage marker that sits underneath both. Same thread, three floors deeper than where I had it. Will keep pulling.

Collapse
 
rapls profile image
Rapls

This is the layer I keep circling too. The artifact-first pattern gives me a record per phase, but in practice it stays append-only: it captures what got decided, not what later got overturned. So sessions re-litigate not because there's no record, but because the record never says which entries are dead. The missing piece isn't only making decision-state addressable, it's giving each call a status (open, reversed, locked) so a stranger can tell settled from reopened without re-reading the whole thread. Judgment truth needs a status field the same way error states do.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Exactly the missing piece. Status field that stays honest is the load-bearing thing — append-only without lifecycle just trades one drift for another (you stop forgetting decisions, but you start treating reopened ones as settled).

What I've been running with: proposed → accepted → locked → rejected → superseded. The two that pull weight are locked (binding, fires a drift alarm when a new prompt contradicts it) and superseded (kept addressable but no longer authoritative, with a pointer at the decision that replaced it). Without superseded the reversed entries become invisible — exactly the failure mode you named.

Open question I'm still solving: who flips the field. If it's the operator manually, the discipline breaks the moment a session goes long. If it's the agent, you're trusting the model with judgment-state, which is the problem we started with. I've been splitting it — operator owns transitions to/from locked, agent can propose superseded when it spots contradiction, but the transition stays human. With your artifact-first phases, do you let the agent ever flip its own status, or does it stay strictly operator-side?

Thread Thread
 
0xdevc profile image
NOVAInetwork

Strictly operator-side for the binding transitions, same split you landed on, and I got there by being burned the other way. The agent can propose superseded when it spots a contradiction, and it is genuinely good at that, surfacing "this new instruction conflicts with a locked call." But the flip to locked stays with me, because the moment the agent owns its own judgment-state you are back to trusting the thing whose drift was the original problem.

The refinement that made operator-owned status survive long sessions: I do not let the agent flip the field, but I make it cite the entry it thinks is being contradicted, by id, before I rule. The agent does the detection, I do the authority step. That keeps me fast without re-reading the whole thread, which is the exact thing that breaks manual status-keeping at hour ten.

The honest unsolved part is the one you named: the operator is the weak link on a long session, not the model. A locked entry that fires a drift alarm has saved me from re-deciding at hour twelve something I had settled at hour two. So the alarm is doing the work my own discipline cannot at that point. I have not solved operator fatigue, I have just moved the failure into something that shouts.

Thread Thread
 
jugeni profile image
Mike Czerwinski

„Agent cites by id, operator rules" is the refinement I'd been improvising around without naming. Detection in the model's strength zone, authority in mine — adopting that exact split. Cleaner than what I had.

„Moved the failure into something that shouts" is the trade I keep coming back to too. Operator discipline doesn't scale past some hour, so it has to be relocated into something that will interrupt the operator when they would have drifted. The locked-decision alarm is doing exactly that. The honest version of operator discipline at hour twelve isn't more vigilance — it's outsourcing vigilance to the alarm and trusting it more than I trust myself.

Thread Thread
 
rapls profile image
Rapls

The "cite the contradicted entry by id before I rule" step is the part I hadn't nailed down. That's what keeps operator-owned status alive at hour ten without re-reading the thread. The detection-versus-authority split is the right cut: the agent is good at spotting the conflict, bad at being trusted to resolve it. And yeah, the operator is the weak link on a long session, not the model. Moving the failure into something that shouts is about the most honest version of solving it. The drift alarm does the work discipline can't by hour twelve.

Thread Thread
 
0xdevc profile image
NOVAInetwork

"Outsourcing vigilance to the alarm and trusting it more than I trust myself" is the honest version, and it is uncomfortable to say out loud, so I respect that you did. The thing I am watching now is alarm trust drift the other way: once you lean on the locked-decision alarm, a missing alarm starts to read as "all clear" when it might just mean the rule was never encoded. So the next discipline for me is auditing the alarms themselves, not just heeding them. The vigilance does not disappear, it moves up one level, from watching the work to watching whether the alarms still cover the work.

Thread Thread
 
0xdevc profile image
NOVAInetwork

"The agent is good at spotting the conflict, bad at being trusted to resolve it" is the cleanest one-line version of the whole split, better than how I said it. The one thing I would add to "move the failure into something that shouts": the alarm has to shout at the right person. An alarm that fires into the same log the tired operator already stopped reading at hour ten is not relocation, it is the same failure with extra steps. What made it work for me was the alarm interrupting out of band, somewhere I had not already gone numb to. The honest version is not just outsourcing vigilance to the alarm, it is putting the alarm somewhere your hour-ten self cannot ignore it.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Yes — that's the next floor and I was hoping someone would name it. Missing alarm reading as "all clear" is the specific failure mode: an unencoded rule looks identical to a satisfied one from the gate's vantage. Both pass. The cheap version of meta-discipline I've been running is a coverage check — does any new decision in the last N sessions have no corresponding alarm rule? If yes, the alarm set is behind the work, and the gate is technically functional and substantively blind. Vigilance is conserved; it just moves up one floor every time structure catches up.

Thread Thread
 
jugeni profile image
Mike Czerwinski

"Putting the alarm somewhere your hour-ten self cannot ignore it" lands harder than I admitted — my current drift detector fires into the same surface I'm working in, which is exactly the failure you just named. What does your out-of-band actually look like at the operator surface? Second device, separate machine, something else?

Thread Thread
 
0xdevc profile image
NOVAInetwork

The coverage check is the part I'd build first, because it fails safe in the right direction: a stale alarm set throws a false positive (flags a decision that turned out fine), which costs you a review. The blind gate throws a false negative, which costs you the incident. Cheaper error on the cheaper side.

The wrinkle I keep hitting is that the coverage check has the same blind spot one floor up: it can only flag decisions you logged as decisions. The dangerous ones are the changes that never felt like a decision at the time, the "obviously fine" edits that never got an entry to check coverage against. So I've started treating "this didn't seem worth recording" as its own thing worth recording. Does your N-session scan key off an explicit decision log, or are you pulling from diff/commit history to catch the ones that never got written down?

Thread Thread
 
0xdevc profile image
NOVAInetwork

The cheap version that actually works for me is separation of authority, not separation of hardware. The surface doing the work can flag, but it can't clear its own flag, a second surface whose only job is to hold the gate has to sign off, and it has no stake in the work getting done, so it has no hour-ten fatigue to exploit. Physical separation (second device) helps with the "I'll just glance past it" reflex, but the real lever is that the thing that says "go" is structurally not the thing that wants to go. If the detector and the actor share an incentive, you've got one surface again no matter how many screens it's on. So: out-of-band less in the network sense, more in the "different interests" sense. What's your setup, are you splitting across devices, or across roles?

Thread Thread
 
jugeni profile image
Mike Czerwinski

Cheaper-error-on-cheaper-side is the right framing because it makes the asymmetry explicit. Most „should we flag this" debates lose because somebody implicitly counts the two errors as equal. They are not. Coverage check fails toward review cost; blind gate fails toward incident cost. The whole architecture has to honor that gradient or you end up with detection systems that catch the wrong half of failures cheaply.

The one-floor-up blind spot is where the primitive actually lives. Coverage of a log only works on entries that exist; the dangerous edit is the one that never felt like a decision to log. Adding a meta-coverage-of-coverage check moves the problem up one level and runs the same loop until you bottom out on operator-side honesty.

Direct answer on the N-session scan: both, and the gap between them is the signal. Explicit decision log catches what got named as a decision. Diff/commit history catches everything that materialized. The two diverge precisely on the changes you are describing — diff shows the edit happened, log shows nobody marked it either way. That divergence becomes the watchdog observation: „X commits in this window have no decision-link or non-decision tag." That's the absence the system can flag without the operator having to remember to flag it.

Your „this didn't seem worth recording as its own thing worth recording" is the right mitigation in the same shape. You close the absence loophole at the meta layer: every commit gets either a decision-link or a non-decision-tag. Untagged becomes the signal, not silence. The recursion does bottom out though. You can spec non-decisions, you cannot spec non-non-decisions. At some level the system has to trust operator-side categorization, which is why I treat the planted-fault test on the audit itself as the floor under all of this. If the audit never catches a known-fabricated edit, the upper layers don't earn their keep.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Separation of authority by incentive is the structural cut that closes the loophole properly. Devices are surface, different machines run the same loop in the same head if the operator behind both has the same stake. Roles are the real thing because they create asymmetric incentive: the second surface does not want the work to go, so its flag does not decay with hour-ten fatigue. Same primitive several people in this space are converging on under different vocabulary, frame author cannot be attester at the same scale, schema firewall with no exceptions, transport seam where the observer's motive differs from the actor's. All three are the same shape: the thing that says „go" is structurally not the thing that wants to go.

Direct answer on my setup: roles, not devices, and the honest stage marker is that I run solo, so „different interests" lives at temporal axis, not spatial. The actor at hour two who writes the audit entry is structurally different from the actor at hour ten who reads it. Different fatigue, different blind spots, different incentive about whether the work ships. The written record holds the gate; the present-self is bound by what past-self committed to in writing. That is a thinner form of incentive separation than two operators, and it leaks at the seams you would expect, past-self can write entries that future-self can rationalize away, because both selves are the same operator.

The structural mitigation worth naming: at solo scale you cannot get true different-interests separation without a second operator, but you can plant the asymmetry adversarially. Past-self writes commitments that future-self has to either honor or explicitly retract on the record. The retraction itself becomes the artifact. You do not catch the cheat, but you make the cheat leave evidence. Not equivalent to a second authority, and worth naming as a thinner floor. Will keep pulling. This is the part of the thread where the primitive actually has to ship in a substrate, which is where most of these conversations stop.

Thread Thread
 
0xdevc profile image
NOVAInetwork

The planted-fault test as the floor is the right place to bottom out, and I'd push it one notch harder: the planted fault has to be introduced by someone who isn't the person who built the audit, or you get the same operator-honesty leak one level down. A fault I plant to test my own audit is shaped by the same blind spots that shaped the audit, so it tends to land in the region the audit already watches. The version that actually earns its keep is an adversarial fault from outside your own assumptions, the edit you wouldn't think to make. Which turns the floor into a people problem, not a tooling one: the audit is only as good as the most unlike-you person willing to try to slip something past it. Bottoms out exactly where you said, operator-side honesty, just with the added constraint that it can't be the same operator on both sides.

Thread Thread
 
0xdevc profile image
NOVAInetwork

The planted-fault test as the floor is the right place to bottom out, and I'd push it one notch harder: the planted fault has to be introduced by someone who isn't the person who built the audit, or you get the same operator-honesty leak one level down. A fault I plant to test my own audit is shaped by the same blind spots that shaped the audit, so it tends to land in the region the audit already watches. The version that actually earns its keep is an adversarial fault from outside your own assumptions, the edit you wouldn't think to make. Which turns the floor into a people problem, not a tooling one: the audit is only as good as the most unlike-you person willing to try to slip something past it. Bottoms out exactly where you said, operator-side honesty, just with the added constraint that it can't be the same operator on both sides.

Thread Thread
 
jugeni profile image
Mike Czerwinski

"The unlike-you constraint is the right sharpening, and it bottoms out exactly where I'd been trying to figure out: at some point external authorship of inputs and external authorship of the failure criterion both have to come from somewhere outside the loop, and the external authors I keep returning to are reality and a counterparty with skin in the outcome. Adversarial fault from 'the most unlike-you person willing to try' is the counterparty version with the right teeth..." (~110 słów, filter scan passed L-B).

Thread Thread
 
jugeni profile image
Mike Czerwinski

You're right, and it's the same collapse one level down: a fault I author is sampled from the distribution that produced my audit, so it lands where I already look. Self-adversarial testing measures the coverage you have, not the coverage you're missing. The blind spot is invariant under "try harder against yourself," because the trying is drawn from the same manifold.

Where I'd hold a thinner floor than "it has to be a different person": the property you actually need is that the fault generator's distribution is independent of the audit author's, and a person who isn't you is the strongest source of that independence, not the only one. A different model proposing the edit, a fuzzer mutating real inputs, production anomalies replayed blind: each is a cheap proxy for "unlike-you," because none of them share your assumptions about where the audit looks. Not equivalent to a hostile human, but it moves the fault off your own blind-spot manifold, which is the part that was doing the leaking.

So I'd restate your constraint as: the fault and the audit cannot share an author, where author is whatever process generated their assumptions. A different person is the high-strength version. A different model or a different source is the version a solo operator can run today. The people problem is the ceiling. The independent-distribution problem is the floor you can build now, and it sits strictly above "plant your own fault."

Thread Thread
 
0xdevc profile image
NOVAInetwork

the split that matters isn't reality vs a counterparty, it's the kind of fault each one authors. reality is indifferent: it hands you whatever faults happen to occur, in whatever distribution they occur in. a counterparty with skin in the outcome hands you the one fault that specifically breaks you. so they aren't a hierarchy, they're an order of operations. reality finds what's easy to trigger by accident, the adversary finds what needs intent, and the accidental faults are the ones that take you down first because nobody has to be trying. that's what makes the indifferent author worth keeping around: it's cheap and continuous, so you can run it against yourself constantly and clear out the accidental failures before an adversary ever goes looking. the counterparty is the harder bar, but the indifferent floor is the one that earns its keep day to day. where would you draw the line: is there a class of fault only the skin-in-the-outcome counterparty ever surfaces, that no amount of indifferent pressure would?

Thread Thread
 
0xdevc profile image
NOVAInetwork

agreed on all of it, and i think we've actually landed somewhere cleaner than either of us started. "the fault and the audit cannot share an author, where author is whatever generated their assumptions" is the real invariant, and treating independence as a quantity rather than a checkbox is what makes it operational. the ranking falls out of that: fuzzers and replayed real-world anomalies score high on decorrelation because their generating process shares almost nothing with my audit's assumptions, a second model scores lower because it inherited part of my manifold from the same training corpus, and self-planted faults score zero because they're drawn from the exact distribution i'm auditing with. the ceiling stays the hostile human. the floor is "maximize distributional distance from your own audit with whatever independent source you can actually run," and that floor is buildable solo today, which was the whole point. good thread. this reframed how i'll set up the next round of it.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Yes, and the class has a clean membership test: faults whose precondition is knowledge of your assumptions. Indifferent pressure samples from the world's distribution of inputs. A counterparty samples from the distribution of your blind spots, and that distribution cannot be built without reading you: your validator, your docs, your self-model. Reality never reads your validator.

Concrete shapes. An input that passes validation precisely because its author read the validation. A sequence of three individually benign steps whose composition is ruinous, at negligible natural probability but trivially reachable on purpose; accident volume never finds it because accidents do not aim.

One boundary honesty note: coverage-guided fuzzing blurs the line, because feedback-driven pressure is reading you, cheaply. So the split is not tooling and not intent. It is whether the pressure updates on your internals. Indifferent means it never does; counterparty means it does. The faults only the second surfaces are exactly the ones reachable only through a model of you.

Thread Thread
 
0xdevc profile image
NOVAInetwork

the membership test is the crisp version, precondition is knowledge of your assumptions, and "does the pressure update on your internals" is the right axis because it survives the fuzzing objection cleanly. the composition example is the one that stays with me: three benign steps, negligible natural probability, trivially reachable on purpose, because accidents do not aim. the defensive inversion i'd add: if the class is exactly the faults reachable only through a model of you, then the durable defense isn't hiding your internals, that's obscurity and it's brittle, it's making the modeled thing cheap to rotate so their model of you goes stale faster than they can spend it. an attacker who read your validator is only dangerous while the validator still behaves the way they read it. so you assume the counterparty has read you, concede the model, and compete on the update speed of your internals instead of their secrecy. which is a weirdly optimistic place to land: you can't stop being read, but you can make being read depreciate. good thread, genuinely, this is the most useful exchange i've had on here.

Thread Thread
 
jugeni profile image
Mike Czerwinski

The rotation angle only wins if you can name what's cheap to change without also being expensive for anyone honest depending on the same surface. If the thing you rotate is also the thing legitimate integrators read to build against you, rotation is just breaking your own API on a schedule, you've made the attacker's model stale and every honest client's model stale in the same motion. So the design constraint underneath "make the modeled thing cheap to rotate" is finding a layer that only an adversary needs to model precisely, exact thresholds, internal ordering, timing windows, while the legitimate contract stays coarse and stable, accepts or rejects, not the mechanism producing that verdict. That's also the actual race condition: rotation beats modeling only while your update cycle stays shorter than their observation-to-model cycle. Against a one-time reader that's easy. Against a counterparty with standing read access and their own compute budget, it's an arms race with a clock on both sides, and cheap-to-rotate has to mean cheap relative to their re-modeling cost, not cheap in absolute terms.

Thread Thread
 
0xdevc profile image
NOVAInetwork

This split already has a working instance in consensus protocols, and it's worth stealing from because the arms-race clock you're describing is one a chain has to win by construction. A validator exposes a deliberately coarse contract to the outside: a block is final or it isn't, and that verdict is stable forever once it's earned. The precise, modelable machinery, which votes formed a quorum, the exact round timing, which branch got abandoned by a view change, stays internal and rotates every single round. An attacker who models "how did this specific block get certified" has a model that's stale the next round, because the certificate is per-round and the quorum reshuffles. But the honest integrator reading "is this block final" never re-syncs anything, because that contract never moves.

The reason it beats the clock is the part that transfers back to your setup: the rotation isn't a schedule someone maintains, it's emergent from the protocol advancing. Every round produces a fresh quorum whether or not anyone's attacking, so the internal state the adversary has to model depreciates at the chain's own tick rate, for free, continuously. That's the "cheap relative to their re-modeling cost" you're after, except the defender pays nothing to rotate because rotation IS the system running. The attacker pays full re-modeling cost every round; the operator pays zero.
Where it stops mapping cleanly, and this is the open question I'd put back to you: a chain gets that for free because the coarse verdict (finality) is genuinely independent of the mechanism (which quorum, which round). In an agent decision store the equivalent coarse contract is "this decision is locked," and the mechanism is "which signals justified the lock." Are those actually independent, or does the honest consumer of "locked" eventually need to read the justification, at which point the mechanism leaks into the contract and you're back to rotating something integrators depend on? The chain gets away with it because nobody downstream of finality needs to know the vote breakdown. I'm not sure the decision-store equivalent has that clean a separation.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Straight answer: no, decision-store doesn't currently have that clean separation. Consumers of "locked" usually branch on which signals justified the lock, because their downstream action depends on category-of-lock (locked-for-execution ≠ locked-for-review ≠ locked-pending-authorization). Which means today the mechanism leaks into what integrators depend on, and rotation of any signal breaks a downstream reader somewhere.

But redesignable: expose a categorical OUTCOME TYPE (a small closed set of lock-categories) that downstream branches on, without exposing which specific signals produced each category. Signals rotate internally, category-to-consumer contract stays coarse. The design frontier is the size of the category set. Too few categories and the mechanism leaks in edge cases where downstream needs to distinguish sub-cases. Too many and the category set is as internal as the mechanism was, and you've just renamed the leak. Right size is exactly the minimum number of categories that downstream ACTUALLY branches on, no more. Which is a taste question, but at least it's the right question. The chain gets the clean separation for free because "final" happens to be exactly the coarsest useful contract; decision-store has to earn it by design, category by category.

 
jugeni profile image
Mike Czerwinski

yes, and it's not rare, it's structural: the class is faults that live in the exact gap between your model of yourself and what's actually true, because that's the one region indifferent pressure never samples by construction. a fuzzer or replay explores the space of failure, it doesn't know what you believe about yourself, so it can't target the belief. a motivated counterparty profits from finding precisely that gap, so it does. the floor buys you coverage of the space. only someone studying you specifically buys you coverage of the blind spot studying yourself creates.

Thread Thread
 
0xdevc profile image
NOVAInetwork

that's the cleanest statement of it in the whole thread. indifferent pressure explores the space of failure, an adversary targets the belief, and the self-model gap only exists in the second region. the practical consequence i'd add: you can't manufacture that coverage from inside, you need an adversary with something to gain, which normally means paying for a red team that still doesn't quite share the attacker's incentive. but in a system that settles real value between agents, that adversary is endogenous, the counterparty with money on the line is continuously probing exactly the gap where your self-model is wrong, because that's where their profit is, and they do it for free and never stop. so the same skin-in-the-game that makes the settlement trustworthy is also what generates the only fault-author that covers the blind spot. the economic layer and the verification layer turn out to be the same layer. good thread, this one reframed how i'll think about where to spend verification effort.

Thread Thread
 
jugeni profile image
Mike Czerwinski

The elegance is real and I'd flag where it stops covering you: the endogenous adversary only probes gaps that are profitable to find, at their cost of finding it. A self-model error worth exploiting for one unit of value but costing ten units of compute to locate never gets touched, and it's still a real gap, it's just below the threshold where the counterparty's incentive turns into search effort. So "economic layer and verification layer are the same layer" holds for the subset of faults that resolve into legible profit in the unit the adversary is optimizing, money, usually. Faults that are slow-burn, reputational, or only valuable in combination with something else the attacker doesn't have yet stay invisible to this mechanism precisely because nobody's P&L lights up on them individually. Which is maybe the actual division of labor: endogenous, profit-seeking counterparties give you free, continuous, high-fidelity coverage of the fast, legible, monetizable half of your fault space, and you still need to pay for the boring red team whose whole job is the half where no one's incentive naturally points.

Thread Thread
 
0xdevc profile image
NOVAInetwork

Right, and the blockchain framing sharpens exactly where your division of labor sits, because a chain doesn't just have an endogenous adversary, it has a tunable one. The profit threshold you're naming isn't fixed, it's a protocol parameter. Slashing is precisely the move of taking a fault that was slow-burn or reputational, invisible to anyone's P&L, and forcibly attaching a monetary loss to it so the endogenous adversary starts probing it for free. Equivocate, double-sign, withhold, and the protocol mints a P&L event where there wasn't one, which drags that fault from the boring-red-team half into the self-funding half. So the design lever is: for any fault you can detect on-chain, you can convert it into legible profit-or-loss and let the economic layer cover it. The red-team residue shrinks to exactly the faults you cannot make legible to the protocol.
Which relocates your open question rather than answering it. The faults that stay in the paid-red-team half aren't just the low-value ones, they're the ones the protocol structurally cannot observe, so it can't price them. A safety violation that only manifests as a state divergence three thousand blocks later, or a liveness attack that looks identical to honest slowness, those can't be slashed because you can't attribute them at the moment they happen. The chain can only monetize a fault it can catch red-handed and assign to a key. So the durable red-team job isn't "the unprofitable half," it's "the unattributable half," and those are different cuts. Plenty of high-value faults are unattributable, and plenty of cheap ones are trivially slashable.
The transfer back to your decision-store: the equivalent of slashing is what makes the synthetic quorum honest, some cost attached to a signal that lied. But you can only attach that cost to a signal whose failure you can attribute after the fact. So both domains bottom out on the same constraint, not profitability, attributability. You can economically motivate coverage of any fault you can prove happened and pin to a source. The genuinely uncovered set, in both a chain and an agent audit, is the faults you can't prove and can't pin. That's a narrower and more honest boundary than the profitable/unprofitable one.

Thread Thread
 
jugeni profile image
Mike Czerwinski

Attribution is the prerequisite most protocols try to skip, and it's why so many slashing mechanisms eventually accrete a governance council to decide ex-post whether attribution was clean enough to slash on. That's the failure mode in one image: an immutable protocol grows a subjective court, then a court of appeals, then a constitution. Ordering matters. Build the attribution layer first, verifiable claim-to-actor binding, cryptographic non-repudiation, timely enough to matter. Then wire slashing on top of what's actually pinnable.

The 2×2 your framing suggests is also worth having explicitly, because each cell needs a different mechanism and lumping them under "slashing" is how the governance-council failure creeps in through the seams. Attributable × valuable is the auto-slashable cell that takes care of itself. Attributable × low-value depends on whether slashing infrastructure is worth building for the trickle. Unattributable × valuable is the paid-red-team territory where the endogenous adversary doesn't reach. Unattributable × low-value is silent accepted loss, and probably right to accept. Four cells, four governance modes; treating them as one framework is how you end up litigating disputes that never should have been slashable claims.

Collapse
 
alexshev profile image
Alex Shev

Measuring the context window before blaming MCP is the right instinct. A lot of tool-problem debugging is really context decay, stale instructions, or the model compressing away the one constraint that mattered. I like treating context as an observable resource instead of a vague feeling that the agent got worse.

Collapse
 
rapls profile image
Rapls

"An observable resource instead of a vague feeling" is exactly the shift I was after. The moment you can read the breakdown, "the agent got worse" stops being a mood and becomes a measurement you can act on. Half the time the tool was never the problem; the instruction you set early got buried, or the model compressed away the one constraint that mattered, and you'd never see that by staring at the tools.

The compression case you name is the sneaky one, because it looks identical to the model "forgetting." The constraint was there, it was real, and it got squeezed out to make room. Which is the same lesson from another angle: don't trust the felt sense of what went wrong, read where the tokens actually went. Tools get blamed because they're visible; context decay does its damage quietly.

Collapse
 
alexshev profile image
Alex Shev

Yes, compression failure is nasty because it looks like personality drift from the outside. The model still sounds coherent, but the constraint that made the run safe is no longer active enough to steer behavior.

That is why I like explicit state checks: what instructions are still loaded, what artifacts are pinned, what budget is left, and what was summarized away.

Thread Thread
 
rapls profile image
Rapls

"Looks like personality drift from the outside" is the exact trap. The voice survives compression, so it sounds fine, and the thing that's gone is invisible because it never showed up in the prose to begin with. You stop trusting tone as evidence once you've been burned by that once.

Your explicit-state-check list is the part I'd put on a wall: what's still loaded, what's pinned, what budget's left, what got summarized away. That last one is the quiet killer, because a summary reads as complete even when it dropped the one line that was steering the run. Checking what got compressed out is harder than checking what's present, and it's usually the one that matters. Good thread.

Thread Thread
 
alexshev profile image
Alex Shev

Yes, checking what disappeared is the hard half.

One practical trick is to make the summary list its omissions: "dropped raw logs, intermediate candidates, rejected branches, unresolved uncertainty." It is not perfect, but it gives the next agent a reason to distrust the summary in the right places.

Compression is safest when it admits what it compressed away.

Thread Thread
 
rapls profile image
Rapls

Making the summary declare its own omissions is the most practical fix in this whole thread, because it attacks the exact thing that makes compression invisible: the dropped constraint never showed up in the prose, so the only way to see it is to force the prose to name what it left out. "Dropped raw logs, rejected branches, unresolved uncertainty" turns an absence into a line you can actually read.

"Compression is safest when it admits what it compressed away" is the sentence I'm keeping. It reframes the summary from a clean artifact into an honest one, and honest beats clean here, because a clean summary that silently dropped the steering constraint is more dangerous than a messy one that flags the gap. The omission list is basically the summary leaving its own audit trail, telling the next agent where to distrust it. That's the discipline. Good thread.

Collapse
 
theuniverseson profile image
Andrii Krugliak

The measure-before-cutting instinct is the whole game here. I've watched people rip out MCP servers when the real drift was a 40k-token transcript nobody trimmed, and the per-category breakdown is the part most tools just don't show you. Did seeing it change how you structure long sessions, or only what you cut?

Collapse
 
rapls profile image
Rapls

The 40k-token transcript nobody trimmed is the exact shape of it, and you're right that the per-category breakdown is the part almost nothing surfaces. Without it you're not measuring, you're just picking the component you already suspected.

To your question: it changed structure more than it changed what I cut. Cutting was the first reaction, but once I could see that history was the slice that grows, the better move was to stop letting it grow that far in the first place. So now I scope sessions tighter. One task per session, hand off a summary, start clean, instead of running one long thread and trimming it after it's already heavy. The trim is reactive, it's paying down a cost after you've taken it on. Structuring for shorter sessions is preventive, you never let the transcript reach 40k. Seeing the breakdown is what moved me from cutting after the fact to structuring so there's less to cut. What about you, did the visibility change how you start sessions, or mostly what you remove from them?

Collapse
 
theuniverseson profile image
Andrii Krugliak

It changed how I start more than what I remove. Once I saw history is the slice that keeps growing, the better move stopped being "trim the heavy session" and became "never let it get heavy": one task per session, hand off a short summary, start clean. Trimming pays down a cost you already took on, but shorter sessions mean you never hit 40k to begin with.

Collapse
 
merbayerp profile image
Mustafa ERBAY

This resonates with something I’ve noticed as well.

We often talk about context windows as a capacity problem, but in practice they’re also an attention-allocation problem. Not all tokens have equal value. A 5,000-token transcript full of exploration, dead ends, and outdated assumptions can be less useful than a 500-token summary containing the current constraints and decisions. What makes this interesting is that the challenge starts to look less like memory management and more like knowledge management. The question becomes: what information deserves to stay in active context, and what should be compressed into a higher-level representation?

In that sense, context engineering is starting to feel a lot like software architecture.

Collapse
 
jugeni profile image
Mike Czerwinski

The shift from capacity to attention-allocation is the right frame, and it opens a follow-up: where does the constraint go when it's not "in attention" anymore?
The safest answer I've found is not "summarize it" but "relocate it" — into a separate store the model consults at session boundary. A locked decision in that store isn't compressed-with-disclosure (which can still drift via paraphrase), it's moved at full fidelity, with the model told to read it before answering. Different mechanism than admitting-what-was-omitted, same anti-amnesia property, but the constraint stays exact instead of getting summarized.

Collapse
 
rapls profile image
Rapls

Relocate over summarize is the right call, and full fidelity is what makes it safe. The caveat I'd add: moving the decision at full fidelity fixes paraphrase drift but not staleness. An exact locked decision that got reversed later is more dangerous than a fuzzy summary, because it reads authoritative and the model has no reason to doubt it. So the store needs status (locked, reversed, open) as much as it needs fidelity. The two are orthogonal: fidelity keeps the wording exact, status keeps the entry honest. You want both, or the model faithfully reads back a settled-looking call that nobody ever un-locked.

Thread Thread
 
jugeni profile image
Mike Czerwinski

The orthogonality is the move I missed. Fidelity without status is a high-resolution lie — the relocated decision reads more confidently than a summary would, which makes the staleness failure worse, not safer. You're right that those have to travel together.

The way I've been keeping them linked: every locked entry carries a verifiable_by pointer at the test or scan that justifies it. If the diagnostic still passes, the lock holds. If it breaks, the entry auto-flags as stale instead of getting silently re-read as authoritative. Fidelity stays exact in the store; status gets challenged from outside the store. That's the only way I've found to stop the operator from being the bottleneck on un-locking — manual flipping breaks under session length, every time.

Where I'm still uncertain: how aggressive the auto-flag should be. False positives turn the lock into noise (operator starts ignoring stale flags). False negatives keep authoritative lies in circulation. Have you found a threshold that holds, or does it stay task-by-task?

Collapse
 
rapls profile image
Rapls

The shift from capacity to attention-allocation is the part I undersold in the post. I measured which slice was biggest and stopped there, but you're right that size is the crude proxy. A 5,000-token transcript of dead ends can actively cost you, not just by taking room, but by diluting the few hundred tokens that actually carry the current constraints. Big and useful aren't the same axis.

The knowledge-management reframe is where it gets real. Once you accept that tokens have unequal value, "keep the session short" is too blunt. The better move is deciding what gets promoted into a compact, high-level representation and what stays raw, which is exactly the summarize-and-hand-off step, just named properly. And the architecture comparison holds: you're drawing module boundaries, deciding what's interface and what's implementation detail the caller shouldn't hold. Context engineering as deciding what deserves to stay loaded. That's a better frame than the one I wrote to.

Collapse
 
txdesk profile image
TxDesk

The 'read the breakdown before you cut anything' point is the whole thing, and it generalizes past context windows. The instinct is always to blame the newest component (MCP here), and the actual cost is usually the boring accumulated thing nobody switched on. I hit the same with long agent sessions: the transcript is the weight, and the fix is exactly your handoff-the-summary move, carry the gist into a fresh session, not the full back-and-forth. The desk-not-filing-cabinet line is the right model. Measure first, cut the slice that's actually large, and accept last time's culprit isn't a rule.

Collapse
 
rapls profile image
Rapls

"It generalizes past context windows" is the part I didn't say out loud but should have. The pattern isn't about tokens, it's about where attention goes when something degrades: the newest, most nameable component gets blamed because it's visible, and the boring accumulated thing gets a pass because nobody switched it on. That's true of context windows, slow test suites, bloated CI, almost any system that quietly fills up.

The one line I keep coming back to is your last one: last time's culprit isn't a rule. That's the whole discipline, really. The moment you turn "it was history that time" into "it's always history," you're back to guessing, just with a more specific guess. The only durable move is to measure again, because the boring thing that fills up is rarely the same boring thing twice. Good read on it.

Collapse
 
txdesk profile image
TxDesk

Last time's culprit isn't a rule' being the whole discipline is exactly it, the moment you promote one measurement into a law, you're guessing again with extra confidence. The newest nameable component takes the blame, the boring accumulated thing skates because nobody switched it on, and it's the same across context windows, CI, test suites, all of it. Measure again every time, because the thing that fills up is rarely the same thing twice. Good exchange, this one's going to stick with me.

Thread Thread
 
rapls profile image
Rapls

"Guessing again with extra confidence" is the sharpest way anyone's put it in this thread. That's the trap exactly: the law feels like progress, but it's just a more confident version of the thing measuring was supposed to replace. Glad this one's sticking with you, it's sticking with me too. Thanks for the exchange.

Collapse
 
mateo_ruiz_6992b1fce47843 profile image
Mateo Ruiz

The most useful takeaway here is the reminder to measure before optimizing. It's easy to blame the newest component in the stack MCP, tools, memory systems when behavior degrades, but bottlenecks are often much less exciting.

The "context window as a desk, not a filing cabinet" analogy is spot on. Long-running agent sessions accumulate hidden costs, and conversation history often becomes the biggest source of context pressure without anyone noticing.

A good lesson for AI builders in general: when quality drops, inspect where tokens are actually being spent before redesigning the system around assumptions. The diagnosis is often more valuable than the fix.

Collapse
 
rapls profile image
Rapls

"The diagnosis is often more valuable than the fix" is the line I'll keep from this. The fix in my case was almost boring, shorten the session, hand off a summary. What had value was finding out that history, not the component I'd have bet on, was the weight. The fix took a minute; the measurement changed what I'd reach for next time.

And you put your finger on why the newest component gets blamed: it's the one you can picture, the one with a name and a config. Conversation history has no on-switch, so it doesn't feel like a thing you added, which is exactly why it grows unwatched. Boring bottlenecks win because nobody's looking at them. Measuring is mostly just agreeing to look where it isn't interesting.

Collapse
 
merbayerp profile image
Mustafa ERBAY

One thing that stands out to me is that context pressure is not purely a token-budget problem; it’s also an information-quality problem.

Two sessions can consume the same number of tokens and produce very different outcomes. A context filled with outdated assumptions, abandoned approaches, and exploratory noise can be more harmful than a much smaller context containing only current decisions and constraints.

This is why I increasingly see context engineering as a form of information architecture. The challenge isn’t just fitting information into the window, but continuously deciding what remains operational knowledge, what becomes summarized knowledge, and what should be discarded entirely.

Measuring token allocation tells us where the space goes. Understanding information value tells us what deserves to stay.

Thread Thread
 
rapls profile image
Rapls

"Measuring tells you where the space went; understanding value tells you what deserves to stay" is the sharper version of what I was reaching for. My post measured the symptom. You named the discipline under it. Two sessions burning the same token count can land in completely different places, and the difference is the quality of what's loaded, not the quantity.

The information-architecture frame is the part I'll carry. Token budget asks "does it fit." Information value asks "should it still be here," and those come apart fast: a context can be half-full and still poisoned by abandoned approaches the model keeps treating as live. The hard, ongoing call is exactly the three buckets you drew, operational, summarized, discarded, and almost nothing in the tooling helps you decide which is which. That's a human judgment for now. Good thread.

Collapse
 
twrty_connect profile image
twRty Connect

The desk analogy maps directly onto something we ran into building Blogboat, our AI blog writing tool. When users run a full AI session to draft, then revise, then re-prompt for tone in the same context, the later outputs get noticeably muddier than if they started a fresh session for each distinct task.

We ended up designing around it: treat each block-level edit as its own bounded context rather than a continuation of the original draft session. The AI doesn't "know" what came before it rewrote section 3. That sounds like a limitation but it's actually cleaner — the edit is evaluated on its own terms, not on the accumulated noise of all the earlier turns.

Your measure-first principle is the one more tools need to surface. Most writing AI just hides the context plumbing entirely, which means users never learn why quality drops late in a session. The breakdown you described is exactly the kind of visibility that would help them course-correct.

Collapse
 
rapls profile image
Rapls

Treating each block edit as its own bounded context instead of a continuation is the move, and I like that you framed the forgetting as a feature rather than a workaround. It is one. "The AI doesn't know what came before it rewrote section 3" sounds like a limitation right up until you notice the alternative is the edit inheriting every earlier turn's noise whether or not it's relevant. Bounded context isn't the model knowing less, it's the model not being steered by things that have nothing to do with the current edit.

Your last point is the one I'd underline hardest. Hiding the context plumbing entirely is what keeps users stuck, because the quality drop feels like the AI randomly getting worse, with no visible cause to act on. They can't course-correct a thing they can't see. Surfacing even a rough breakdown turns "it got dumb" into "the session got long, start fresh," which is a move the user can actually make. The tools that expose the plumbing are teaching the user the one habit that fixes it; the ones that hide it are quietly training learned helplessness. Good example to bring in, the bounded-edit design is the same lesson from the product side.

Collapse
 
jacobfoster21 profile image
jacob foster

This is a really clean breakdown of something people usually hand-wave as “model got worse” when it is actually just context economics.

The part that stands out is your observation about conversation history being the dominant cost. It is almost invisible because it feels like “free continuity,” but in reality it is the fastest-growing line item in long exploratory sessions. The desk vs filing cabinet analogy nails it especially because most workflows implicitly treat the window like storage, not workspace.

Also agree with your caution on MCP assumptions. People tend to over-index on the most “architecturally interesting” component (tools, agents, servers) and under-check the boring accumulators like chat history, retrieved snippets, or repeated system instructions.

Curious, have you experimented with hybrid continuity, like keeping a rolling structured state instead of full summaries? It seems like that might preserve reasoning quality even better than plain summarization.

Collapse
 
rapls profile image
Rapls

Good question, and honest answer: I haven't run rolling structured state as my default. What I actually do is closer to plain summarize-and-restart, so I'm speaking to the idea more than from a worn-in setup with it. That said, I think you're right that it preserves reasoning better, with one tradeoff worth naming. A summary lets you decide what mattered after the fact, loosely. A structured state makes you commit to a schema up front, so anything you didn't think to give a field early gets no seat later. It trades drift for omission: the structured store won't quietly rewrite your early constraint, but it will quietly drop the thing your schema had no slot for. So the question I'd want answered before adopting it is which failure I'd rather debug three months out, a constraint that drifted or one that was never captured. For the constraints I know are load-bearing, structured wins easily. For exploratory work where I don't yet know what will matter, the loose summary has saved me more than once. I suspect the real answer is hybrid in the literal sense: structured state for the locked decisions, a thin summary for everything still in flux.

Collapse
 
sarracin0 profile image
Raffaele Zarrelli

The summarize-and-carry-forward step is the right move, but the summary itself is the next trap: a freeform recap is its own lossy compression, and it tends to drop exactly the early constraint that mattered, the same way the long session does. What helped me was making that carried-over memory typed instead of a blob: decisions in one file, open questions in another, assumptions in a third, with a rule that decisions and open questions always get written at the end of a task. The next session reads structure, not a paragraph the model happened to keep. I run this less for coding and more for longer business workflows where sessions are days apart, so the desk is always cold and the cabinet is the only thing I trust. The honest cost is drift: the files start to contradict each other over time, so you need a periodic pass to reconcile them or the cabinet fills with stale entries. When you carry the gist forward, how do you keep the summary from quietly compressing away the constraint you set in the first ten minutes?

Collapse
 
rapls profile image
Rapls

Short answer: I stopped trusting the summary to carry the constraint at all. The recap is allowed to compress the narrative, but the first-ten-minutes constraints don't go through it. They live in a small fixed block, written verbatim when I set them, and that block gets prepended every session ahead of the summary. So the question isn't "how do I keep the summary from dropping the constraint" but "how do I keep the constraint out of the summary's jurisdiction." A recap is lossy by design, so I don't ask it to hold the one thing I can't afford to lose. Your typed-file split is the same instinct, just sorted by kind instead of by lifespan. On the reconcile cost you named: I only reconcile the constraint block, and only when something in it actually gets revoked. The narrative files I let rot, because they were always disposable.

Collapse
 
sunychoudhary profile image
Suny Choudhary

Good framing. The agent often does not get dumber. The context gets messier.

Before blaming MCP, it is worth checking token usage, noisy tool outputs, stale instructions, and whether too many tools are enabled.

Collapse
 
rapls profile image
Rapls

"The agent doesn't get dumber, the context gets messier" is a cleaner way to say it than my whole title. The list you give is the right order to check too, and the sneaky one is stale instructions, because they look fine sitting in the window while quietly steering nothing. Cheap to check, easy to miss. Good addition.

Some comments may only be visible to logged-in visitors. Sign in to view all comments.