|
| 1 | +<!-- |
| 2 | +SPDX-License-Identifier: MPL-2.0 |
| 3 | +Copyright (c) Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk> |
| 4 | +--> |
| 5 | +# Data Governance |
| 6 | + |
| 7 | +flat-mate's data posture in one sentence: **ordinary UK GDPR Art. 6 controller duties accepted; no Art. 9 (special-category) data by schema construction; every stored field carries machine-readable governance metadata.** This is Art. 25 data-protection-by-design — a risk reducer and obligation organiser, **not** a compliance exemption. Spec §5/§5.1 of [`docs/design/squad-audit-v1.adoc`](../blob/main/docs/design/squad-audit-v1.adoc). |
| 8 | + |
| 9 | +## No Art. 9 by construction |
| 10 | + |
| 11 | +The schema (`packages/shared/src/matching/profile.js`) contains **no special-category fields, and no fields from which one is straightforwardly derived**: |
| 12 | + |
| 13 | +- **Removed: `accessibilityNeeds` free text.** It is Art. 9 health data — and even a boolean flag indirectly reveals disability. The governing authority is CJEU C-184/20: derived data liable to reveal a sensitive attribute inherits special-category status. So neither the text nor the flag exists. |
| 14 | +- **Never stored: guarantor status.** Whether a student has a UK guarantor is a strong nationality proxy; storing or filtering on it creates indirect-discrimination exposure. No field exists. |
| 15 | + |
| 16 | +The constants registry states this as policy: there are **deliberately no `revealingness: "sensitive"` fields** in the schema; any future sensitive field must set `minTier: 2` *and* go through explicit-consent design first (modelled as `WellGoverned` in the proven core — see [[Conceal-Lattice]]). |
| 17 | + |
| 18 | +## The universal-prompt pattern |
| 19 | + |
| 20 | +Removing the fields does not remove the *needs* — it relocates the conversation to where no data is stored. The pattern: **prompt the conversation unconditionally for every group, store zero signal.** |
| 21 | + |
| 22 | +| Need | Where it surfaces | What is stored | |
| 23 | +|---|---|---| |
| 24 | +| Access needs | The house agreement draft (`agreement.js`) includes an **"Access & needs"** section for *every* group, unconditionally: "is there anything about the home setup you need to work — access, allergies, medical storage, prayer or study space, temperature, anything else? Discuss in person; the platform deliberately stores nothing here." | **Nothing.** Because the section is universal, its presence reveals nothing about any member. | |
| 25 | +| Guarantors | The agreement's **"Guarantors & tenancy setup"** section and the search brief checklist (`brief.js`) carry an unconditional per-member guarantor confirmation item ("the platform stores no guarantor data"). | **Nothing.** | |
| 26 | + |
| 27 | +Same conversation prompted, zero stored signal. See [[Squad-Audit-Walkthrough]] for these sections in the real artifact output. |
| 28 | + |
| 29 | +## The field governance registry |
| 30 | + |
| 31 | +Every profile field is registered in `FIELD_GOVERNANCE` (`packages/shared/src/matching/constants.js`) with three coordinates: |
| 32 | + |
| 33 | +``` |
| 34 | +{ purpose: identity | feasibility | harmony | agreement, |
| 35 | + revealingness: innocuous | contextual (sensitive: deliberately unused), |
| 36 | + minTier: 0 | 1 | 2 } |
| 37 | +``` |
| 38 | + |
| 39 | +`minTier` gates the **raw value**; tier-1 views carry only relational narration rebuilt from structured factors (see [[Conceal-Lattice]]). Current registry, as in code: |
| 40 | + |
| 41 | +| Fields | purpose | revealingness | minTier | |
| 42 | +|---|---|---|---| |
| 43 | +| `name`, `universityEmail` | identity | contextual | 2 (FULL) | |
| 44 | +| `university`, `moveInFlexDays`, `leaseLengthMonths` | feasibility | innocuous | 1 (RELATIONAL) | |
| 45 | +| `budgetMin`, `budgetMax`, `preferredMoveInDate` | feasibility | contextual | 1 (RELATIONAL) | |
| 46 | +| all harmony fields (`cleanliness`, `cleanlinessTolerance`, `bedtime`, `noiseGenerated`, `noiseTolerance`, `socialPreference`, `guestFrequency`, `guestTolerance`, `partnerStays`, `smoking`, `smokingTolerance`, `drinking`, `drinkingTolerance`, `hasPets`, `petTolerance`, `dealbreakers`) | harmony | contextual | 2 (FULL) | |
| 47 | +| `conflictStyle`, `billSplitPreference` | agreement | contextual | 2 (FULL) | |
| 48 | + |
| 49 | +This registry is designed to be the **single source** for (a) read-time tier gating on the server, (b) the conceal lattice's redaction rules, (c) the future retention schedule and DPIA documentation. The schema mirrors the formally verified field-governance types in `proven-servers/protocols/proven-epistemic`. |
| 50 | + |
| 51 | +## Adjacent honesty: what the engine refuses to infer |
| 52 | + |
| 53 | +- Missing answers are stored as `null` and scored neutrally (0.5) **with a warning** — absence of evidence never scores better than adverse evidence ([[Engine-v2-Reference]]). |
| 54 | +- The disclosed-output caveat is owned, not hidden: redaction cannot prevent *self-inference* from one's own data ([[Conceal-Lattice]]). |
| 55 | + |
| 56 | +## What remains owed before launch |
| 57 | + |
| 58 | +Stated in the spec and restated here so it cannot quietly disappear: |
| 59 | + |
| 60 | +1. **Privacy notice** (Art. 13/14). |
| 61 | +2. **Retention schedule**, driven off the `FIELD_GOVERNANCE` registry. |
| 62 | +3. **Verified VerisimDB erasure + subject-access-export story** — VerisimDB is the estate's sole persistence layer, and "we can delete you and show you your data" must be *demonstrated*, not asserted. |
| 63 | + |
| 64 | +**Honest status note:** today the registry and lattice live in the engine library and its tests. Server-side read-time enforcement does not exist yet — the apps (`apps/api`, `apps/web`, `apps/mobile`) are **not wired to engine v2** and still implement the legacy v0 flow. The legacy v0 schema (`packages/shared/src/domain.js`) predates this posture; it is marked LEGACY and is not the v1 product surface. Until the wiring lands, the governance posture is a property of the engine, not of any deployed system. |
0 commit comments