v0.0.60 — Mock cards, smart layout, org-isolation cohort
Released: 2026-05-08. Thirty-three commits — bug-fix heavy on the dashboards layout battle, with three substantial feature pieces.
Mock-data cards​
Operators can now author dashboards visually before the SQL is ready. Cards flagged is_mock=true carry a 🎨 MOCK badge and render against fabricated sample data instead of executing SQL. Honeyframe's chat agent will never invent live results — when a question can't be answered with real data, the response is a mock card with the badge.
A custom CSS hover tooltip on the badge (no JS portal needed) shows immediately on hover with a Why mock: label, so the meaning is unambiguous. cursor-help signals the badge is hoverable.
Mock cards are first-class in:
- The chat prompt (LLM-emitted
is_mock+ reason) - POST / PATCH validation paths
- The
set_layoutrebalance logic - The MODIFY action (you can ask chat to swap a mock card's type)
Set-layout auto-balance​
The SET_LAYOUT prompt section now spells out a deterministic auto-tidy algorithm so "tidy up" produces the same canonical layout every time:
- KPIs in rows of 4 at the top
- Charts paired at
size_x=12below - Tables / maps full-width
Plus a new clear_all_cards mutation type for the equivalent of "start over from scratch". The auto-rebalance fires for add_card mutations (not just set_layout) and handles rows that would overflow 24 columns — smart reflow groups orphan KPIs into 3-up rows.
Vertical page nav rail​
In Chat mode, a vertical page-tab rail mounts on the right of the canvas (collapsible to a 32 px sliver). The chat panel + rails are arranged as flex siblings; the Layout cap is mode-aware (1600 px in View, no cap in Edit).
The page width tracker is rewritten from scratch (useContainerWidth → bespoke implementation) to capture canvas-width changes immediately:
- Observes both the wrapper and its parent. In chat mode the canvas grows first; the wrapper inherits one tick later.
- Re-measures on
window.resize, a customchat-canvas-resizeevent, and on everylayoutKeybump. - Runs measurement in
useLayoutEffectplus two rAF ticks afterward. - Inline ref-callback measurement so the very first render already has a real width.
View mode cap bumped 1280 → 1600 px. Belt-and-suspenders overflow-x-hidden in chat mode so even a one-frame measurement lag can't surface as a horizontal page scrollbar.
Tier-1 org-isolation cohort​
Four routers swept into per-org scope to close cross-tenant read paths:
analytics— overview / activity / KPI counts now filter byorg_idlineage— lineage walks scoped to caller's org boundarydata_dictionary— column dictionary reads filteredschema—information_schemareads tagged as org-scope-exempt (already-public) where the column-fetch needs DWH-wide visibility; everything else gated
A handful of fixes also closed cross-tenant readers in datasets.py /browse/{schemas,tables}, pipeline.py /row-counts/live, and the warehouse_overview template's seed cards — every newly-seeded dashboard previously embedded FROM information_schema.tables WHERE table_schema = 'marts' into card_config, leaving cross-tenant readers in plain sight. Rewritten to read from honeyframe.datasets WHERE project_id = {project_id}.
Recipe I/O contract — relaxed to OR​
The strict v0.0.59 "inputs AND outputs" rule rejected two valid shapes:
- Ingestion recipes — raw source → DWH, no upstream Honeyframe input
- Pure-export recipes — DWH → external sink, no Honeyframe output
The contract is now "produce OR consume" — a recipe is valid as long as one side is non-empty. The standalone AI-utility exemption stays in place.
LLM-emitted artifact-card title​
The system prompt now asks for an optional dashboard_title field on assistant turns. The chat panel surfaces this in the artifact card so users see a Figma-Make-style descriptive title for the dashboard's current direction (e.g. "Pediatrics revenue overview — Jakarta") without manually editing the dashboard name.
A regression guard on the chat handler: bad LLM output (title returned as a list / non-string / malformed JSON) no longer 500s — it falls through to the dashboard's existing title.