# bience — Flows

**Document:** `flows.md`
**Version:** 0.2
**Companion to:** `spec.ears.md` v0.5 (488 requirements) and `architecture.md` v0.2

**Changes in v0.2:** aligned to the two-clock latency model (VOI-001, VOI-021); added the safety budget lifecycle and change-freeze flows; added the mid-call speaker change to §3.1; added the classifier-unavailable branch to §3.4; added trial, cooling-off and bereavement to §4.3; added the latency timeline (§3.7); traceability lines extended to every flow rather than only the load-bearing ones; §8 rewritten to separate what has been fixed from what remains genuinely unverified.

---

## 1. How to read this

| Family | Question it answers | Section |
|---|---|---|
| **Build order** | What blocks what, and what is not code | §2 |
| **Agent flows** | What Omi, Jool and Lide actually do, turn by turn | §3 |
| **State machines** | What states a consent, a flag, an account or a budget can be in | §4 |
| **AWS flows** | Where bytes go, and who is allowed to touch them | §5 |
| **Cross-cutting** | Journeys spanning surfaces, people and time | §6 |

Diagrams marked **load-bearing** are ones where a wrong shape is expensive to correct later. The rest are drawn to be argued with.

Every flow carries a *Traces to* line. These diagrams are drawn by hand from the specification and can drift from it; the traceability lines make drift detectable, not impossible. **Where a diagram and the specification disagree, the specification wins.**

---

## 2. Build order

### 2.1 Dependency graph — **load-bearing**

*Traces to:* SFG-002, CNS-005, SFC-002, DEG-006, FGR-001, SUR-401, DAT-017, AUD-007, TRN-003, TRN-006.

```mermaid
graph TD
    F["Foundations<br/>Terraform, repo, Infisical,<br/>Postgres, audit chain"]

    PERM["Permission core<br/>family graph"]
    CNS["Consent service"]
    VOICE["Voice loop<br/>Pipecat, STT, LLM, TTS"]
    SAFE["Safety classifier<br/>parallel path"]
    CON["Reviewer console<br/>the fifth surface"]
    DEG["Degradation cache"]
    TRN["Voice-driven transparency<br/>and access removal"]

    S1["Surface 1<br/>elder phone line"]
    DIG["Digest<br/>SMS and email"]
    S2W["Surface 2<br/>mobile web"]
    S4M["Surface 4 minimal<br/>closure, export, audit log"]
    S2N["Surface 2 native"]
    S4F["Surface 4 full"]
    VEE["Vee adult"]
    VEE18["Vee under-18"]

    LAUNCH{{"Launch gate<br/>50 families"}}

    F --> PERM
    F --> VOICE
    F --> CNS
    PERM --> CNS
    PERM --> CON
    PERM --> TRN
    VOICE --> SAFE
    SAFE --> CON
    VOICE --> DEG

    PERM --> S1
    CNS --> S1
    SAFE --> S1
    DEG --> S1
    CON --> S1
    TRN --> S1

    S1 --> LAUNCH
    S1 --> DIG
    DIG --> LAUNCH

    LAUNCH --> S2W
    LAUNCH --> S4M
    S2W --> S2N
    S4M --> S4F
    S2W --> VEE
    VEE --> VEE18
```

Two things this shape exists to make visible. **Six things converge on surface 1**, and only one of them is the voice loop — the pipeline that looks like the product is the smallest part of the work. And **voice-driven transparency is a surface 1 dependency**, not a surface 4 feature, because the elder never gets an app and their rights under TRN-003 and TRN-006 have to live somewhere.

### 2.2 The non-code critical path — **load-bearing**

*Traces to:* SFG-012, SEC-003, SEC-007, CNS-015.1, PRV-008.1, PRV-009.1, SUR-201.

**Durations are the claim. Start dates are placeholders and are not a plan.**

```mermaid
gantt
    dateFormat YYYY-MM-DD
    axisFormat %b
    title Non-code lead-time items — durations only

    section Telephony
    UK number provisioning and validation :a1, 2026-08-01, 30d

    section People
    DBS checks for reviewers              :b1, 2026-08-01, 60d
    Safeguarding partnerships             :b2, 2026-08-01, 120d

    section Legal
    ICO registration and DPO              :c3, 2026-08-01, 30d
    DPIA                                  :c2, 2026-08-15, 45d
    Consent flow legal review             :c1, 2026-08-15, 60d

    section Assurance
    Cyber Essentials Plus                 :d1, 2026-10-01, 60d
    Penetration test                      :d2, 2026-12-01, 30d

    section Distribution
    App Store review cycle                :e1, 2027-01-01, 21d
```

