Skip to content

M4-01 Dart workspace and architecture test

No Date Ruling Reason
D-M4-01-0 2026-10-14 The ticket was built on an integration base and ported onto main with only its own commits; the English docs and spec of main win (chapters 15-client-architecture.md and 23-quality.md), text this ticket adds is English, and its first commit (R-QA-14 into chapter 23) is left out because main has R-QA-14 since its baseline. ci-ok on main has no needs and requires the jobs of ci.yml by name through RULES in tools/ci/ci_ok.py, so the two app jobs are added there. The tickets are built in parallel on integration bases; main takes each ticket as one pull request; merged names win (D-W-100, D-W-114).
D-M4-01-1 2026-10-14 The Flutter pin lives in environment.flutter of the root pubspec.yaml (3.47.7, Dart ^3.13.5), CI reads it there (flutter-version-file: pubspec.yaml in gates, sonar, apps-macos, apps-windows and the Pages build), and every member repeats the same exact environment lines; test_flutter_pins_agree holds the fifteen manifests equal. Replaces D-M2-38-12. One known Flutter for every job and member; the workspace root is the one manifest every member shares.
D-M4-01-2 2026-10-14 packages/bothy_noise joins the workspace (resolution: workspace), its pubspec.lock is deleted and its code and tests stay unchanged; its OSV-Scanner overrides move with the lock file to the root osv-scanner.toml, with a new checked entry for every package or version the one resolution adds. The dev dependency test is ^1.31.1 in every pure Dart member, because flutter_test of Flutter 3.47.7 pins test_api 0.7.12 and test 1.33 needs 0.7.15; one resolution cannot hold both. Replaces D-M2-38-13; D-M2-38-20 applies to the root file. Brief note 1; OSV-Scanner reads the override file next to the lock file it scans.
D-M4-01-3 2026-10-14 The reach of the diagram of 15 3.1 is an allow list: tools/arch-check/rules.yaml holds the arrows, and a member may depend on and import exactly the members they reach (arrows and transitive closure), checked in make arch. A new arrow changes 15 3.1 and rules.yaml in the same change; test_rules_edges_equal_the_spec_diagram holds both equal. 15 3.1 gains rule 8 (the reach) and rule 9 (every manifest a listed member), and the check details of rules 1, 4 and 7. Findings on a manifest name its line 1. A deny list would let every new edge in silently (brief note 2).
D-M4-01-4 2026-10-14 Generated Dart code (*.g.dart, *.freezed.dart, *.drift.dart, lib/src/generated/, build/) is out of the doc lint and the style lint (analyzer exclude in the root analysis_options.yaml), the format check (DART_GENERATED in the root Makefile) and coverage (tools/ci/lcov_filter.py). It stays in the compile check: the members that import it are analyzed, and flutter test compiles it. An excluded file is not analyzed itself, so an analyzer error inside it shows only through its users and the compiler. Each member includes its base set and then the root file through a list under include (Dart 3.6 and later). Generators format and document their own output (M4-02, M4-12); the same split as M2-23 note 8 for the other languages.
D-M4-01-5 2026-10-14 make lint runs flutter pub get --enforce-lockfile and flutter analyze --fatal-infos once at the workspace root, which analyzes every member, and dart run custom_lint in each member that declares it; make test resolves once at the root and runs flutter test --coverage per member, after checking that every member has test/. One resolution and one analysis for the workspace (brief note 4); a stale lock file still fails instead of being rewritten (D-M2-38-21).
D-M4-01-6 2026-10-14 The Dart API pages are generated for every build and never tracked: tools/docs/dart_api_docs.py runs dart doc per package into the ignored folder docs/api/dart/, and a warning or an error fails it. make docs runs it whenever a Dart member is tracked, for every component selection, not only with apps, because docs/reference/dart-api.md links the pages and mkdocs build --strict fails on a missing target; make linkcheck builds them first when the folder is missing, for the same reason (lychee checks the links offline). No validation setting changes. Generated pages cannot drift from the code (brief note 5); the strict site build and the link check stay as they are.
D-M4-01-7 2026-10-14 Platform tests are outside gates: make apps-platform (tools/ci/apps_platform.py) runs the argument lists of each member's platform-tests.json for the host system, and the CI jobs apps (macOS) (macos-15) and apps (Windows) (windows-2025) run it when the apps component is selected; ci-ok requires each to end with success or skipped. They need a desktop session (brief note 6, ADR 0039); a skipped job (component not selected) must not block.
D-M4-01-8 2026-10-14 The root files pubspec.yaml, pubspec.lock and analysis_options.yaml and the prefix tools/arch-check/ select the gate component apps (tools/ci/components.py). A change there must run the Dart gates (brief note 7); before, the root files selected all.
D-M4-01-9 2026-10-14 The packages of the Flutter SDK in the root lock file (flutter, flutter_test, sky_engine; source sdk, version 0.0.0) get license overrides in osv-scanner.toml: BSD-3-Clause, the license of the Flutter repository. The LICENSE file of sky_engine also collects the notices of the third-party code compiled into the engine (Apache-2.0, MIT, BSD, Zlib, Unicode, IJG and FreeType texts among them); its review is the ScanCode step before a release (docs/quality/licenses.md item 4). deps.dev does not know SDK packages, so the license gate reports them as UNKNOWN; every Flutter app ships the engine (ADR 0027).
D-M4-01-10 2026-10-14 Skeletons: each package library is a library; directive with its doc comment and no other public symbol, so each first test imports it with // ignore: unused_import (the import is what it checks). device_key is created from flutter create --template=plugin --platforms=macos,windows reduced to a Flutter package without native files, without the example app and without a flutter: plugin: section, because no platform class exists until M4-10. The apps show an empty MaterialApp without text and have no platform folders yet. Brief note 8 and rule 4: no native code before its ticket.
D-M4-01-11 2026-10-14 packages/api_client gets a Makefile whose generate-check passes while no generated code is tracked and fails as soon as lib/src/generated/ or a *.g.dart file is tracked; M4-02 replaces the target with the generation, the compile and the comparison. make api-clients stays fail-closed for a manifest without the target. tools/ci/apps_platform.py resolves the program of each command with shutil.which before it runs it. Code review M4-01: the tracked skeleton manifest made make api-clients (and so make gates and CI) fail, and without a shell Windows does not find flutter.bat for the job apps-windows.
D-M4-01-12 2026-10-15 Port onto main: dart doc links Google Fonts (a preconnect and two stylesheets) in every page, which the external asset check of M7-19 refuses, so tools/docs/dart_api_docs.py removes every <link> to another origin from the generated pages, which then use the fonts of the system. The generated folder api/dart/ is listed in not_in_nav of mkdocs.yml, because main's strict build fails on a page missing from the navigation and docs/reference/dart-api.md is the entry to those pages. The site loads nothing from another origin (M7-19/3); the generated pages are reached through one reference page, like the single ADRs through the ADR index.