Visualization - Implementation Checklist¶
Package: mineproductivity.visualization
Governing specification: docs/architecture/12_Visualization_Design_Specification.md
Architecture Decision Record: docs/adr/ADR-0012-Visualization.md
Status: Implemented and released (software v1.11.0, 2026-07-12).
All items below are satisfied: the complete design spec §6 module list is implemented, the unit suite passes with ≥95% coverage (99% including branches), the five examples/visualization/ scripts and both benchmark/reports/visualization/ reports exist and are mypy --strict/ruff-clean, and the §35 acceptance proofs each run as dedicated tests. This is the final package milestone; the platform's architecture is complete. No architectural changes were made relative to the locked v1.4.0 design.
Binding, locked implementation contract for visualization - the seventh package built on top of the Foundation Layer and the final package in the platform's architecture, sitting directly above the now-locked agents. Nothing described here may be implemented before this checklist and its governing specification exist in reviewed form, and nothing may be implemented that is not represented by an item on this list. Complete in order; every box must be checked or explicitly deferred with a linked issue and Chief Software Architect sign-off before merge.
Pre-Implementation Gate¶
- Design specification (
12_Visualization_Design_Specification.md) read in full by the implementer, including every cross-reference to specs 01–11. - ADR-0012 read in full; the rationale for
visualizationexisting as a separate package aboveagents(and for the interface-only treatment ofVisualizationandRenderer) is understood, not merely accepted. -
core,events,ontology,registry,plugins,connectors,kpis,analytics,decision,digital_twin,simulation,optimization,agentsavailable and importable, exactly as released; no lower package file is modified as a side effect of this work. - Confirmed:
visualizationimports nothing above itself - no future package exists (design spec §5, §34). - Confirmed: no lower package (
corethroughagents) will be modified to import or otherwise referencevisualization(design spec §5). - Confirmed: no concrete charting, templating, or document-generation library (e.g. Plotly, Matplotlib, Jinja2, WeasyPrint) is added as a dependency of this package - rendering backends are out of scope (design spec §4's non-responsibilities, §33's no-backend-coupling proof).
Package Structure¶
-
src/mineproductivity/visualization/created matching design spec §6 exactly:abstractions.py,presentation.py,theme.py,layout.py,widget.py,dashboard.py,dashboard_builder.py,report.py,report_builder.py,renderer.py,pipeline.py,export.py,discovery.py,persistence.py,_registry.py,exceptions.py,__init__.py,README.md. -
visualization/README.mdwritten following thecore/README.mdtemplate. - Confirmed
renderer.py(Renderer) andabstractions.py(Visualization) each contain zero concrete, non-test subclasses (mechanical grep/AST check - design spec §8, §16, §33's interface-purity proof). - Confirmed no module under
src/mineproductivity/visualization/performs direct KPI, statistical, decision, twin-state, simulation-projection, solved-plan, or agent-decision computation of its own - every such value arrives via the corresponding lower package's public API (design spec §3.2, §33's no-fact-recomputation proof). - Confirmed no module under
src/mineproductivity/visualization/imports, or contains a string reference to,plotly,matplotlib,jinja2,weasyprint, or any other charting/templating/document-generation library (design spec §33's no-backend-coupling proof).
Public API¶
-
visualization/__init__.pyexports exactly the symbol list in design spec §7, alphabetized__all__. -
test_public_api.pymirrorstests/unit/core/test_public_api.pyand every existing package's own copy of it. -
TestNoForbiddenDependenciesAST-walks everyvisualizationsubmodule confirming it imports nothing above itself - mirrors every existing package's own copy of this test (design spec §5). - A second, reverse-direction test asserts no file under
src/mineproductivity/{core,ontology,events,registry,plugins,connectors,kpis,analytics,decision,digital_twin,simulation,optimization,agents}/importsmineproductivity.visualization(design spec §5) - theagents-package precedent for this test extended one final layer up.
Visualization Abstractions (§8)¶
-
Visualization(§8) -meta: ClassVar[VisualizationMetadata]; one shared abstract method_render(widget, *, context) -> PresentationModel, mirroringdecision.DecisionModel's/agents.Agent's shared-method posture. -
VisualizationContext(§8) -kpi_results,analytics_results,decision_results,twin_snapshot,simulation_results,optimization_results,agent_audit_entries, each defaulting to an empty sequence orNone; caller-assembles pattern only, no session-assembles variant. - Confirmed
Visualizationsubclasses (of every category) are stateless - no instance attribute is mutated by any_renderimplementation; all statefulness lives inDashboard(§10, §26, §29).
Presentation Model (§9)¶
-
PresentationModel(§9) - frozencore.BaseValueObject;category,title,series(open mapping, default empty),evidence_refs(default empty tuple),warnings(default empty tuple). - Confirmed
PresentationModelcarries no rendered bytes/HTML/pixels of its own - that responsibility belongs exclusively toRenderer(§16). - Confirmed
PresentationModel.evidence_refsis populated with realKPIResult.code/AnalyticsResult.model_code/DecisionResult.model_code/OptimizationResult.run_id/AgentAuditEntry.agent_code-shaped references in every concrete implementation's tests, never left empty when evidence was actually consulted.
Dashboard Domain Model (§10)¶
-
Widget(§10) - frozencore.BaseValueObject;code,visualization_code,binding(open mapping, default empty). -
Layout(§10) - frozencore.BaseValueObject;code,slots(open mapping, default empty); confirmed never parsed by this package's own code, only stored and handed to aRenderer. -
Dashboard(§10) - subclassescore.BaseEntity[str]directly;name,owner,widgets(default empty tuple),layout(defaultNone),theme_code(default""); modified exclusively viadataclasses.replace, never in place. - Confirmed
Dashboardcarries nostatusfield and nowith_state()method - a deliberate, documented departure fromTwin/SimulationRun/OptimizationRun/Task's own precedent (§10, §3.3). - Identity/equality proven:
Dashboard.__eq__/__hash__inherited unchanged fromBaseEntity(identity-based onid, ignoringwidgets/layout/theme_code); no override anywhere in the package.
Rendering Pipeline (§11)¶
-
RenderingPipeline(§6, §11) - resolveswidget.visualization_codeagainstREGISTRY, dispatches to_render, resolvesrenderer_codeagainstRENDERERS, dispatches toRenderer.render. -
RenderingPipeline.render's dispatch sequence tested against design spec §11's sequence diagram exactly. - Confirmed a widget bound to incomplete or not-yet-computed evidence returns a
PresentationModel/RenderedOutputcarrying a warning, never a raised exception (§30's central rule).
Dashboard Builder (§12)¶
-
DashboardBuilder(§12) - subclassescore.BaseBuilder[Dashboard]directly (the first concretecore.BaseBuildersubclass anywhere in this series);with_name,with_widget,with_layout,with_themefluent methods;build()raisesVisualizationValidationErrorfor an emptyname/owner. - Confirmed
DashboardBuilder.build_result()is the inherited, unoverriddencore.BaseBuilder.build_result()- no second non-raising variant introduced. - Confirmed
DashboardBuilder.reset()is exercised in at least one test proving the builder is reusable after abuild()call, percore.BaseBuilder.reset()'s own contract.
Report Model (§13)¶
-
Report(§13) - frozencore.BaseValueObject;report_code,generated_at,sections(default empty tuple ofRenderedOutput),warnings(default empty tuple). - Confirmed no
ReportRepositoryexists anywhere in the package -Reportis a produced-once artifact, never independently persisted, the same treatment every prior*Resulttype already receives.
Report Builder (§14)¶
-
ReportBuilder(§14) - subclassescore.BaseBuilder[Report]directly;with_section(widget, *, context, renderer_code)composesRenderingPipeline.renderfor each section;build()assembles the finalReport. - Confirmed
ReportBuildernever duplicatesRenderingPipeline's own dispatch logic - every section is produced by an actualRenderingPipeline.rendercall, never a re-implementation of it. - Confirmed a section that produced a warning-carrying
RenderedOutputpreserves that warning on the finalReport.warnings, never silently drops it.
Worked Examples (§15, §19)¶
- A scripted integration test reproduces design spec §15's worked example shape (a multi-widget dashboard combining a
KPI_CARD, anOPTIMIZATION_COMPARISON, and anAGENT_EXPLANATIONwidget), each rendered independently viaRenderingPipeline. - A scripted integration test reproduces design spec §19's worked example shape (the same widgets composed into an exported
ReportviaReportBuilder), proving the live-render and export code paths never diverge (§18, §33's export round-trip test).
Renderer (§16)¶
-
RendererMetadata(§16) -code,description,version(default"1.0.0"). -
Renderer(§16) -meta: ClassVar[RendererMetadata];render(model, *, context) -> RenderedOutputabstract; zero concrete subclasses shipped. -
RenderedOutput(§16) - frozencore.BaseValueObject;format,payload,warnings(default empty tuple). - Confirmed this package never invokes or interprets
Widget.binding/Layout.slotson aRenderer's behalf - a concreteRendererimplementation interprets both entirely on its own.
Domain-Specific Presentation Views (§17)¶
- Confirmed
SIMULATION_PLAYBACK,DIGITAL_TWIN_VIEW,OPTIMIZATION_COMPARISON, andAGENT_EXPLANATIONare each an ordinaryVisualizationCategorymember (§26) - no separate ABC, no separate object model, no per-category module exists for any of the four. - Unit tests confirm at least one flagship
Visualizationimplementation per domain-specific category binds to exactly theVisualizationContextfield its own category name implies (e.g.SIMULATION_PLAYBACKreadssimulation_results, neveroptimization_results).
Export (§18)¶
-
ExportRequest(§18) - frozencore.BaseValueObject;renderer_code,dashboard_id(defaultNone),report(defaultNone). -
ExportResult(§18) - frozencore.BaseValueObject;format,payload,exported_at. - Confirmed
Exportintroduces no separate execution mechanism - every export is an ordinaryRenderingPipeline.rendercall targeting a file-producingRenderer, wrapped in anExportResult. - Confirmed
Exportshares no code withconnectors- the two are documented as opposite-direction concerns (§5, §18).
Visualization Registry and Renderer Registry (§20)¶
-
visualization._registry.REGISTRY/register(§20) -Registry[str, type[Visualization]], raisingVisualizationValidationErrorfor an empty code andVisualizationVersionConflictErrorfor a materially-different re-registration under an existing code. -
visualization._registry.RENDERERS/register_renderer(§20) -Registry[str, type[Renderer]], identical error semantics, specialized forRenderer. -
EntryPointSpec(group="mineproductivity.visualization", target_registry="visualization")andEntryPointSpec(group="mineproductivity.visualization.renderers", target_registry="visualization.renderers")discovery wired viaregistry.EntryPointDiscovery(§28). - Confirmed
REGISTRYandRENDERERSare never merged into one - aVisualizationtype and aRenderertype remain orthogonal registrable concepts throughout the codebase.
Theme (§21)¶
-
Theme(§21) - frozencore.BaseValueObject;code,palette(open mapping, default empty),typography(open mapping, default empty). - Confirmed no
Registryexists forTheme- it is plain configuration data, never looked up polymorphically.
Persistence (§22)¶
-
DashboardRepositoryimplemented astype DashboardRepository = BaseRepository[Dashboard, str]- a type alias, not a new ABC or subclass. - Reference implementation uses
core.InMemoryRepository[Dashboard, str]()directly, with zero new persistence code. - Test suite for
DashboardRepositorybehavior written against thecore.BaseRepository[Dashboard, str]contract alone, never againstInMemoryRepository-specific internals (§33's repository-substitutability proof).
Versioning (§23)¶
-
VisualizationMetadata.version/RendererMetadata.version(a registered type's own SemVer) confirmed independent of anyDashboard's own contents - no code path derives one from another. -
VisualizationVersionConflictErrorraised at registration time for a materially-different re-registration under an existingVisualizationMetadata/RendererMetadatacode - never deferred. - Confirmed two
Dashboards sharing the samenameunder differentowners is never treated as a conflict anywhere in the codebase.
Caching (§24)¶
- Confirmed no dedicated cache module exists anywhere in the package (§24's documented, deliberate non-need; §32's recorded anti-pattern against introducing one "for consistency").
- Confirmed any
Renderer-internal memoization is documented as thatRenderer's own implementation detail, never a shared package-level cache abstraction.
Validation (§25)¶
-
VisualizationMetadata.validate()/RendererMetadata.validate()- non-emptycode, category matches the closedVisualizationCategorynamespace where applicable. -
Dashboard.validate()- non-emptynameandowner. -
Widget.validate()- non-emptycodeandvisualization_code. -
Layout.validate()- non-emptyslots. -
Theme.validate()- non-emptycode.
Metadata (§26)¶
-
VisualizationCategoryenum (§26) - exactlyChart/Graph/KpiCard/Timeline/SimulationPlayback/DigitalTwinView/OptimizationComparison/AgentExplanation; a closed enum, adding a member is a governance-reviewed change. -
VisualizationMetadata(§26) -code,category,description,version(default"1.0.0");validate()rejects an emptycode. - Confirmed
VisualizationMetadata.codenames a visualization type and is never confused with aWidget.codeanywhere in the codebase.
Discovery (§27)¶
-
by_theme()/by_owner()(§27) - plaincore.PredicateSpecificationfactories; composed withDashboardRepository.list(); confirmed to return an empty sequence (never raise) for a filter matching nothing. - Confirmed the three-way distinction (
REGISTRY/RENDERERS= which types are known;DashboardRepository= which dashboard instances currently exist;discovery.py= query facade over the instance store) is never conflated anywhere in the codebase.
Extension Points & Plugin Integration (§28)¶
- Entry-point groups
mineproductivity.visualizationandmineproductivity.visualization.renderersdocumented and wired exactly per §28. - A scripted integration test exercises a fixture "sitepack" plugin (registered via entry points, mirroring
examples/registry/01_register_and_discover.py's pattern) that subclassesVisualization, proving the platform-side dispatch and registration path works end to end. - A second fixture plugin subclasses
Rendererand is proven discoverable viaRENDERERSindependently of theVisualizationfixture.
Thread Safety & Concurrency (§29)¶
-
Visualizationinstances (of every category) confirmed stateless and safe to share/read across threads with no locking. -
Dashboardinstances confirmed immutable and safe to share/read across threads with no locking. -
DashboardRepository's per-id write serialization contract documented and tested against any production-grade implementation candidate; confirmed the barecore.InMemoryRepositoryreference implementation provides no locking of its own - any concurrent-write test against it must add external synchronization itself. -
visualization.REGISTRY/visualization.RENDERERSeach confirmed read-only and thread-safe after startup discovery, inheritingRegistry's own contract. - Independent widget renders (different widgets, or the same widget under different contexts) proven to execute fully in parallel without contention.
Error Handling (§30)¶
- Full exception hierarchy (design spec §6
exceptions.py):VisualizationValidationError,DashboardNotFoundError,RenderingError,VisualizationVersionConflictError- each subclassing the matchingcoreorregistryexception (VisualizationVersionConflictErrorsubclassesregistry.RegistrationError; the rest subclass acoreexception). - Confirmed no
Visualization._render/Renderer.renderimplementation raises for a legitimately incomplete widget binding or empty evidence - returns aPresentationModel/RenderedOutputcarrying a warning instead.
Security (§31)¶
- Confirmed no concrete
Rendererimplementation evaluatesWidget.binding/Layout.slotsas executable code or a dynamic template - both are treated strictly as data. - Confirmed
by_owner(§27) is documented and tested as a convenience query only, never as an access-control boundary. - Confirmed no new cryptographic, network, or credential-handling surface is introduced by this package.
Tests¶
-
tests/unit/visualization/mirrorssrc/mineproductivity/visualization/1:1. - Coverage ≥95%.
- Unit tests per concrete visualization category - at least one flagship visualization per
VisualizationCategory, each against a scripted widget and context with a known expectedPresentationModel(§33). - Identity/equality tests, builder contract tests, rendering-dispatch tests, interface-only ABC contract tests, registry/discovery isolation tests, export round-trip tests, warning-propagation tests, and concurrency stress tests as enumerated in design spec §33.
- The five package acceptance proofs in design spec §33 (no-fact-recomputation, immutability, interface-purity, no-architectural-drift, no-backend-coupling) each independently verified and recorded in the PR description.
Documentation¶
-
visualization/README.mdcomplete. - Every registered
Visualization/Renderertype's docstring restates itsVisualizationMetadata.description/RendererMetadata.descriptionfor source-level readability.
Examples¶
-
examples/visualization/01_single_widget_render.py- a singleVisualizationcategory rendering oneWidgetend-to-end viaRenderingPipeline. -
examples/visualization/02_multi_source_dashboard.py- the design spec §15 worked example (KPI_CARD/OPTIMIZATION_COMPARISON/AGENT_EXPLANATIONwidgets composed viaDashboardBuilder), end-to-end. -
examples/visualization/03_export_report.py- the design spec §19 worked example (ReportBuildercomposing the same widgets into an exportedReport). -
examples/visualization/04_simulation_playback.py- aSIMULATION_PLAYBACK-category widget rendering aSimulationResult's state trajectory. -
examples/visualization/05_plugin_visualization_and_renderer.py- a third-party-styleVisualizationandRenderersubclass registered via entry points, mirroringexamples/registry/01_register_and_discover.py's pattern. - All examples pass
mypy --strict+ruff.
Benchmarks¶
-
DashboardRepository.get()/list()latency at representative dashboard-population scale, recorded inbenchmark/reports/visualization/. - A multi-widget dashboard's parallel-render throughput at representative widget counts, recorded.
Certification¶
- Design spec §33's five package acceptance proofs pass and are recorded in the PR description (duplicated here from Tests for merge-gate visibility).
Type Hints, Mypy, Ruff, Coverage¶
- 100% type-hinted;
mypy --strictclean. -
ruff checkandruff format --checkclean. - Coverage report attached; ≥95%.
Release¶
-
CHANGELOG.mdupdated. - Root README dependency diagram cross-checked - confirm
visualizationgained no forbidden import, and confirm no lower package gained a newvisualizationimport. - Version bump proposed and reviewed.
- Design spec §33's acceptance proofs re-verified as final merge gate.
Derived from 12_Visualization_Design_Specification.md. Keep in sync with the governing specification and with ADR-0012-Visualization.md.