[privacy-audit] Privacy-sensitive fields leak into main DB and PersonDetail metrics — link to Little Black Book #169

Closed
opened 2026-09-10 02:52:52 +00:00 by Mark · 0 comments
Owner

Context

User directive: "tie any other private concerns back to it" (the Little Black Book vault). This is the audit. The LBB is the right architectural home for anything intimate or privacy-sensitive — it already exists (src/vault/), is physically isolated (separate IndexedDB), is auto-lock gated, and architecturally separate from the main DB.

What's NOT vault-bound but should be

Audited every privacy-sensitive field on Person / Interaction / Gift / DateEvent. The following live in the main DB but are clearly intimate or private and should be vault-bound:

Field Schema Currently surfaces on Why it should be vault
pronouns Person PersonDetail, Home (filter chips), People Reveals identity; not always public
nicknames Person PersonDetail, Home, People Often intimate; what you'd never call them publicly
orientation derived from relationshipTags People filter Identity data, not casual to share
intimacyLevel (1-5) Interaction LogInteraction input, PersonDetail (chart line 2206), Metrics tab (line 1275-1282) Explicitly named "opt-in, off by default" but stored in main DB
mood ("happy"/"excited"/"tired"/"neutral"/"loved"/"stressed") Interaction PersonDetail Metrics tab (line 3011 "Average mood: 4/5", line 3016 "7-day trend") Mental-health adjacent; never safe to share
isConflict Interaction PersonDetail Pattern Insights (line 1228), conflict cards (line 2059-2068) Sensitive — discloses fights happened
repairAttempt (free text) Interaction PersonDetail (line 2066) Often the most private thing in the relationship
conflictResolved Interaction PersonDetail (line 2063) Status of an active wound
qualityRating (1-5) Interaction PersonDetail Metrics, dates quality feedback Subjective judgment of partner's company
notes (free text, person-level) Person, Interaction Everywhere Most private thing users log — explicitly opt-in to vault per-person

What's NOT vault-gated but should be

The vault lock (vaultLocked from the store) is checked in only one place in PersonDetail (line 1912 — romantic partner sections like cadence/goals). The following surfaces on PersonDetail render regardless of vault state:

  • Engagement Overview (line 3010+) — surfaces moodAverage, 7-day mood trend (moodTrendInfo)
  • Pattern Insights (line 3125+) — surfaces "you go quiet after conflict with X" even when locked
  • Conflict history cards (line 2059+) — "Resolved"/"Open" status, repair attempt notes
  • Intimacy chart (line 2206) — visualizes intimacyLevel over time

The vault UI itself (src/pages/Vault.tsx) is gated, but the PersonDetail metrics panel reads from main DB and bypasses the lock. Privacy by design — broken in implementation.

What's correctly vault-bound already

  • Vault-only Person records (people marked inVault: true — stored only in kin_vault)
  • Vault-only Interaction, Gift, DateEvent records (per-person vault storage)
  • vaultNotes table — the explicit private-note surface

Architectural fix sketch

For each field above, the right move is:

  1. Move the field into the vault schema — extend src/vault/vault-db.ts with vaultSensitiveFields, vaultIntimacy, vaultMood, vaultConflicts tables
  2. Route reads through vault-only metrics — vault-metrics-engine.ts that reads only vault data and is gated by assertUnlocked()
  3. Gate the PersonDetail metrics panel — when vaultLocked && person.relationshipType in [Romantic/Partner/Spouse] (or any person with sensitive fields), show a "Unlock to see mood/intimacy/conflict patterns" placeholder instead of the data
  4. Make intimacyLevel truly opt-in per-person — currently it's a schema field with no toggle; should be vaultSettings.intimacyEnabled[personId]
  5. Move mood to a vault-only field — once user opts into mood tracking, it lives in vault; main DB strips it on import
  6. Audit notes — add a notesInVault toggle per person; vault notes live in vaultNotes, main notes are summary only

Severity

High — this is the kind of issue where a user thinks "I have the vault on, my partner's mood trend is hidden" and the actual code path renders it on the unlocked app home page regardless. The vault is currently a partial feature: it hides the things it owns, but not the things it should own.

