spec: step 3 built on analytics-step3; the eleven step 3 rulings in §8
Status line names the branch and its plan; §8 lists the rulings made on Paul's behalf while building the browser door, each cheap to overturn; the pinfra collision grep for /__carlos/ is recorded as run.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
1 file changed,
+42
−2
docs/superpowers/specs/2026-09-07-errors-and-analytics-design.md+42 −2
CI passed — run details
diff --git a/docs/superpowers/specs/2026-09-07-errors-and-analytics-design.md b/docs/superpowers/specs/2026-09-07-errors-and-analytics-design.md| index 30d307ecf..c1c0ec571 100644 |
| --- a/docs/superpowers/specs/2026-09-07-errors-and-analytics-design.md |
| +++ b/docs/superpowers/specs/2026-09-07-errors-and-analytics-design.md |
| @@ -4,8 +4,12 @@ |
| **Status:** approved (Paul, 2026-09-07: "go ahead with that and plan, build |
| review cycle overnight"). Rollout step 1 (§7) is merged (forge main 1a99060; plan |
| `docs/superpowers/plans/2026-09-07-errors-step1-log-and-edge.md`). Step 2 is |
| -implemented on branch `analytics-step2` (plan |
| -`docs/superpowers/plans/2026-09-07-analytics-step2-edge-counting.md`). Every |
| +merged (forge main 40c6ab7; plan |
| +`docs/superpowers/plans/2026-09-07-analytics-step2-edge-counting.md`). Step 3 |
| +(the browser door and `carlos.js`) is built on branch `analytics-step3` (plan |
| +`docs/superpowers/plans/2026-09-07-analytics-step3-browser-door.md`; its |
| +planning rulings and the whole-branch review's rulings are listed at the end |
| +of §8). Every |
| choice below is marked **(decision)** and can be overturned cheaply; the |
| four in §8 are Paul's **(ruling)**s of 2026-09-07 and are marked where |
| they land. Drafted by Claude Fable, |
| @@ -775,6 +779,42 @@ Four questions were open in the draft; Paul answered all four. |
| The `platform-infrastructure` collision check for `/__carlos/` is still |
| worth one grep before step 3 ships; the double underscore makes a hit |
| unlikely enough that it is a checklist line, not an open question. |
| +(Run 2026-09-07 while building step 3: no hit.) |
| + |
| +**Step 3 rulings (Claude, 2026-09-07, made on Paul's behalf while building |
| +`analytics-step3`; each is cheap to overturn):** |
| + |
| +1. Both switches travel as one `telemetry.Switches{Count, Door}` map from |
| + the host pass into the edge. |
| +2. A refused beacon is counted in `dropped` whenever the door is open, |
| + regardless of the `count` switch (the tab shows `dropped` regardless; |
| + the fleet default is count off / door on, so without this every |
| + refusal on a default app is invisible; a drop-only day file carries no |
| + visitor data). `door: off` records nothing: the owner shut it. |
| +3. Drops that happen before the body is read (origin, size) are charged |
| + to the hostname's root app. |
| +4. The per-visitor rate key is `fnv64(clientIP ‖ UA)` in edge memory, |
| + unsalted, never stored. |
| +5. The loader `/__carlos/carlos.js` is a two-line script that appends the |
| + hashed asset; errors thrown before the asset runs are missed. |
| +6. `validPathPrefix` refuses `__carlos` and `lookupUpstreamPath` ignores |
| + such a key defensively; the intercept matches the cleaned first |
| + segment too, so `/./__carlos/x` is never proxied. |
| +7. Coverage lines: the Analytics tab shows `edge` always and adds |
| + `browser` once the range has a named event or a browser drop; the |
| + Errors tab shows `log, edge` always and adds `browser`/`server` once a |
| + record with that source is in the window. |
| +8. The reserved path sits before the observer wrap and so before the |
| + password gate: the snippet and both beacons are reachable on a gated |
| + host; the Origin rule, caps and buckets are the defence there. Pinned |
| + by a test. |
| +9. The door is checked before the body is read: a door-off hostname |
| + answers 202 and reads nothing. |
| +10. The Origin rule accepts the port the edge listens on (`-https`), |
| + and `http` origins only under `--dev`. |
| +11. The coalescing budget (§3.2's 1,000 per app-hour) is per (app, |
| + source) with one `_overflow` row per source, so a browser flood |
| + cannot blind edge errors. |
| ## 9. Review round 1 |