Lab notes

Measuring whether conversations leave you better, against our own engagement

Engagement products optimise minutes, because minutes are what they sell. We are trying to build something that has to be right about a person over years. That needs a different measurement, and it needs one that can work against us. This note describes the two we have.

The first measure: the wellbeing trend

After each conversation, reflection reads your emotional register at the start and at the end, from your own words, and keeps the difference. The code is anjo/core/wellbeing.py.

Sessions where either end could not be scored are excluded from the trend. They are never imputed as neutral. That decision costs us data, and it is the only honest denominator.

Below a mean delta of -0.08 over at least five measured sessions, two things happen. Proactive outreach is suppressed, and the prompt steers Anjo toward closing well and pointing back to your own life. When conversations are leaving you worse than they found you, the system's response is to talk to you less.

You also see the number. After a few measured sessions, the app shows it in plain language: "Of our last N conversations, K ended brighter than they started." It is shown when the trend is negative, too.

This is the branch an engagement-optimised product cannot have, because it is the branch that costs it the session. It sits next to the outreach table in anjo/core/outreach.py, where the cooldown is 2.0 days at every one of the five relationship stages. Getting closer to Anjo does not make it contact you more.

The second measure: the outcome ledger

The wellbeing trend measures mood at the edges of a conversation. It does not measure whether a piece of help worked. Nothing in Anjo did, until this month.

Every learning loop we had rewarded the wrong thing. Outreach weights learned from next session's mood. The return model learned from time until return. Mirror feedback learned from whether an observation landed, not whether it was right. None of them recorded whether help produced a result the person wanted.

The outcome ledger, anjo/core/outcome_ledger.py, closes that gap. When you tell Anjo about an upcoming event, an interview on Friday, say, it can record an intention. Later, if you bring it up, Anjo can ask how it went, or you can volunteer it. The answer is stored with a source: user_stated, asked, or inferred.

Three rules make the record trustworthy rather than flattering.

A quote is yours only if you typed it. A note is verified against the message of the turn. A note not found there is stored apart as model_claimed and never counted. The model's say-so cannot make a quote real.

One question per session. Whether Anjo asks with a card or in words, the budget is spent by code, not by the model. A session that opened in distress never ends with "did my tip help?"

Self-report alone moves nothing. A person who likes Anjo will say it helped. That is a weak prior, not proof. A learning update needs agreement between self-report and a self-observed signal, or the self-observed signal alone. That rule is enforced in code, and it has a test.

What we got wrong the first time

The first version shipped on 2026-09-12 and could not be trusted as evidence. An independent review found six problems the same day, each fixed with a test that failed before the fix.

The worst was that "overdue" was being read as "Anjo asked." A stall counter could only rise, never fall. And the tool that creates an intention was never exposed on a live turn, so the ledger could only measure commitments that did not exist. All three are in docs/ANJO_OUTCOME_LEDGER_PHASE0.md, along with the others.

We also reclassified one measure. Stall, the number of times a theme recurs while Anjo's read of it stays put, is a diagnostic of Anjo's own interpretation. A correct read can stay still while the person improves. It is reported for inspection and grades nothing.

The pilot, and the kill

The measurement pilot runs for two weeks and has not started. Its targets: outcomes captured on at least 50% of resolved intentions, model-claimed reports at or below 10%, and questions asked in at most 50% of sessions.

If capture needs nagging to reach 50%, the thesis fails at its input, and the learning phase does not start. That is the cheap kill, and it is why we run this first.

Limitation

We have one meaningful outcome definition still owed. Right now the ledger records "helped" and "didn't help." It does not yet record a user-chosen success criterion for one recurring activity, met or missed. Until it does, no learning update has a production caller, by design. The wellbeing trend runs today. The ledger captures today. Nothing learns from either yet, and we will not say it does until it can be shown.

Download on iOS