product

Downstream — session handoff (start here to continue)

Written 2026-07-15. Everything a fresh session needs to pick up Downstream (the "stress curves" app — the user's north-star "holy grail"). Full vision: DOWNSTREAM.md. This doc = current state + the exact deploy steps

  • open threads.

What Downstream is (one paragraph)

A deferred/maintenance thing isn't a due date — it's a curve (how its cost + stress grow the longer you wait). Downstream triages your list by where each thing is on its curve, leads with relief ("let these drift; do this one"), runs a cost-vs-stress mirror (high-dread/low-cost → just do it; low-dread/ high-cost → the sneaky trap), and, when something crosses the knee, speaks a short nudge — in your own cloned voice — via in-app banner + web push. The maintenance half of the self (DreamPro = the aspiration half).


Build state (2026-07-15)

MERGED to main (#1266): curve model + inference + triage + mirror + resolve/calibrate + snooze + the curve-timed nudge cron. Migrations 481 (downstream_items) + 482 (downstream_nudges) applied to prod.

OPEN — PR #1267 (branch feat/downstream-quiet-hours), NOT yet merged:

  • Public landing page /downstream + Features catalog entry + footer link.
  • Quiet-hours (migration 483 downstream_prefs, browser-tz captured).
  • Traceability log ("what Downstream has told you") on the dashboard.
  • Web push (migration 484 downstream_push_subs; web-push dep; service worker apps/frontend/public/sw.js; "Turn on nudges" button).
  • Rename JQ Glasses → Downstream Glasses across the app + admin surfaces.

⚠️ To land #1267 (do these, in order)

  1. Apply migrations 483 + 484 to prod (supabase/migrations/483_*.sql, 484_*.sql). Both degrade gracefully if skipped, but apply them.
  2. Set VAPID env vars (web push is a no-op until these exist):
    • Backend (Railway): VAPID_PUBLIC_KEY, VAPID_PRIVATE_KEY, VAPID_SUBJECT (e.g. mailto:hello@hivejournal.com).
    • Frontend (Vercel): NEXT_PUBLIC_VAPID_PUBLIC_KEY (= the same public key).
    • Generate a pair with cd apps/backend && npx web-push generate-vapid-keys. (A pair was generated for the user on 2026-07-15 and shared in chat — reuse or regenerate; never commit the private key.)
  3. Merge #1267 (gh pr merge 1267 --squash --delete-branch).
  4. Turn the cron on to feel it: /dashboard/admin/cronsdownstream_nudge (OFF by default). Add a couple of items at /dashboard/downstream first.

File map

  • Curve math (deterministic, tested 8/8): apps/backend/src/services/downstream-curves.ts
  • Service (inference + CRUD + triage + prefs): apps/backend/src/services/downstream.ts
  • Nudge cron (compose + voice + push): apps/backend/src/services/downstream-nudge.ts
  • Web push: apps/backend/src/services/downstream-push.ts + apps/frontend/public/sw.js
  • Routes: apps/backend/src/routes/downstream.ts (/api/downstream/*)
  • App UI: apps/frontend/src/app/dashboard/downstream/page.tsx
  • Landing: apps/frontend/src/app/downstream/page.tsx
  • Migrations: 481 (items), 482 (nudges), 483 (prefs), 484 (push_subs)

Open threads / next steps

Downstream product:

  • Glasses nudge delivery — the glasses app can already GET /api/downstream/nudges; this is a glasses-app change, backend is ready.
  • Normative / open-science curves — aggregate the resolve-time calibration (resolution_feedback) into per-category crowd curves on the citizen-science infra ("the shape of human procrastination cost"). Personal-vs-normative overlay.
  • Household/shared curves (JQ Bridge / family).
  • Quiet-hours UI — today tz is auto-captured but the quiet window (default 21:00–08:00) isn't user-editable in the UI yet (backend supports it).
  • Inference tuning — deadlines for ramp items are LLM-guessed (taxes came back Oct-15 not Apr-15); fine for v1 (user edits), but a calendar-anchored prior would sharpen it.

Downstream Glasses (the AR hardware layer):

  • Rename sweep — DONE (task 75650d60): app surfaces (prior) + now the code and docs. apps/glasses class JqGlassesAppDownstreamGlassesApp + header/session comments; INDEX.md "JQ on glasses" heading → "Downstream Glasses"; JQ_SPEECH_MIRROR.md product-name refs. Confirmed clean: the other glasses docs (DREAMPRO_GLASSES_VOICE_PROGRAM.md, AR_GLASSES_LIVING_VOICE.md, OWNED_HARDWARE_HORIZON.md) and routes/glasses.ts / jq-voice.ts had no product-name debt — every "JQ" in them is the assistant voice (/api/jq/voice/*, "JQ forward-voice nudges"), which stays by design. Rule: product name = "Downstream Glasses"; JQ = the assistant voice on them.
  • Gesture + scene check-ins (task cee81c72): read the wearer's hand (thumbs/palm/finger-count) + background/setting from a glasses photo as a wordless check-in.
  • Traceability log (task 429a1306): the downstream_nudges table already seeds this ("what did it tell me"). Extend to all in-ear audio when the glasses app lands.
  • Sophia/Cicero local NLU (task 1bbcdca3): Matt (cicero.sh) — HA edition LIVE at https://nlu.to/ha/ (24MB, 160MB RAM, offline, ms latency). The on-device intent pre-filter for always-listening glasses. Warm WhatsApp intro offered — reach out.

Landmines / conventions (so you don't relearn them)

  • ESM jest: run backend tests with NODE_OPTIONS=--experimental-vm-modules npx jest <name> (the npm test script sets it; bare npx jest falls into a broken CJS path). jest.config.js ignores TS1378 for the dynamic-import mock pattern.
  • gh pr edit --body is BLOCKED on this repo (Projects-classic GraphQL error). Set the PR body at gh pr create time; you can't edit it after.
  • Migration-gate merge flow: PRs that add tables aren't auto-applied — the user applies the SQL to prod, then you gh pr merge --squash --delete-branch.
  • Crons: every recurring task needs isCronEnabled guard + recordHeartbeat
    • CRON_REGISTRY (cron-toggles.ts) + CRON_LABELS (system-health.ts). New cost-bearing crons ship OFF by default. downstream_nudge follows this.
  • Frontend preflight: cd apps/frontend && npm run check before a PR; run the full npm run build when adding a [param] dynamic route or useSearchParams.
  • Supabase MCP ≠ prod (see CLAUDE.md). Trust the user on "migration applied."
DOWNSTREAM HANDOFF — Docs | HiveJournal