The documents the mediator reasons from, why they have no fixed shape, and the few parts that do

Two layers of memory

The system remembers at two ranges.

Room memory is the working document of one room: what has been learned in these conversations, where each negotiation stands, the planner's instructions to the agents. It lives and dies with the room.

Durable account memory follows a person across rooms. Rooms are permanent, so "closing" is no longer the trigger. On a live home room (Update Agent), Arvist promotes after every Distil so a preference just written is in durable memory before the host tests their z-link (ZLY-1897). On other rooms, a few minutes after the sitting goes quiet, Arvist promotes what is worth keeping — who this person is, their standing rules, how they like to be spoken to — into the account document. That document seeds every room the account is bound to, so the planner never starts from zero. If Distil has written the home host branch more recently than the last promotion, a new deal room seeds from that home branch instead of waiting for Arvist. Rooms are permanent, so a seed at bind is not the last word: when that durable document changes later, AccUpdate merges it into the participant's branch of the still-open room before the next planner run. This is how a host's terms, settled once in their permanent home room, are already known in a brand-new deal room — and stay current in rooms that were bound earlier — without the host doing anything. Deals this account has actually closed are part of that document: the price it accepted, the deliverables, the usage rights it granted. A rate already agreed to is what anchors the next negotiation, so losing it means re-deriving the account's own commercial position from scratch every time.

Durable account memory is one flat, free-form document per account. Identity, inbound preferences, outbound goals, and roster context can all inform the same agent, so a person never has to reintroduce themselves for another capability. Exact physical settings such as the Bouncer offer floor remain in account_service.settings, outside intelligent memory. When each standing fact in that document last changed is also kept outside the document — see When a standing fact was recorded. See Capabilities, Seats, and Derived Role.

Facts still belong on the account they describe. Recording that a deal closed with a named counterparty is the deal history of the account being promoted for; profiling that counterparty — its contacts, its budget, how it haggles — is not, and belongs on the visitor's own document.

A room running a mock tape never promotes. Scripted fiction must not become standing knowledge on a real account, so the Arvist records a skipped run and leaves the durable document alone — the same spirit as suppressing push email from a scripted room.

Two halves, two writers

A room keeps two things apart:

  • Distilled memory — what has been learned: facts, mandates, flags, the planner's notes. Distil writes it, in the background, after a reply.
  • Conversation progress — where the conversation stands: the goals, each persona's working plan, and the principal's one-time answers. The persona that is speaking writes it, in its own turn, alongside its reply and any message it sends to the other side.

They are stored separately. Every agent still reads them as one document, but a write from Distil can only change distilled memory and a write from the persona can only change progress. Distil cannot flip a goal, even by rewriting its whole document, and a persona cannot rewrite a fact.

Within distilled memory, a single author avoids the failure mode where two conversations record contradictory things about the same fact, and it means there is exactly one place to look to understand why the system behaved as it did. There are two deliberate exceptions. The guard corrects the document when a quiet-room audit finds it does not match what actually happened — a proofreader, not a second author. AccUpdate brings standing account knowledge into one participant's branch when the durable document has changed — a courier, not a second author. Neither may steer, write guidance, or touch anything outside its lane, precisely so the single-writer property survives in spirit.

The planner is told to be generous: not just the transactional facts, but how the person talks, what they care about, what is going on in their life — because detail it skips is detail no agent will ever have. Everything the planner itself records must come from the transcript. A persona's own unsupported claim is an error to correct, not information to record, and a counterparty's reference to something off-screen ("the document in your inbox") is recorded as a claim, never as fact. Standing knowledge the system merged from the account's durable memory is the exception that is not contamination: it is announced in the transcript as a system line, and the planner is told never to delete or quarantine it as unsourced just because this sitting's messages did not mention it.

Why there is no fixed schema

The obvious design is a defined structure: preferences here, offers there, notes in a third place. We tried that and abandoned it.

Real conversations produce facts no schema anticipates. A host mentions they are racing abroad every October and unavailable. That is not a preference, not an offer, and not a note — but it is decisive, because an otherwise perfect offer with an October timeline has to be pushed. With a fixed structure, either that fact is discarded or an engineer ships a migration for every new kind of thing a person might say.

So the document has no fixed shape. The planner decides how to organise it and reorganises it when something new does not fit. In practice it invents sensible structures on its own and keeps them stable across a conversation.

The cost is that nothing downstream can assume a particular field exists. We accepted that: the alternative is a system whose understanding of a person is capped by what was imagined in advance.

The four reserved parts

Exactly four parts of the document are fixed, because the rest of the product needs to know them. Everything else is the planner's to shape.

Goals

