Skip to content

Standard dashboard renderer + validate the rendered view against presentation #6

Description

@jaakla

Problem

Nothing makes the next project's dashboard.html resemble the one in examples/tartu-development. The rendered view is the one part of the open-gis-project/v1 contract that is steered by prose alone.

Current enforcement, strongest first:

Layer Covers Enforced?
view_controls_match_pipeline gate canonical control positions == thresholds the pipeline ran ✅ fails the run — but only if the new pipeline implements the check
presentation: in project.yaml tabs/sections, controls.filters, controls.scenarios, layer_groups, semantic roles ❌ declared, never verified against the artifact
SKILL.md:50, project-spec.md §3 reconfigurable-view rules, GIS UX defaults, stable roles ❌ prose
templates/ the declaration skeleton ⚠️ shape only, no renderer
examples/tartu-development the actual HTML/CSS/JS ⚠️ example, not a dependency

The structural cause is that the renderer is per-project:

examples/tartu-development/pipeline.py   # DASHBOARD_TEMPLATE, ~1500 lines of HTML/CSS/JS
templates/pipeline.py                    # 119 lines, zero dashboard code

A new analysis scaffolds from templates/pipeline.py, which has no renderer at all, and SKILL.md says to compile a project like the example without ever saying copy its renderer. So the HTML gets re-invented from prose each time.

Expected drift: the structure (tabs, sections, layer groups, control semantics, tier roles) probably survives, because it is declared in YAML the agent copies. The design — tokens, spacing, component CSS, switch/slider/accordion components, theme handling — almost certainly does not.

Proposed work

1. Extract the renderer into templates/dashboard.py

Make the shared renderer a real dependency instead of an example to imitate. The seam already exists: render_dashboard in the Tartu pipeline is already split into "assemble a view descriptor dict" → "substitute into DASHBOARD_TEMPLATE".

  • Move DASHBOARD_TEMPLATE + the substitution step into templates/dashboard.py.
  • Define the view-descriptor contract (project, objective, assumptions, warnings, overrides, sources, validation, run, outputs, tiers, layerGroups, landUse, canonical, bounds, …) in project-spec.md.
  • Per-project code keeps only what is genuinely domain-specific. Today that is TIER_STYLE, LAYER_BINDINGS (layer-group id → MapLibre layer ids + swatch), and the assembly of view.
  • Generalise the parts of the current renderer that are Tartu-specific: it asserts the filter ids min_area / max_road_distance / education_threshold / land_use by name, and hardcodes PALETTE + TIER_STYLE. Drive controls from presentation.controls generically (range | choice | multi_select | toggle) and colours from semantic roles.

2. Validate the rendered artifact

New gate, e.g. view_matches_presentation: parse the emitted dashboard.html and assert it realises what project.yaml declared.

  • one control per declared controls.filters[] and controls.scenarios[] entry
  • one visibility toggle per map.layer_groups[] entry
  • a canonical-reset affordance when controls.canonical_reset: true
  • every declared sidebar tab/section present when layout.sidebar.organization: tabs
  • off-canonical labelling present when off_canonical_labelling: required

Cheap to implement (data- attribute census over the HTML; the current renderer already emits data-layer, data-scenario, data-landuse, data-reset, data-acc, data-panel). This turns the presentation contract into something checked like the rest of the project.

3. Optional: references/dashboard-design.md

Token palette, spacing scale, component inventory and the semantic-role → colour mapping, for the cases where a bespoke renderer is genuinely warranted (non-map primary view, report intent, embedded contexts).

Acceptance

  • examples/tartu-development renders from templates/dashboard.py with no visual regression against the current dashboard.html.
  • A second, unrelated worked example (different domain, different filters) produces a visually consistent dashboard without touching the shared renderer.
  • view_matches_presentation fails when a declared filter, scenario or layer group has no control in the emitted HTML.

Context

Follows #5 and the reconfigurable-view work in ffd77f7, which added the tabbed sidebar, layer toggles, live filter/scenario controls and the view_controls_match_pipeline gate.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions