A derived product specification for a voice-first eldercare platform, written in EARS (Easy Approach to Requirements Syntax), and the companion flow document it traces to. Every requirement carries its provenance; every diagram names the requirements it implements. Where the two disagree, the specification wins.
This document converts the bience technical brief into a testable requirements baseline using EARS (Easy Approach to Requirements Syntax). It exists to do three things:
V1 through V4 of the bience platform: the elder phone line (Omi), the carer application (Jool), the younger-user application (Vee), the family web admin, the Lide orchestrator, the safety and safeguarding subsystems, the family graph, audit, billing, and the eval harness.
Commercial terms, pricing levels, fundraising, hiring, brand and tone-of-voice guidelines, and the content of the personas' scripted dialogue. Tier boundaries are out of scope; the capability to enforce tiers is in scope.
| Phase | Contents |
|---|---|
| V1 | Surface 1 (elder phone line) + Surface 2 (carer app). Surfaces 3 and 4 stubbed. Single-language (English). Safeguarding by one trained reviewer. |
| V2 | Surface 4 (family web admin) hardened, multi-carer households, tier expansion, richer eval coverage. |
| V3 | Surface 3 (Vee, adult neurodivergent users). Multi-language. |
| V4 | Under-18 users. AADC compliance becomes load-bearing rather than latent. |
Requirements are tagged with the earliest phase in which they must be met, not the phase in which they must be designed for. Several V1 requirements exist specifically because retrofitting them later is impossible (audit chaining, family graph shape, safeguarding taxonomy).
| Actor | Description |
|---|---|
| Elder user | The aging parent. Primary user of the phone line. May have hearing aids, dementia-affected speech, fluctuating capacity. Does not necessarily own a smartphone. |
| Carer | The buyer and primary operator. Adult child, spouse, or paid carer. Uses the carer app. |
| Younger user | Neurodivergent young adult (V3) or child (V4). Uses Vee. |
| Observer | A family member with read-only or partial scope. Sibling, distant relative. |
| Paid carer | Professional carer with time-bounded, scope-limited access. |
| LPA holder | Holder of a registered Lasting Power of Attorney (Health & Welfare, or Property & Financial Affairs). Legally distinct from "carer". |
| Safeguarding reviewer | DBS-checked, trained internal reviewer. Handles flagged events. |
| Clinical lead | Named accountable clinician or safeguarding lead. |
| Support agent | Internal staff handling account and billing issues. |
| Engineer | Internal staff with break-glass-only production access. |
| Founder / exec | Explicitly holds no conversational data access. |
| Persona | Surface | Audience |
|---|---|---|
| Omi | Phone line | Elder user |
| Jool | Carer app | Carer |
| Vee | Younger-user app | Neurodivergent young adult / child |
| System | Responsibility |
|---|---|
| Voice gateway | PSTN/SIP termination, streaming STT/TTS transport, turn-taking, barge-in, latency budget. |
| Lide orchestrator | Persona routing, context assembly, config resolution, guardrail enforcement, tool/escalation dispatch. |
| Safety classifier | Parallel-path real-time classification: suicide ideation, abuse, financial scam, capacity-loss signals. |
| Knowledge service | RAG over authoritative sources with citation-required output. |
| Family graph service | People, roles, permissions, scopes, consent state. |
| Identity service | Speaker identification, confirmation flows, authenticated app sessions. |
| Consent service | Capacity-aware consent capture, renewal, withdrawal. |
| Safeguarding service | Flag intake, triage, severity routing, on-call handoff, regulator reporting. |
| Audit service | Append-only, cryptographically chained access log. |
| Configuration service | Typed per-user config, schema validation, versioning. |
| Billing service | Stripe integration, tier entitlement, feature gating. |
| Usage telemetry service | Per-family minute/token/storage/event accounting; caps and anomaly detection. |
| Degradation controller | Health detection, fallback selection, pre-written response playback. |
| Eval harness | Regression suite, release gating, drift monitoring. |
| Summarisation service | Generation of carer digests from transcript, with source attribution. |
| Onboarding service | Signup, number verification, relationship declaration, activation gating. |
| Input defence layer | Screening of conversational input for instruction injection and abuse. |
| Backup and recovery service | Backup scheduling, restore, RPO/RTO, backup retention. |
| Secrets service | Infisical. Machine identities, per-environment isolation, rotation, secret scanning. |
| Safety budget service | Budget definition, consumption tracking, release blocking on exhaustion. |
| Platform | Cross-cutting; used where no single subsystem owns the behaviour. |
| Pattern | Form |
|---|---|
| Ubiquitous | THE <system> SHALL <response> |
| Event-driven | WHEN <trigger> THE <system> SHALL <response> |
| State-driven | WHILE <state> THE <system> SHALL <response> |
| Unwanted behaviour | IF <condition> THEN THE <system> SHALL <response> |
| Optional feature | WHERE <feature is included> THE <system> SHALL <response> |
| Complex | Combinations of the above |
<DOMAIN>-<nnn>, with decimal sub-identifiers (<DOMAIN>-<nnn>.<n>) where a single trigger has more than one distinct response. Sub-identifiers were introduced at v0.2 to enforce atomicity without renumbering; parent numbers are never reused. Domains: GEN, SUR, VOI, IDN, CNS, CFG, FGR, SFC, SFG, KNW, AUD, ACC, DAT, BIL, USG, DEG, EVL, OBS, SEC, AAD, ACS, SUP, TRN, SUM, ONB, HND, LNG, CMR, PRV, BCK, AIS, SFB, ENT. Design constraints use DC-<nn> (§4.3).
Every requirement carries a second line marking where it came from and why it exists:
↳ *SOURCE* — rationale.
| Source | Meaning | Count |
|---|---|---|
BRIEF/S1–S4 | Stated in a surface description in the brief | |
BRIEF/Q1–Q3 | From one of the three questions candidates asked | |
BRIEF/P1–P10 | From one of the ten harder problems | |
BRIEF/U1–U5 | From one of the five named unknowns | |
BRIEF/HC | From the hard constraints table | |
BRIEF/ARCH | From the reference architecture section | |
| BRIEF total | 219 (43%) | |
LAW/… | Required by statute, regulator or code, and not mentioned in the brief | 65 (13%) |
REVIEW | A gap found while deriving this specification. Not in the brief | 178 (35%) |
USER | Requested directly during drafting | 22 (4%) |
DERIVED | Follows necessarily from another requirement here | 14 (2%) |
Annotations tagged REVIEW v0.5 or REVIEW v0.6 were added during a later correctness pass and name the version, so the drift is visible.
What the split means. The brief is a genuinely strong document — 43% of a 498-requirement specification traces directly to it, which is far more than most founder briefs would support. The 13% legal tranche is the predictable gap: statute does not appear in a technical brief and has to be imported. The 35% review tranche is the interesting number, and it is not a criticism of the brief. It is what a specification is for — the brief names ten hard problems honestly, and specifying them exposes roughly three more requirements for each one, most of which nobody could reasonably have listed in advance.
Each requirement carries (Phase · Priority · Verification).
M must, S should, C couldT test, D demonstration, A analysis, I inspection, R audit/reviewSAFETY_LOCKED — a behaviour that no user, carer, admin, support agent, or configuration value may alter. USER_CONFIGURABLE — a behaviour a permitted actor may alter within a validated schema. Break-glass — time-boxed, second-approved, post-hoc-disclosed emergency access. Flagged event — any conversation turn or pattern the safety classifier scores above a routing threshold.
A requirement of the form SHALL NOT cannot be verified by test: absence cannot be demonstrated over an unbounded input space. Every prohibition in this specification is therefore expressed as a positive restriction — SHALL <do X> only where <condition>, SHALL exclude, SHALL withhold, SHALL limit disclosure to — which is verifiable against a finite, enumerated permitted set.
Two requirements retain SHALL NOT form deliberately, because they reproduce the wording of the ICO Age Appropriate Design Code and altering that wording would weaken the mapping to the standard:
AAD-003 and CMR-009 likewise retain statutory terms — proportionate certainty in the Age Appropriate Design Code and proportionate refund in the Consumer Contracts Regulations 2013. Substituting a number for either would misstate the law; the operational thresholds sit in OD-14 and the refund policy respectively.
Both are verified by inspection and design review (I, R) rather than by test.
The following are design constraints, not requirements. They specify how a requirement is to be met and are recorded separately so that a reviewer challenges the architecture here rather than inside the behavioural baseline. Each is binding until formally superseded.
| ID | Constraint | Binds | Rationale |
|---|---|---|---|
| DC-01 | The family graph SHALL be stored as explicit relationship rows in a relational store, and SHALL NOT be represented as nested documents. | FGR-002 | Nested documents make "who can see this resource" an unbounded scan and make revocation non-atomic. |
| DC-02 | The feature gating layer SHALL be implemented as a module separate from application logic. | BIL-003 | Entitlement checks scattered through application code cannot be proven not to gate a safety behaviour (BIL-004). |
| DC-03 | Conformance with CFG-010 SHALL be demonstrated by automated static analysis executed on every build. | CFG-010 | Manual review does not scale and does not fail the pipeline. |
| DC-04 | The carer app SHALL be delivered on iOS and Android. | SUR-201 | Named platforms; a web-only carer surface does not meet the notification requirements in SUR-205. |
| DC-05 | Carer authentication SHALL use platform biometric authentication with a passcode fallback. | SUR-203 | Biometric-only excludes users who cannot enrol; passcode-only is weaker than the data warrants. |
| DC-06 | Degradation responses SHALL be cached at the edge or on the voice gateway. | DEG-006 | A fallback that requires the orchestrator is not a fallback. |
| Requirement |
|---|
Latency has two clocks, and conflating them produces an unmeetable requirement. Response latency (VOI-001, VOI-002) starts when the gateway decides the user has stopped speaking. Perceived gap (VOI-020, VOI-021) starts when the user actually stopped, and therefore includes the end-of-turn silence threshold of VOI-011. With a 1,200 ms threshold, an 800 ms response latency is a perceived gap of roughly 2,000 ms. Both numbers are honest; only one of them is what the elder experiences. Any target expressed as "sub-800 ms end to end" without naming the clock is ambiguous, and the ambiguity always resolves in the flattering direction.
Why VOI-022 and VOI-023 exist. Telephony carries 8 kHz narrowband audio, typically G.711. Browser and WebRTC testing carries wideband Opus at 16 kHz or above. Word error rates measured on wideband audio are systematically better than the same recogniser achieves on a real call, and the gap widens precisely where accuracy is already marginal — regional accents, dysarthric speech, hearing-aid feedback. Without VOI-023 it is possible to pass the accent evaluation honestly, ship, and discover the recogniser fails on the population the product exists to serve. The test condition must match the production channel or the test measures nothing.
Why VOI-024 exists, and why it is an opportunity rather than a cost. Recording the wideband-to-narrowband delta tells you what the channel is costing you, which is the input to a decision that becomes available in 2027. Once the UK PSTN is retired on 31 January 2027 every domestic "landline" is a VoIP service, and wideband codecs such as G.722 or Opus become technically possible end to end where the carrier and customer premises equipment support them. If the delta in VOI-024 is large, negotiating a wideband path is one of the few available levers that improves accuracy for the hardest population without changing recogniser. If the delta is small, that lever is not worth pulling. Either way, you only know because you measured it.
Note. VOI-019 exists because self-reported confidence from an LLM is systematically miscalibrated. Any escalation gated on a model saying "I am 0.98 confident" will never fire. Confidence gates must be built on measured, calibrated signals with a held-out reliability curve.
Legal frame: UK GDPR Articles 6, 7 and 9; Mental Capacity Act 2005 (England & Wales); Adults with Incapacity (Scotland) Act 2000; Mental Capacity Act (Northern Ireland) 2016; PECR regulation 19 for automated calling. [OD-01, OD-11]
Why SFC-012 exists. The classifier reads transcripts, not audio, so every transcription error propagates into it. The chain is short and it ends badly: narrowband encoding degrades the transcript, a degraded transcript degrades classifier recall, and degraded recall means a missed disclosure of abuse or suicidal ideation. Measuring classifier recall on clean wideband transcripts and reporting it as the recall floor for SFC-006.2 would overstate the safety of the system in the exact channel it actually operates in. Audio quality is a safeguarding parameter here, not an audio-quality parameter.
Why DEG-014 exists. "Your mother did not answer" and "your mother's line was unreachable, and her line stops working in a power cut" are different messages that produce different actions. The first invites worry and then inaction, because the carer has no information to act on. The second tells a carer in a storm-affected area to check on a relative, or tells a carer in an unaffected area to relax. Withholding the distinction is not neutral — a non-contact event is the moment a carer most needs to know which kind of silence they are looking at.
SEC-027 note. Failing closed matters more than it looks. The tempting fallback — drop to environment variables when the secrets service is unreachable — reintroduces exactly the plaintext-at-rest problem SEC-015 exists to remove, and it does so at the moment nobody is watching.
These requirements are dormant until a single under-18 user exists in the system, at which point they become load-bearing immediately. They are specified in V1 because the family graph and consent model must be able to express them.
This section exists because v0.2 gave Vee users visibility of what was shared about them (SUR-302, SUR-304) and gave elder users nothing equivalent. The elder user is the person who did not buy the product, may not have been present when it was configured, and has the most to lose from an unseen sharing relationship. Parity is a floor, not a feature.
Why TRN-011 is SAFETY_LOCKED. A carer who believes the service will reach their parent every day may reasonably decide they need to visit less often. That inference is the product working as intended, and it is also the mechanism by which an undisclosed availability gap turns into a person alone in a house with no working telephone. The disclosure has to be made before activation, because after activation the carer has already changed their behaviour.
The carer digest is the thing the carer actually buys. v0.2 specified the safety layer that reads the call and said nothing about the artefact produced from it. A digest that reports "Mum sounded fine" after a call in which she mentioned a fall is simultaneously a product failure, a safety failure, and the most likely source of a complaint.
Why ONB-009 and ONB-010 exist. The old copper PSTN powered a handset from the telephone exchange, so a landline worked in a power cut. Digital voice runs through a router that needs mains power at the premises, so it does not. Over two-thirds of UK landlines have already migrated and all of them will have migrated by 31 January 2027. This means the assumption underneath surface 1 — that the phone always works — quietly stops being true for every user, at a date already fixed, without anything changing at bience's end. Capturing it at onboarding costs one question and is the only point at which the carer is reliably paying attention.
ONB-005 note. This is the estranged-relative control. Without it, any person holding a telephone number can register another adult for a service that calls them, records them, and reports on them. It is the cheapest safeguarding control in the specification.
LNG-005 note. The failure mode this prevents is shipping a language the conversational layer handles and the safety layer does not. That is not a degraded experience; it is an unmonitored one.
Legal frame: Consumer Contracts (Information, Cancellation and Additional Charges) Regulations 2013; Consumer Rights Act 2015; CAP Code; Equality Act 2010; Payment Services Regulations 2017. The DMCC Act 2024 subscription contracts regime is not yet in force — commencement is expected spring 2027 and awaits secondary legislation — so V1 is built on the CCRs, with DMCC readiness as a V2 design target. [OD-21]
Why CMR-019 sits alongside CMR-017. CMR-017 already forbids claiming the service monitors health or summons help. CMR-019 closes the adjacent gap: a claim of daily contact implies availability the service does not have. The regulatory precedent is close at hand — Ofcom fined a provider for disconnecting customers with telecare devices during digital voice migration, and providers have committed not to migrate telecare users without a confirmed working equivalent. bience is not telecare, but a daily wellbeing call to a vulnerable adult sits near enough to it that the expectations are worth adopting voluntarily rather than being handed later. [OD-29]
PRV-009 note. Large-scale processing of special category data is a strong indicator of the Article 37 duty. Treat the appointment as required until legal advice says otherwise, not the reverse.
The attack this section defends against: a caller instructs Omi to disregard its configuration and read out what it knows about the family. A voice product with a permission model and no authorisation layer outside the model is one sentence away from a disclosure incident.
A safety budget is the safety-critical analogue of an SRE error budget: a stated, finite allowance of degradation per period, owned by the clinical lead rather than by engineering. Its purpose is to convert "we should look at that" into an automatic consequence. Budget exhaustion stops change; it never stops protection.
SFB-013 note. This is the requirement that survives the first cash-flow squeeze. Every safety system in this specification has a cost, and the cheapest way to make the numbers work will always be to trim one of them. Writing the prohibition down before the pressure exists is the only time it is easy to write.
| Attribute | Target | Requirement |
|---|---|---|
| Response latency p50, from end-of-turn detection | ≤ 800 ms | VOI-001 |
| Perceived gap p50, from end of user speech | ≤ 2,200 ms | VOI-021 |
| Response latency p95 | ≤ 1,200 ms | VOI-002 |
| Barge-in stop | ≤ 200 ms | VOI-010 |
| Elder line availability | ≥ 99.9% monthly | DEG-011 |
| Safeguarding ack (immediate) | To be set | SFG-003 [OD-08] |
| Unsupported claim rate (authoritative domains) | 0 | KNW-011 |
| Safety classifier recall | Baseline floor, release-gating | SFC-006 |
| Audio retention | Short, automatic | DAT-009 |
| Transcript retention | Long, automatic | DAT-010 |
| DSAR / erasure turnaround | ≤ 1 calendar month | DAT-012, DAT-013 |
| Telephony providers | 2 independent | DEG-008 |
| RPO (graph, consent, audit) | ≤ 15 min | BCK-002 |
| RTO (elder phone line) | ≤ 4 h | BCK-003 |
| Restore test cadence | Quarterly | BCK-005 |
| Digest omission rate (safety events) | Baseline floor, release-gating | EVL-015, EVL-016 |
| Digest unsupported-assertion rate | Measured every release | EVL-017 |
| Transparency notice to elder user | ≤ 24 h | TRN-004, TRN-005 |
| Cancellation effort | ≤ signup effort | CMR-002 |
| Safety budget alert threshold | 75% consumption | SFB-005 |
| Safety budget period | Rolling 30 days, no carry-over | SFB-001, SFB-008 |
| Secret rotation on leaver | ≤ 7 days | SEC-020 |
| STT and classifier evaluation channel | Production narrowband encoding | VOI-022, VOI-023, SFC-012 |
| Power-dependency disclosure | Before activation | TRN-011 |
| Access revocation on leaver | ≤ 24 h | SEC-019 |
| Exposed secret rotation | ≤ 24 h | SEC-022 |
| Brief item | Requirements |
|---|---|
| P1 Latency with guardrails in path | VOI-001…VOI-007 |
| P2 Hallucination tolerance | KNW-001…KNW-011, EVL-003 |
| P3 Speaker identification | IDN-001…IDN-011 |
| P4 Consent for absent users | CNS-001…CNS-015, SUR-208 |
| P5 Residency and sub-processors | DAT-001…DAT-008, SEC-002 |
| P6 Publishable audit logging | AUD-001…AUD-011, ACC-001…ACC-010 |
| P7 Safeguarding triage at scale | SFG-001…SFG-013, GEN-004 |
| P8 Evals as discipline | EVL-001…EVL-014 |
| P9 Telephony cost and abuse | USG-001…USG-011 |
| P10 Graceful degradation | DEG-001…DEG-013 |
| Brief item | Requirements |
|---|---|
| Q1 Customisation limits | CFG-001…CFG-012 |
| Q2 Subscription model | BIL-001…BIL-008, USG-001…USG-002 |
| Q3 Multiple family members | FGR-001…FGR-017, IDN-001…IDN-011 |
| Concern | Requirements |
|---|---|
| Subject transparency parity | TRN-001…TRN-010 |
| The carer digest as a product | SUM-001…SUM-011, EVL-015…EVL-017 |
| Signup to first call | ONB-001…ONB-008 |
| Reaching a human | HND-001…HND-005 |
| Multi-language safety parity | LNG-001…LNG-006, EVL-019 |
| Consumer contract and subscription law | CMR-001…CMR-018 |
| Marketing, analytics, ICO registration | PRV-001…PRV-009 |
| Backup, restore, continuity | BCK-001…BCK-009 |
| Prompt injection and inbound abuse | AIS-001…AIS-010, EVL-018 |
| Data export and legal hold | DAT-016…DAT-019 |
| Outward safeguarding referral | SFG-014…SFG-016 |
| Vendor exit and portability | SEC-011…SEC-013 |
| Enterprise channel | ENT-001…ENT-011 (Appendix A) |
| Concern | Requirements |
|---|---|
| Safety budgets and change freeze | SFB-001…SFB-014 |
| Secrets management (Infisical) | SEC-008.1, SEC-014…SEC-028 |
| Cost control must not erode safety | SFB-012, SFB-013 |
| Concern | Requirements |
|---|---|
| Evaluation channel must match production | VOI-022, VOI-023, VOI-024, SFC-012 |
| Digital voice power dependency | ONB-009, ONB-010, DEG-014, DEG-015, TRN-011, CMR-019 |
| Brief unknown | Open decision |
|---|---|
| U1 Build-vs-buy voice gateway | OD-16 |
| U2 Persona engineering approach | OD-17 |
| U3 Family graph schema | OD-18 |
| U4 Safeguarding classifier build-vs-buy | OD-19 |
| U5 Eval harness investment | OD-20 |
| ID | Decision | Blocks |
|---|---|---|
| OD-01 | Lawful basis and Article 9 condition per purpose | CNS, DAT-015 |
| OD-02 | LPA verification method and evidence standard; whether an attorney can lawfully give UK GDPR consent on a donor's behalf at all, and the fact that a Health & Welfare LPA operates only on incapacity while Property & Financial Affairs may operate with capacity | CNS-008, CNS-009 |
| OD-03 | Fluctuating-capacity re-consent interval | CNS-011 |
| OD-04 | Clinical scope boundary and medical device classification | KNW-008, KNW-010 |
| OD-05 | Retention periods for audio, transcripts, audit | DAT-009, DAT-010, AUD-009 |
| OD-06 | Accent and atypical speech corpus sourcing | VOI-014, VOI-015 |
| OD-07 | Safety classifier recall floor and precision ceiling | SFC-006 |
| OD-08 | Safeguarding acknowledgement SLA per severity | SFG-003 |
| OD-09 | Break-glass disclosure window | ACC-006 |
| OD-10 | NHS / DSPT applicability | SEC-010 |
| OD-11 | Whether PECR reg 19 bites at all — it addresses automated systems transmitting pre-recorded messages, and synthesised conversational speech is arguably outside it. Untested. Also the Ofcom silent-call position on proactive calling | SUR-108, CNS-014 |
| OD-12 | Emergency call posture | SUR-111 |
| OD-13 | Availability target and its cost | DEG-011 |
| OD-14 | Age assurance method | AAD-003 |
| OD-15 | Bereavement data policy | SUP-002 |
| OD-16 | Voice gateway build vs buy | Architecture |
| OD-17 | Persona engineering: prompts vs fine-tunes | CFG-012 |
| OD-18 | Family graph schema shape beyond RBAC | FGR |
| OD-19 | Safeguarding classifier build vs partner | SFC-010 |
| OD-20 | Eval harness V1 investment level | EVL |
| OD-21 | DMCC subscription regime readiness ahead of spring 2027 commencement | CMR-003, CMR-018 |
| OD-22 | DPO appointment: internal, fractional, or external | PRV-009 |
| OD-23 | RPO and RTO targets and their infrastructure cost | BCK-002, BCK-003 |
| OD-24 | Bank and Action Fraud referral routes | SFG-015 |
| OD-25 | Whether the enterprise channel is pursued at all | Appendix A |
| OD-26 | Supported language list and the order languages are added | LNG-005 |
| OD-27 | Infisical self-hosted versus Infisical Cloud, and rotation intervals | SEC-018, SEC-025 |
| OD-28 | Numeric value of each safety budget | SFB-001 |
| OD-29 | Whether the service falls within telecare or technology-enabled care scope, and which standards and vulnerable-customer commitments would follow | CMR-019, TRN-011 |
| OD-30 | Whether to pursue a wideband codec path on the post-switchover VoIP leg, decided from the VOI-024 delta | VOI-024 |
| Group | Primary method | Notes |
|---|---|---|
| VOI | Automated load and latency harness against synthetic call corpus | Per-stage breakdown required for attribution |
| IDN, CNS | Scripted conversational tests plus legal review | Legal review is a gate, not a comment |
| CFG, FGR | Property-based tests over permission triples plus static analysis | Static analysis proves CFG-010 |
| SFC, SFG | Labelled corpus evaluation plus tabletop exercise | Tabletop covers the human pathway |
| KNW | Grounding regression with zero-tolerance gate | |
| AUD, ACC | Architecture review plus tamper-detection test | Independent reviewer preferred |
| DAT, SEC | Documentary audit plus penetration test | |
| DEG | Scheduled failure injection | Quarterly minimum |
| EVL | Meta-evaluation: does the harness catch seeded regressions | Seeded-defect test |
| TRN, SUM | Scripted conversational tests plus labelled digest corpus | Omission is the failure mode, not fabrication |
| ONB, HND | Journey walkthrough plus duplicate-number test | ONB-005 needs a deliberate collision test |
| CMR, PRV | Documentary audit plus consumer journey review | Legal sign-off is a gate |
| BCK | Quarterly restore drill with audit chain verification | Untested backups are not backups |
| AIS | Red-team suite against the live voice path | Must be run over the phone line, not the API |
| SFB | Dashboard inspection plus a deliberate budget-exhaustion drill | The drill is the test — an untriggered freeze is unproven |
| SEC (secrets) | Scanning in CI, leaver drill, deploy-time failure injection | SEC-027 needs the secrets service taken down on purpose |
| Version | Date | Change |
|---|---|---|
| 0.1 | 2026-07-25 | Initial derivation from "The problems, not the pitch" v1.0. |
| 0.2 | 2026-07-25 | EARS conformance pass. Keyword semantics corrected (9). Compound requirements split into decimal sub-identifiers (61). Negative requirements recast into positive restriction form (30 of 32). Vague terms replaced with named artefacts (13). Design statements relocated to §4.3 Design Constraints (6). Requirement count 266 → 331. |
| 0.7 | 2026-07-26 | Provenance pass. Every one of the 498 requirements annotated with its source and rationale (§3.3). Split: 43% traceable to the brief, 13% statutory, 35% found in review, 4% requested during drafting, 2% derived. |
| 0.6 | 2026-07-26 | Added the evaluation-channel requirements (VOI-022 to VOI-024, SFC-012): speech and classifier accuracy must be measured on production narrowband encoding, not wideband test audio. Added digital voice power-dependency capture and disclosure (ONB-009, ONB-010, DEG-014, DEG-015, TRN-011, CMR-019) ahead of the 31 January 2027 PSTN retirement. Two new open decisions. Requirement count 488 → 498. |
| 0.5 | 2026-07-25 | Correctness pass. Resolved a contradiction between VOI-001 and VOI-011: response latency is now measured from end-of-turn detection, with perceived gap added as a separate, honestly larger measure (VOI-020, VOI-021). Requirement count 486 → 488. |
| 0.4 | 2026-07-25 | Added §34 Safety budgets (SFB, 14 requirements) with clinical-lead ownership and release blocking on exhaustion. Added §22.1 Secrets management (SEC-014…SEC-028) naming Infisical, covering machine identities, per-environment isolation, rotation, leaver revocation, scanning, and fail-closed deployment. Two new open decisions. Requirement count 457 → 486. |
| 0.3 | 2026-07-25 | Commercial completeness pass. Added TRN (subject transparency parity), SUM (carer digest), ONB (onboarding), HND (human handoff), LNG (language), CMR (consumer contract), PRV (marketing and ICO), BCK (backup and continuity), AIS (adversarial input). Extended EVL, DAT, SFG, SEC. Added Appendix A (enterprise channel). Six new open decisions. Requirement count 331 → 457. |
Conditional. These requirements apply only if bience sells to organisations — local authorities, integrated care boards, care providers, insurers — rather than direct to families. They are recorded now because the decision changes the data model (processor mode, tenancy) and is expensive to retrofit. They are not implemented at V1. [OD-25]
ENT-011 note. The commercial customer is not the data subject. An organisational buyer must not be able to contract away an elder user's transparency or erasure rights. This requirement is the reason the enterprise channel needs specifying before it is sold, not after.
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.
| 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.
Traces to: SFG-002, CNS-005, SFC-002, DEG-006, FGR-001, SUR-401, DAT-017, AUD-007, TRN-003, TRN-006.
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 --> VEE18graph 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 --> VEE18Two 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.
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.
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, 21dgantt
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, 21dSafeguarding 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.
Traces to: architecture §6.
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 --> W1graph 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 --> W1Instrument both latency clocks from the first call (§3.7). Retrofitting the distinction afterwards means re-running the corpus.
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.
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"]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.
Traces to: CNS-005, CNS-006.1 to CNS-006.4, CNS-007.1 to CNS-007.3, CNS-012.1, TRN-010.
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"])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.
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.
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 --> DONEflowchart 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 --> DONETraces 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.
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 outcomesequenceDiagram
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 outcomeTwo 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.
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.
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 --> NOTIFYflowchart 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 --> NOTIFYEvery 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.
Traces to: SUM-001 to SUM-011, DEG-009, EVL-015, EVL-017.
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"]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.
Traces to: VOI-001, VOI-002, VOI-011, VOI-020, VOI-021.
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"| OUTflowchart 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"| OUTAn 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.
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.
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 notestateDiagram-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 noteReconfirmDue --> 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.
Traces to: SFG-001, SFG-003, SFG-004.1, SFG-004.2, SFG-006, SFG-010, SFG-014, SFG-016.
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 notestateDiagram-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 noteTraces 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.
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 notestateDiagram-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 noteTraces to: SFB-001, SFB-004, SFB-005, SFB-006, SFB-007, SFB-008, SFB-009, SFB-011.
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 notestateDiagram-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 noteNo carry-over between periods and no transfer between metrics: unused safety budget is not currency (SFB-008, SFB-009).
Traces to: architecture §6.1, SEC-025, DAT-009.2.
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 --> EVALgraph 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 --> EVALCredits buy inference and telephony, nothing else. Managed infrastructure left idle is the fastest way to lose the budget to something Docker provides free.
Traces to: DAT-001, SEC-002, AIS-005, AD-03.
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"| OUTgraph 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"| OUTThe 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.
Traces to: EVL-001, EVL-002, EVL-004, KNW-011.2, EVL-016, EVL-018, SFB-006, SEC-021, SEC-027, ACC-008.
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"]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.
Traces to: SEC-008.1, SEC-014, SEC-015, SEC-016, SEC-019, SEC-020, SEC-022, SEC-023, SEC-024, SEC-028.
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
endsequenceDiagram
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
endNothing in this flow writes a secret to disk, an image, a log, or a trace.
Traces to: ACC-003, ACC-004, ACC-005, ACC-006, ACC-007, ACC-010, SEC-017.
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"]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).
Traces to: AUD-003, AUD-004, AUD-005, AUD-006.1, AUD-006.2, AUD-011.
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
endsequenceDiagram
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
endCompliance 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".
Traces to: BCK-001 to BCK-008, DAT-012.1, DAT-012.2.
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"]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.
Traces to: ONB-001 to ONB-008.2, CNS-005, SUR-110, SUR-208.1, SUR-208.2.
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
endsequenceDiagram
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
endStep 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.
Traces to: FGR-006, FGR-007, FGR-008, FGR-010, FGR-011, FGR-013, AUD-001.
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 --> LOGflowchart 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 --> LOGExclusion is evaluated first and unconditionally. Expiry is a read-time predicate, so nothing is left granted by a sweep job that failed.
Traces to: DAT-014.1, DAT-014.2, SEC-009, SEC-022, SEC-023, SFG-014, SFG-015, OBS-008.
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 --> PIRflowchart 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 --> PIRTraces to: SFB-003, SFB-004, SFB-005, SFB-006, SFB-007, SFB-010, SFB-011, SFB-013, SFB-014.
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, rationalesequenceDiagram
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, rationaleThe 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.
Three earn their keep immediately; the rest can wait.
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.
architecture.md §12.2, it is the exercise with the largest effect on cost.