Every room declares its goals — for a host-and-visitor deal room: the host's setup is complete (account-setup), and the negotiation reaches an outcome (negotiation). Goals live in the conversation progress, and the speaking persona rules them. Each goal is a small envelope: what it is, who it is for, and a status — open, met, blocked, or abandoned.

Status is the one field code reads, and code acts the moment it flips. A goal turning "met" can trigger real effects: notifying a participant, or generating the formal offer document. That makes goals the hinge between the intelligent layer and the physical one — the persona judges, and the flip makes it real. Distil reads goals as context and cannot change them.

Two things took iteration to get right. First, a goal can end without succeeding: a rejected offer or a visitor that walks away is marked abandoned, which is as final as met — the persona stops steering toward it. Abandoned of a goal whose run is new-offer is the exception that still fires: code runs reject-offer so the live written offer closes (ZLY-1935). Other abandoned goals do not fire. Second, a goal is about its substance, not the follow-up chores: things still needed from a participant afterwards (a signature, an address) do not hold a goal open — they become messages pushed to that participant instead.

A persona also creates goals of its own, under the same envelope, whenever it takes on an obligation — something it promised a participant, or something one participant is waiting on another for — and closes them once resolved.

What the persona sees

Every speaking persona reads the whole room document except plannerNotes and flags (and leftover guidance from older rooms). Distil steers later turns only through what it records: facts and mandates. Goals, plans, pendingPrincipalDecisions, and pushes to the other side come from the personas. Private numbers that a visitor-facing persona must not say belong under plannerNotes, or are worded in the host branch as a boundary, not a floor.

Flags

The planner's channel to human operators. If a participant is losing patience — repeated asks that keep getting deflected, sarcasm about talking to a machine, an outright request for a human — the planner raises a frustration flag with a level and a one-line justification from the transcript. Flags are visible to operators, invisible to every agent, and change nothing in any conversation. The planner keeps them honest: escalate when it worsens, delete when the tone genuinely recovers, because a stale flag is noise operators learn to ignore.

The planner's private notes

The planner's own working thinking — strategy across the next few exchanges, unconfirmed hunches, per-counterparty negotiation patterns, what it would do differently. Never shown to any agent, and removed before the context filter can even see it (see the privacy boundary below). This is where unconfirmed thinking lives; only what the transcript actually supports gets promoted to the facts.

What is not in memory: the physical layer

Some truths are deliberately kept out of memory and shown to the agents live instead.

When a participant is bound to a real account, the account's facts are appended to the agent's instructions at call time — always current, never duplicated into a document that could go stale. When a negotiation produces a formal offer, the memory holds a reference (offers.<key>.offerId) and every agent is shown the offer's real stage live — one canonical vocabulary from offer-stage.ts (NO_WRITTEN_OFFER, WRITTEN_OFFER_DRAFT, WRITTEN_OFFER_AWAITING_TALENT, BRAND_ACKED_AWAITING_TALENT, BOOKED_AWAITING_PAYMENT, …). Distil never copies that stage into memory. A principal's chat yes is recorded at pendingPrincipalDecisions.<key>.principalInstruction; it is an instruction, not a stage. The terms themselves live only in the offer document that Offer-Gen produced. Both sides Approve that document in the product; the brand pays in Send Payment after talent accept. AgreementAg then writes a lawyer-reviewable draft from those Offer fields — never from the chat. And every planner and guard run receives the dispatch record — the system's ground-truth list of messages actually delivered to participants — because the one thing an intelligence must never be allowed to remember wrongly is what it has and has not done. And when a standing fact last changed in durable account memory is a record too: the Arvist is shown those dates live, and they are never copied into the document it writes. The rule of thumb: memory holds understanding, the physical layer holds records, and records are projected in rather than copied.

When a standing fact was recorded

The planner can date events — a deal closed, a campaign ran — because those have a date in the conversation. Most of durable memory is not events. It is states: a floor, a hard rule, a preference. Those have no event date to extract. The date that matters is when the system last treated the fact as current knowledge — so we can tell if it is extremely old — and that is a property of the write, not of the content. When the fact was first created does not matter.

Code stamps that date. Every durable write goes through one locked function, which compares the document before and after and records one calendar date per leaf that actually changed: when its value last changed. An unchanged leaf keeps the date it already had. A leaf that never had a stamp — written before this existed — stays unstamped; we do not invent a date. Paths that no longer exist are dropped, so a rename does not leave a graveyard of stale keys.

The stamps live in a sibling column on the durable row, not inside the document. That is why a seed into a room cannot carry them, why they never show up as branches the Arvist can write, and why a wholesale replace of the document cannot wipe the clock. Intermediate objects are not stamped: if every touch of a parent refreshed the date, the field would mean "last time the Arvist reworded this paragraph", which is noise.