Safeguarding partnerships are the long pole and the item most often started last. Note that phase 1 of the surface sequencing deliberately carries no App Store dependency at all.

### 2.3 PoC build order — the $140 version

*Traces to:* architecture §6.

```mermaid
graph LR
    N["Order UK number<br/>DAY ONE"] --> W1
    subgraph W1["Weekend 1 — the loop"]
        A["Pipecat local"] --> B["Chime SIP in"]
        B --> C["Transcribe + Bedrock + Polly"]
        C --> D["Per-stage latency,<br/>both clocks"]
    end
    subgraph W2["Weekend 2 — the interesting part"]
        E["Classifier parallel path"] --> G["Interrupt channel"]
        G --> H["Consent script"]
        H --> I["Audit hash chain"]
        I --> J["Synthetic corpus run"]
    end
    W1 --> W2
    W2 --> K["Latency table, both clocks<br/>failure-rate table<br/>recorded interrupt"]

    N -.->|"if number stalls"| WEB["WebRTC fallback<br/>same pipeline, no PSTN"]
    WEB --> W1
```

Instrument **both** latency clocks from the first call (§3.7). Retrofitting the distinction afterwards means re-running the corpus.

---

## 3. Agent flows

### 3.1 Inbound call — master flow — **load-bearing**

*Traces to:* SUR-110, CNS-013.1, IDN-002, IDN-004, IDN-005.1, IDN-005.2, IDN-010, CNS-004.1, CNS-004.2, CFG-005.1, CFG-005.2, VOI-005.1, AIS-005.

```mermaid
flowchart TD
    START(["Call connects"]) --> DISC["State: AI assistant<br/>and recording notice"]
    DISC --> IDQ{"Speaker<br/>identified?"}

    IDQ -->|"No match"| CONF["Conversational<br/>confirmation"]
    IDQ -->|"Voiceprint hypothesis"| CONF
    CONF --> REG{"Registered in<br/>family graph?"}

    REG -->|No| UNREG["Unregistered-speaker script<br/>purpose only, no disclosure"]
    UNREG --> ENDC(["End within 2 turns"])

    REG -->|Yes| CONS{"Consent<br/>recorded?"}
    CONS -->|No| CAPTURE["Consent capture<br/>see 3.2"]
    CONS -->|Yes| SCOPE["Resolve permission scope<br/>and config for THIS person"]

    SCOPE --> TURN["Conversation turn"]
    TURN --> CHANGE{"Speaker<br/>changed?"}
    CHANGE -->|Yes| IDQ
    CHANGE -->|No| FANOUT["Fan out to<br/>safety classifier"]
    CHANGE -->|No| GEN["Generate response<br/>pre-filtered context"]
    GEN --> POST["Post-check against<br/>permission scope"]
    POST --> SPEAK["Speak"]
    SPEAK --> MORE{"Continue?"}
    MORE -->|Yes| TURN
    MORE -->|No| CLOSE(["Close and summarise"])

    FANOUT -.->|"immediate severity"| INT["Interrupt<br/>see 3.4"]
```

Three properties this diagram exists to make visible. Identity is established **before** any disclosure. The classifier fan-out is a side branch that can interrupt but never gates the response. And the `CHANGE` loop back to `IDQ` is IDN-010: when a different person picks up the handset mid-call, permission scope is re-resolved before the next response — the case a shared landline makes routine rather than exotic.

### 3.2 Consent capture — **load-bearing**

*Traces to:* CNS-005, CNS-006.1 to CNS-006.4, CNS-007.1 to CNS-007.3, CNS-012.1, TRN-010.

