fluttersdk_wind_diagnostics_contracts 1.1.0
fluttersdk_wind_diagnostics_contracts: ^1.1.0 copied to clipboard
Wind UI widget state contracts for Flutter debug-tooling and AI agents (MCP). Zero-dep abstract interface implemented in fluttersdk_wind, consumed in fluttersdk_dusk.
Changelog #
All notable changes to this project will be documented in this file.
This project follows Semantic Versioning 2.0.0. Entries follow the Keep a Changelog shape.
[Unreleased] #
1.1.0 - 2026-08-25 #
Added #
-
WindPerfResolverabstract class (lib/fluttersdk_wind_diagnostics_contracts.dart): a second, separate contract alongsideWindDebugResolver, with a single methodMap<String, Object?> stats(). WhereWindDebugResolver.resolve(Element)resolves per-Element widget state,WindPerfResolver.stats()resolves process-wide performance counters that have no single Element to attach to. The returned map's key set is pinned as the cross-repo contract read byfluttersdk_dusk's performance snapshot, allint:cacheHits,cacheMisses,cacheBypasses,cacheSize,wDivBuilds,wTextBuilds. Additive-growth rule applies: new keys are a minor bump, renaming or removing a key is a major bump. -
WindDebugRegistryperf slot: a second, distinct static slot mirroring the existing debug-resolver triad.WindDebugRegistry.currentPerf(getter,nullwhen unregistered),WindDebugRegistry.registerPerf(resolver)(canonical install path, idempotent, most-recent-call wins).resetForTesting()now clears both slots. Registering a perf resolver never touches the debug slot and vice versa. -
WindDebugRegistry.registerPerfForTesting: the sibling ofregisterForTesting, and it exists for the same reason.registerPerfis documented as wind's canonical install path, so a consumer's test installing a fake through it reads as production wiring at the call site. -
6 contract tests (
test/fluttersdk_wind_diagnostics_contracts_test.dart): null-when-unregistered, register stores + lookup viastats(),resetForTestingclears the perf slot, registering a perf resolver leaves the debug slot untouched,registerPerfidempotency (most-recent-call wins), andregisterPerfForTestingtouching only the perf slot.
Changed #
- The coverage gate is no longer balanced on a single line.
WindDebugRegistry._()is a private constructor whose only job is to stop this static-only registry being instantiated, so no test can reach it, and it was one of only five executable lines in the package: coverage sat at exactly 80.00% (LH=4, LF=5) against an 80% floor, and one new uncovered line anywhere would have failed CI. It now carries// coverage:ignore-linewith the reason above it, which takes the count to 100.00% (LH=4, LF=4). This adds no test; it stops counting a line that cannot be tested. Verified thatflutter test --coveragehonours the pragma in this toolchain rather than assuming it. (lib/fluttersdk_wind_diagnostics_contracts.dart)
Fixed #
analysis_options.yamlnow carries theanalyzer.excludeblock that the Flutter tool's migrator writes, so the migrator is a no-op and a CI checkout stays clean. The migrator runs on everyflutter pub get, which is the first step of bothci.ymlandpublish.yml, andflutter pub publish --dry-runlater in the same job then reported1 checked-in file is modified in gitand exited 65. Nothing had caught it because the last CI run here predates the migrator (2026-05-21); the next run on any branch would have failed, and the publish workflow shares the step, so it would have blocked a release too. Verified by reproducing the exit 65 and then confirming a secondpub getleaves the tree clean with the explanatory comment intact. The same fix landed influttersdk_windas #178.
1.0.0 - 2026-05-21 #
Initial stable release. Neutral abstract contracts that let debug-tooling packages read Wind UI widget state at runtime without a compile-time dependency on fluttersdk_wind.
Added #
-
WindDebugResolverabstract class (lib/fluttersdk_wind_diagnostics_contracts.dart): single-method interfaceMap<String, Object?> resolve(Element element). Implementations live influttersdk_wind(production) and test fakes (debug-only). The returned map's key set is documented as the v1 frozen contract:className:String(required when the widget is a W-prefixed widget with a non-emptyclassName).breakpoint:String(e.g.'sm','md','lg').brightness:String('light'or'dark').platform:String(e.g.'web','ios','android','macos').states:List<String>(e.g.['hover', 'focus']).bgColor:Stringhex (e.g.'#3B82F6'); present only when resolved.textColor:Stringhex; present only when resolved. Implementations MUST returnconst {}for elements that are not Wind widgets, guaranteeing a graceful no-op for consumers walking arbitrary widget trees.
-
WindDebugRegistrystatic registry (lib/fluttersdk_wind_diagnostics_contracts.dart): process-global single-slot registration for the activeWindDebugResolver. Wind installs its concrete resolver at app boot (gated bykDebugMode) viaWind.installDebugResolver(); debug-tooling consumers look up the current resolver viaWindDebugRegistry.current. The registry exposes:WindDebugRegistry.currentgetter (returnsnullwhen no resolver is registered).WindDebugRegistry.register(resolver)(canonical install path; idempotent, most-recent-call wins).WindDebugRegistry.resetForTesting()andWindDebugRegistry.registerForTesting(resolver)(both@visibleForTesting; test-only seams).
-
6 contract tests (
test/fluttersdk_wind_diagnostics_contracts_test.dart): cover null-when-unregistered, register stores + lookup, idempotent register (last-wins),resetForTestingclears,registerForTestingoverrides, and the contract assertion that resolver implementations returnconst {}for non-Wind elements. -
GitHub Actions workflows (
.github/workflows/ci.yml,.github/workflows/publish.yml): CI runsflutter pub get+dart format --set-exit-if-changed+dart analyze+flutter test --coveragewith an 80% line-coverage floor +flutter pub publish --dry-run. Publish runs on a SemVer tag push, validates, performs the OIDC publish to pub.dev, then creates a GitHub Release whose body is extracted from this CHANGELOG.
Why this package #
Wind UI exposes 6 widget-state fields (className, breakpoint, brightness, platform, states, bgColor, textColor) that debug-tooling packages such as fluttersdk_dusk need to embed in their snapshot output. Shipping that handoff through fluttersdk_wind's own surface would force every debug-tooling package to compile-time depend on Wind (heavy, transitively pulls Flutter's rendering surface), and would force Wind to compile-time depend on every debug-tooling package it wants to feed.
This package breaks the loop. Both sides depend on the abstract contract here; neither side imports the other. The pattern mirrors Flutter's *_platform_interface convention (4.97M downloads on plugin_platform_interface as the canonical precedent).