Newshot
Account

The Body: Putting the Trust Layer Inside a Real Platform — How to Sign Off on 88,000 Lines

AI summary

The third post in the series "Reining In AI: From Weekend MVP to Multi-Channel Command Console." The previous post laid out the groundwork: v2's trust layer — authorization contracts, guardrails, the four-stage chain — was all green in the test environment, but it was in an awkward position: it existed on its own. No matter how healthy the heart is, it won't beat until it's inside a body. For the trust layer to prove it is actually being used, it has to run on a real agent platform and be continuously hammered by real tasks. On October 1, v3 started. This post is about that body: how to build it from scratch, and the engineering

Translation(model translation, not the source's own text)

Body: Installing the Trust Layer into a Real Platform — How 88,000 Lines Get Accepted

Third installment of the series "Bridling AI: From Weekend MVP to Multi-Channel Command Console."

The previous installment laid it all out: v2's trust layer — authorization contract, fences, four-segment chain — was all green in the test environment, but it sat in an awkward position: it existed on its own. No matter how healthy the heart is, it won't beat until it's installed in a body. For the trust layer to prove it's actually being used, it has to run on a real agent platform and be hammered continuously by real tasks.

On October 1, v3 broke ground. This piece is about that

Title: Body: Packing the Trust Layer into a Real Platform — How 88,000 Lines Get Accepted

Body: Fixing it didn't help. After launch, the Agent still declared "TaskCreate panel unavailable due to host failure (consistent with prior)" and simply bypassed the planning tool. I checked its memory store and found it: that failure had been written into its cross-run persistent memory layer, five entries, accumulated over the previous several runs. The planning instruction written plain as day in the system prompt was being overridden by those stale memories — experiential memory beats out instructions; this is a common failing of the model, not disobedience.

My first instinct was to revise the prompt again: bold it, pin it to the top, say it three times. Halfway through I realized — useless. Prompts are read-time confrontation; memory is write-time contamination. The source is still writing, so no amount of read-side hedging will do anything but whack-a-mole. In the end I landed four layers:

  • Write side: memory-tiering discipline — temporary environment and tool state (tool errors, host failures, transient network anomalies) may only be written to the local tier (discarded when the session ends), strictly forbidden from the persistent tier. Environment failures get repaired by the platform; persisted environment state will inevitably go stale, and stale is poison;
  • Storage side: soft-delete the five poisoned memories (keep deletion timestamps, no physical deletion, preserving the audit standard);
  • Read side: authoritative declaration in the system prompt — the Task tool is taken over by the platform and is always available; any "host failure" in historical memory is an outdated record, and bypassing on that basis is forbidden;
  • Detection side: write the disinfection discipline into the rulebook, executed at deploy time.

        0fe4eda fix(prompt): memory tiering discipline — environment state goes only to the local tier, plugging the source of poisoned-memory writes
bdba07f fix(prompt): authoritative declaration of planning-tool platform takeover — hedging against poisoned knowledge from stale memory
      
Source: v3 git log (2026-10-14, two commit bodies containing evidence of the five poisoned memories).

The lesson from this pit is worth more than the incident itself: an Agent's memory is an asset, and also a contamination surface. That it learns is a good thing, but one class of what it learns is "correct observation of the environment at the time" — the shelf life of this kind of knowledge is bound to the environment, and once the environment changes it turns to poison. You're fixing the machine, and you also have to manage its memory hygiene.

Zombie runs and infinite loops: three ways to die

In real combat I've collected all three forms of run death.

The first, "went silent." The thread exits, no terminal event of any kind, the UI freezes mid-way, and a refresh doesn't help. A death the user can notice is not the worst; the worst is a death that is itself unobservable.

The second, zombies. After an engagement is interrupted, the run's registry state is still running; the platform restarts, and they become zombies — state lives in memory, lost on restart, and the sandbox container session goes with it.

The third, declaration infinite loop. The Agent wants to end the task and calls task_complete — the bootstrap file uses the bare name, so the call doesn't go through; it switches to plain text saying "I'm done," but plain-text rounds have no exit determination, so the conversation continues; it says "I'm done" again… the observed record: 48 conversation rounds.

The fixes for the three deaths each landed in place: interrupt path corpse-collection + startup corpse-scan (converge orphaned run states after a restart); corpse-collection must emit a terminal event (the UI refresh then shows the real terminal state); a run thread exiting must check for a terminal state — an exit with no terminal state is itself an audit event; plain-text rounds get an exit and the bootstrap gets corrected.


        8b1adba fix(runtime): double fallback for zombie runs — interrupt corpse-collection + startup corpse-scan
2220b68 fix(runtime): event-stream closure — corpse-collection must emit a terminal event, curing the frozen death image where refresh is useless
5bef90c fix(runtime): silent-exit audit — a run thread exiting must check for a terminal state, eliminating the "went silent" class of death
4319c7f cure the completion-declaration infinite loop (conv=48 evidence: bare-name task_complete bootstrap call doesn't go through + plain-text rounds have no exit)
      
Source: v3 git log (2026-10-14).

One more word on the lesson from the infinite loop: an Agent's "done" is a protocol, not a sentence. Its saying "I'm done" doesn't mean done — there has to be a machine-recognized exit — and the exit itself can break, and the way it breaks is an infinitely polite repetition of farewells.

Checklist: the rest of the pits aren't expanded on, but they're all on record

More than 40 commits in three days; picking the ones with general applicability:

PitOne line
Told to do pwn, it went off and did crypto on its ownThe plan declared the task type, execution swapped in whatever was convenient — hard-validate the declared task type; whatever is declared must be what's executed
The model outputs entirely in EnglishThe user can't understand what their own Agent is saying — a hard rule for Chinese output goes into the system prompt
Time display 8 hours early ×3 placesThree places bypassed centralized parsing and each computed its own timezone — converge to a single point
Typing a letter in the rename input box got fully overwritten by select-allfocus+select placed in nextTick, and a fast user typed before select fired — make it synchronous, eliminating the race window
A question got expanded into executionThe user asks a question, the Agent treats it as a task and starts working — whitelist-based task boundary
Model hallucinated and dropped the gunIt "thought" the budget was insufficient and gave up early — inject the true campaign budget number into the system prompt
Source: v3 git log (each commit from 2026-10-12~14); internal "Technical Summary Report on the Combat-Feedback Fix Batch" (2026-10-13).

Half a word more on the topic-boundary item: it's the same line of thinking as v2's overreach — between "what it wants to do" and "what it's allowed to do" there must be a seam enforced by machine; prompts can't paper it over.

Life savings: two-stage circuit breaker

The budget story deserves its own telling, because it's the most intuitive sample of "cost."

After the single-round budget circuit breaker went live, real combat surfaced an awkward fact: what the breaker cuts off is often the wrap-up. A run burns its budget down to the line, the breaker trips — but the wrap-up actions (writing memory, precipitating experience cards, generating reports, declaring completion) also cost money, and these actions happen precisely after the most expensive summarization phase. Tripping right at the line leaves the Agent dying at the spot "just about to be able to write its will," and all the money burned earlier is thrown away.

The solution is a two-stage circuit breaker: the offensive stage gets 85% of the budget, and the breaker trips when it burns to the line; after tripping, the wrap-up stage opens with the remaining 15% — the life savings. In the wrap-up stage, attack-type tools are all refused (audit-trailed), and only the four-piece wrap-up set is allowed: write memory, write experience cards, generate reports, declare completion.


        offensive stage 85% —burn to the line—→ breaker error —one-click wrap-up—→ wrap-up stage 15% (all attack tools banned)
      

On the pricing side there was another unexpected finding: the Agent runtime prices third-party models on a compatible endpoint (non-native model IDs) at the highest list price. Measured on one run: input 121K + cache read 546K + output 3.3K, estimated at that tier at $3.09, which just barely pushed past 85% of the $3 budget line (2.55) to trigger the breaker — at the cheaper tier it would be only $0.57, which doesn't explain it. So early-warning estimates use the conservative tier (better to remind early), precise breaker decisions go by measured values; the display layer added a conversion coefficient, so switching endpoints in the future only changes one constant. This finding itself was written into the regression test, becoming an empirical anchor.

Source: internal "Technical Summary Report on the Combat-Feedback Fix Batch," Chapter 9 (run 66 evidence, including the $3.09 > $2.55 regression anchor).

Decapitated pipelines: a feature existing ≠ a feature working

The last batch of pits hurt the most: three functional surfaces all existed, all intact — but had never once been triggered.

The kill-chain swimlanes were always empty, the audit chain read "chain complete (0 entries)," and all three knowledge bases were 0. My first instinct was a frontend bug. After checking, I found the frontend was faithfully rendering an action that had never happened: the planning generator had zero callers across the whole repo — no code path would ever call it; the audit chain only hooked into two paths, approval and circuit breaker, and the everyday main paths (boundary solidification, state changes) never wrote to the chain at all; the three knowledge bases' write tools were fully functional, but the system prompt never guided the Agent to use them — the Agent just wrote memory and experience cards as it went, leaving structured results invisible to the platform.

Another one of the same kind: the evidence-package capture function had an except Exception: pass, and failures were silently swallowed. In combat all 10 runs completed the terminal chain (157 experience cards precipitated, covering every run), but there was not a single evidence package. The cause of failure is undeterminable — because the failure itself had no log. The fix isn't "fix the capture," it's make failure observable: at the exception-swallowing points add warning, stack trace, context. The swallowing semantics are preserved (a capture failure must never affect run convergence), but it goes from silent to audible.

The commonality of these two classes of problem matters more than any single bug: a mechanism existing ≠ a mechanism working. The feature is written, the tests are green, the page is there, and nothing ever triggers it, so it's as good as nonexistent. And "never triggered" throws no error — it's silent. Real combat is the only revealing mirror — which is another reason "the trust layer must be packed into a real platform": in a test environment, a decapitated pipeline and a connected pipeline look exactly the same.

The failure boundaries of this approach

Single-focus is a hard ceiling. The whole platform is single-engagement, single-focus by design: one war room, one conversation stream, one sandbox. It makes "one engagement" into a closed loop, at the cost that a person can only watch one line at a time. In combat I hit this wall fast: the Agent is running, and I have to watch it; step away to do something else, and when I come back it may already have looped 48 rounds. This isn't an implementation defect, it's an architectural positioning — one person watching one line, the person's attention is the throughput ceiling.

Quenching fixes the pits you stepped in. The 40-plus fix commits are the number of "discovered" problems, not the number of "existing" problems. Unstepped pits exist as usual; the next infinite loop may be on the road in a different form.

The gatekeeping model has a single point: the person who defines the gates. I can't read through even a tenth of 88,000 lines line by line; acceptance relies entirely on three mechanical gates: matrix, regression, proof points. This system can defend against "implementation fooling acceptance," but it cannot defend against "the gates themselves being wrongly defined" — the matrix misses registering one functional surface, and the zero-regression check misses one column. A gate design error is my human error, and it gets mechanically amplified.

The governance numbers are on a test basis. The 87 out-of-bounds interceptions come from measured results on the test set; during combat, no real out-of-bounds event was intercepted — which shows both that the Agent keeps to the rules and that the enforcement surface has never been tested with real swords and guns. Stopping out-of-bounds in tests and stopping out-of-bounds in combat are two different propositions.

Series navigation (scrolling through the published list):

  • F0 "I Open-Sourced a Tool That Can Prove What an AI Did"
  • Post 1 "One Weekend, I Had an LLM Build Me My First Security Agent"
  • Post 2 "Reins: One Prompt Can't Stop an Agent"
  • This post: Post 3 "Body: Packing the Trust Layer into a Real Platform — How 88,000 Lines Get Accepted"

Project entry: GitHub TLotU-lab/cyberseccat-fence — the public artifact repo of the v2 trust layer (authorization contract model, 87+25 test sets, M3/M4 gate records). The v3 platform proper is open-source-ready and not yet public; this post's v3 numbers can be reconciled once the repo opens.

Article title: Body: Putting the trust layer into a real platform — how to sign off on 88,000 lines

Next: the incident unit. A mechanism existing does not mean a mechanism working — three real incidents, three mechanisms already written and already tested, receiving wrong values on the real path. An authorization quota turning infinite out of thin air, seven minutes of zero-token deadlock, 48 rounds that would not stop — the same shape, three ways to die.

The translation is machine-generated and individual terms may be off. Nothing is rewritten or cut; the original is authoritative.

Published by FreeBuf
This site only summarises and aggregates; copyright stays with the original author. Headlines and summaries follow the source — where they differ, the original wins.
Read the original ↗