Relationship to existing issues

  • #167: Intimate-timing predictions for romantic partners — intimacy aggregation now goes through vault
  • #168: Intimate-state awareness — all cycle/mood/precursor work is vault-scoped
  • This issue (#169) is the parent: any PR that addresses intimate-state or intimate-timing should reference this audit

Acceptance criteria

A future PR that closes this issue should:

  • Move pronouns, nicknames, orientation, intimacyLevel, mood, isConflict, repairAttempt, conflictResolved, qualityRating, person-level notes to vault tables (with backward-compat shim that migrates existing data)
  • Gate the PersonDetail metrics panel + Pattern Insights + conflict cards + intimacy chart on !vaultLocked
  • Add a per-person "intimate tracking opt-in" toggle in Settings
  • Add vault-metrics-engine.ts for vault-scoped analysis
  • Verify: with vault locked, no intimate data renders on PersonDetail or Home (e2e test on Kindle)
  • Update the existing behavior-pattern-engine.ts wiring in PersonDetail.tsx:203 to be vault-aware (only run when unlocked)
## Context User directive: "tie any other private concerns back to it" (the Little Black Book vault). This is the audit. The LBB is the right architectural home for anything intimate or privacy-sensitive — it already exists (`src/vault/`), is physically isolated (separate IndexedDB), is auto-lock gated, and architecturally separate from the main DB. ## What's NOT vault-bound but should be Audited every privacy-sensitive field on `Person` / `Interaction` / `Gift` / `DateEvent`. The following live in the **main DB** but are clearly intimate or private and should be vault-bound: | Field | Schema | Currently surfaces on | Why it should be vault | |---|---|---|---| | `pronouns` | `Person` | PersonDetail, Home (filter chips), People | Reveals identity; not always public | | `nicknames` | `Person` | PersonDetail, Home, People | Often intimate; what you'd never call them publicly | | `orientation` | derived from `relationshipTags` | People filter | Identity data, not casual to share | | `intimacyLevel` (1-5) | `Interaction` | LogInteraction input, PersonDetail (chart line 2206), Metrics tab (line 1275-1282) | Explicitly named "opt-in, off by default" but stored in main DB | | `mood` ("happy"/"excited"/"tired"/"neutral"/"loved"/"stressed") | `Interaction` | PersonDetail Metrics tab (line 3011 "Average mood: 4/5", line 3016 "7-day trend") | Mental-health adjacent; never safe to share | | `isConflict` | `Interaction` | PersonDetail Pattern Insights (line 1228), conflict cards (line 2059-2068) | Sensitive — discloses fights happened | | `repairAttempt` (free text) | `Interaction` | PersonDetail (line 2066) | Often the most private thing in the relationship | | `conflictResolved` | `Interaction` | PersonDetail (line 2063) | Status of an active wound | | `qualityRating` (1-5) | `Interaction` | PersonDetail Metrics, dates quality feedback | Subjective judgment of partner's company | | `notes` (free text, person-level) | `Person`, `Interaction` | Everywhere | Most private thing users log — explicitly opt-in to vault per-person | ## What's NOT vault-gated but should be The vault lock (`vaultLocked` from the store) is checked in **only one place** in PersonDetail (line 1912 — romantic partner sections like cadence/goals). The following surfaces on PersonDetail render regardless of vault state: - **Engagement Overview** (line 3010+) — surfaces `moodAverage`, 7-day mood trend (`moodTrendInfo`) - **Pattern Insights** (line 3125+) — surfaces "you go quiet after conflict with X" even when locked - **Conflict history cards** (line 2059+) — "Resolved"/"Open" status, repair attempt notes - **Intimacy chart** (line 2206) — visualizes `intimacyLevel` over time The vault UI itself (`src/pages/Vault.tsx`) is gated, but the **PersonDetail metrics panel reads from main DB and bypasses the lock**. Privacy by design — broken in implementation. ## What's correctly vault-bound already - Vault-only `Person` records (people marked `inVault: true` — stored only in `kin_vault`) - Vault-only `Interaction`, `Gift`, `DateEvent` records (per-person vault storage) - `vaultNotes` table — the explicit private-note surface ## Architectural fix sketch For each field above, the right move is: 1. **Move the field into the vault schema** — extend `src/vault/vault-db.ts` with `vaultSensitiveFields`, `vaultIntimacy`, `vaultMood`, `vaultConflicts` tables 2. **Route reads through vault-only metrics** — `vault-metrics-engine.ts` that reads only vault data and is gated by `assertUnlocked()` 3. **Gate the PersonDetail metrics panel** — when `vaultLocked && person.relationshipType in [Romantic/Partner/Spouse]` (or any person with sensitive fields), show a "Unlock to see mood/intimacy/conflict patterns" placeholder instead of the data 4. **Make `intimacyLevel` truly opt-in per-person** — currently it's a schema field with no toggle; should be `vaultSettings.intimacyEnabled[personId]` 5. **Move `mood` to a vault-only field** — once user opts into mood tracking, it lives in vault; main DB strips it on import 6. **Audit `notes`** — add a `notesInVault` toggle per person; vault notes live in `vaultNotes`, main notes are summary only ## Severity High — this is the kind of issue where a user thinks "I have the vault on, my partner's mood trend is hidden" and the actual code path renders it on the unlocked app home page regardless. The vault is currently a *partial* feature: it hides the things it owns, but not the things it should own. ## Relationship to existing issues - #167: Intimate-timing predictions for romantic partners — intimacy aggregation now goes through vault - #168: Intimate-state awareness — all cycle/mood/precursor work is vault-scoped - This issue (#169) is the parent: any PR that addresses intimate-state or intimate-timing should reference this audit ## Acceptance criteria A future PR that closes this issue should: - [ ] Move `pronouns`, `nicknames`, `orientation`, `intimacyLevel`, `mood`, `isConflict`, `repairAttempt`, `conflictResolved`, `qualityRating`, person-level `notes` to vault tables (with backward-compat shim that migrates existing data) - [ ] Gate the PersonDetail metrics panel + Pattern Insights + conflict cards + intimacy chart on `!vaultLocked` - [ ] Add a per-person "intimate tracking opt-in" toggle in Settings - [ ] Add `vault-metrics-engine.ts` for vault-scoped analysis - [ ] Verify: with vault locked, no intimate data renders on PersonDetail or Home (e2e test on Kindle) - [ ] Update the existing `behavior-pattern-engine.ts` wiring in `PersonDetail.tsx:203` to be vault-aware (only run when unlocked)
Mark 2026-09-10 02:53:53 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Mark/kimi_agent_kin_app_sync#169
No description provided.