Skip to content

Commit 00dc6bf

Browse files
committed
Merge branch 'personal-recommender'
Personal recommender feature: interests + recommendations persistence, recipe cook-timeline, Checkly monitoring plan, operations docs, and embedded Postgres test-startup fix. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> # Conflicts: # docs/operations.md # plans/2026-07-14-checkly-playwright-suite/DESIGN.md # plans/2026-07-14-checkly-playwright-suite/PLAN.md # test/kaleidoscope/persistence/interests_test.clj
2 parents 6cfd628 + 099d8ea commit 00dc6bf

9 files changed

Lines changed: 1748 additions & 3 deletions

File tree

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,7 @@ kaleidoscope.iml
5151
# Generated per-environment Fly configs (scripts/ephemeral/deploy-app)
5252
fly.kal-eph-*.toml
5353

54-
.neon
54+
.neon
55+
56+
# Playwright MCP browser-debug artifacts (console logs, page snapshots)
57+
.playwright-mcp/

CLAUDE.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,7 @@ When debugging test failures, never pipe full test output directly into the conv
173173
3. **Don't refactor legacy CMS code** (articles, albums, portfolio) unless it's explicitly the task.
174174
4. **Every feature needs automated tests.** Unit or end-to-end — discuss the right layer, but "no tests" is not acceptable.
175175
5. **Keep `Taskfile.yml` in sync with `bin/`.** If a bin script is added, renamed, or changes its interface, update the Taskfile.
176+
6. **Keep `docs/operations.md` current.** Any change to deployment (`fly.toml`, `bin/` deploy scripts, Docker/build, secrets/env) or to the Taskfile/`bin/` interface must be reflected in `docs/operations.md` in the same change.
176177

177178
---
178179

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@ For local development, see [local-development.md](./docs/local-development.md)
158158
## Deployment
159159
To deploy, follow instructions in [deployment.md](./docs/deployment.md)
160160

161+
## Operations
162+
For operational concerns of running the app, see [operations.md](./docs/operations.md)
163+
161164

162165
# TODO:
163166
3) Update to stop using hash-routing

docs/operations.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
# Operations
22

3+
Operational concerns for running Kaleidoscope in production. This document
4+
covers how the app is set up to operate, the guardrails around that setup, and
5+
the decisions behind them.
6+
7+
> **Maintenance:** Keep this document current. Any change to deployment
8+
> (`fly.toml`, `bin/` deploy scripts, Docker/build, secrets/env) or to the
9+
> Taskfile / `bin/` interface must be reflected here in the same change.
10+
311
## Synthetic monitoring (Checkly)
412

513
Synthetic checks live in `checkly/` as a standard Playwright project
@@ -32,3 +40,36 @@ is include-only.
3240
**Deployed monitors need these Checkly environment variables** (set once in the
3341
Checkly account, not committed): `AUTH0_CLIENT_ID`, `AUTH0_CLIENT_SECRET`.
3442
`ENVIRONMENT_URL` is omitted in production so checks default to the live site.
43+
44+
## Claude Code workspaces
45+
46+
Kaleidoscope's AI features (the workflow engine and project scorer) call the
47+
Anthropic API. Rather than running Claude Code against the same Anthropic
48+
account and API key used for production traffic, we provision a **separate,
49+
dedicated Claude Code workspace** with its own key.
50+
51+
That workspace is capped at a **hard spend limit of $10 per month**.
52+
53+
**Why a separate workspace with a hard cap:**
54+
55+
- **Blast radius.** A Claude Code API key can end up in more places than a
56+
production key — shell history, local config, CI logs, a subagent's
57+
environment. Isolating it in its own workspace means a leaked or misused key
58+
can never draw down the production Anthropic budget or touch production usage.
59+
- **The cap bounds the damage.** $10/month is the ceiling on what a leaked key
60+
can cost before it's cut off. It's high enough for normal development use and
61+
low enough that a compromised key is an annoyance, not an incident.
62+
- **Clean attribution.** Keeping the workspaces separate makes Claude Code
63+
spend legible on its own, distinct from the app's production API usage.
64+
65+
**Operational notes:**
66+
67+
- The workspace key is only for development tooling (Claude Code). It is **not**
68+
the key the deployed app uses for its own Anthropic calls — that key lives in
69+
Fly.io secrets (`ANTHROPIC_API_KEY`) and is scoped to the production
70+
workspace/budget.
71+
- If the $10 cap is hit mid-month, Claude Code requests will start failing.
72+
That's the intended signal — investigate the spend before raising the limit,
73+
don't reflexively bump it.
74+
- If the workspace key is ever suspected leaked, rotate it in that workspace;
75+
no production credential or budget is affected.

