From 621c4f9cb37ce43641e966a3b8b9cc09f55b95e0 Mon Sep 17 00:00:00 2001 From: daniel-c-harvey Date: Fri, 19 Jun 2026 15:10:15 -0400 Subject: [PATCH] docs(phase-16): draft anonId privacy-note copy; note deferred Postgres integration harness --- PLAN.md | 1 + product-notes/phase-16-privacy-note.md | 131 +++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 product-notes/phase-16-privacy-note.md diff --git a/PLAN.md b/PLAN.md index 3a3571b..67b8480 100644 --- a/PLAN.md +++ b/PLAN.md @@ -152,6 +152,7 @@ A small set of items that are real but don't fit a phase yet. Surface them when - **Identity / accounts.** Currently no user concept. Needed before web upload (2.4); also a precondition for favourites, listening history, per-user playlists. Decide the shape before any of those lands. `[speculative]` until Daniel signals interest. - **`ITrackService` interface.** Audit-suggested. Low value today (one consumer pair); higher value when the test surface expands beyond FileDatabase. - **Test coverage outside FileDatabase.** Tests today cover the FileDatabase subsystem comprehensively and nothing else. As features in Phases 1–4 land, test scope should expand — at minimum `WavOffsetService`, `AudioProcessor`, `TrackService` (both sides), and the streaming player services. Not a phase of its own; an attached cost to feature work. + - *Real-Postgres integration harness (deferred per Daniel — big lift).* The Phase 16 distinct-listener aggregation LINQ (`EventRepository.CountDistinctListenersAsync` / `...ForTrackAsync` / `...ForReleaseAsync`) is currently exercised only against the EF in-memory provider, which does not validate real Npgsql SQL translation — the distinct-count queries want translation verification against an actual Postgres instance. More broadly, an integration-test harness against a real Postgres is the deferred prerequisite for trusting any non-trivial LINQ across the EF surface. **Explicitly deferred by Daniel (big lift); a note for now, not committed work — no timeline.** --- diff --git a/product-notes/phase-16-privacy-note.md b/product-notes/phase-16-privacy-note.md new file mode 100644 index 0000000..a3dc2a8 --- /dev/null +++ b/product-notes/phase-16-privacy-note.md @@ -0,0 +1,131 @@ +# Phase 16 — Privacy-Note Copy (DRAFT — awaiting Daniel sign-off) + +Status: **DRAFT — NOT FINAL. Awaiting Daniel's sign-off on (a) wording and (b) placement.** Author: +product-designer. Date: 2026-06-19. Surface: **public site only** (`DeepDrftPublic` / +`DeepDrftPublic.Client`). **No code, no shipped copy** — this is a copy draft for review. + +This note drafts the short privacy line that `phase-16-play-share-tracking.md` **§3 (Option A, +RESOLVED D5)** explicitly calls for: *"a short privacy-note line rather than a cookie wall."* It +explains, in plain language, the anonymous first-party `anonId` token minted in wave 16.3. + +## What the copy has to be honest about (from the spec §3) + +The line must be accurate to the actual mechanism — no more, no less: + +- A **random, first-party** token kept in this browser (`localStorage`), minted on first visit. +- **No accounts, no personal data, no names, no email** — there is no identity model behind it. +- **No cross-site tracking, no fingerprinting** — it never leaves as anything but an opaque token, and + a third-party embed cannot read it (storage is partitioned). +- **Listener-clearable** at any time (clear site data) — and clearing it simply mints a new one. +- Used **only** to estimate *how many* listeners a track or release reached, in aggregate — never + *who*. We label the number "listeners," not "people," because it over-counts by design (phone + + laptop = two). + +Voice target: the DeepDrft collective wrote this. Smart, plain, a little dry. No "we value your +privacy," no "your trust matters to us," no marketing reassurance theatre. State the mechanism and +stop. The honesty *is* the reassurance. + +--- + +## Copy variants (pick one, or splice) + +### Variant 1 — "the plain mechanism" (recommended) + +> We keep a random tag in your browser so we can count how many people a track reaches — not who they +> are. No account, no name, nothing personal, nothing shared with anyone else. Clear your browser data +> and the tag's gone. + +**Why this one:** it leads with the mechanism ("a random tag in your browser"), names the exact limit +("how many people... not who they are"), and closes on the listener's control. Reads like a person +explaining a thing, not a policy. Shortest honest version that covers all five facts. + +### Variant 2 — "the counter framing" (matches the 90s-hit-counter vibe) + +> The play counter works off a random tag stored in your browser — enough to tell that a listen is a +> distinct one, never enough to tell who you are. No login, no personal data, no tracking across other +> sites. It's yours to clear whenever you like. + +**Why this one:** ties the note directly to the Plays card it explains ("the play counter works +off..."), which reads well if the line lives near the home stats. Slightly longer; "distinct one" +nods honestly at the approximate-count nature. + +### Variant 3 — "the one-liner" (footer-scale) + +> We count listens with a random, anonymous tag in your browser — how many, never who. No accounts, no +> cross-site tracking. Clear it any time. + +**Why this one:** tightest. Fits a single footer line or a caption. Drops the explanatory rhythm of +1 and 2 for density — best where space is the constraint and a fuller line would look heavy. + +### Variant 4 — "the editorial aside" (for the /about page treatment) + +> A note on the numbers: the play and listener counts you see run on a random tag we keep in your +> browser — no account, no name, nothing that says who you are, nothing handed to anyone else. It tells +> us a track reached *some number of* listeners, not which ones. Clear your site data and you're a +> fresh tag; we'd never know the difference. + +**Why this one:** written to sit inside the About page's editorial prose voice (the "Liner Notes" +register), longer and more conversational. Only appropriate if the line lives on `/about`; too much +for a footer. + +--- + +## Placement options (also Daniel's call) + +### A. Footer line (site-wide) + +- **Pro:** always reachable, conventional home for a privacy note, set-and-forget, decouples the line + from any one feature so it survives card/layout changes. +- **Con:** low-salience — nobody reads footers; satisfies the "we disclosed it" bar more than the + "listener actually understands" bar. A full sentence can look heavy in a footer; favours Variant 3. + +### B. A line on the `/about` page + +- **Pro:** `/about` is already the collective's voice explaining itself (the "presentation and proof of + effort" page); a privacy aside fits its register and reaches the curious reader who'd actually care. + Variant 4 was written for exactly this slot. +- **Con:** lowest reach — only the fraction who open `/about` see it. Weak as the *sole* disclosure; + better as the *expanded* version with a shorter pointer elsewhere. + +### C. A small note near the home stats card + +- **Pro:** highest contextual relevance — it sits right where the listener-count it explains is + rendered, so the disclosure lands at the moment the number does. This is the most *honest* placement: + you see the count and the "here's how we got it" in the same glance. Variant 2 is tuned for it. +- **Con:** real estate is tight by the odometer cards; risks visual clutter on the hero. May need to be + a small caption / info-affordance (a quiet "?" or "how we count" toggle) rather than always-on prose. + And the card is the wave-16.5 capstone — this placement only exists once the card goes live, which + couples the note's ship to the last wave. + +### Recommendation + +**Primary: A (footer line), using Variant 1 or 3 — ship it with the substrate, independent of the +capstone card.** A footer line is the lowest-coupling, always-available disclosure and does not wait on +the 16.5 card. Because the `anonId` token is minted in **wave 16.3** (already landed on dev), the +disclosure arguably *should* exist before the capstone, and the footer is the only placement that +doesn't depend on the card being live. + +**Pair it with C (a quiet "how we count" affordance by the home stats) when the capstone card lands in +16.5**, using Variant 2 — so the explanation also appears exactly where the number does. B (`/about`) +is a nice-to-have third surface for the curious reader (Variant 4), not load-bearing. + +This gives a tiered disclosure: an always-present footer line (legal/ethical floor), a contextual note +at the point of display (honesty high-water mark), and an editorial expansion for the reader who wants +it — without a cookie wall anywhere, per the spec. + +**One sequencing flag for Daniel:** the token already ships (16.3 landed); the disclosure does not yet +exist. If the footer line is the chosen floor, it can land independently of the 16.5 card and arguably +should not trail it. Not urgent (first-party, no cross-site tracking, clearable — the lightest-touch +case under GDPR/ePrivacy per spec §3), but worth a deliberate call rather than letting it ride to the +capstone by default. + +--- + +## What this note is NOT + +- Not a privacy policy. If a full policy page is ever wanted, that is a separate, larger artifact — this + line is the privacy-light disclosure the spec asked for, not a legal document. +- Not a consent mechanism. Per spec §3 (D5), a random first-party id used for first-party aggregate + counts is the lightest-touch case and is **deliberately not** behind a banner or wall. This note + *informs*; it does not *gate*. +- Not final. **Every variant above is a draft pending Daniel's wording sign-off and placement pick.**