The design brain: toggleable BI/UX intelligence for dashboard generation (v1 + verified v2 iteration) - #2
Conversation
Two-tier architecture: a generative design brief for the LLM (Tier G) and a deterministic, auto-fixing spec critic (Tier L), sharing one versioned rulebook with audience presets. Full CLI/spec/skill surface, 27-rule initial catalog, phased delivery, and a decision log in lieu of review gates.
Tier G: `chartwright brief` renders audience-tuned design guidance (executive/analytical/operational presets) from packaged guidelines and the rule registry, for the LLM to read before authoring a spec. Tier L: `chartwright advise` runs a 27-rule deterministic critic over the spec (sizes, composition, chart choice, narrative), with a presentation-only autofix subset (--fix, convergent and idempotent) and per-rule/per-chart suppression via the spec design block. check and apply carry advice by default (--design off|warn|strict). Phase 2: advise --profile adds data-aware rules — the resolver now keeps column types (temporal-axis check) and bounded cardinality probes catch spaghetti series, 40-slice pies, and oversized heatmap grids. design.yaml overlay for house style (params, disabled rules, extra brief guidance). Phase 3: absorb logs human height polish; `chartwright calibrate` mines it (one vote per chart, latest wins) and proposes/records recommended heights that the brief and autofixes then honor. Fractional (absorbed) heights silence sizing rules: human polish outranks the brain. Off is really off: --design off is byte-identical to 0.1.0 behavior. Example spec now advises clean (the two warnings it fired were real). 157 tests pass.
…oard decompile -> data-aware audit -> safe geometry fixes -> redesigned spec, plus the decompile losses and the remaining structural findings for the spec author to act on. Ownership picks the landing zone: tool-born dashboards redesign in place; UI-born ones come back under a -redesign slug (title suffixed) so apply builds side by side and never touches the original. MCP tool + skill step 8 wire the same flow.
88b407d to
4c809ff
Compare
Multi-lens review of the shipped design brain: seven independent lenses (core machinery, per-rule logic, adversarial spec fuzzing, BI/UX domain expertise, tool ergonomics, architecture/learning-loop, doc truth), each executing the code against scratch specs; every bug/edge-case/doc-drift claim independently re-verified by an adversarial reviewer. 80 findings survived, 0 refuted; deduplicated into 37 ranked roadmap items under six themes, headlined by a real absorb crash, an autofix echo chamber that forges the human-polish signature, overlay trust-boundary validation, sketch-stack false positives, and a pivot_table rule pack.
1f39e9e to
8a4b850
Compare
…sitives
Roadmap items 1-15 of docs/DESIGN-BRAIN-V2.md:
- absorb: missing json import crashed AFTER mutating the spec; serialize
the report before any file side effect (1)
- echo chamber closed: autofix targets are ceiled integers so tool output
can never mint absorb's fractional human-polish signature; suppression
narrowed to height-driven findings (width complaints survive polish);
explicit design.ignore intent always lands in `ignored` (2)
- design.yaml overlay: values validated (types, 1..100 height range,
audience keys) with typed errors; recommended_heights merges per key
across all four layers; advice payload degrades on any exception (3)
- grain-vs-range applies the compiler's P1D default when grain omitted (4)
- new size.min-width rule (3/12 hard floor, KPI 2/12); presets made
arithmetically self-consistent (operational max_row_charts 4, fold 22;
executive kpi_row_min 2) (5, 9)
- pie-slices no longer teaches truncated-pie lies; guideline added (6)
- row-density and kpi-band reason over horizontal slots, so sketch stacks
and KPI sidebars stop being condemned (7)
- MCP: stale tool pin fixed, fix_spec tool added, advice block on
check_spec, resolution_errors on advise_spec, audience validation (8)
- calibrate reports non-actionable candidates instead of dropping them (10)
- heatmap-grid re-probes a saturated side ("at least NxM") (11)
- acronyms don't vote in title-style; boolean/numeric filter values don't
trigger filtered-title (12)
- axis-min-height defers to heatmap-geometry and hbar-window (13)
- duplicate tab titles rejected at the spec boundary (14)
- fix loop: convergence invariant documented + no-progress guard (15)
184 tests pass (27 new).
Roadmap items 16-24 of docs/DESIGN-BRAIN-V2.md: - pivot_table pack, ending the rulebook's worst blind spot: size.pivot-window, chart.pivot-dims (<= 3 total), chart.pivot-columns (data-aware rendered- column budget), row-limit-intent coverage, guideline limits (16) - filter-bar pack: filters.count (per-audience max_filter_selects param), duplicate-column, select-cardinality probe (> 500 distinct), time-default, range-default; spec docstring corrected (17) - grain-vs-range v2: per-type point budgets (bars ~40, lines ~300), PT1M/PT1S and week-anchor grains, zero-span message; new chart.trend-grain for full-history sparklines with no defaulted window (18) - data.top-n-sort: a limit without an order is a sample, not a ranking (19) - factually wrong sort guidance rewritten per chart family; new chart.ordinal-order flags weekday/month dims that will sort Apr-Aug-Dec (20) - brief upgrade: canonical exemplar sketch per audience, compiler-defaults table, d3 format and ISO grain vocabulary (21) - narrative.format-consistency across KPI cards; guideline softened to what the spec can express (22) - first color knowledge: chart.format-bands (overlapping bands warn, lone band info) + RAG-polarity and heatmap-scale guidelines (23) - chart.treemap-vs-bar and the fixable layout.markdown-height (markdown blocks addressed by layout position; fix.py learned md targets) (24) The example gained a design.ignore block for its two deliberate exceptions -- demonstrating the mechanism the review asked users to reach for. 198 tests pass (14 new).
…est learning loop
Roadmap items 25-34 of docs/DESIGN-BRAIN-V2.md:
- ignore/disable entries validated up front (typos surface as
unmatched_ignores, never silent no-ops); band findings get scoped
positional keys (rule@tab-Ops-row-1) accepted alongside rule@Chart (25)
- STANDALONE_TYPES declared; contract test makes the chart-type taxonomy
exhaustive, so a 15th type fails CI until classified (26)
- promises made true: design_brain version constant (bumped to "2"),
Rule.since metadata + alias table for renames, golden dogfood test on
the example, seeded advise-never-raises fuzz (27)
- per-deployment severity overrides in the overlay, applied at the single
collection choke point; Rule.severity documented as the default (28)
- calibration v2: absorb events log the audience; proposals group by
(audience, type) and --write lands under audiences.<aud>; --since 90d
is the decay knob (29)
- geometry caching: parse_sketch memoized, RuleContext heights memoized —
advise was measured ~cubic on sketch dashboards; a test pins one parse
per sketch holder (30)
- autofixes disclose their diff: fixed entries carry {set, was}, the CLI
payload names the rewritten file (31)
- check --design strict emits the same design_gate error entry as apply (32)
- implicit row widths use largest-remainder so 5-chart rows sum to 12:
the phantom right-edge hole disappears from renders AND row-fill stops
blaming users for the tool's arithmetic (33)
- sketch WYSIWYG: height fixes on sketch-drawn charts disclose that the
drawing goes stale and how to redraw instead (34)
213 tests pass (15 new).
…-proof Roadmap items 35-37 of docs/DESIGN-BRAIN-V2.md, closing the burn-down: - README gains a design-brain section with the three-command quick start; MCP tool count corrected; VERIFICATION covers the design test suites; a worked design.yaml house-style reference lands in DESIGN-BRAIN §6 (35) - precision sweep: §7's rule table is now GENERATED from the live registry (47 rules, cannot rot), §10 shows the real v2 payload (fixed diffs, unmatched_ignores, design_brain "2"), §12 lists the tests that actually exist, audience table matches the shipped presets, prose de-numbered (36) - CLI polish: help strings on every verb, degraded advice payloads carry the audience, redesign refuses to clobber its default output path (37) - deviations 7-10 recorded (0-indexed rows kept; time-default severity via overlay; sketch WYSIWYG as disclosure; per-metric formats = spec v-next) Version 0.3.0. 213 tests pass. All 37 review items executed.
… inner scroll) Closes #1. Grid heights are fixed layout properties while rendered rows are data-driven: when a row dimension gains members after authoring, the new rows render below the chart's inner scrollbar and every check stays green. Two layers, per the issue: - smoke now compares the rows its query already fetched against the configured height (pivots: distinct row-dimension tuples; tables: result rows) and warns on every apply -- the silent regression becomes an apply-time warning at zero extra query cost - new data-aware rule size.grid-fit probes single-dimension pivots and aggregate tables pre-apply and autofixes the height when sane - the sizing formula and the "table height is a data-dependent property" guidance land in the guidelines the brief ships 217 tests pass (4 new: the issue's exact 5-to-9-leaf-rows scenario among them).
Review of the design-brain branch found seven things worth fixing before it lands. Each is reproduced by a test that fails without the fix. 1. CI runs on pull requests. The offline matrix (Linux + Windows) and the live matrix (three Superset versions) only ran on push to main, so this 4,900-line branch had never been through either. 2. `sort_by` actually sorts. It compiled to `order_desc: true` and nothing else - a direction with no column - so a "top 10" table returned ten arbitrary rows. Three symptoms, one field: the compiler dropped it, the resolver never checked it (a typo passed `check`), and `plan` reported the chart changed forever because decompile could not produce a field the compiler never wrote. Aggregate mode now emits timeseries_limit_metric, raw mode order_by_cols; both are declared by the Table plugin on 4.1.4, 5.0.0 and 6.1.0, and params_drift stays clean. The kitchen-sink fixture carries a sorted table so live CI applies one against all three versions. Made worse by the branch: data.top-n-sort told users to set the field. 3. `--design strict` fails closed. Advice degrades to an error note rather than crashing check/apply - right for `warn`, but under `strict` it meant counts of zero, so one typo in an org-wide design.yaml silently disarmed the gate everywhere it was used. 4. Rows of equal markdown blocks no longer overflow the grid. Blocks compare by value, so every identical block resolved to the first one's index, took the largest-remainder +1, and pushed the row past 12 columns. Regression from this branch's own width fix; positions now match by identity. 5. One grid model, three consumers. size.table-window (0.8 units/row + 1 header), size.grid-fit (0.75 + 3) and smoke (30px/row + 3x40px) each measured a rendered row differently, so a 20-row table at height 8 passed offline while the data-aware rule and the apply warning both said it hid ten rows - the exact defect the branch's newest commit exists to catch. Constants live once in chartwright/spec.py. table_visible_ratio is 0.5 for every audience (was 0.25 on analytical/operational): below half, most of the rows the author asked for sit behind the inner scrollbar. 6. The polish skip is disclosed (`polished` in the advice payload). Deferring to a human-dragged height is an INFERRED signal, and v2 theme 1 named it alongside unmatched_ignores and the strict-gate ok - only the other two landed. Known limits of the inference are recorded in DESIGN-BRAIN 15.13. 7. Doc counts are true and enforced. "125 tests" outlived four batches across five locations; v2 roadmap item 20 flagged it and only half-landed while the page asserted all 37 items were done. Counts now live in one row of VERIFICATION.md that tests/test_docs.py checks against what pytest collects, and the v2 status line records the miss instead of hiding it. Not covered here (from the same review, still open): the design brain has no live-CI or rendered-output verification, probes ignore chart filters and are unbounded in warehouse work, `advise --strict` still prints ok:true while exiting 1, and the MCP fallback hardcodes design_brain "1". 235 tests pass; params_drift clean against 4.1.4, 5.0.0 and 6.1.0.
Caught by the pull_request trigger the previous commit added, on its first run: the offline job failed on Linux and Windows before this branch could merge. `tests` has no __init__.py, so pytest puts tests/ on sys.path, not the repo root. `from tests.test_design_data import ...` resolved only under `python -m pytest` (which adds the CWD) and never under the bare `pytest` console script ci.yml runs, so the module was uncollectable in CI while passing locally. Import the sibling directly, like every other test module. A test now asserts no module imports through the `tests.` package, so the class cannot come back for contributors who run it the other way. Local verification of the previous commit used `python -m pytest`, which is exactly why this survived to CI. 236 tests pass under BOTH invocations; params_drift clean.
Pre-merge review pass: two commits pushedA full review of this branch (core + design brain) turned up seven items 1. CI runs on pull requests. Both matrices only ran on push to main, so 2. 3. 4. Rows of equal markdown blocks no longer overflow the grid. Blocks 5. One grid model, three consumers. 6. The polish skip is disclosed as 7. Doc counts are true and enforced. "125 tests" outlived four batches The PR trigger caught a real failure on its first runThe offline job failed on Linux and Windows: Verification236 offline tests pass under both pytest invocations, Linux and Windows. Scope note on item 2: live CI proves Superset accepts Known gaps, deliberately not closed here
|
What
Chartwright guaranteed a dashboard imports correctly; this adds the layer that makes it read well — a codified, continuously-improvable body of BI/UX design knowledge (Few, Tufte, IBCS, plus Superset rendering facts), on by default and off with one flag. Reference:
docs/DESIGN-BRAIN.md. The branch lands the feature twice over: the initial three-phase implementation, then a full second iteration (design brain "2") executing every item of an adversarially-verified review of the first (docs/DESIGN-BRAIN-V2.md).How it works
One rulebook, two delivery mechanisms, split by who can apply the rule:
chartwright brief): audience-tuned design guidance (executive/analytical/operationalpresets) read before authoring a spec: a canonical sketch to start from, compiler-defaults table, budgets, chart choice, composition. Improvable by editing markdown.chartwright advise): a 47-rule deterministic linter over the finished spec — readable minimum geometry, KPI-first composition, fold budgets, chart/filter/pivot/color limits, narrative polish — with a presentation-only autofix subset (--fix, convergent, idempotent, and disclosing every diff as{set, was}).check/applycarry advice by default (--design off|warn|strict).The surface
design.yamloverlay — parameter overrides, per-audience calibrated heights, rule disables, per-deployment severity overrides, extra brief guidance — every value validated at load with typed errors.absorblogs the heights humans drag charts to (with audience);calibratemines them (one vote per chart,--sincedecay) into recommendations the brief prints and autofixes target.-redesignslug — the original is never overwritten.design_brief,advise_spec,fix_spec,redesign_dashboard, advice oncheck_spec).The v2 iteration
A seven-lens review of the initial implementation (each lens executing the code against scratch specs; every bug/edge-case/doc-drift claim independently re-verified with a refute-by-default stance) produced 80 confirmed findings, 0 refuted, ranked into 37 roadmap items — all executed in the four
batch A–Dcommits:unmatched_ignores, scoped band keys), chart-type taxonomy contract test (a 15th type fails CI until classified), rulesince/alias metadata, severity overrides, calibration v2, memoized sketch geometry (was ~cubic), fix diffs, WYSIWYG disclosure on sketch fixes.DESIGN-BRAIN.md§7 is generated from the live registry; deviations from the review's proposals recorded in §15.Guarantees kept
ignoredandunmatched_ignoresin every report.--design offis byte-identical to pre-brain behavior;spec_versionunchanged; compiled bundles untouched.Testing
213 tests pass (95 added across the branch): per-rule tables, fix-loop convergence/idempotence/no-fractional invariants, seeded advise-never-raises fuzz, taxonomy and cache contracts, design.yaml trust-boundary rejections, calibration grouping/decay/round-trips, the golden dogfood (the shipped example advises clean, its two deliberate exceptions recorded in its
designblock), and MCP parity.Deferred, tracked in the doc: live-Superset UI verification (side-by-side advised-vs-unadvised screenshots); thresholds come from field notes and BI literature. Version bumped to 0.3.0.