25 March 2026
Full E2E pipeline — zero intervention Live
Complete automated pipeline from build server POST to live deployed site. 8 menu images → OCR → enrichment → generation → deploy. 53 food items, 117 bottles with descriptions and tasting scores. No manual steps needed.
OCR schema validation sanitizer New
Programmatic JSON sanitizer runs before schema validation. Fixes price: null, vintage type mismatches, and unknown properties. Previously, schema validation failed every time and the Claude repair step returned narrative text instead of JSON.
OCR fallback in build server Fix
When OCR schema validation fails, the build server now builds menu.json from raw extraction data in the catch block. Previously, the fallback code was unreachable because it sat after an await that threw.
grx-menu.js rendering — 5 critical fixes Critical
Root cause of blank menus on ALL pipeline-generated sites:
nameEs → name normalizer (pipeline uses nameEs, widget expected name)
- Null-safe
normName() — crashed on undefined
fmtPrice → fmt — undefined function reference
- Always create tab bar on every render (second render from API wiped first render's tabs)
- Bilingual CSS injected for
.lang-es / .lang-en visibility
Build timeouts increased Fix
Stale build timeout: 30 → 60 min. Pipeline execSync timeout: 15 → 45 min. Large wine lists (100+ bottles) need 15-20 min for enrichment alone.
Validation gate — structural only Fix
Pre-deploy validation now only blocks on structural failures (missing widget, no seed data, bad HTML). Cosmetic checks (lang switcher style, sticky bar, data-accent) no longer block deployment.
build_patch.py hardened — Steps 17-19 Fix
- Step 17: Section replacement preserved surrounding HTML (was dropping entire page)
- Step 18: IIFE cleanup for stray
); after JS removal
- Step 19: Duplicate seed removal in reverse order (position safety)
- Step 5: JS syntax errors downgraded to warning (dead code)
grx-menu.js — tabs scoped to container Fix
Tab creation and initTabs() now scoped to the widget container. Host page tabs (e.g. Cantina Tita Paca's 4-tab layout) no longer interfere with the widget's own Comida/Vinos tabs.
enrich-menu.py — score2 fix Fix
Fixed UnboundLocalError when Tavily Pass 2 is skipped (no API key). Wine classification now gracefully falls back to Pass 1 results.
Test suite green — 66/66 Live
Updated 9 stale test expectations in test_build_patch.py. All tests pass.
AGENTS.md + PIEBALD_PROFILE.md New
Created project knowledge base with architecture rules, 14-item DO NOT list, pipeline flow, and a Piebald system prompt for session continuity.
24 March 2026
Wine tasting scores in full stack New
cuerpo, acidez, tanino scores (1-5) stored in DB, returned by API, rendered by grx-menu.js as dot scales. 133/134 wines scored for Antonio Pérez.
Tavily wine verification New
Multi-pass wine classification: context-based → Tavily web search → targeted retry. Caught 4 misclassifications (e.g. "Diez Días de Marzo" tinto → blanco).
Onboarding wine preferences New
4 new fields deployed to onboard.nexogrx.es: wine list ordering, display format, color coding, language switcher style.
Empty API guard in grx-menu.js Critical
Root cause of empty menus: API returned empty arrays → widget overwrote seed data with nothing. Guard now checks liveFood.length > 0 || liveWine.length > 0 before re-rendering.
23 March 2026
One-command pipeline — 11 steps Live
generate-site.sh upgraded from 3-step to 11-step full pipeline. Closes 5 gaps: admin registration, enrichment, menu import, validation, Cloudflare project creation.
validate_site.py — 29 checks New
Automated validation across 5 categories. Pre-deploy gate blocks broken HTML, post-deploy verifies live site.
enrich-menu.py — AI enrichment New
Uses claude -p (free on Max plan) for allergen inference + wine descriptions. Multi-pass scoring until quality threshold met.