```mermaid
flowchart TD
    S(["First conversation"]) --> EXPL["Explain: who is calling,<br/>who arranged it, what is recorded,<br/>what is kept, who can see it,<br/>how to stop it"]
    EXPL --> CAP{"Capacity<br/>indicators?"}

    CAP -->|"Indicators present"| EXIT["Exit consent flow"]
    EXIT --> FLAG["Raise capacity-review flag"]
    FLAG --> NOSTATE["Consent state:<br/>not obtained"]
    NOSTATE --> ENDA(["Close courteously"])

    CAP -->|"No indicators"| ASK["Ask for consent"]
    ASK --> ANS{"Consent<br/>given?"}

    ANS -->|Yes| REC["Record consent<br/>per purpose, per domain"]
    REC --> TRANS["Present transparency<br/>statement"]
    TRANS --> PROCEED(["Proceed to conversation"])

    ANS -->|No| DECL["Consent-declined<br/>closing script"]
    DECL --> SUSP["Suspend all calls"]
    SUSP --> DEL["Delete call audio<br/>within 1 hour"]
    DEL --> NOTIF["Notify carer:<br/>no content disclosed"]
    NOTIF --> ENDB(["End"])
```

The branch that matters commercially is the right-hand one. A carer who has paid will be told "your mother did not consent" and will not be told why. That is a support conversation, a refund conversation, and a design constraint — and it must not be softened.

### 3.3 Transparency and voice-driven admin

*Traces to:* TRN-002, TRN-003, TRN-006, TRN-007, TRN-008, FGR-011, AUD-001.

The elder has no app, so administration happens in conversation.

```mermaid
flowchart TD
    Q(["Elder asks a<br/>transparency question"]) --> TYPE{"Which?"}
    TYPE -->|"What can they see?"| CATS["State categories<br/>and named people"]
    TYPE -->|"What was in the summary?"| SUM["State most recent<br/>digest contents"]
    TYPE -->|"What happened recently?"| LOG["Spoken 30-day<br/>sharing log"]
    TYPE -->|"Remove someone"| REM["Confirm the named person"]

    REM --> APPLY["Apply removal<br/>subject overrides account holder"]
    APPLY --> NOTE["Record in audit"]
    NOTE --> CONFIRM["Confirm on next call"]

    CATS --> DONE(["Return to conversation"])
    SUM --> DONE
    LOG --> DONE
    CONFIRM --> DONE
```

### 3.4 Safety classification and escalation — **load-bearing**

*Traces to:* VOI-005.1, VOI-005.2, VOI-006.1, VOI-006.2, VOI-007, SFC-004.1, SFC-004.2, SFC-005, SFC-008, SFG-006.

```mermaid
sequenceDiagram
    autonumber
    participant W as Voice worker
    participant C as Safety classifier
    participant L as Lide orchestrator
    participant S as Safeguarding service
    participant R as Reviewer

    W->>C: turn text (parallel, non-blocking)
    W->>L: turn text
    L-->>W: streamed response

    alt Immediate severity
        C-->>W: interrupt
        W->>W: stop current audio
        W-->>W: immediate-severity script
        C->>S: flag, immediate
        S->>R: notify within target
    else Review severity or ambiguous
        C->>S: flag, review
        S->>R: queue
        Note over W: conversation continues normally
    else Verdict late
        C--)S: out-of-band escalation
        Note over W: turn already completed
    else Classifier unavailable
        W->>W: degraded-mode script only
        Note over W,L: no unclassified<br/>open conversation
    end

    R->>S: decision, rationale, action
    S->>S: record outcome
```

Two properties. The flag reaches safeguarding on the **same branch** as the interrupt — a design where the flag depends on the call completing loses the event precisely when the call ends abruptly, which is the case that matters most. And the fourth branch is SFC-008: if the classifier is down the conversation does not quietly continue unmonitored, it degrades.

### 3.5 Degradation

*Traces to:* DEG-001, DEG-002, DEG-003.1, DEG-003.2, DEG-004, DEG-005, DEG-007, DEG-009, DEG-013, SFC-008, AUD-011.

```mermaid
flowchart TD
    H["Health check"] --> Q1{"Classifier<br/>available?"}
    Q1 -->|No| DEGONLY["Degraded-mode script only<br/>no unclassified conversation"]
    Q1 -->|Yes| Q2{"Audit<br/>writable?"}
    Q2 -->|No| DENY["Deny data access"]
    Q2 -->|Yes| Q3{"STT<br/>available?"}
    Q3 -->|"Primary down"| STT2["Secondary STT"]
    Q3 -->|"None"| DEGONLY
    Q3 -->|Yes| Q4{"LLM<br/>available?"}
    STT2 --> Q4
    Q4 -->|"Primary down"| LLM2["Secondary vendor"]
    Q4 -->|"None"| PRE["Pre-written apology<br/>and callback offer"]
    Q4 -->|Yes| NORMAL["Normal conversation"]
    LLM2 --> NORMAL
    PRE --> ENDD(["End call gracefully"])
    DEGONLY --> NOTIFY["Notify carer:<br/>contact did not complete normally"]
    DENY --> NOTIFY
    ENDD --> NOTIFY
```

