fix: characterization-pass follow-up defects (#149, #150, #155, #156)#201
Conversation
c8adf4f to
f852d36
Compare
Code review — multi-personaScope: 6 files, core services ( Findings are confidence-gated (≥0.60) and deduped; cross-reviewer agreement noted. All in-scope findings were addressed in the pushed commits; two pre-existing/out-of-scope items were filed as issues. P2 — High
P2 — High (pre-existing, out of scope → filed)
P3 — Moderate
Not actioned (advisory)
Coverage
VerdictReady to merge once CI is green. All P2/P3 in-scope findings are fixed in the pushed commits (66/66 targeted specs pass, lint + dev build clean); the two pre-existing items are tracked in #205 and #206. Review by 6 independent persona agents; synthesis deduped and confidence-gated. |
timeoutPathObservable matched a single registration with _pathRegister.find(item => item.path == path) — loose == and first-match by path only. When the same path was registered under multiple $sources, only the first-registered subject received the timeout reset; other-source registrations kept their stale value. Switch to _pathRegisterByPath.get() (strict keyed lookup) and reset every registration for the path. Closes #155 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDu7zsKECA9SvBR5DLdUex
…ding deltaStatusCodes carried descriptions for 500/502/504, but handledStatusCodes omitted them, so those responses fell to the "Unknown Request Status Code" error toast — which then printed the very description it claimed not to know. Add them to the handled set and surface them as an error toast carrying their description plus any server message. Also fix the statusCode 200 wording: "The request was successfully." → "The request was successful." Closes #156 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDu7zsKECA9SvBR5DLdUex
Blank-dashboard seeding spread DefaultDashboard entries shallowly, so a new dashboard's configuration array (and its widget objects) were the same objects as the module-level DefaultDashboard constant; any in-place widget mutation corrupted the shared default for every later blank creation. Deep-clone the default (same defect class as the already-fixed #35/#100). Closes #150 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VDu7zsKECA9SvBR5DLdUex
…actional
delete() only clamped an active index that overflowed the end; when a
lower-indexed dashboard was removed, activeDashboard silently pointed at a
different dashboard. Follow the active dashboard to its new index when a lower
one is deleted, then clamp.
Guard delete() against an out-of-range itemIndex (matching duplicate()/
navigateTo()/setActiveDashboardIndex()): without it the new remap shifts —
or, for a negative index with active 0, sets a negative — active index for a
delete that removes nothing.
Fold in two siblings from the same characterization pass:
- setActiveDashboardIndex accepted fractional indexes (Number('1.5') passed
the bounds check), so a URL id like '1.5' set a non-integer active index;
require an integer.
- Two console.error prefixes in duplicate() read "Dashboard Service]" with no
opening bracket.
Closes #149
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VDu7zsKECA9SvBR5DLdUex
f852d36 to
504bbfe
Compare
What
Fixes four correctness defects surfaced by the #27 characterization pass (PR #147/#146). Each fix intentionally re-pins the characterization test that previously asserted the buggy behavior.
dashboard.service.delete()index bookkeeping. Deleting a lower-indexed dashboard leftactiveDashboardpointing at a different dashboard (only end-overflow was clamped). Now the active index follows its dashboard down and clamps. Folds in two same-file siblings:setActiveDashboardIndexaccepted fractional indexes (a URL id like1.5passed the bounds check), and twoconsole.errorprefixes induplicate()read"Dashboard Service]"with no opening bracket.DefaultDashboard, so the new dashboard'sconfigurationarray was the same object as the module-level constant; in-place widget edits corrupted the shared default. Now deep-cloned (same defect class as the already-fixed [PCS-05] Default-config singletons are mutated by reference instead of cloned #35/app-initNetwork mutates the shared DefaultConnectionConfig singleton by reference (sibling of #35) #100).data.service.timeoutPathObservablefirst-match only. Used_pathRegister.find(item => item.path == path)(loose==, first match); when a path was registered under multiple$sources only the first reset. Now iterates all registrations via_pathRegisterByPath.get(path).signalk-requests500/502/504 routing + 200 wording. 500/502/504 had descriptions but were routed to the "Unknown Request Status Code" toast (which then printed the description it claimed not to know). Now handled as known server errors surfaced as an error toast with their description. Also fixes the 200 message typo ("successfully"→"successful").Not included: #148
#148 (prev/next navigation inverted) was requested but is already fixed on
mainbyc5b858c4(2026-07-04), which corrected both cycling methods and theirnavigateTo*siblings, did the caller audit, and re-pinned the direction assertions. That commit recordedCloses #184, leaving #148 open as a stale duplicate — it should just be closed.Verification
npm run lint— clean.ng teston the three affected specs — 61/61 pass. Each updated/new assertion is a genuine regression catch (fails on the pre-fix code).npm run build:dev— clean.CI runs the full matrix (lint, vitest 20/22/24, build 20/22/24).
🤖 Generated with Claude Code