# The four memory tiers

Connect keeps memory at four scopes and resolves them narrowest-first: contact beats endpoint, endpoint beats channel, channel beats workspace. `tiers()` returns all four for a piece of work, each labelled with the tier that owns it, and a tier with nothing in it comes back empty rather than being left out. That is the whole model — there is no fifth scope and no hidden precedence.

- **Status:** Available
- **Audience:** both
- **In the app:** #/relationships, #/mailboxes
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/memory/tiers/

## The four scopes

| Tier | Identified by | Typical content | Applies to |
|---|---|---|---|
| Workspace | The workspace itself | What the business does, how it talks, standing policy | Everything |
| Channel | `email`, `whatsapp`, `sms`, `voice` | Conventions that hold for one medium | Every conversation on that channel |
| Endpoint | One mailbox, or one phone number | The purpose of a particular line or address | Work arriving at or leaving that endpoint |
| Contact | One person | Preferences, constraints, history that shapes tone | Every conversation with that person |

**Endpoint** is the tier people misjudge most often. It is not "the email channel" and it is not "this customer" — it is one address or one number. A workspace with a sales mailbox and a support mailbox will get two different, correct behaviours out of two endpoint memories, where a channel memory would have flattened both.

## How resolution actually runs

1. Connect establishes the four coordinates for the work in hand: the workspace, the channel, the endpoint it arrived at or will leave from, and the contact, when one has been resolved.
   - Result: Any coordinate that is unknown simply contributes nothing. An unidentified caller has no contact tier, not a wrong one.
2. `tiers()` collects the memory that applies at each coordinate and returns it grouped by owning tier.
   - Result: You get four labelled sets, not one merged blob, so it stays possible to say which tier a behaviour came from.
3. The consuming code — the drafting step, or `voice_engine.brief()` on a call — reads them narrowest-first.
   - Result: Where two of them speak to the same subject, the narrower one is the one that governs. The broader line is not deleted; it is outranked.

> **Note** Narrowest-first is the same order autonomy resolves in: contact, endpoint, channel, workspace. If you already know why a rule set against one contact overrides the channel's, you already know how memory resolves.

## Why nothing is silently dropped

A scope with nothing in it is included in the result as an empty set. The alternative — omitting it — makes two genuinely different situations look identical: "this business has said nothing about this person" and "this code path never asked about this person". Those need different fixes, and a missing key cannot tell you which one you have.

The visible consequence is in the memory viewer, which shows four headings whether or not each has rows underneath. A support agent looking at a difficult thread can see at a glance that the contact tier is empty and the workspace tier is doing all the work, which is usually the explanation for a reply that was correct but impersonal.

## Choosing where a line belongs

**It is true of the business** — Workspace. Opening hours policy, what is never promised, how the business refers to itself.
**It is true of a medium** — Channel. That voice replies stay under a couple of sentences; that WhatsApp is answered in the caller's language.
**It is true of one line or mailbox** — Endpoint. That the accounts mailbox never discusses pricing; that one number is the after-hours line.
**It is true of one human** — Contact. A preference, an accessibility need, a constraint on when they may be contacted.
**It is a prohibition on contacting somebody** — Contact, as a directive — see [block and guidance directives](/docs/memory/directives/). The tag is what carries it, not the sentence.

Writing a line at too broad a scope is the most common self-inflicted problem: one customer's request not to be called before noon, written at the workspace tier, quietly becomes a rule about every customer. It will behave exactly as written, which is the point — but the fix is to move it down, not to argue with the reply.

> **Careful** Writing at too narrow a scope fails more quietly still. A pricing rule written against one contact is invisible to every other conversation, and nothing will tell you it should have been at the workspace tier. When a correction only half-works, check the scope before you check the wording.

## Questions

### What happens when two tiers contradict each other?

The narrower one governs the behaviour, and the broader one stays in place for every other piece of work. Nothing is deleted and nothing is merged. If the contradiction is a mistake rather than a deliberate exception, correct or supersede the line at the level that is wrong instead of adding a third line.

### Can memory be attached to a company rather than a person?

No. There are exactly four scopes and a company is not one of them. Something true of every person at an organisation is usually better expressed as memory on each contact, or as workspace-level policy if it really is a rule about how the business operates. Company records themselves live in [relationships](/docs/relationships/).

### Does contact memory follow a person across channels?

Yes. A contact is a person, not an address, so a memory written while working an email thread applies on a later phone call with the same person, provided the call resolves to that contact. Identity resolution is what makes that hold — a number that has never been linked to anyone has no contact-level memory to read.

## Related

- [Memory in Connect](https://connectbyjbrh.com/docs/memory/)
- [Business memory](https://connectbyjbrh.com/docs/memory/business-memory/)
- [Person memory](https://connectbyjbrh.com/docs/memory/person-memory/)
- [Channel and endpoint memory](https://connectbyjbrh.com/docs/memory/channel-context/)
- [What Connect may do](https://connectbyjbrh.com/docs/autonomy/)
- [Connect ignored what I told it](https://connectbyjbrh.com/docs/troubleshooting/memory-not-applied/)

## What this page is based on

- docs-source/sources/GENERAL.md §6 — tiers(), narrowest-first resolution
- docs-source/sources/GENERAL.md §5 — autonomy scopes in the same order
- `docs-source/facts.py` — CANONICAL_TERMS.Memory, CAPABILITY_STATUS.memory_tiers
