📓 journal may 20, 2026 sat singh

ghost schema closed.

Three years of informal structure formalized in one session — city, domain, and funnel stage are now validated, canonical, and load-bearing on all 80 AICV nodes.

the problem

The AICV node corpus operated on a ghost schema. Eighty nodes carried three structural axes — city, domain, and funnel stage — but only city was in Zod, and even that was free-text. Forty-seven nodes (59%) used non-canonical city values like "Valley Wide" and "adjacent-communities." Domain didn't exist as a schema field at all. Funnel stage lived in agent_intent, an unvalidated array completely outside the Astro content API. The corpus was well-written but not machine-queryable.

what shipped

Two commits. The first (30a1bf5) added three validated fields to src/content.config.ts: city as an enum of 11 canonical geography values, domain as an enum of 13 life-domain values, and funnel_stages as a validated array requiring at least one of 6 canonical stages. That commit intentionally broke the build.

The second commit (8c27101) repaired it across all 80 nodes. A Python migration script applied a per-node lookup table — city normalization for 32 nodes, domain assignment for all 80, funnel stage arrays for all 80. The diff: 80 files changed, 192 insertions, 32 deletions. Zero errors. astro check passed clean. Both commits were pushed together so production never saw the broken state.

the numbers

32 city normalizations: 26 "Valley Wide" → "Coachella Valley," 4 "adjacent-communities" → "Adjacent Communities," 2 hyphenated and lowercase variants corrected. Three axes are now formally enforced — geography (11 canonical values), life-domain (13 values), funnel stage (6 values: Discover, Visit, Return, Satellite, Relocate, Build). The corpus is a machine-queryable three-axis knowledge graph.

what's deferred

The static JSON layer needs a re-run of build-static-json.cjs to propagate the new fields into nodes.json and llms-full.txt. The legacy agent_intent array remains alongside funnel_stages — structural debt, not a blocker. The four truly-meta nodes (node-zero, coachella-valley-intelligence-index, luxury-corridor, wellness-positioning) carry funnel_stages: ["Discover"] only for now; a proper concepts collection refactor is parked in the queue.

Session opened with a quick sync: aicv-playbook STATE.md updated to 147 briefs, sunshine-fm MEMORY.md live counter updated to 345 entries.

Tools: Claude, Claude Code, Python, Astro, Wrangler · Commits: 55545da (aicv-playbook) · 850d502 (sunshine-fm) · 30a1bf5 + 8c27101 (com/) · Deploy: aicoachellavalley.com · Est. tokens: ~350,000