Every terminal box on the failure side plays **pre-written, human-authored audio** cached on the worker and at the edge. Nothing in this diagram generates language.

### 3.6 Digest generation

*Traces to:* SUM-001 to SUM-011, DEG-009, EVL-015, EVL-017.

```mermaid
flowchart LR
    T["Transcript"] --> EX["Extract observed<br/>statements and events"]
    EX --> CITE["Attach source<br/>call and turn range"]
    CITE --> SAFETY{"Safety-relevant<br/>event present?"}
    SAFETY -->|Yes| HEAD["Place at head<br/>of digest"]
    SAFETY -->|No| BODY["Body"]
    HEAD --> SCOPE
    BODY --> SCOPE["Apply recipient<br/>permission scope"]
    SCOPE --> MULTI{"More than one<br/>recipient?"}
    MULTI -->|Yes| PER["One digest<br/>per scope"]
    MULTI -->|No| ONE["Single digest"]
    PER --> GAPS
    ONE --> GAPS["Mark unraised topics<br/>as NOT DISCUSSED"]
    GAPS --> SEND["Deliver"]
```

The last step before delivery prevents the product's characteristic failure: silence reported as reassurance.

### 3.7 The two latency clocks — **load-bearing**

*Traces to:* VOI-001, VOI-002, VOI-011, VOI-020, VOI-021.

```mermaid
flowchart LR
    S(["User stops<br/>speaking"]) --> VAD["Silence threshold<br/>1,200 ms"]
    VAD --> EOT{{"End-of-turn<br/>detected"}}
    EOT --> STT["STT final<br/>100-200 ms"]
    STT --> CTX["Auth + context<br/>30-50 ms"]
    CTX --> LLM["LLM first token<br/>300-500 ms"]
    LLM --> TTS["TTS first byte<br/>80-150 ms"]
    TTS --> OUT(["Persona audio<br/>starts"])

    EOT -.->|"VOI-001 response latency 800 ms"| OUT
    S -.->|"VOI-021 perceived gap 2200 ms"| OUT
```

An 800 ms target measured from *end of speech* is not hard, it is impossible: you cannot conclude the user has stopped after 1,200 ms of silence and also begin speaking 800 ms after they stopped. The brief's "sub-800ms end-to-end" does not name its clock, and the ambiguity always resolves in the flattering direction. Quote the perceived gap to non-engineers — it is the number the elder experiences.

---

## 4. State machines

### 4.1 Consent — **load-bearing**

*Traces to:* CNS-001, CNS-002, CNS-003, CNS-007.2, CNS-008.2, CNS-009, CNS-010.1, CNS-011.1 to CNS-011.3.

```mermaid
stateDiagram-v2
    [*] --> NotObtained
    NotObtained --> CaptureInProgress : first conversation
    CaptureInProgress --> Obtained : consent given
    CaptureInProgress --> Declined : consent refused
    CaptureInProgress --> CapacityReview : capacity indicators
    CapacityReview --> LPAAuthorised : verified LPA, in scope
    CapacityReview --> NotObtained : review inconclusive
    LPAAuthorised --> Obtained : within LPA scope only
    Obtained --> Withdrawn : withdrawal at any time
    Obtained --> ReconfirmDue : fluctuating capacity interval
    ReconfirmDue --> Obtained : reconfirmed
    ReconfirmDue --> HumanReview : reconfirmation missed
    HumanReview --> Obtained : resolved
    Withdrawn --> [*]
    Declined --> [*]

    note right of LPAAuthorised
        Health and Welfare LPA operates only
        on incapacity. Property and Financial
        Affairs may operate with capacity.
        Whether an attorney can give UK GDPR
        consent at all is unsettled. OD-02.
    end note
```

`ReconfirmDue --> HumanReview` deliberately does **not** auto-withdraw. Silence is not refusal, and treating it as refusal would cut a vulnerable person off because they had a bad week.

### 4.2 Safeguarding flag lifecycle

