diff --git a/startos/versions/v0.1.0.ts b/startos/versions/v0.1.0.ts index 19c2e89..cef825d 100644 --- a/startos/versions/v0.1.0.ts +++ b/startos/versions/v0.1.0.ts @@ -9,8 +9,28 @@ import { VersionInfo } from '@start9labs/start-sdk' export const v0_1_0 = VersionInfo.of({ - version: '0.1.0:46', + version: '0.1.0:47', releaseNotes: [ + `Alpha-iteration revision 47 of v0.1.0 — Opt-in community analytics, plus draft v0.2.0:0 release notes parked for the upcoming milestone cut.`, + ``, + `**Opt-in community analytics.** Off by default. Toggle on the admin Overview page sends a daily anonymous heartbeat to a configurable collector URL, with full disclosure of exactly what gets sent (and what doesn't). Closes the last T2 v0.2-plan item.`, + ``, + `Heartbeat shape (asserted by test):`, + ` - install_uuid: random UUIDv4 generated on first opt-in. NOT derived from operator_name, store id, or public URL. Wipeable via the Reset button.`, + ` - daemon_version + tier label (creator/pro/patron/unlicensed).`, + ` - counts: products / active_licenses / settled_invoices, each FLOORED TO THE NEAREST 5 to prevent fingerprinting an operator by their exact license count over time.`, + ` - uptime_bucket: \`<1d\` | \`1-7d\` | \`1-4w\` | \`>4w\`.`, + ``, + `Never sent (test asserts none of these strings appear in the heartbeat): operator_name, public_url, store_id, api_key, buyer_email, btcpay_url. Also no product/policy slugs or names, no license/invoice ids, no fingerprints, no webhook secrets.`, + ``, + `The "Show me exactly what gets sent" disclosure on the admin card renders the LIVE preview heartbeat — no pretend examples, the operator sees exactly the JSON the daemon would POST. Toggle requires confirming a collector URL; without one, the toggle being on is "armed but silent" (daemon never beacons until both are set).`, + ``, + `**v0.2.0:0 plumbing parked.** \`startos/versions/v0.2.0.ts\` is drafted with milestone release notes, ready to swap into the version graph when we cut. \`CUTTING_V0.2.0.md\` documents the 4-step cutover and rollback. NOT wired in as current yet — that's the release decision, separate from this routine increment.`, + ``, + `**Test count: 32** (was 31; +1 community_analytics_opt_in_and_privacy_contract — seeds 23 licenses, asserts the heartbeat reports 20 active_licenses, proving the floor-to-5 anti-fingerprinting is in effect).`, + ``, + `**Upgrade path.** v0.1.0:46 → v0.1.0:47 is a straight drop-in. No new migrations, no schema changes. The community-analytics toggle is OFF on first boot — operators must explicitly opt in before any heartbeat is sent.`, + ``, `Alpha-iteration revision 46 of v0.1.0 — Idempotent BTCPay Connect, plus the Go SDK is now part of the published toolchain.`, ``, `**Idempotent Connect.** "Connect BTCPay" no longer blindly initiates a fresh authorize flow when Keysat is already connected. It now checks \`/v1/admin/btcpay/status\` first; if a connection exists, it returns a clear "already connected" message that points the operator at "Disconnect BTCPay" → "Connect BTCPay" for the re-authorize case. Closes the v0.2-plan T1 item that was the last outstanding BTCPay UX gap. Without this, re-clicking Connect spawned a new webhook subscription on BTCPay's side every time, leaving orphan webhooks BTCPay would keep trying to deliver to.`,