The Arvist is shown the dates at call time, the same way it is shown account facts — a projected block, not part of the JSON. It is told to use them to tell whether a standing fact is extremely old, and never to write, copy, or invent those dates. The planner does not see them. Room memory is not stamped. A room is the length of one sitting; staleness is a durable-memory problem.

Future work: asking whether old facts still hold

An old date that only the Arvist sees is a post-mortem: the sitting already used the fact. Two ways to put a human look on it are still open, and they answer different failures. Either way the dates stay out of the document — projected at call time, never seeded into a room — and "old" does not mean "unknown". The fact is still used; it is confirmed when it is about to matter, or when a quiet review reaches it.

A confirm that does not change the value still has to refresh the date. Today the stamp moves only when the leaf's value changes, so "yes, still $20k" would leave March on the clock and the next pass would ask again. That write is a code-level touch: same value, new date, no model-written stamp.

In the room, only the extremely old. A threshold (a year, or tighter for commercial constraints) would project just those leaves into the planner, and only when this sitting can actually verify them with this person. A live floor or a hard rule about to be used is the case; a Scout room should not start auditing Bouncer terms.

A monthly adviser, out of band. Rooms are sparse — a person can go months with no sitting, so the planner never gets a chance. A separate agent on a clock would read the stamp column and send a push only when something is actually old, then continue in a short room (or the home room) rather than a form. A few load-bearing facts, not a profile audit. This is hygiene. It does not replace a check at the moment of use: a push from last Tuesday that nobody opened does not save a pricing room tomorrow.

The two can coexist. The adviser is how facts get a look when no room is open. The threshold is how a load-bearing fact is checked before it is acted on.

Account-memory merges are announced

A silent merge looks like unsourced contamination to a planner told that everything must come from the transcript. So after AccUpdate writes, the room stores an assistant-role message on that participant's pane carrying the account's name and the paths that changed. The transcript renderer turns that into a line of the form SYSTEM [account-memory merge]: standing knowledge about the account merged into the participant's branch (paths: …). The planner, the guard and the Arvist all read it. The playground shows a banner — "Updates from durable memory about the account" — with the same collapsible change list used for planner writes. Product panes ignore the part, so the person in the conversation never sees it.

The merge itself is a locked write: the room's memory is re-read under a transaction lock, the path updates are applied to whatever is there now, and only then is the document stored. A concurrent planner cannot be clobbered by a precomputed snapshot, and the planner does not start until the merge has landed.

Changes are targeted, not rewrites

When the planner updates memory, it names the specific parts that changed rather than returning a fresh copy of the whole document.

This is a reliability decision. A model asked to rewrite a large document will occasionally drop something unrelated on the way past, and that loss is silent — the host's October blackout simply stops existing, and nobody finds out until an offer is mishandled. A targeted change cannot damage a part it did not name.

It also makes the history readable: every change is recorded as what changed, when, in response to which message, and what the memory looked like before and after.

Sessions: what the planner re-reads

Conversations accumulate, but understanding does not need to be re-derived. The transcript is partitioned into sessions — a session starts when the planner reaches out unprompted, or when a participant returns after a long pause — and the planner reads only the current session. Everything earlier was already reviewed by the planner runs that followed each turn and distilled into memory, so the trimmed transcript simply tells the planner to trust the memory for anything before this sitting.

This mirrors how a human assistant works: they remember the relationship, not every word of every past meeting. It is also what keeps cost flat — without it, each planner run re-reads the whole history and the cost of a room grows with the square of its length.

The privacy boundary

The planner's private notes must never reach a conversational agent. The reason is concrete: a note like "this visitor is clearly desperate and will pay more than they claim" is exactly the kind of thing that is useful to the planner and damaging if it reaches the agent negotiating with that visitor.

We first tried instructing a filter to withhold them. It did not hold. The filter is also told to be generous, generosity won, and internal notes reached the visitor-facing agent.

The boundary is now enforced structurally: plannerNotes and flags are stripped before any persona sees the document, so they are not available to quote, and no instruction can override it.

The general principle is worth stating plainly, because it applies well beyond this feature: a confidentiality guarantee should not depend on a model's judgement. If it matters, it belongs in the mechanism, not in a prompt.

Auditability

Because there is one writer and changes are targeted, the system can answer after the fact:

  • What did the agent know at the moment it said that?
  • What changed in the system's understanding, and which message caused it?
  • Which standing knowledge was merged from durable memory, and from which account?
  • When did a standing fact on the account last change?
  • Which instruction was the agent following?
  • When was a goal judged met or abandoned, and on what basis?
  • What did each step cost? Every model call is recorded with its tokens and its actual billed price.

For a system acting on someone's commercial interests, being able to reconstruct why it did what it did is not a nice-to-have.