Skip to content

Commit 2a191c0

Browse files
authored
Phase 1040: Companion Notification Center (#180)
Acknowledgeable notification inbox hosted in the Event Viewer (resizable right panel) + companion bell indicator. Human-verified; phase suites green (2 pre-existing env orphan-timer flakes only).
1 parent c02e34d commit 2a191c0

25 files changed

Lines changed: 4690 additions & 29 deletions

.planning/PROJECT.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ The SensorThreshold subsystem has been fully rebooted on a unified `Tag` foundat
5252

5353
**Vocabulary:** `SensorTag`, `StateTag`, `MonitorTag`, `CompositeTag`, `TagRegistry`, `EventBinding`. FastSense API: `addTag(t)`.
5454

55+
**Companion (Phase 1040, 2026-06-02):** the FastSenseCompanion **Event Viewer** now hosts an acknowledgeable notification inbox (`NotificationCenterPane`) as a horizontally-resizable right panel (draggable divider); a toolbar **bell** shows the unacked count + highest-severity color and opens the viewer. Dismiss == shared, audited `EventStore.acknowledgeEvent`.
56+
5557
## Current Milestone: v2.1 Tag-API Tech Debt Cleanup
5658

5759
**Goal:** Close the 4 non-blocking tech debt items surfaced by the v2.0 milestone audit so the Tag-API codebase is free of dead code, test-skip gaps, and stubbed example demos.
@@ -146,4 +148,4 @@ This document evolves at phase transitions and milestone boundaries.
146148
4. Update Context with current state
147149

148150
---
149-
*Last updated: 2026-04-22v2.1 milestone (Tag-API Tech Debt Cleanup) started*
151+
*Last updated: 2026-06-02Phase 1040 (Companion Notification Center) complete*

.planning/ROADMAP.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,3 +425,16 @@ Plans:
425425

426426
Plans:
427427
- [ ] TBD (promote with /gsd:review-backlog when ready)
428+
429+
### Phase 1040: Companion Notification Center
430+
431+
**Goal:** Add an acknowledgeable in-app notification inbox to `FastSenseCompanion` — a collapsible right-hand `NotificationCenterPane` (toggled by a toolbar bell + unacked-count badge) that live-lists unacknowledged threshold-violation events from the shared `EventStore` and lets operators acknowledge them (dismiss = `EventStore.acknowledgeEvent`, shared + audited). Predominantly a new UI surface over existing event + acknowledge infrastructure.
432+
**Requirements**: none mapped — 1040-CONTEXT.md locked decisions + the phase GOAL are the contract (must_haves derived in each PLAN)
433+
**Depends on:** Phase 1039
434+
**Plans:** 4/4 plans complete
435+
436+
Plans:
437+
- [x] 1040-01-test-foundation-PLAN.md (Wave 1) — StubEventStore double + NotificationCenterPane static pure-logic helpers + flat test
438+
- [x] 1040-02-notification-pane-PLAN.md (Wave 2, depends 01) — full detachable inbox pane (attach/detach/refresh/ack/filter/stale/theme) + TestNotificationCenterPane
439+
- [x] 1040-03-companion-integration-PLAN.md (Wave 3, depends 02) — Companion 4th-column grid + toolbar bell+badge + onLiveTick_ refresh hook + detach wiring
440+
- [x] 1040-04-companion-tests-verify-PLAN.md (Wave 4, depends 03) — TestFastSenseCompanion toolbar-col updates + 9 integration tests + full-suite gate + human live-verify

.planning/STATE.md

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,14 @@
22
gsd_state_version: 1.0
33
milestone: v4.0
44
milestone_name: Multi-User LAN Concurrency
5-
status: shipping
6-
stopped_at: PR #152 ready for merge (v4.0); PR #114 (Phase 1028 perf) shipped 2026-05-19 on parallel branch.
7-
last_updated: "2026-05-19T10:00:00Z"
8-
last_activity: 2026-05-19 -- Phase 1028 (Tag update perf — MEX + SIMD) COMPLETE on parallel branch claude/adoring-ishizaka-edc93c; v4.0 milestone separately shipping via PR #152.
5+
status: verifying
6+
last_updated: "2026-06-02T11:44:53.304Z"
7+
last_activity: 2026-06-02
98
progress:
10-
total_phases: 12
11-
completed_phases: 6
12-
total_plans: 26
13-
completed_plans: 30
9+
total_phases: 16
10+
completed_phases: 4
11+
total_plans: 20
12+
completed_plans: 39
1413
---
1514

1615
# State
@@ -20,25 +19,27 @@ progress:
2019
See: .planning/PROJECT.md (updated 2026-05-13)
2120

2221
**Core value:** A MATLAB engineer can ingest a million-sample sensor stream, monitor thresholds, build sub-second-responsive dashboards, and navigate it all from a single Companion app — without leaving MATLAB and without external toolboxes.
23-
**Current focus:** Phase 1029Concurrency Foundation
22+
**Current focus:** Phase 1040companion-notification-center
2423

2524
## Current Position
2625

27-
Phase: 1028 (tag-update-perf-mex-simd) — COMPLETE 2026-05-19 (this branch)
28-
Plan: 6 of 6 executed (with 03/04 deferred per Plan 02d data). Shipped plans: 01, 02, 02b, 02d, 05, 06.
26+
Phase: 1040
27+
Plan: Not started
2928
Milestone: v3.0 FastSense Companion — SHIPPED 2026-04-30; v4.0 Multi-User LAN Concurrency — shipping via PR #152 (parallel branch); v1.0 perf line tracks phase 1028 — now COMPLETE via PR #114.
30-
Status: Phase 1028 closed. WithIO `tickMin` reduced 4497 ms → 3603 ms (−19.9%) on Octave Linux x86_64 CI run 26089658442, almost entirely from Plan 02d's in-memory prior-state cache. Plan 06 ships per-tick fs-stat coalescing reducing 1600 → 1 syscalls/tick (−99.94% mechanism-level; wall-time +3.2% within variance on tmpfs CI). PR #114 carries the phase. Follow-up candidates for a future perf phase: in-memory propagation refactor; `containers.Map` → struct-array refactor; `.mat` save-side optimization. K2/K3/K4 deferred per data (target regions bucket as 0 ms post-cache).
31-
Last activity: 2026-05-29 - Completed 260529-fnt (via /gsd:fast): FunctionTransport adapter — reuse an external/company MATLAB mailer as a NotificationService Transport, no SMTP config
29+
Status: Phase complete — ready for verification
30+
Last activity: 2026-06-02
3231

3332
### Note on parallel v4.0 work (main branch state)
3433

3534
While Phase 1028 was in flight on this branch, main shipped v4.0 Multi-User LAN Concurrency (phases 1029-1033) via PR #152. The two efforts touched some shared files (`LiveTagPipeline.m`, `build_mex.m`) — merged here on this commit with both feature sets preserved:
35+
3636
- Plan 02d in-memory prior-state cache + Plan 06 fs-stat coalescing live in the single-user code path of `LiveTagPipeline.processTag_`.
3737
- v4.0 cluster-mode (TagWriteCoordinator + AtomicWriter) lives in the `if obj.IsClusterMode_` branch.
3838
- `bench_tag_pipeline_1k` continues to drive the single-user path (no SharedRoot set).
3939
- v4.0's STATE.md / ROADMAP.md entries (phases 1029-1033 Complete) preserved verbatim; phase 1028 Complete entry added alongside.
4040

4141
Three main PRs touched files v4.0 also modified — all auto/manually merged without functional conflict:
42+
4243
- PR #143 (260513-s0y) — Tile + Close all toolbar buttons. Tracking fixes (syncOpenedFigures_ Engines_ walk, public trackOpenedFigure hook, de-maximize + Units=pixels coercion) live alongside v4.0 cluster-mode wiring.
4344
- PR #149 (260519-bs4) — Tag Status Table window. TagStatusTableWindow handle + Tags toolbar button live alongside v4.0 cluster-mode + pipeline-observer state.
4445

@@ -113,6 +114,7 @@ Phase 1019 [██████████] 100% (3/3 plans complete in Phase 10
113114
- 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
114115
- 2026-05-13 — Milestone v4.0 Multi-User LAN Concurrency started; PROJECT.md updated, REQUIREMENTS.md created (14 P1 REQ-IDs across CONC/IDENT/EVTLOG/ACK/OPS categories; 6 P2 deferred to v4.1); research/ phase produced SUMMARY/STACK/FEATURES/ARCHITECTURE/PITFALLS markdown
115116
- 2026-05-13 — v4.0 roadmap created: 5 phases (1029-1033) covering all 14 P1 REQ-IDs, full coverage no orphans; phase structure mirrors research-recommended build order (Foundation → TagWriteCoordinator → EventLog → Single-Source Events → Companion Integration); three PITFALLS corrections (OFD locks, mtime heartbeat, lock-serialised appends) baked into Phase 1029 success criteria
117+
- 2026-06-02 — Phase 1040 added: Companion Notification Center (acknowledgeable in-app inbox pane in `FastSenseCompanion`; design brainstormed in-session and approved; EventStore-backed feed, dismiss = `acknowledgeEvent`, new collapsible right column + toolbar bell badge; `1040-CONTEXT.md` written)
116118

117119
### Phase Numbering Note
118120

.planning/phases/1040-companion-notification-center/.gitkeep

Whitespace-only changes.
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
---
2+
phase: 1040-companion-notification-center
3+
plan: 01
4+
subsystem: testing
5+
tags: [matlab, notification-center, eventstore, test-double, pure-logic, tdd]
6+
7+
requires:
8+
- phase: 1032-ack-events
9+
provides: EventStore.acknowledgeEvent + Event.AckedAt (unacked filter key)
10+
provides:
11+
- StubEventStore test double (getEvents/numEvents/acknowledgeEvent + ThrowOnGet_/ThrowOnAck_)
12+
- NotificationCenterPane class shell + 7 static pure-logic helpers (filter/sort/diff/badge)
13+
- Flat headless test pinning all helper + stub semantics
14+
affects: [1040-02-notification-pane, 1040-03-companion-integration, 1040-04-companion-tests-verify]
15+
16+
tech-stack:
17+
added: []
18+
patterns:
19+
- "Interface-first TDD: static pure-logic helpers as the contract before any UI"
20+
- "Stub-with-failure-switches test double (ThrowOnGet_/ThrowOnAck_) modeled on CaptureNotificationService"
21+
22+
key-files:
23+
created:
24+
- tests/StubEventStore.m
25+
- libs/FastSenseCompanion/NotificationCenterPane.m
26+
- tests/test_notification_center_pane.m
27+
modified: []
28+
29+
key-decisions:
30+
- "Event fixtures use the real 6-arg constructor Event(start,end,sensor,label,thresholdValue,direction); the planning docs' 4-arg shorthand does not construct (direction is required + validated against {'upper','lower'})"
31+
- "filterUnacked_ treats both empty AND all-NaN AckedAt as unacked, mirroring Event.computeDisplayState"
32+
- "diffIds_ is order-insensitive via sort(ids(:)) with {} guards so identical sets in any order report no change (no badge flicker)"
33+
34+
patterns-established:
35+
- "NotificationCenterPane.<helper> static call surface — the pane's pure logic is callable + testable without a uifigure"
36+
37+
requirements-completed: []
38+
39+
duration: ~15 min
40+
completed: 2026-06-02
41+
---
42+
43+
# Phase 1040 Plan 01: Test Foundation Summary
44+
45+
**StubEventStore test double + the NotificationCenterPane pure-logic core (7 static helpers: unacked filter incl. NaN, newest-first sort, order-insensitive id-diff, severity/badge mapping), pinned by an 18-assertion headless flat test.**
46+
47+
## Performance
48+
49+
- **Duration:** ~15 min
50+
- **Completed:** 2026-06-02
51+
- **Tasks:** 3
52+
- **Files modified:** 3 (all created)
53+
54+
## Accomplishments
55+
- `tests/StubEventStore.m` — fake EventStore handle with `ThrowOnGet_`/`ThrowOnAck_` switches that drive the stale-read and ack-race paths later plans need.
56+
- `libs/FastSenseCompanion/NotificationCenterPane.m` — class shell (events block + full private property declaration) plus 7 pure static helpers; no UI primitives instantiated.
57+
- `tests/test_notification_center_pane.m` — 18 headless assertions covering the stub round-trip + ack-race throw and all 7 helpers; runs green in milliseconds.
58+
59+
## Task Commits
60+
61+
1. **Task 1: StubEventStore test double**`2b51ac88` (test)
62+
2. **Task 2: NotificationCenterPane static pure-logic helpers**`3a05c8c6` (feat)
63+
3. **Task 3: flat pure-logic test**`bd19fb85` (test)
64+
65+
## Files Created/Modified
66+
- `tests/StubEventStore.m``classdef StubEventStore < handle`; getEvents/numEvents/acknowledgeEvent; records acked ids + mutates AckedAt.
67+
- `libs/FastSenseCompanion/NotificationCenterPane.m` — shell + filterUnacked_/sortNewestFirst_/maxSeverity_/idsOf_/diffIds_/badgeText_/badgeColor_.
68+
- `tests/test_notification_center_pane.m` — flat function test (`add_companion_path` + local `check`), prints "All 18 tests passed."
69+
70+
## Decisions Made
71+
- See key-decisions frontmatter. The Event 6-arg constructor correction is the most consequential — Plans 02/04 build Event fixtures and must use the full signature.
72+
73+
## Deviations from Plan
74+
75+
### Auto-fixed Issues
76+
77+
**1. [Rule 3 - Blocking] Event constructor requires 6 args, not the 4 shown in the plan**
78+
- **Found during:** Task 3 (writing the flat test)
79+
- **Issue:** The plan's `<interfaces>` block and Task 3 examples construct `Event(startTime, endTime, sensorName, thresholdLabel)` (4 args). The real `Event` constructor is `Event(startTime, endTime, sensorName, thresholdLabel, thresholdValue, direction)` and throws if `direction` is missing/not in `{'upper','lower'}` — the 4-arg form cannot construct.
80+
- **Fix:** Built all test fixtures with the full 6-arg signature (e.g. `Event(30, NaN, 'P-101', 'HighPressure', 100, 'upper')`).
81+
- **Files modified:** tests/test_notification_center_pane.m
82+
- **Verification:** Test runs green (18/18).
83+
- **Committed in:** bd19fb85
84+
85+
---
86+
87+
**Total deviations:** 1 auto-fixed (1 blocking).
88+
**Impact on plan:** No scope change — only the fixture construction syntax. Carries forward to Plans 02 + 04 (their Event fixtures need the same 6-arg form).
89+
90+
## Issues Encountered
91+
None. (Note: the plan's strict "no UI primitives" grep matches doc-comment mentions of `uifigure`/`uitable` in the property block, but a call-syntax grep confirms **zero** actual UI primitive calls — pure logic only.)
92+
93+
## Next Phase Readiness
94+
- Plan 02 can extend `NotificationCenterPane` with the attach/detach/refresh/ack lifecycle on top of the static helpers; `StubEventStore` is ready to drive the headless suite.
95+
- No blockers.
96+
97+
---
98+
*Phase: 1040-companion-notification-center*
99+
*Completed: 2026-06-02*

0 commit comments

Comments
 (0)