Gap 1 — click and served share one label: trackDownload now takes a
stage ("click" | "served") carried on a new VisitorAnalytics.stage
column; the Nook door and the tRPC proxy record clicks, the DMG file
route records served. summariseDownloads() and the /analytics downloads
block are untouched — the stage is a separate column, so the path
grouping cannot change.
Gap 2 — checkout start records nothing: the checkout route records a
created Stripe session through the shared trackRequest writer (same
referrer, campaign, country dimensions as every door) under its own
path, and STAGES.checkout reads it instead of the /checkout page proxy.
Gap 3 — loopback addresses, no host dimension: every writer now
resolves the client address through resolveClientIp, which trusts
x-forwarded-for only when the direct peer is the loopback production
proxy (trust boundary stated in request-client.ts), and records the
host on each row through the same site-context extractor routing uses.
stage and host reach the table through VISITOR_ANALYTICS_ADDED_COLUMNS;
the weekly job applies the same bootstrap before reading so it renders
seven stages against a database no deploy has migrated yet.
The weekly read splits downloadClick/dmgServed, scopes visits to
nook.freno.me, and computes its caveats from the window: pre-instrumentation
rows are stated and excluded, and the loopback warning now fires only
when rows recorded since the instrumentation still carry it.
`marketing/metrics/weekly.md` has been a placeholder since the marketing tree
landed — it promised a funnel and the one thing that moved, and nothing
produced it. This adds the producer: one command reads the live databases and
rewrites the file.
`scripts/weekly-metrics.ts` writes `marketing/metrics/weekly.md` from
`VisitorAnalytics` (visits, downloads, campaigns) and the-nook's `trials`,
`licenses`, `activations` (the paid funnel). It needs four env vars —
TURSO_DB_URL/TOKEN and NOOK_DB_URL/TOKEN — and imports no server env, so the
job runs from a checkout that has no Stripe or Apple secrets.
`src/server/weekly-metrics.ts` holds the queries and the renderer, taking both
connections as arguments; the tests run them against an in-memory SQLite shaped
like production, the same way the backfill suite does.
The campaign breakdown groups exactly as `getAnalyticsSummary.topCampaigns`
does (top 10, untagged excluded), so the weekly read and /analytics cannot
drift into different label sets.
The first real report says more about the instrumentation than about demand,
and the renderer computes that rather than asserting it:
- every addressed row the table has ever held (12,035 of 12,048) is loopback,
so "unique visitors" is one host and per-channel reach cannot be read;
- the landing door and the file route both write `/api/downloads/thenook`, so
"download click" and "DMG served" are one label — one served click writes two
rows, a failed click one, a Sparkle update one;
- `POST /api/the-nook/checkout` records nothing, so checkout start is only a
page-view proxy;
- `VisitorAnalytics` has no host dimension, so the Nook's `/` is freno.me's `/`.
Those three gaps are reported beside the numbers, not papered over. Week 0
(2026-10-22 → 2026-10-29): visit 61, download 156, trial 2, checkout 0,
purchase 0, activation 0 — and the one thing that moved is the download stage,
0 → 156, because the label was introduced that week.
Tests: `bun test src/server/weekly-metrics.test.ts` — 12 pass, 0 fail. The full
suite's 15 failures are pre-existing: this checkout's .env lacks
NOOK_LICENSE_PRIVATE_KEY, NOOK_STRIPE_SK/WEBHOOK/PRICE and LINEAGE_JWT_SECRET,
and every failure is that env validation.
Scripts/ is gitignored, so `scripts/weekly-metrics.ts` was added with `-f`, the
way the existing tracked scripts are.
FRE-202
copy.md said the sentences were "removed from the live site" and
rationale.md said "the landing page now says only what the product can back
today". Neither is true: nook.freno.me still serves all of them (HTTP 200,
re-fetched 2026-10-29T14:20Z) because the push is blocked on a write
credential (card 82d1e1b7). Both files now say committed-not-deployed, and
positioning.md's excluded-count row records FRE-359 verdict B and where the
count was removed.
Co-Authored-By: Paperclip <noreply@paperclip.ing>
The source-of-truth file still sold claims the board has since ruled on:
- 'thirteen agents' as a public coverage count — FRE-322 §1 counts 18 specs,
9 of which can raise an approval card; no count is publishable (FRE-203 plan-b).
- 'Price rises to 5 at 1.0' — withdrawn by the Chief of Staff on 2026-10-29
04:01; price stays $10 and is not a launch asset.
- 'macOS 14+' — the app cannot start below 14.2 (881190d, site 134f41e).
- Approved-claims table carried no launch sentence at all, and no row for the
remote-SSH hold or the banned absolute privacy sentences.
- Pointed at the-nook/docs/marketing-strategy.md, which no longer exists.
Now: the Plan B claim set, a per-claim status table with verdict pointers,
FRE-354's corrections to the hook/bridge sentence and the Sentry disclosure,
the iPhone TestFlight state, and an explicit excluded/banned list.
FRE-323. The one-click remote install is app-UI-only and needs hand-edited ~/.ssh/config plus a one-time ssh-copy-id (FRE-320); FRE-315 and FRE-322 hold the claim unverified and demo-gated.
- drop the Remote tile and its mock from the feature collage
- drop the "Any SSH box, one click away" breakdown, its demo and bullets
- drop "Works across every hooked agent, local or remote"
- drop the "One-click SSH setup" chip
- move the copy to marketing/drafts/remote-ssh/ and mark remote held in marketing/positioning.md
No replacement claim was added. Deploy waits on a push credential for the GitHub repo Vercel builds.
nook.freno.me/agents listed twelve agents and said "twelve" in its meta
description, OG title and intro, while the app's registry (AgentSpec.all)
gained Muse in 0.10.0 as its thirteenth. The page mirrors that registry
by hand from another repo, so nothing flagged the drift.
Adds the Muse card from its plugin manifest and registry row: the plugin
body at ~/.nook/plugins/muse installed through Muse's own plugins CLI,
its fourteen hook events, approvals answerable from a card (every tool
call under Verify), and this Mac only since remote hosts skip it. The
positioning claims table and copy move to thirteen with it.
Tests: src/routes/nook/agents.test.ts pins the roster to the registry's
names in order (red on master: Muse missing) and every stated count to
the number of entries (red when the intro says twelve again).
NOOK-336
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One voice, one place, so agent-drafted assets stop inventing framing
per artifact. positioning.md carries the wedge, the category-noun rule
(freno-dev/AGENTS.md competitor ban), claims each backed by code, the
honest privacy scoping and the voice/banned-phrasings list. The tree
adds calendar.json, per-channel briefs, drafts → pending → approved →
posted, metrics and listening — with the hard rule up front: approved/
is the only thing a human ever publishes from, nothing posts itself.
Issue: FRE-17