privacy: name the IP address and describe the TestFlight build as it ships (FRE-1480)
CTO verdict at FRE-1480: two sentences atdb3e695were false. (b) sendDefaultPii = false does not stop Sentry receiving the connection IP (sentry-cocoa 9.26.1 sets infer_ip = auto for Cocoa; only the Sentry project's Prevent Storing of IP Addresses switch stops it) — the shipped Settings rows already say so. The IP sentence is restored. The iPhone paragraph described an opt-in build no tester has: the build in TestFlight (ios-v0.3.2, 2026-10-22) predates FRE-355 and starts Sentry on every launch with no off switch. The paragraph now says that. Header comment and marketing/drafts/privacy-page.md rows corrected to match (release range narrowed to 0.3.0-0.15.0; evidence rows record the IP and the TestFlight provenance). privacy-page.patch regenerated. Suite: merge tree ofa0e6ff1+ this branch runs the same failure set as cleana0e6ff1(2 junit failures, the known Lineage-redirect environmental pair); the host's env-validation aborts account for the count noise. Zero new failures.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
# `/privacy` — replacement copy, FRE-354 corrections applied 2026-11-04
|
||||
|
||||
**Status:** applied on branch `faq/from-objections-2026-10-29` (commit after `bb6cf27`), per the CTO's FRE-354 verdict — "apply the corrections above and the page is signed." The two copy decisions the verdict delegated to the CMO are taken: the **fuller iPhone paragraph** (its push-token evidence row is recorded in the evidence table below and routed to FRE-333's owner to append to the signed inventory), and the **full (c) block with the LAN/tailnet sentence**, which pulls the corresponding Section 3 clause in. Nothing here is published; the sponsor's merge + push on card [`392a8465`](/FRE/issues/FRE-326#interaction-392a8465) is still the deploy step.
|
||||
**Sequencing fact, updated 2026-11-06:** the contingency has **fired**. `v0.15.1` (tagged 2026-11-04, first tag containing FRE-355's merge `6e74b261`) and `v0.15.2` are live on the appcast (`freno.me/api/TheNook/appcast.xml`, newest item 0.15.2). Shipped behaviour when enabled: crash/error reports, session pings (`enableAutoSessionTracking` untouched), traces at 0.1, and **no IP attached** (`sendDefaultPii = false`). Paragraph (b) and the iPhone paragraph are therefore swapped to the opt-in form in this commit, with two corrections against the pre-written swap text: pings and traces are named (the contingency's own completeness warning), and the IP sentence is dropped rather than kept. Builds before `v0.15.1` started Sentry on every launch with no off switch; the page describes the current release.
|
||||
**Sequencing fact, updated 2026-11-06:** the contingency has **fired**. `v0.15.1` (tagged 2026-11-04, first tag containing FRE-355's merge `6e74b261`) and `v0.15.2` are live on the appcast (`freno.me/api/TheNook/appcast.xml`, newest item 0.15.2). Shipped behaviour when enabled: crash/error reports, session pings (`enableAutoSessionTracking` untouched), traces at 0.1, and **Sentry also receives the connection's IP address** (`sendDefaultPii = false` is the SDK default and does not suppress it; only the Sentry project's *Prevent Storing of IP Addresses* switch does — FRE-1480). Paragraph (b) and the iPhone paragraph are therefore swapped to the opt-in form in this commit, with two corrections against the pre-written swap text: pings and traces are named (the contingency's own completeness warning), and the IP sentence is kept. Releases 0.3.0 through 0.15.0 started Sentry on every launch with no off switch; the page describes the current release.
|
||||
**Patch:** `marketing/drafts/privacy-page.patch` — applies cleanly to `c1c498e` (`git apply --check`, verified 2026-10-29; parse-checked with esbuild, not the site suite).
|
||||
**Evidence base:** [FRE-333 `egress-inventory`](/FRE/issues/FRE-333#document-egress-inventory) rev 1, eleven destinations, file:line per row, read at `The-Nook` `3c3ba7ee`; and the same document's §G, which proposed a page text. This patch is the §G text **corrected against the inventory** — the differences are listed below, each with the row that forces it.
|
||||
**Why this exists:** [FRE-326](/FRE/issues/FRE-326) + [FRE-334](/FRE/issues/FRE-334#document-decision) recorded option A — the privacy claim is withdrawn everywhere, and no privacy claim returns until the inventory exists, `/privacy` matches it, the CTO verifies both, and the sponsor approves the replacement copy. The inventory landed on 2026-10-29. This is the page half.
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
The live page (fetched 2026-10-29T09:2xZ and again 09:4xZ, HTTP 200, `Last Updated: August 26, 2026`, unchanged) says the app "runs locally on your device and sends only the minimal data required for trial and licensing" and lists four things. Against the inventory that is wrong in two directions: it **omits** Sentry (crash reports with IP address, every launch, no off switch), the relay and its install ID, the licence key crossing to the relay, sealed phone payloads, weather coordinates going to the relay *and* to Apple, the GeoIP third parties, the speed test, the changelog fetch, bug-report contents and update checks. It also calls the hardware UUID "masked", which the code contradicts — it sends the raw `IOPlatformUUID`.
|
||||
|
||||
The replacement is organised by *connection*, not by *data type*, because that is how a reader checks it: eleven rows in the inventory, ten of them reachable from the page, one (Sentry) prominent because it is the only one a reader can turn off entirely and still miss in older builds. On the current release (`v0.15.1`+) it is opt-in and off by default; see *Contingency*.
|
||||
The replacement is organised by *connection*, not by *data type*, because that is how a reader checks it: eleven rows in the inventory, ten of them reachable from the page, one (Sentry) prominent because it is the only one a reader can turn off entirely and still miss in older builds. On the current Mac release (`v0.15.1`+) it is opt-in and off by default; the iPhone build in TestFlight (`ios-v0.3.2`, 2026-10-22) predates it. See *Contingency*.
|
||||
|
||||
## Differences from FRE-333 §G, and what forces each
|
||||
|
||||
@@ -31,7 +31,7 @@ The replacement is organised by *connection*, not by *data type*, because that i
|
||||
| 2 | (d) Weather: relay registration implied only with Phone | (d) adds that Weather registers **even with Phone off, and on a licensed Mac that registration presents the license key** | §A.3 + §D.2. `SidecarController.weather()` routes through the same `keystore.relayCredential(licenseKey:)` as the phone path (`SidecarController.swift:269-279`, `SidecarRelayAPI.swift:298-312`). §G under-disclosed it. |
|
||||
| 3 | (a) trial/activate/status only | (a) adds `/deactivate` (key + UUID) and the trial email (email + UUID, sent once) | §A.2, `/D.4`. §G omitted both endpoints. |
|
||||
| 4 | (i) "The email you give at trial start or checkout delivers your license key" | (i) checkout delivers the key; a trial email is one reminder before the trial ends | `LicenseService.submitTrialEmail` + `OnboardingExtrasStep` say the trial email is an expiry reminder; the key is issued at purchase. §G's sentence promised a key that the trial email does not deliver. |
|
||||
| 5 | (b) Sentry: opt-in, "off unless you turn it on" | (b) is the opt-in form, applied 2026-11-06: off unless enabled in Settings, and it names session pings and the trace sample; **no IP sentence** | The contingency fired with `v0.15.1`. Corrections against the pre-written swap text: pings/traces named because they still flow when enabled; IP dropped because `sendDefaultPii = false` in the shipped starter. |
|
||||
| 5 | (b) Sentry: opt-in, "off unless you turn it on" | (b) is the opt-in form, applied 2026-11-06: off unless enabled in Settings, and it names session pings and the trace sample; **the IP sentence, kept** | The contingency fired with `v0.15.1`. Corrections against the pre-written swap text: pings/traces named because they still flow when enabled; IP kept because `sendDefaultPii = false` does not stop Sentry receiving the connection IP (FRE-1480); the Contingency text already said so. |
|
||||
| 6 | No (j) | (j) carries the CTO's FRE-322 §2 code fact, with the remote-machine exception | Not required for truth; it is the one favourable sentence, and the CTO may decline it. Delete the block if he does. |
|
||||
|
||||
Two facts the inventory corrected and the page does not repeat wrongly: Sparkle's automatic checks are **off by default** here (`UpdateManager` owns the schedule; FRE-322 §2.4 said "on by default" and is stale on this row), and the UUID is **raw, not masked**.
|
||||
@@ -41,7 +41,7 @@ Two facts the inventory corrected and the page does not repeat wrongly: Sparkle'
|
||||
| Paragraph | What it now says | Evidence at `3c3ba7ee` |
|
||||
|---|---|---|
|
||||
| (a) Licensing/trial | raw UUID + device name; every launch while trialing; key-only once licensed; deactivate sends key + UUID; trial email sends email + UUID once; trial/status fail open, activation needs a connection once | `LicenseService.swift:300-313` (`/trial`), `:271-284` (`/status`), `:247-262` (`/activate`), `:286-302` (`/deactivate`), `:219-231` (`/trial-email`) |
|
||||
| (b) Crash reporting | opt-in, **off by default**; when enabled: crash/error reports, session pings, traces at 0.1; **no IP attached**; no prompts or code | `Sources/NookApp/main.swift` `startIfEnabled` — `sendDefaultPii = false` (`policy.sendDefaultPii`), `tracesSampleRate = 0.1` while on (`CrashReporting.onTracesSampleRate`); `CrashReporting.registerDefaults` pins `enabledKey: false`; evidence read 2026-11-06 |
|
||||
| (b) Crash reporting | opt-in, **off by default**; when enabled: crash/error reports, session pings, traces at 0.1; **Sentry also receives the IP address** (`Options.swift:267-275` at 9.26.1: `sendDefaultPii = false` is the default and does not suppress it); no prompts or code | `Sources/NookApp/main.swift` `startIfEnabled` — `sendDefaultPii = false` (`policy.sendDefaultPii`), `tracesSampleRate = 0.1` while on (`CrashReporting.onTracesSampleRate`); `CrashReporting.registerDefaults` pins `enabledKey: false`; evidence read 2026-11-06, IP row per FRE-1480 |
|
||||
| (c) Phone relay | off by default; relay is the default path, LAN/tailnet direct pairing available; install ID + license key at registration; sealed payloads; relay sees device IDs/names/platforms, timing and volume, not content | `SidecarRelayAPI.swift:144-153`, `SidecarPayload.swift:484-490`, `RemoteEndpoint.swift:14-24`, `docs/sidecar-frames.md` (sealing), inventory §B |
|
||||
| (d) Weather | 0.1° grid snapped **on the Mac**; registers with the relay even with the phone off, licence key included on a licensed Mac; Apple sees place lookups and position | `WeatherForecast.swift:25-30`, `SidecarController.swift:269-279`, `SidecarRelayAPI.swift:298-312`, `WeatherLocation.swift:14-77`, `:89-143` |
|
||||
| (e) Network panel | third-party IP lookup sees your IP; speed test uploads zeros only | `NetworkInfoService.swift:82,276`, `SpeedTest.swift:10-11,36` |
|
||||
@@ -50,11 +50,11 @@ Two facts the inventory corrected and the page does not repeat wrongly: Sparkle'
|
||||
| (h) Bug reports | user-sent only; machine snapshot listed in full | `BugReportClient.swift:44-94`, `BugReportSnapshot.swift:17-36` |
|
||||
| (i) Email/payment | checkout email delivers the key; trial email is a reminder; Stripe | `LicenseService.swift:219-231`, `OnboardingExtrasStep.swift:86-110` |
|
||||
| (j) What does not leave your Mac | hook and bridge are not a cloud service; helper has no networking; two paths carry agent data across the network, both user-switched: remote machines over SSH or the tailnet, and the sealed phone relay | `hook/transport.go:143` (`resolveBridge`), `BridgeBindPlan.swift:9-23`, `RemoteEndpoint.swift:14-24`, inventory §B + §C |
|
||||
| iPhone companion (TestFlight beta) | same Sentry config as the Mac (IP only, no username, session pings); other traffic is the phone connection in (c) plus the APNs push token given to the relay | `ios/AgentNookMobile/App.swift:12-20`, `RelayLink.pair` `RelayLink.swift:104-118`, `updatePushToken` `:226-232` — row added per FRE-354; append to the FRE-333 inventory |
|
||||
| iPhone companion (TestFlight beta) | the TestFlight build (`ios-v0.3.2` = `2e322da5`, 2026-10-22) predates FRE-355: unconditional start, `sendDefaultPii = true`, traces 1.0, no off switch (`ios/AgentNookMobile/App.swift:13-20`); the opt-in code exists at `v0.15.2` but no `ios-v*` tag carries it; other traffic is the phone connection in (c) plus the APNs push token given to the relay | `RelayLink.pair` `RelayLink.swift:104-118`, `updatePushToken` `:226-232` — row added per FRE-354, TestFlight provenance per FRE-1480; append to the FRE-333 inventory |
|
||||
|
||||
## Contingency — the Sentry paragraph is the only one that moves
|
||||
|
||||
**FIRED 2026-11-06 — applied on the branch.** `v0.15.1` is the first release containing FRE-355 and is live on the appcast. The swap below was applied with the corrections recorded in the sequencing paragraph at the top of this document (pings and traces named; IP sentence dropped). The original text is kept for the record:
|
||||
**FIRED 2026-11-06 — applied on the branch.** `v0.15.1` is the first release containing FRE-355 and is live on the appcast. The swap below was applied with the corrections recorded in the sequencing paragraph at the top of this document (pings and traces named; IP sentence kept — the pre-written text below had it, and dropping it was wrong; FRE-1480). The original text is kept for the record:
|
||||
|
||||
(b) as committed describes today's build. The inventory's recommendation (§E.1) is an opt-in setting, default off, dropping `sendDefaultPii` and cutting `tracesSampleRate`, on Mac **and** iOS. If that ships, (b) is replaced in the same commit that changes the behaviour:
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/src/routes/nook/privacy.tsx b/src/routes/nook/privacy.tsx
|
||||
index da0cc1d..d0fe761 100644
|
||||
index da0cc1d..db27d8c 100644
|
||||
--- a/src/routes/nook/privacy.tsx
|
||||
+++ b/src/routes/nook/privacy.tsx
|
||||
@@ -1,9 +1,33 @@
|
||||
@@ -1,9 +1,38 @@
|
||||
/**
|
||||
* The Nook privacy policy — `nook.freno.me/privacy`.
|
||||
*
|
||||
@@ -19,17 +19,22 @@ index da0cc1d..d0fe761 100644
|
||||
+ * releases v0.15.1 and later — FRE-355 (merge `6e74b261`) first shipped in
|
||||
+ * `v0.15.1` (2026-11-04), and the live appcast serves `v0.15.2`. When enabled,
|
||||
+ * Sentry receives crash and error reports, session pings, and performance
|
||||
+ * traces at a 0.1 sample rate (`tracesSampleRate = 0.1`), and no IP address is
|
||||
+ * attached (`sendDefaultPii = false`, `Sources/NookApp/main.swift` and
|
||||
+ * `Sources/NookCore/System/CrashReporting.swift`). Builds before `v0.15.1`
|
||||
+ * started Sentry on every launch with `sendDefaultPii = true` and no off
|
||||
+ * switch; this page describes the current release.
|
||||
+ * traces at a 0.1 sample rate (`tracesSampleRate = 0.1`), and it also receives
|
||||
+ * the connection's IP address (`sendDefaultPii = false` is the SDK default and
|
||||
+ * does not suppress it — sentry-cocoa 9.26.1 sets `infer_ip = auto` for Cocoa,
|
||||
+ * and only the Sentry project's *Prevent Storing of IP Addresses* switch stops
|
||||
+ * that; FRE-1480). Releases 0.3.0 through 0.15.0 started Sentry on every
|
||||
+ * launch with `sendDefaultPii = true` and no off switch; this page describes
|
||||
+ * the current release. The iPhone paragraph describes `ios-v0.3.2`
|
||||
+ * (2026-10-22, the build in TestFlight) until an `ios-v*` tag carries
|
||||
+ * FRE-355's opt-in code.
|
||||
+ *
|
||||
+ * The *Contingency* in `marketing/drafts/privacy-page.md` fired with `v0.15.1`
|
||||
+ * and is applied in this commit, with two corrections against the pre-written
|
||||
+ * swap text: the shipped build still sends session pings and traces while
|
||||
+ * enabled, so they are named (the contingency's own completeness warning), and
|
||||
+ * `sendDefaultPii = false` means the IP sentence is dropped rather than kept.
|
||||
+ * the IP sentence is kept — the pre-written swap text already had it, and
|
||||
+ * `sendDefaultPii = false` does not stop Sentry receiving the IP (FRE-1480).
|
||||
+ *
|
||||
+ * Corrected against the CTO's /privacy verdict (FRE-354): no macOS username
|
||||
+ * from Sentry (sendDefaultPii sets the IP only), session pings named, (a)
|
||||
@@ -39,7 +44,7 @@ index da0cc1d..d0fe761 100644
|
||||
*/
|
||||
import { buildMainSiteUrl } from "~/lib/subdomain-url";
|
||||
import { PageHead } from "~/components/PageHead";
|
||||
@@ -21,39 +45,141 @@ export default function NookPrivacyPolicy() {
|
||||
@@ -21,39 +50,139 @@ export default function NookPrivacyPolicy() {
|
||||
<SubdomainHeader />
|
||||
<div class="min-h-screen px-[8vw] py-[10vh]">
|
||||
<div class="py-4 text-xl">The Nook's Privacy Policy</div>
|
||||
@@ -95,9 +100,8 @@ index da0cc1d..d0fe761 100644
|
||||
+ and a sample of performance traces to Sentry, our
|
||||
+ crash-reporting processor. Each report carries the app version,
|
||||
+ the macOS version, the Mac model and what the app was doing
|
||||
+ when it failed. Your IP address is not attached to the reports.
|
||||
+ They never include your prompts, your code or your session
|
||||
+ content.
|
||||
+ when it failed. Sentry also receives your IP address. They
|
||||
+ never include your prompts, your code or your session content.
|
||||
+ </div>
|
||||
+ <div class="pb-2">
|
||||
+ <div class="-ml-6">(c) Phone connection:</div> The phone
|
||||
@@ -186,13 +190,12 @@ index da0cc1d..d0fe761 100644
|
||||
- <div class="-ml-6">(d) Payment:</div> Payments are processed by
|
||||
- Stripe. We never see or store your card details.
|
||||
+ <div class="-ml-6">The iPhone companion.</div> The iPhone and
|
||||
+ Apple Watch app is in TestFlight beta. Its crash reporting is
|
||||
+ the same opt-in: off unless you turn it on in its settings.
|
||||
+ When it is on, it sends crash reports, session pings and a
|
||||
+ sample of performance traces to Sentry — the app version, the
|
||||
+ iOS version and the iPhone model, with no IP address attached.
|
||||
+ Those reports never include your prompts, code or session
|
||||
+ content.
|
||||
+ Apple Watch app is in TestFlight beta. The build in TestFlight
|
||||
+ starts Sentry on every launch, with no setting that turns it
|
||||
+ off: it sends crash, error and hang reports, session pings,
|
||||
+ performance traces, the app version, the iOS version, the
|
||||
+ iPhone model and your IP address. Those reports never include
|
||||
+ your prompts, code or session content.
|
||||
+ Its other network traffic is the phone connection in (c) — the
|
||||
+ relay, or a direct LAN/tailnet link — plus, if you allow
|
||||
+ notifications, the push token it gives the relay so Apple can
|
||||
@@ -200,7 +203,7 @@ index da0cc1d..d0fe761 100644
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -63,9 +189,11 @@ export default function NookPrivacyPolicy() {
|
||||
@@ -63,9 +192,11 @@ export default function NookPrivacyPolicy() {
|
||||
<span class="-ml-4 pr-2">2.</span> How We Use It
|
||||
</div>
|
||||
<div class="pb-2 pl-4">
|
||||
@@ -215,7 +218,7 @@ index da0cc1d..d0fe761 100644
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -74,9 +202,13 @@ export default function NookPrivacyPolicy() {
|
||||
@@ -74,9 +205,13 @@ export default function NookPrivacyPolicy() {
|
||||
<span class="-ml-4 pr-2">3.</span> Data Security
|
||||
</div>
|
||||
<div class="pb-2 pl-4">
|
||||
|
||||
@@ -11,17 +11,22 @@
|
||||
* releases v0.15.1 and later — FRE-355 (merge `6e74b261`) first shipped in
|
||||
* `v0.15.1` (2026-11-04), and the live appcast serves `v0.15.2`. When enabled,
|
||||
* Sentry receives crash and error reports, session pings, and performance
|
||||
* traces at a 0.1 sample rate (`tracesSampleRate = 0.1`), and no IP address is
|
||||
* attached (`sendDefaultPii = false`, `Sources/NookApp/main.swift` and
|
||||
* `Sources/NookCore/System/CrashReporting.swift`). Builds before `v0.15.1`
|
||||
* started Sentry on every launch with `sendDefaultPii = true` and no off
|
||||
* switch; this page describes the current release.
|
||||
* traces at a 0.1 sample rate (`tracesSampleRate = 0.1`), and it also receives
|
||||
* the connection's IP address (`sendDefaultPii = false` is the SDK default and
|
||||
* does not suppress it — sentry-cocoa 9.26.1 sets `infer_ip = auto` for Cocoa,
|
||||
* and only the Sentry project's *Prevent Storing of IP Addresses* switch stops
|
||||
* that; FRE-1480). Releases 0.3.0 through 0.15.0 started Sentry on every
|
||||
* launch with `sendDefaultPii = true` and no off switch; this page describes
|
||||
* the current release. The iPhone paragraph describes `ios-v0.3.2`
|
||||
* (2026-10-22, the build in TestFlight) until an `ios-v*` tag carries
|
||||
* FRE-355's opt-in code.
|
||||
*
|
||||
* The *Contingency* in `marketing/drafts/privacy-page.md` fired with `v0.15.1`
|
||||
* and is applied in this commit, with two corrections against the pre-written
|
||||
* swap text: the shipped build still sends session pings and traces while
|
||||
* enabled, so they are named (the contingency's own completeness warning), and
|
||||
* `sendDefaultPii = false` means the IP sentence is dropped rather than kept.
|
||||
* the IP sentence is kept — the pre-written swap text already had it, and
|
||||
* `sendDefaultPii = false` does not stop Sentry receiving the IP (FRE-1480).
|
||||
*
|
||||
* Corrected against the CTO's /privacy verdict (FRE-354): no macOS username
|
||||
* from Sentry (sendDefaultPii sets the IP only), session pings named, (a)
|
||||
@@ -86,9 +91,8 @@ export default function NookPrivacyPolicy() {
|
||||
and a sample of performance traces to Sentry, our
|
||||
crash-reporting processor. Each report carries the app version,
|
||||
the macOS version, the Mac model and what the app was doing
|
||||
when it failed. Your IP address is not attached to the reports.
|
||||
They never include your prompts, your code or your session
|
||||
content.
|
||||
when it failed. Sentry also receives your IP address. They
|
||||
never include your prompts, your code or your session content.
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<div class="-ml-6">(c) Phone connection:</div> The phone
|
||||
@@ -169,13 +173,12 @@ export default function NookPrivacyPolicy() {
|
||||
</div>
|
||||
<div class="pb-2">
|
||||
<div class="-ml-6">The iPhone companion.</div> The iPhone and
|
||||
Apple Watch app is in TestFlight beta. Its crash reporting is
|
||||
the same opt-in: off unless you turn it on in its settings.
|
||||
When it is on, it sends crash reports, session pings and a
|
||||
sample of performance traces to Sentry — the app version, the
|
||||
iOS version and the iPhone model, with no IP address attached.
|
||||
Those reports never include your prompts, code or session
|
||||
content.
|
||||
Apple Watch app is in TestFlight beta. The build in TestFlight
|
||||
starts Sentry on every launch, with no setting that turns it
|
||||
off: it sends crash, error and hang reports, session pings,
|
||||
performance traces, the app version, the iOS version, the
|
||||
iPhone model and your IP address. Those reports never include
|
||||
your prompts, code or session content.
|
||||
Its other network traffic is the phone connection in (c) — the
|
||||
relay, or a direct LAN/tailnet link — plus, if you allow
|
||||
notifications, the push token it gives the relay so Apple can
|
||||
|
||||
Reference in New Issue
Block a user