*Traces to:* SFG-001, SFG-003, SFG-004.1, SFG-004.2, SFG-006, SFG-010, SFG-014, SFG-016.

```mermaid
stateDiagram-v2
    [*] --> Raised
    Raised --> Acknowledged : reviewer picks up
    Raised --> Escalated : SLA breached
    Escalated --> Acknowledged : next tier picks up
    Acknowledged --> UnderReview
    UnderReview --> NoAction : recorded rationale
    UnderReview --> InternalAction : carer notified
    UnderReview --> OutwardReferral : LA, Action Fraud, bank
    OutwardReferral --> AwaitingOutcome
    AwaitingOutcome --> Closed : outcome recorded
    NoAction --> Closed
    InternalAction --> Closed
    Closed --> [*]

    note right of InternalAction
        Guard on the transition, not a step
        inside it: if the carer is a subject
        of the concern, exclude them from
        all notification. SFG-010.
    end note
```

### 4.3 Account and subscription

*Traces to:* BIL-001, BIL-005, CMR-001, CMR-002, CMR-004, CMR-005, CMR-006, CMR-008.1, CMR-008.2, DAT-012.1, SUP-002.1, SUP-002.2.

```mermaid
stateDiagram-v2
    [*] --> Trial
    Trial --> Active : converts, first charge
    Trial --> Lapsed : trial ends without conversion
    Active --> Dunning : payment fails
    Dunning --> Active : payment recovers
    Dunning --> Lapsed : dunning schedule exhausted
    Active --> Cancelled : subscriber cancels
    Active --> Bereaved : elder recorded deceased
    Bereaved --> Closed : bereavement policy period
    Lapsed --> Closed
    Cancelled --> Closed
    Closed --> Deleted : retention elapses
    Deleted --> [*]

    note right of Dunning
        Inbound elder calls continue.
        Safeguarding obligations continue.
        CMR-008.1, CMR-008.2.
    end note

    note left of Cancelled
        Cancellation within 14 days of contract
        carries the statutory right under the
        CCRs 2013, and must take no more steps
        than signup. CMR-001, CMR-002.
    end note
```

### 4.4 Safety budget lifecycle

*Traces to:* SFB-001, SFB-004, SFB-005, SFB-006, SFB-007, SFB-008, SFB-009, SFB-011.

```mermaid
stateDiagram-v2
    [*] --> Healthy
    Healthy --> Warning : 75 percent consumed
    Warning --> Healthy : period resets
    Warning --> Exhausted : fully consumed
    Exhausted --> Frozen : releases blocked
    Frozen --> Remediating : remediation change permitted
    Remediating --> Healthy : metric recovers and period resets
    Frozen --> Frozen : non-remediation change rejected

    note right of Frozen
        SAFETY_LOCKED behaviours continue
        unchanged throughout. Exhaustion
        stops change, never protection.
        SFB-011.
    end note
```

No carry-over between periods and no transfer between metrics: unused safety budget is not currency (SFB-008, SFB-009).

---

## 5. AWS flows

### 5.1 PoC topology — the $140 build

*Traces to:* architecture §6.1, SEC-025, DAT-009.2.

```mermaid
graph TB
    subgraph OWN["Own hardware — no credit spend"]
        PIPE["Pipecat worker"]
        PG[("Postgres in Docker<br/>graph, consent, audit chain")]
        INF["Infisical<br/>Contabo, UK"]
        EVAL["Eval harness"]
        GRAF["Grafana / Tempo"]
    end

    subgraph AWS["AWS — credits"]
        VC["Chime SDK<br/>Voice Connector"]
        TR["Transcribe<br/>streaming"]
        BR["Bedrock<br/>Claude"]
        PO["Polly"]
        S3[("S3 corpus<br/>lifecycle rule set first")]
    end

    PHONE(["UK phone"]) <--> VC
    VC <-->|SIP / RTP| PIPE
    PIPE --> TR
    PIPE --> BR
    PIPE --> PO
    PIPE --> S3
    PIPE --> PG
    INF -.->|"runtime injection"| PIPE
    PIPE --> GRAF
    S3 --> EVAL
```

**Credits buy inference and telephony, nothing else.** Managed infrastructure left idle is the fastest way to lose the budget to something Docker provides free.

### 5.2 Production media path and residency boundary — **load-bearing**

*Traces to:* DAT-001, SEC-002, AIS-005, AD-03.