fly.toml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ primary_region = "iad"
44
[build]
55
dockerfile = "Dockerfile"
66

7+
# Non-secret config only. Secrets are supplied via `fly secrets set` and are
8+
# NOT declared here (fly.toml can't hold their values). Required secrets:
9+
# ANTHROPIC_API_KEY — llm scorer, llm workflow executor, claude-vision transcriber
10+
# FIRECRAWL_API_KEY — firecrawl recipe fetcher
11+
# GOOGLE_VISION_API_KEY — only if IMAGE_TRANSCRIBER_TYPE=google-vision
12+
# KALEIDOSCOPE_DB_PASSWORD — Neon Postgres password
13+
# KALEIDOSCOPE_BUGSNAG_KEY — Bugsnag exception reporting
14+
# KALEIDOSCOPE_STRIPE_API_KEY — Stripe client
15+
# AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY — S3 static content + storage
716
[env]
817
KALEIDOSCOPE_DB_TYPE = "postgres"
918
KALEIDOSCOPE_DB_HOST = "ep-polished-frost-an34qo7y.c-6.us-east-1.aws.neon.tech"
@@ -31,6 +40,14 @@ primary_region = "iad"
3140
# Set to "none" until SNS/image-resizer is migrated off AWS
3241
KALEIDOSCOPE_IMAGE_NOTIFIER_TYPE = "none"
3342

43+
# AI / pluggable components. Real backends below require ANTHROPIC_API_KEY
44+
# (scorer, workflow executor, claude-vision transcriber) and FIRECRAWL_API_KEY
45+
# (recipe fetcher), supplied via `fly secrets`.
46+
KALEIDOSCOPE_SCORER_TYPE = "llm"
47+
KALEIDOSCOPE_WORKFLOW_EXECUTOR_TYPE = "llm"
48+
KALEIDOSCOPE_RECIPE_FETCHER_TYPE = "firecrawl"
49+
KALEIDOSCOPE_IMAGE_TRANSCRIBER_TYPE = "claude-vision"
50+
3451
AWS_REGION = "us-east-1"
3552

3653
OTEL_SERVICE_NAME = "kaleidoscope-publishing"

plans/2026-07-14-recipe-cook-timeline/DESIGN.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,23 @@ level. This matches the approved prototype exactly.
6767
Only the **authored overrides** must never be silently dropped. Everything else
6868
is persisted purely as an optimization.
6969

70+
### Load-bearing invariant: overrides annotate phases
71+
72+
An override is **not** a fact about content — it's an *annotation on a derived
73+
phase*. Its key (`"{component}/{label}"`) names a phase the segmenter invented;
74+
it can't even be expressed without the timeline to point at. Override and phase
75+
therefore share one identity and one lifecycle, which is why they live together
76+
in the blob rather than being split into an "authored" store — they are not
77+
independent things.
78+
79+
What keeps an annotation valid across regenerations is **phase-identity
80+
stability**, and that is exactly what the trust boundary (below) guarantees: for
81+
an unchanged component the cached phases are kept verbatim (the LLM's
82+
re-segmentation is discarded), so the phase key an override points at does not
83+
move. When a component's steps *do* change, its phases are legitimately new and
84+
its overrides are legitimately dropped — the annotation's target is gone. This
85+
coupling is cohesion, not complecting; the trust boundary is what makes it safe.
86+
7087
---
7188

7289
## Data model

0 commit comments

Comments
 (0)