|
| 1 | +--- |
| 2 | +gsd_state_version: 1.0 |
| 3 | +milestone: v3.0 |
| 4 | +milestone_name: FastSense Companion |
| 5 | +status: shipped |
| 6 | +last_updated: "2026-04-30T09:50:00.000Z" |
| 7 | +last_activity: 2026-04-30 -- v3.0 milestone shipped (audit passed post 1023.1 gap closure) |
| 8 | +progress: |
| 9 | + total_phases: 6 |
| 10 | + completed_phases: 6 |
| 11 | + total_plans: 18 |
| 12 | + completed_plans: 18 |
| 13 | +shipped_at: 2026-04-30 |
| 14 | +--- |
| 15 | + |
| 16 | +# State |
| 17 | + |
| 18 | +## Current Position |
| 19 | + |
| 20 | +Milestone: v3.0 FastSense Companion — SHIPPED 2026-04-30 |
| 21 | +Status: Awaiting next milestone (run `/gsd:new-milestone` to scope v3.x or v4.0) |
| 22 | +Last activity: 2026-04-30 -- v3.0 archived to .planning/milestones/v3.0-ROADMAP.md |
| 23 | + |
| 24 | +## Progress Bar |
| 25 | + |
| 26 | +``` |
| 27 | +v3.0 FastSense Companion |
| 28 | +Phase 1018 [██████████] 100% (3/3 plans complete in Phase 1018; 1/6 phases complete overall) |
| 29 | +Phase 1019 [██████████] 100% (3/3 plans complete in Phase 1019; 6/6 plans complete overall) |
| 30 | +``` |
| 31 | + |
| 32 | +## Accumulated Context |
| 33 | + |
| 34 | +### Roadmap Evolution |
| 35 | + |
| 36 | +- 2026-04-29 — Milestone v3.0 FastSense Companion started (programmatic MATLAB uifigure companion app; design brainstormed prior; v2.1 Tag-API Tech Debt Cleanup carried forward in parallel) |
| 37 | +- 2026-04-29 — v3.0 roadmap created: 5 phases (1018-1022) covering 28 REQ-IDs across COMPSHELL, CATALOG, BROWSER, INSPECT, ADHOC categories |
| 38 | +- 2026-04-29 — v3.0 phase 1023 added (Industrial Plant Demo Integration): wraps `demo/industrial_plant/run_demo.m` in `FastSenseCompanion`; 4 new COMPDEMO REQ-IDs; total now 6 phases / 32 REQ-IDs |
| 39 | + |
| 40 | +### Phase Numbering Note |
| 41 | + |
| 42 | +v2.1 phases in the phases/ directory extend to 1017 (1012, 1013, 1014, 1017). v3.0 phases start at 1018 to avoid collision. |
| 43 | + |
| 44 | +### Brainstorm Outcomes (v3.0) |
| 45 | + |
| 46 | +Design decisions locked during the v3.0 brainstorm conversation (2026-04-29): |
| 47 | + |
| 48 | +- **Scope:** A + B + C combined — library browser + live monitoring + tag-first explorer. **Not** D (no in-app dashboard authoring/editing). |
| 49 | +- **UI tech:** Programmatic `uifigure` (no App Designer, no `.mlapp`). |
| 50 | +- **Connection contract:** Loose handoff via constructor: `FastSenseCompanion('Dashboards', {d1, d2}, 'Registry', TagRegistry)`. Tags pulled from `TagRegistry` singleton by default; pass `'Registry', reg` to override. Single project per app instance (no multi-project switcher). |
| 51 | +- **Dashboard rendering:** Opening a dashboard pops it into its own MATLAB figure via existing `DashboardEngine.render()`. Companion is purely a control panel / navigator. Zero changes required to `DashboardEngine`. |
| 52 | +- **Layout:** Three-pane window — left = searchable tag catalog with multi-select checkboxes and filter pills; middle = dashboard list; right = adaptive inspector. |
| 53 | +- **Inspector states:** `welcome` (empty) / `tag` (single tag selected — metadata, thresholds, "used in" cross-references, "Plot this tag" → `SensorDetailPlot`) / `multitag` (N>1 — plot composer with Linked grid / Overlay, time range All / Last 1h, Live Off/2s/5s) / `dashboard` (dashboard tile selected — summary + open + live toggle). Most-recent click wins (`LastInteraction = 'tags' | 'dashboard'`). |
| 54 | +- **Tag grouping:** Derived from `Tag.Labels` (existing property; no new model field). Filter pills also reflect `Tag.Criticality`. |
| 55 | +- **Ad-hoc plotting modes:** Linked grid (`FastSenseGrid` with shared `LinkGroup`) and Overlay (single `FastSense` instance with multiple lines). Dropped "Separate figures" as YAGNI. |
| 56 | +- **Live refresh:** Companion does **not** own a refresh timer for dashboards — uses each `DashboardEngine`'s own `LiveInterval` and start/stop. For ad-hoc plots, companion runs a `timer` that calls `tag.getXY()` and `updateData()` on the open figure; timer stored on figure `UserData`, stops on figure close. |
| 57 | +- **File structure:** |
| 58 | + - `libs/FastSenseCompanion/FastSenseCompanion.m` (orchestrator, public API) |
| 59 | + - `libs/FastSenseCompanion/TagCatalogPane.m` (left pane) |
| 60 | + - `libs/FastSenseCompanion/DashboardListPane.m` (middle pane) |
| 61 | + - `libs/FastSenseCompanion/InspectorPane.m` (right pane) |
| 62 | + - `libs/FastSenseCompanion/CompanionTheme.m` (static color/font helper, mirrors `DashboardTheme`) |
| 63 | + - `libs/FastSenseCompanion/private/companionUsageIndex.m` (tag → dashboards map) |
| 64 | + - `libs/FastSenseCompanion/private/filterTags.m` (search + filter pure logic) |
| 65 | + - `libs/FastSenseCompanion/private/openAdHocPlot.m` (figure factory) |
| 66 | +- **Event wiring:** MATLAB `events`/`notify`. Pane events: `TagSelectionChanged`, `DashboardSelected`, `OpenSensorDetail`, `OpenAdHocPlot`, `OpenDashboard`. Orchestrator owns selection state (`SelectedTagKeys`, `SelectedDashboardIdx`, `LastInteraction`). |
| 67 | +- **Public API:** `FastSenseCompanion(name-value)`, `setProject(dashboards, registry)`, `addDashboard(d)`, `removeDashboard(key)`, `selectTags(keys)`, `close()`. Private: pane handles. Not on surface: live-refresh control (delegates to `DashboardEngine`), dashboard creation/edit (out of scope). |
| 68 | +- **Errors:** All namespaced `FastSenseCompanion:*`. Constructor / `setProject` validate eagerly. Every event callback wrapped in try/catch → `uialert(fig, ...)`. Downstream throws (e.g., `DashboardEngine.render`) never crash the companion. |
| 69 | +- **Testing:** Pure-logic unit tests (`tests/test_companion_filter_tags.m`, `tests/test_companion_usage_index.m`). Class-based integration suite (`tests/suite/TestFastSenseCompanion.m`) — hidden `uifigure('Visible','off')`, drives state via `selectTags`, mocks `openAdHocPlot` via DI seam (constructor accepts a callable, defaults to real helper). No pixel-perfect UI tests. |
| 70 | +- **Out of scope (v1 of Companion):** dashboard authoring; multi-project; cross-session persistence; status strip with global KPIs; custom time-range picker; detachable panes; WebBridge integration. |
| 71 | + |
| 72 | +### Cross-Cutting Engineering Constraints (locked in Phase 1018) |
| 73 | + |
| 74 | +These apply to every phase and are reflected in phase success criteria rather than separate REQ-IDs: |
| 75 | + |
| 76 | +- `Listeners_` cell array on every class that calls `addlistener`; `delete(obj.Listeners_)` in `CloseRequestFcn` |
| 77 | +- `stop(t); delete(t);` always in that order for every timer (companion and ad-hoc) |
| 78 | +- Companion is the only `uifigure`; all spawned figures are classical `figure` — never parent one inside the other |
| 79 | +- `axes(uipanel)` not `uiaxes(uipanel)` for embedded plots (9x performance difference) |
| 80 | +- Errors namespaced `FastSenseCompanion:*`; every callback wrapped in try/catch + non-blocking `uialert` |
| 81 | +- Pure-logic helpers (`filterTags_`, `flattenWidgets_`) ship with unit tests |
| 82 | + |
| 83 | +### Research Flags for Planning |
| 84 | + |
| 85 | +- **Phase 1020 planning:** Read `libs/Dashboard/DashboardPage.m` and `libs/Dashboard/GroupWidget.m` to confirm `Widgets` and `Children` GetAccess. Determines whether `DashboardEngine.getWidgets()` wrapper is required or if `d.Widgets`/`d.Pages{i}.Widgets` suffices. |
| 86 | +- **Phase 1021 planning:** Run 20-line scratch test of `SensorDetailPlot(tag, 'Parent', uipanelHandle)` to verify resize behavior under embedded panel parenting. |
| 87 | +- **Phase 1022 planning:** Write standalone 50-line `FastSenseGrid` + `timer` + `CloseRequestFcn` prototype before full implementation; verify zero orphan timers in `timerfindall` after close. |
| 88 | + |
| 89 | +### Decisions (Phase 1020) |
| 90 | + |
| 91 | +- **1020-02:** applyFilter_() is the single rebuild path for DashboardListPane row list; onRowClicked_ sets SelectedIdx_ then calls applyFilter_() for highlight rather than painting individual buttons |
| 92 | +- **1020-02:** addDashboard uses handle identity (==) for duplicate detection; removeDashboard uses Name (case-sensitive strcmp) for lookup per CONTEXT.md |
| 93 | +- **1020-02:** Listeners re-wired in setProject after detach clears them; SelectedDashboardIdx_ clamped to 0 in refresh() when engine list shrinks |
| 94 | + |
| 95 | +### Carry-Forward |
| 96 | + |
| 97 | +- **v2.1 Tag-API Tech Debt Cleanup** — in flight, parallel to v3.0. Phases 1012-1017. Does not block v3.0 work. |
0 commit comments