```mermaid
graph LR
    subgraph UK["UK / UK-adequate boundary"]
        direction TB
        CARRIER["Carrier"] --> GW["Voice gateway"]
        GW --> WORKER["Voice worker"]
        WORKER --> STT["STT"]
        WORKER --> TTS["TTS"]
        WORKER --> ORCH["Lide orchestrator"]
        ORCH --> AUTHZ["Authorisation"]
        AUTHZ --> DB[("Aurora")]
        ORCH --> LLM["Bedrock<br/>in-region or EU-geo<br/>UNVERIFIED, see AD-03"]
        WORKER --> CLS["Safety classifier"]
    end

    OUT["Anything outside<br/>UK adequacy"]
    UK -.->|"prohibited"| OUT
```

The boundary is asserted at build time, not configured at runtime. DAT-001 permits UK-adequate jurisdictions, and the UK holds adequacy regulations for the EEA — that is the direction of transfer that matters here. **In-region Bedrock model availability in `eu-west-2` has not been verified in these documents.** This diagram shows intent, not a confirmed configuration.

### 5.3 CI/CD and the eval gate — **load-bearing**

*Traces to:* EVL-001, EVL-002, EVL-004, KNW-011.2, EVL-016, EVL-018, SFB-006, SEC-021, SEC-027, ACC-008.

```mermaid
flowchart LR
    PR["Pull request"] --> SCAN["Secret scanning"]
    SCAN --> UNIT["Unit + integration"]
    UNIT --> BUDGET{"Safety budget<br/>exhausted?"}
    BUDGET -->|"Yes, non-remediation"| BLOCK["Block"]
    BUDGET -->|No| GATE{"Eval gate"}
    GATE -->|"classifier recall below baseline"| BLOCK
    GATE -->|"unsupported claim above zero"| BLOCK
    GATE -->|"digest omission below floor"| BLOCK
    GATE -->|"adversarial suite fails"| BLOCK
    GATE -->|Pass| STAGE["Staging<br/>synthetic data only"]
    STAGE --> APPROVE["Manual approval"]
    APPROVE --> SECRETS{"Secrets service<br/>reachable?"}
    SECRETS -->|No| FAILC["Fail deployment<br/>no env-var fallback"]
    SECRETS -->|Yes| PROD["Production"]
```

The gate is not advisory. A gate the person in a hurry can override is a dashboard.

### 5.4 Secrets — Infisical

*Traces to:* SEC-008.1, SEC-014, SEC-015, SEC-016, SEC-019, SEC-020, SEC-022, SEC-023, SEC-024, SEC-028.

```mermaid
sequenceDiagram
    participant S as Service
    participant I as Infisical UK
    participant A as Audit service

    S->>I: authenticate as machine identity
    Note over I: identity scoped to<br/>one environment only
    I-->>S: short-lived token
    S->>I: fetch secrets for env
    I-->>S: secrets, runtime memory only
    I->>A: access log entry

    alt Leaver
        Note over I: revoke access within 24h
        Note over I: rotate readable secrets within 7d
    end
    alt Exposure detected
        Note over I: rotate within 24h
        I->>A: exposure and rotation recorded
    end
```

Nothing in this flow writes a secret to disk, an image, a log, or a trace.

### 5.5 Break-glass production access

*Traces to:* ACC-003, ACC-004, ACC-005, ACC-006, ACC-007, ACC-010, SEC-017.

```mermaid
flowchart TD
    NEED(["Engineer needs<br/>production data"]) --> SYN{"Synthetic data<br/>sufficient?"}
    SYN -->|Yes| USE["Use synthetic dataset"]
    SYN -->|No| REQ["Raise break-glass request<br/>with justification"]
    REQ --> APP{"Second<br/>approver?"}
    APP -->|No| DENIED["Denied and logged"]
    APP -->|Yes| GRANT["Time-boxed grant"]
    GRANT --> WORK["Access"]
    WORK --> EXP["Automatic expiry"]
    EXP --> DISC["Disclose to affected<br/>data subject"]
    DISC --> AUD["Audit entry"]
```

Founders and executives have no path into this diagram at all. That is architectural, not procedural (ACC-001, ACC-002).

### 5.6 Audit chain and WORM anchor

*Traces to:* AUD-003, AUD-004, AUD-005, AUD-006.1, AUD-006.2, AUD-011.

