docs: Build 1 settled/live gate recorded + live anonymous fingerprint

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QJs13VsyiSKYQP6rj3NNmc
This commit is contained in:
Kev
2026-07-31 07:21:36 -04:00
parent 6d36e05bfe
commit 7ddf159e4a
2 changed files with 51 additions and 0 deletions
+18
View File
@@ -724,3 +724,21 @@ grades server-side, never infer resolution from time, fail closed to LIVE.
count** — the real counter (`/api/founders/count`, live 0/100) only displays and is cached 300s, so count** — the real counter (`/api/founders/count`, live 0/100) only displays and is cached 300s, so
making it a transactional gate is a genuine build; (b) the user base is **3 free, 0 paid**, so the making it a transactional gate is a genuine build; (b) the user base is **3 free, 0 paid**, so the
migration is a courtesy note, not a mass event — effort belongs on the settled-record proof surface. migration is a courtesy note, not a mass event — effort belongs on the settled-record proof surface.
---
# BUILD 1 — THE SETTLED/LIVE GATE (shipped 2026-07-31)
Unresolved = paid (Analyst+), resolved = free. Serving/gating only; `src/services/` untouched.
Resolution is read **only from a written outcome** (never time or game status), `void`/`unrecoverable`
count as resolved, and `isResolved` **fails closed to LIVE** so a settle failure withholds rather than
exposes. Free gets **settled grades in full including reasoning** — the proof product — which also
turns the old unenforced board-reasoning leak into a deliberate rule. Live grades become a **shell**:
judgment stripped, real data kept (incl. `fair_odds`, which is never the paywall), `locked: true`
stamped. The tease is **aggregate only** (`live_locked {count, tiers}`) and no gated row carries a
grade, so nobody can tell which prop is the A.
**Live anonymous fingerprint:** 25 grades → **5 settled free-full, 20 locked**, `live_locked
{"count":20,"tiers":{"B":13,"C":7}}`, **judgment-field leak: NONE**. 319 suites / 3,971 tests green,
web build exit 0.
+33
View File
@@ -1007,6 +1007,39 @@
> **CANNOT DETERMINE: whether the four Stripe price objects exist in the dashboard** (env not readable > **CANNOT DETERMINE: whether the four Stripe price objects exist in the dashboard** (env not readable
> here) — flagged as a prerequisite for build 3. > here) — flagged as a prerequisite for build 3.
> ## 🔒 BUILD 1 SHIPPED 2026-07-31 — THE SETTLED/LIVE GATE (unresolved = paid, resolved = free)
> **Serving/gating change ONLY** — `src/services/` untouched (diff empty): no grade, model or
> settlement-logic change. Pricing = Build 2, migration = Build 3.
> **THE RULE:** a grade is **PAID while its outcome is unknown** and becomes **FREE the moment it
> resolves**. **Resolution is read ONLY from a written outcome** — never from time, game status or
> `gradedAt` (a game can be final long before the settle pass runs; treating "probably over" as
> settled is exactly how a live edge leaks — a test asserts an hours-old `gradedAt` with no outcome is
> still LIVE). `void`/`unrecoverable` **are** resolutions. **`isResolved` FAILS CLOSED** — null
> outcome, `{}` with no result, empty-string result all read LIVE — so a **settlement failure
> withholds rather than exposes**, the same direction `resolveTierFromRequest` fails.
> **FREE = SETTLED IN FULL** (reasoning + kill conditions included — settled is the proof product and
> costs nothing post-resolution). **This also converts the previously-UNENFORCED board-reasoning leak
> into a deliberate rule.** **LIVE = SHELL**: all model JUDGMENT dropped (`grade`, `confidence`,
> `confidence_basis`, `reasoning`, `kill_conditions_triggered`, `projection`, `edge_pct`,
> `matchup_grade`, `form`, `alt_lines`, `kelly`) + `locked: true`; the free-side DATA stays so the
> tease is REAL, not empty (player · market · line · `book_odds` · **`fair_odds` — the de-vigged fair
> number is the free hook and is NEVER the paywall** · season/last10 · archetype · gradedAt · history).
> **THE TEASE IS AGGREGATE ONLY** — `live_locked {count, tiers}` computed from the ungated rows and
> **never joined back to one**, and **no gated row carries a grade**, so a free viewer learns N reads
> exist and their shape **without being able to work out WHICH prop is the A**.
> **✅ FINGERPRINT — LIVE, ANONYMOUS, DECISIVE** (deploy boundary captured: attempts 1-2 no
> `live_locked`, attempt 3 yes): **25 grades → 5 SETTLED served free-full · 20 LIVE locked ·
> `live_locked {"count":20,"tiers":{"B":13,"C":7}}`**. **LEAK CHECK: judgment fields on live rows =
> NONE ✓**, all 20 stamped `locked`. Live shell still carries real data (Natasha Cloud · assists ·
> 6.5 · book 145 · **fair 123** · season 4.6). Settled row keeps full proof (grade B · reasoning ✓ ·
> 2 kill conditions · edge 2.2 · `outcome {"result":"hit","actual":1}`).
> **FLOOR: 319 suites / 3,971 tests green (10 new), web build exit 0.**
> **⚠️ TEST NOTE:** the route-level supertest case was **deliberately removed** — it needs a live
> Redis and hangs on ioredis' reconnect timer in a single-suite local run (known, CLAUDE.md). The
> gate's contract is fully covered by pure tests; **the wire is verified against PROD anonymously**
> (above). **Chrome audit:** free board (settled full + locked shells + unlock prompt) and the
> entitled board (live full) both need a visual pass — the entitled half needs Kev's Desk session.
- **Redirect EXISTS + WIRED:** `closingCapture.buildCaptureRows``closing_captures` (append-only, - **Redirect EXISTS + WIRED:** `closingCapture.buildCaptureRows``closing_captures` (append-only,
provenance: captured_at/book/line_type/both-prices/missed_reason) via `intradayRefreshService:221` provenance: captured_at/book/line_type/both-prices/missed_reason) via `intradayRefreshService:221`
+ internal endpoint; `ledgerService.attachClosingProb``closing_prob` (de-vigs both raw sides, + internal endpoint; `ledgerService.attachClosingProb``closing_prob` (de-vigs both raw sides,