This is the third entry in the Digital Companion Build Journal. Companion systems eventually meet a content-classification problem. This project divides operation into normal mode and private mode. The requirement is not a reminder in the prompt; normal mode must be structurally unable to read any private-context content. Three failures and a reconstruction made this mechanism the most important engineering record in the project.
The valve: asymmetry is deliberate
There is only one door between the modes, and its rules were fixed from the beginning:
- Boot always lands on the normal side. The first version resumed private mode. Remembering the previous state turned restart into a way around verification.
- Every failure collapses to the normal side. A timed-out mode query, unreachable endpoint, or missing configuration all produce normal mode. A fail-safe must fall in the safe direction.
- Entry is verified; exit is not. The asymmetry is a design decision. Entering private mode by mistake is an incident; leaving it by mistake is only inconvenient.
- Automatic classification may tighten access but never relax it. Automation can push the system toward normal mode only.
Four walls around memory
- Two personas. Private additions are injected only in private mode; their text does not exist in the normal prompt.
- Two summaries. Rolling summaries use separate keys. Crucially, the normal summary folds a masked view: private segments disappear before older material is compressed into long-term context.
- Two long-term memory pads. Stable facts are stored separately, and the private pad is never loaded in normal mode.
- Segment masking. When normal mode reads the full timeline, each private interval is replaced by one bridge placeholder.
Why the placeholder must be constant
The placeholder is a hand-written constant meaning roughly: “There was an earlier private interval; it need not be repeated; everyday conversation has resumed.” A more natural bridge generated from context was considered and rejected:
If a bridge is generated from protected content, the bridge becomes a leakage channel.
Any bridge that summarises the interval carries information, however discreetly. A constant carries zero content. Normal mode knows only that an interval existed. Naturalness is handled by writing a sufficiently general sentence, not by weakening isolation.
The same principle shapes the transition line spoken when leaving private mode: fixed intent, variable wording. The constant instruction asks her to show care, offer water, return to ordinary conversation, and mention no specifics. Variation exists only in phrasing.
Crash semantics: fail closed
A crash during private mode leaves an open interval with a start but no end. On restart, every open interval is closed at the end of the stored record. Everything before the crash remains inside the masked segment; everything after restart begins outside it. Hiding a little ordinary conversation is preferable to exposing one protected line.
Three isolation failures
Incident one: isolation never activated, while every test passed. The page and local service used different origins. Browser policy silently blocked the mode query. By fail-safe design, a failed query meant normal mode, so the system stayed normal and the isolation path never ran. Network mocks kept every test green. The fail-safe behaved correctly, but a mocked test cannot discover that the real link does not exist. Real-link checks were added afterward.
Incident two: double trimming. During a refactor, the context window subtracted the material already covered by the summary twice. Visible history became empty on every turn. She greeted repeatedly and appeared to lose her intelligence; the root cause was window arithmetic. A regression check now targets that exact symptom.
Incident three: deleting the entire prefix. The first masking method removed everything before a private segment. It was simple, but also erased earlier normal history, so ordinary conversation could not continue across the interval. Segment-level masking restored continuity before and after, with the placeholder between them.
Verification
Twenty-two regression tests protect the semantics: normal mode retains its own history on both sides of a private interval; every interval produces exactly one placeholder; multiple intervals remain separate; a crash-open interval is closed and restart content stays outside it; summary watermarks advance independently; normal-summary input contains zero private characters; and normal-mode retrieval searches only the masked view. When the memory system was later rewritten outside the upstream project, all 22 tests moved unchanged and became the migration acceptance criteria.
Reusable principles
- Content classification belongs at the data-visibility layer. A prompt is courtesy, not a wall.
- The failure direction of every automated action must be declared and must point toward safety.
- Metadata generated from protected content is a leakage channel, including seemingly harmless transition text.
- A good fail-safe can conceal a broken link; the better it works, the more important an independent connectivity test becomes.