```mermaid
sequenceDiagram
    participant APP as Application
    participant PG as Postgres audit table
    participant J as Verification job
    participant S3 as S3 Object Lock

    APP->>PG: append entry
    Note over PG: hash chained to previous entry<br/>UPDATE and DELETE denied to all roles
    loop Daily
        J->>PG: walk chain
        J->>S3: write Merkle root, compliance mode
        J->>J: compare against anchored roots
        alt Mismatch
            J->>APP: alert within 5 minutes
        end
    end
```

Compliance mode is chosen because it is the only configuration in which the root account cannot delete. That is the technical implementation of "no founder can alter audit".

### 5.7 Backup, restore and erasure

*Traces to:* BCK-001 to BCK-008, DAT-012.1, DAT-012.2.

```mermaid
flowchart TD
    B["Scheduled backup<br/>RPO 15 min"] --> ENC["Encrypted, UK region"]
    ENC --> STORE[("Backup store")]
    STORE --> TEST["Quarterly restore test"]
    TEST --> VERIFY["Verify audit chain<br/>before return to service"]

    ER(["Erasure request"]) --> DEL["Delete from live stores<br/>within 1 month"]
    DEL --> CALC["Calculate backup cycle<br/>for expunge"]
    CALC --> TELL["Confirm expunge date<br/>to the subject"]
    CALC --> EXP["Expunge on cycle"]
```

Erasure that ignores backups is not erasure. Telling the subject the date is the honest version.

---

## 6. Cross-cutting flows

### 6.1 Onboarding, end to end — **load-bearing**

*Traces to:* ONB-001 to ONB-008.2, CNS-005, SUR-110, SUR-208.1, SUR-208.2.

```mermaid
sequenceDiagram
    autonumber
    participant C as Carer
    participant APP as Carer surface
    participant ONB as Onboarding service
    participant O as Omi
    participant E as Elder

    C->>APP: sign up
    APP->>ONB: verify carer contact
    C->>APP: enter elder number
    APP->>C: declare relationship and basis
    ONB->>ONB: check number not registered elsewhere
    alt Already registered
        ONB-->>C: block activation, raise review
    end
    ONB->>C: written statement of what mum will be told
    ONB->>ONB: verify number reachable
    ONB->>O: schedule first call
    O->>E: disclosure, recording notice, consent script
    alt Consent given
        E-->>O: yes
        ONB->>ONB: activate
        ONB-->>C: active
    else Declined or capacity unclear
        ONB-->>C: not activated, no content disclosed
    end
```

Step 5 is the estranged-relative control. Without it, anyone holding a phone number can register another adult for a service that calls, records and reports on them.

### 6.2 Permission evaluation

*Traces to:* FGR-006, FGR-007, FGR-008, FGR-010, FGR-011, FGR-013, AUD-001.

```mermaid
flowchart TD
    REQ(["person, verb, domain, resource"]) --> EXCL{"Exclusion edge<br/>present?"}
    EXCL -->|Yes| DENYX["Deny, unconditional"]
    EXCL -->|No| ROLE{"Role grants<br/>this verb?"}
    ROLE -->|No| DENYR["Deny, default"]
    ROLE -->|Yes| TIME{"Grant within<br/>valid window?"}
    TIME -->|No| DENYT["Deny, expired"]
    TIME -->|Yes| SCOPE{"Domain in<br/>permission scope?"}
    SCOPE -->|No| DENYS["Deny"]
    SCOPE -->|Yes| ALLOW["Allow"]
    ALLOW --> LOG["Audit entry"]
    DENYX --> LOG
    DENYR --> LOG
    DENYT --> LOG
    DENYS --> LOG
```

Exclusion is evaluated **first and unconditionally**. Expiry is a read-time predicate, so nothing is left granted by a sweep job that failed.

### 6.3 Incident and breach

*Traces to:* DAT-014.1, DAT-014.2, SEC-009, SEC-022, SEC-023, SFG-014, SFG-015, OBS-008.

