Skip to content

M6-12 bothy_viz: six views

No Date Ruling Reason
D-M6-12-0 2026-10-16 Base int/m1-wave27 at 3d4f0f3, branch feat/M6-12-viz-views in its own worktree; not merged locally and not pushed, the PR lane ports it. The schemas, operations and rulings the brief uses (T7, T8, D-W-100, D-W-120) are on the base; the statistics schemas differ from origin/main only in the chapter names of their descriptions, so no contract change enters first. Names that differ from the brief (D-W-100): the spec chapter is 25-visualisierung.md on this base; the golden test lives in test/goldens/views_golden_test.dart next to the mark goldens (the golden path resolver of M6-11); the switch "As table" is a toggle button with toggled semantics, because the Material switch animates in the reduced motion context; the performance test runs through harness/tool/perf_macos.sh, listed in the harness platform-tests.json, because the platform folders of the harness are not checked in (D-M6-11-6). New fixture states: StatsBackendReport.rate_limits.json (every rate_limit state, I2 and I3 denials, a mismatch) and StatsTimeline.day_boundary.json; StatsTimeline.normal.json gains buckets of the delivery metrics for the history of 6.3. Instructions of the launcher; merged layout wins over the brief (D-W-100).
D-M6-12-1 2026-10-16 Every view is XxxView({live, queries, options, onOpenThread}). VizHostOptions carries what only the host knows: form factor, scope (VizScope.instance() or VizScope.space(id)), the period of the queries, allowTvMode, showCostsInTv (default viz.tv_show_costs), onOpenGrafana (only with telemetry.dashboard_url), display names, the time zone of the person, the clock and the app configuration. vizViewRegistry lists per VizViewKind the title key, the icon, whether the view is instance only and whether it appears on mobile; vizViewsFor never offers TV mode on mobile or without allowTvMode. An error of a source (forbidden, not_found, feature_disabled, rate_limited) shows its problemText and stops the live source and every further query until the host builds the view again. Without a live source a live view reads getStatsLive once. Brief, design note 1; 15 principle 1 (no permission logic in the client).
D-M6-12-2 2026-10-16 In a space scope delivery and sync live shows "Only for the owner" and calls neither source; the other views pass the space to their sources and show what the server delivers. Brief, design note 1; 25 4 rule 1.
D-M6-12-3 2026-10-16 Data per view as 25 6: the live topology and delivery read the frames (delivery adds the history of its six metrics from getStatsTimeline), the backend view reads getStatsBackends once and takes presence, reported mode and rate limit from the agents of every frame, the executive page reads the five queries once, the timeline reads getStatsTimeline once. forbidden from getStatsSlo shows "Only for the owner" in the traffic light tile; forbidden from getCostStats leaves the cost tiles out (no cost.read.aggregate), never zero. The offline state shows the last frame with the stale marker. Delivery shows the count of the SLI window with its good share and the deliveries per minute as history, because the frame does not carry the length of stats.live_sli_window (build note in 25 6.3); catch-ups show their count and summed duration of the last minute. Brief, design note 2; 25 4 rules 2 to 5.
D-M6-12-4 2026-10-16 Each view has a toggle "As table" that swaps the chart for VizTables with the same texts and column headers from l10n; a header tap sorts by its column (numbers by value), a second tap reverses. The render table gives the table, row and cell roles; header cells add the column header role and a "Sort by" label, every cell the label "column: value". A column that would only show "none" (cost without any cost) is left out. Brief, design note 3; 25 7.4.
D-M6-12-5 2026-10-16 TV mode is the route-less overlay TvMode(views, options, live, queries, onExit): dark theme, density comfortable, the text scale times the step from type.body-sm to type.body, no controls (the views read VizTvScope), rotation every viz.tv_rotation_interval on the clock of the options with an AnimatedSwitcher of motion.duration-move-slow (zero in the reduced context), costs only with showCostsInTv, TV mode takes the keyboard focus after its first frame (autofocus would not take it from a focused host control behind an overlay), and the first key press or pointer down calls onExit once; the timeline keeps its playhead at the end there, so a screen shows the whole period. A view that leaves the rotation (or a tab) does not stop the live source when a newer view already started it: the closed stream tells the old view that the source is no longer its own. Constructing it without allowTvMode or on mobile fails an assertion; buildVizView refuses tvMode. Brief, design note 4; 25 6.6; components.md 11.
D-M6-12-6 2026-10-16 The performance test is harness/integration_test/topology_perf_test.dart: the load frame and a variant with every third run in another state, alternated every stats.live_interval of the fixture clock for 200 frames; it fails when the p95 of FrameTiming.buildDuration is above viz.perf.frame_build_p95. It runs with flutter drive --profile -d macos through tool/perf_macos.sh (which makes macos/ for the run and removes everything the run added, because a native folder under packages/ fails rule 4 of make arch) from make apps-platform (the discovery of platform-tests.json now includes packages/*/harness) and from make perf, whose new Dart step runs every member's tool/perf_macos.sh on macOS (PERF_HOST) and prints SKIP perf-dart elsewhere. The live topology keeps the widget of every unchanged card and lane between frames and paints each lane in its own layer, so a frame rebuilds only changed cards. Brief, design note 6; 25 7.3; PLAN P-07.
D-M6-12-7 2026-10-16 Goldens: every view with every fixture state that applies (the load frame belongs to the performance test), the delivery view in a space scope, the executive page of a space manager and TV mode, each in the full matrix as CI goldens; the timeline is split into one file per theme because its minute areas pass repo.max_file_kb in one file. Platform goldens on macOS keep one representative per view (the normal state and TV mode), as the size rule of D-M6-11-7 allows. Brief, Tests; M6-11 design note 8.
D-M6-12-8 2026-10-16 The timeline playhead moves in whole minutes, one minute every 60 / speed seconds of the clock, and starts at the end of the period so the whole day is visible first; play at the end starts again at the beginning. In the full motion context the playhead glides with motion.duration-move, in the reduced context it jumps. Controls are buttons with text, because the icon set has no play or pause glyph. The rates leave out the cost buckets: they count bookings, and a count is no amount with currency and label (25 4 rule 2). Brief, design note 5; 25 6.5 (minute precision); components.md 11.
D-M6-12-9 2026-10-18 The ticket was ported from its integration base onto main with only its own commits, stacked on the port of M4-07, whose DsBanner the views use (the brief names only M6-11); the English docs of main win: the build note of 25 6.3 and the perf paragraph of docs/quality/gates.md sit in the English chapters, and the code comments point to 25-visualization.md. The lock file is resolved again on main (flutter pub get), and nine view goldens are rerendered, macOS and CI variant. Main carries its own value of color.warning.subtle (palette.amber.100), which the banners and warning chips of these views show, as D-M4-07-9 found for the components; no other token differs between the base and main.
D-M6-12-10 2026-10-19 Ruling of the steering (the owner left it to the steering): performance budgets are defined for the reference hardware, not for shared hosted CI runners. On the GitHub macOS runner the live topology measured a frame build p95 of about 23 ms against the 8 ms of viz.perf.frame_build_p95. The test keeps running there and records its p95 (reportData and a perf: log line), but fails only above the separate named CI budget viz.perf.frame_build_p95_ci (50ms, about twice the measured runner value as headroom), documented next to the reference budget in 25 7.3 and 25 15 and in the configuration reference. tool/perf_macos.sh passes the budget as --dart-define=BOTHY_PERF_BUDGET=reference\|ci: unset, a set CI selects ci and reference otherwise; another value stops with exit code 2. make perf sets BOTHY_PERF_BUDGET=reference, so the reference budget stays unchanged and is enforced by the perf target on reference hardware. 25 7.3; P-07; CI log of PR #131 (apps macOS).