el_h1/h2/h3/h4 and el_button were calling el_escape() on their
content, converting any HTML children (e.g. <span class="gold">)
into literal entity text on screen.
These functions accept composed HTML children, not raw text — they
should pass the argument through like el_div/el_p/el_span do.
el_text, el_attr, el_title, el_textarea, and el_img keep escaping
(they handle actual text/attribute values, not HTML children).
Workflow file changes don't require rebuilding the El binary. Without
this, merging workflow fixes to main triggers a full El build which
hits a codegen issue in the CI version of elb.
migrations/, scripts/, tests/ changes don't require rebuilding the El
binary. Classifying them as asset-only avoids spurious full builds that
regenerate dist/*.c and can hit codegen incompatibilities.
Same-origin browser fetches don't send Origin. The server correctly
allows them — blocking was the bug that broke checkout. Update the
test to match the fixed behavior.
The shallow clone (fetch-depth: 2) doesn't include origin/dev, so
git merge-base --is-ancestor was silently failing. Fetch dev with
depth=1 first so custom merge commit titles still pass the check.
DROP POLICY IF EXISTS before CREATE POLICY so migrations can be
re-applied to a DB that already has the policy (e.g. demo_config
was manually applied before migration tracking was set up).
go-yaml (Gitea's parser) mishandles << inside block scalars, treating the
bash heredoc delimiter as a YAML merge key. Move the migration logic to a
standalone script called via python3 scripts/run_migrations.py.
map_get returns null (0) for missing headers. str_eq(null, "") is false
because EL_CSTR(0) is NULL != "". Same-origin browser fetches don't send
Origin at all, so the missing-origin case was incorrectly being denied.
Fix: use str_starts_with(req_origin, "http") to detect a present origin.
If no origin header (null first arg → str_starts_with returns false),
origin_present is false and the request is allowed unconditionally.
Adds a "Run database migrations" step to both stage.yaml and deploy.yaml.
Uses the Supabase Management API (access token from GCP Secret Manager)
to apply pending migrations tracked in a schema_migrations table.
Migrations run unconditionally before every deploy — asset-only or full.
Also adds migrations/** to paths filter so a migrations-only commit
triggers the pipeline.
Two-card grid above the enterprise box — sales (enterprise@) and
security (security@) — with email links and one-line descriptions.
Visible without filling out the form, which is what enterprise and
security teams look for first.
Callout above the provider list recommends o4-mini/o3, Claude Sonnet 4,
Gemini 2.5 Pro, or Grok-3 for best performance, notes that model choice
happens in the app, and points to Neuron Inference launching Q3 2026.
Each provider row now has a collapsible details panel with accurate
step-by-step instructions and a direct link to the key creation page.
Includes billing notes for OpenAI and Anthropic (easy to miss gotchas),
free tier note for Gemini, and credits note for Grok.
All three pricing CTA buttons now share the same solid navy background,
white text, and blue hover state. Previously only anchor-element rules
existed for the solid variant; the button elements had no explicit
background so all three appeared unstyled.
chat-widget.el: apostrophe in El native_js double-quoted strings caused
the El compiler to drop the backslash, producing broken JS single-quoted
strings. Switched those four string literals to double-quoted JS strings
using \" escaping so the compiled output is valid.
main.el: /api/supabase-config was returning 403 for all stage Cloud Run
origins. Added marketing-stage-* prefix to the allowed list so the
checkout page can initialise Supabase during CI E2E runs.
El's native_js() compiles to eval(). checkout-auth.el uses native_js()
to embed the auth logic, so all window globals (showSignIn, initStripe,
etc.) live inside an eval call. Stage CSP was blocking it, leaving the
page with no auth functions defined.
Stage CSP blocks 'unsafe-eval' which javascript-obfuscator introduces.
checkout-auth.js IIFE was crashing before assigning window globals,
causing all checkout E2E tests to fail.
- Block real Stripe CDN (js.stripe.com) in injectMockStripe() so the
addInitScript mock is never overwritten by the async-loaded SDK
- Replace waitForFunction(signUpWithEmail) with waitForLoadState in
all 8 free-plan auth tests; defer scripts run before DOMContentLoaded
so the function is guaranteed present without polling for it
- Strip [javascript-obfuscator-cli] progress line from elc --obfuscate
output before writing to dist/js/ (was prepended to every compiled JS
file, causing browser parse errors on stage)
- Remove spurious waitForFunction(signUpWithEmail) guards from
buyer-name and buyer-email structural tests (pure DOM tests, no auth)
- Switch chat.spec.ts beforeEach to domcontentloaded (SSR elements
present at DOM ready; networkidle caused cold-start timeouts)
- Per-page title/description/canonical/OG tags: about, checkout (per-plan),
terms, enterprise-terms, success all get unique SEO blocks
- Homepage title updated to em-dash form; meta description adds CTA
- og:site_name added to all pages
- noindex/nofollow on checkout, success, account pages
- Sitemap (/sitemap.xml) with all public pages; robots.txt updated with
Sitemap directive and Disallow for private paths
- Schema: WebSite type added, Organization gains logo ImageObject, SoftwareApplication
gains url field, billingIncrement corrected to billingPeriod (ISO 8601 P1M),
sameAs gains x.com/neurontechai alongside GitHub
- marked.min.js given defer attribute (was render-blocking)
- page_head refactored into page_head_base + page_seo_block + page_open_seo
for clean inner-page overrides without duplicating the CSS/script block
- Switch to http_serve_v2/http_set_handler_v2 so request headers are available
to El handler code (prerequisite for all header-based security checks)
- Stripe webhook (CVE-class): add HMAC-SHA256 signature verification against
Stripe-Signature header using STRIPE_WEBHOOK_SECRET env var. Previously any
unauthenticated POST could forge a payment_intent.succeeded event and
increment the founding counter or trigger Supabase account provisioning for
arbitrary emails.
- CORS on /api/supabase-config: restrict to neurontechnologies.ai and localhost
origins only. Cross-origin requests now get 403.
- /api/soul-health: require X-Internal: true header; otherwise return 404.
Endpoint was publicly accessible and leaked internal soul service URL,
network topology, and raw probe responses.
- Static asset / JS headers: add X-Frame-Options, Referrer-Policy,
Permissions-Policy, and Content-Security-Policy to static_asset_headers_json
and js_headers_json. These were only present on HTML/API responses before.
- Fix state key bug: share_card_page read state_get("__neuron_origin__") but
the key registered at startup is "__origin__", causing empty base URLs in
share card og: meta tags.