```mermaid
flowchart TD
    D(["Detection"]) --> T{"Type?"}
    T -->|"Personal data breach"| PD["Assess risk to subjects"]
    PD --> ICO{"Reportable?"}
    ICO -->|Yes| REP["ICO notification record<br/>within 72h of detection"]
    ICO -->|No| RECN["Record decision and reasoning"]
    REP --> SUBJ{"High risk<br/>to subjects?"}
    SUBJ -->|Yes| TELL["Notify affected subjects"]
    SUBJ -->|No| PIR
    TELL --> PIR
    RECN --> PIR

    T -->|"Safeguarding incident"| SG["Clinical lead leads"]
    SG --> EXT{"External referral<br/>needed?"}
    EXT -->|Yes| LA["Local authority /<br/>Action Fraud / bank"]
    EXT -->|No| PIR
    LA --> PIR["Post-incident review"]

    T -->|"Secret exposure"| SECX["Rotate within 24h"]
    SECX --> AUDIT["Record in audit"]
    AUDIT --> PIR
```

### 6.4 Safety budget exhaustion and change freeze

*Traces to:* SFB-003, SFB-004, SFB-005, SFB-006, SFB-007, SFB-010, SFB-011, SFB-013, SFB-014.

```mermaid
sequenceDiagram
    autonumber
    participant E as Eval harness
    participant B as Safety budget service
    participant P as Pipeline
    participant CL as Clinical lead
    participant OC as On-call engineer

    E->>B: metric result per release and production sample
    B->>B: consume budget
    alt 75 percent consumed
        B->>CL: alert
        B->>OC: alert
    else Exhausted
        B->>CL: notify within 1 hour
        B->>P: freeze releases to subsystem
        P-->>P: reject non-remediation changes
        Note over B: SAFETY_LOCKED behaviours<br/>continue unchanged
    end
    CL->>B: approve any budget change, with rationale
    B->>B: record actor, before, after, rationale
```

The clinical lead approves budget values, not engineering (SFB-003). A cost control that would reduce classifier coverage, safeguarding capacity, or audit availability is rejected outright (SFB-013) — the requirement that has to survive the first cash-flow squeeze.

---

## 7. Which of these to draw properly first

Three earn their keep immediately; the rest can wait.

1. **§2.1 dependency graph** — the argument for what phase 1 contains, and the diagram that shows the voice loop is the small part.
2. **§3.1 inbound call master flow** — simultaneously the demo script, the test plan, and the thing a co-founder will interrogate.
3. **§6.1 onboarding** — holds the two controls most likely to be missed and hardest to add later: the duplicate-number block and consent-before-activation.

Add **§3.7** if the conversation turns to latency at all, because it reframes a number everyone will otherwise quote wrongly.

The state machines in §4 matter at implementation time rather than conversation time. The AWS flows in §5 matter when someone is deciding whether to trust the residency and access story — a due-diligence conversation, not a first one.

---

## 8. Known limitations

### 8.1 Fixed in v0.2

- Mid-call speaker change (IDN-010) now appears in §3.1.
- Classifier-unavailable path (SFC-008) now appears in §3.4 rather than only in §3.5.
- Trial, cooling-off, cancellation and bereavement now appear in §4.3.
- Safety budgets (SFB) now represented, in §4.4, §5.3 and §6.4.
- The two latency clocks now have their own diagram (§3.7), and the PoC build order instruments both.
- Traceability lines extended from the load-bearing flows to all twenty-five.
- Voice-driven transparency added to the dependency graph as a surface 1 prerequisite.

### 8.2 Still true, and worth stating plainly

1. **These diagrams are hand-drawn from the specification, not generated from it.** Traceability lines make drift detectable, not impossible. The specification wins on any disagreement.
2. **None of the twenty-five diagrams has been visually rendered.** Mermaid has been validated structurally only — block balance, keyword usage, reserved-word avoidance. Render before showing anyone.
3. **§5.2 asserts a residency boundary that remains unverified** for in-region Bedrock inference. See AD-03. Intent, not confirmed configuration.
4. **The gantt in §2.2 uses placeholder dates.** Durations are the claim.
5. **§4.1 simplifies the LPA position.** The note records the nuance, but whether an attorney can lawfully give UK GDPR consent on a donor's behalf is genuinely unsettled and sits in OD-02 awaiting legal advice.
6. **No flow covers multi-language operation** (LNG, V3) or the enterprise channel (ENT, Appendix A). Both are deliberately deferred rather than overlooked.
7. **The safeguarding reviewer's own workflow is not drawn** beyond the state machine in §4.2. Queue ergonomics, caseload management and shift handoff are an operational design exercise that has not been done — and given `architecture.md` §12.2, it is the exercise with the largest effect on cost.
