S10 (a1): public ledger profiles v1

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Kev
2026-07-11 19:32:22 -04:00
parent aaafc3e0f2
commit b20145c215
19 changed files with 1226 additions and 6 deletions
+21
View File
@@ -880,6 +880,27 @@ phased plan in the Session-57 conversation / BUILD-STATE Next section).
- Box-side ops (Uptime Kuma, Coolify deploy-failure webhook, ntfy phone
setup) = `docs/OPS-RUNBOOK.md`.
## Public Ledger Profiles v1 (Session 10, A1 board — non-obvious)
- **`public_profiles` (migration 022) is PRIVATE BY DEFAULT** — `published`
DEFAULT FALSE, one explicit toggle in Settings, service-role writes only.
`GET /api/profiles/:handle` returns the SAME 404 body for unknown AND
unpublished handles (no existence leak) — keep them byte-identical; a
test diffs the two responses. A malformed handle 404s WITHOUT a DB query.
- **`getModelAggregate({ userId })`** swaps `.is('user_id', null)` for
`.eq('user_id', uid)` on BOTH the settled and pending queries — the same
30d window + n≥20 gate over one user's ledger. The no-userId default is
the public model record and must stay untouched.
- **The user's public entries are SETTLED rows only** (`.not('outcome',
'is', null)`, newest 50, same columns as /api/ledger) — pending reads are
not public until they settle, and nothing is curated: misses included.
- **`/u` is in OPEN_ROUTES on purpose** — the share surface must load
anonymous; the privacy gate is the API's 404, never the router.
- **Jest from a worktree gotcha:** the repo config's `testPathIgnorePatterns`
includes `/.claude/`, which matches EVERY path inside
`.claude/worktrees/...` → "No tests found". Run with
`npx jest --testPathIgnorePatterns "/node_modules/"` from a worktree
(CLI replaces the config array).
## Active Skills
- vyndr-voice (all user-facing output)
- prop-analysis (grading methodology)