Inspiration

A hub closes at 2am. 51,000 people are stranded across 20,000 bookings, and 2,888 seats exist. One duty manager decides who flies, and the queue is not getting shorter.

Reasoning is now cheap enough to give every stranded traveller their own agent. Nobody does it, because twenty thousand agents means twenty thousand model calls — and by the time you've paid for them, the seats are gone.

Unless the identical reasoning is only computed once.

What it does

Chorus gives every booking a real, independent ADK agent, and charges for the diversity of their situations, not their population. Twenty thousand agents cost 1,962 distinct thoughts and $1.89, against $19.24 if each thought alone — a 10.2× collapse.

Nothing groups the agents. None of them knows the others exist.

How we built it

Every boundary an agent crosses — model call, tool call, delegation — is intercepted at the ADK BasePlugin boundary and recorded as an effect addressed by its entire causal history:

$$\text{address} = H(\text{kind}, \text{role}, \text{causal parents}, \text{request})$$

Two agents arriving at the same question from the same causal position compute the same address and collide. The second is served the first one's answer for nothing. This is record-replay debugging, event sourcing, and content-addressed build graphs — three solved techniques, combined in a domain that hadn't used them.

Each agent reasons over a bucketed projection of its situation, never its name. Two stranded platinum passengers travelling alone, both needing to move within four hours, face the same decision. Their names differ. Their reasoning doesn't.

The kernel knows nothing about ADK. One file does.

Challenges we ran into

Most of what we learned came from measurements that went against us.

The collapse is lossy. We measured it rather than assuming: roughly 13% of outcomes differ from reasoning each traveller separately. Replicated three times. It's in the README.

Hand-written rules beat us. Six arms scored identically, and a regex baseline with no model at all wins on tier-weighted satisfaction. We ship that row because it's true, and it's why the escalation path exists.

Gemma scored 26.7% on urgency — below a regex. That was our prompt, not the model. One line defining the bands took it to 80.8%.

Our tracing exporter reported success while writing nothing. The Cloud Trace API was disabled, every batch was refused, and the code returned the span count anyway. "39,996 spans" reached the README and sat there while the backend held nothing. It now raises on refusal and reads the spans back to verify. There are 39,976 spans in Cloud Trace, and that number was checked by fetching them.

A round-anchor mismatch meant the console could never replay the shipped proof. Our first hypothesis was wrong; profiling redirected us. 90 calls per 96 agents became 0 calls per 200 agents — an 88× speedup, found only because we measured instead of guessed.

What we learned

The uncomfortable one: the thing that makes a demo impressive and the thing that makes a system honest are often in tension. A warm store makes the live site instant and free — which is precisely the product's thesis — but shows a visitor none of the collapse happening. We kept the honest version and wrote down the trade-off.

Interposition beats instrumentation. Because causality was recorded first (replay required it), the distributed trace is a projection of data that already existed, rather than a parallel bookkeeping system that can disagree with it.

What's next

Merge conflict resolution across branches, a global rate limit in Cloud Armor rather than per-instance, and lifting the public demo ceiling once the lattice is pre-warmed — its 2,304 cells bound total lifetime spend at about $2.22.

377 tests pass. Every number above is reproducible with a command in the README.

Built With

  • blake2b
  • cloud-run
  • cloud-tasks
  • cloud-trace
  • content-addressing
  • docker
  • event-sourcing
  • fastapi
  • firestore
  • gemini
  • gemma
  • google-adk
  • google-cloud
  • model-armor
  • opentelemetry
  • pixijs
  • pytest
  • python
  • react
  • secret-manager
  • server-sent-events
  • terraform
  • typescript
  • vertex-ai
  • vite
Share this project:

Updates

posted an update

Write-up, demo video, and the post Three things that didn't fit in the submission itself.

The demo videohttps://youtu.be/jqS_f5T93ak

Four minutes. The console clip is a real 20,000-agent run, unedited and sped up: 20,000 agents, 1,962 distinct thoughts, $1.89 against $19.24 at one call per agent. The run genuinely takes about ninety minutes, because 1,962 real Gemini calls have to happen for the counters to say $1.89.

The write-uphttps://medium.com/@uniquedsdave/cache-poisoning-in-collapsed-agent-fleets-b21accf5f0e2

Cache poisoning in collapsed agent fleets. Written for this hackathon, about a vulnerability I haven't seen described anywhere: collapse amplifies prompt injection by exactly the collapse ratio. The saving and the blast radius are the same number. In the largest cohort, that number is 128.

The defence turned out to be structural rather than a filter. A shared answer is addressed by H(kind, role, causal_parents, request), and the request carries only a bucketed projection — eight fields, closed vocabularies, no free text. No attacker-controlled byte participates in a shared address, so cache poisoning here isn't filtered, it's unaddressable.

That implies a constraint that generalises past this project: any design admitting free text into shared reasoning either loses collapse entirely or becomes poisonable. There is no version that keeps both.

The posthttps://x.com/i_am_dflame/status/2094628183484280867


Everything in the video regenerates from a command in the README, including the measurements that go against us: collapse costs ~13% of tier-weighted satisfaction, and two baselines with no model at all beat us on that metric. Both are in the repo with the commands that reproduce them.

Log in or sign up for Devpost to join the conversation.