Skip to content

feat(fleet): live health indicators with staleness detection (#1375) - #1389

Merged
jeonghun-jj-lee merged 6 commits into
feature/free-tier-fleetfrom
wt/live-fleet-health-1375
Sep 21, 2026
Merged

jeonghun-jj-lee merged 6 commits into
feature/free-tier-fleetfrom
wt/live-fleet-health-1375

Conversation

@jeonghun-jj-lee

Copy link
Copy Markdown
Contributor

Summary

Fleet sidebar connection indicators are now live and robust — peer dots reflect real-time reachability, not frozen enrollment-time health.

What changed

Two-layer heartbeat + staleness detection:

  1. FleetHeartbeat class (fleet_heartbeat.ts) — each machine periodically re-POSTs its own roster row with a fresh last_report timestamp (60s interval). Single-writer invariant preserved: each machine only writes its own row.

  2. effectiveHealth() (sidebar_fleet_section.ts) — computes display health from last_report age:

    • < 3 min → green (reachable)
    • 3–5 min → yellow (degraded)
    • > 5 min → red (down)
    • Enrollment-time failures (degraded/down) are never overridden by staleness.
  3. Staleness sweep — 60s setInterval in sidebar view calls pushFleetStatus() so dots transition even when roster.json is static.

  4. Enhanced tooltips — dot and row tooltips show relative age + staleness annotation when display health differs from roster health.

Tests

28 new tests across 3 files covering:

  • effectiveHealth boundary conditions (all threshold transitions)
  • formatAge output formatting
  • Staleness-annotated tooltips
  • Heartbeat start/stop/tick lifecycle
  • Staleness sweep timer in sidebar view

Also fixes 2 pre-existing test failures:

  • skills_integrity: added create-a-fleet/SKILL.md:companion to known-list
  • amicode_service_runner: replaced gitignored ENGINE_BIN with stub executable

Full suite green: 260 files, 4136 tests passed, 0 failed.

Closes #1375

…uildFleetSectionModel (#1375)

Layer 1: effectiveHealth pure function with DEGRADED_AGE_MS (180s) and
DOWN_AGE_MS (300s) staleness thresholds. formatAge helper for tooltips.

Layer 2: buildFleetSectionModel now accepts an injectable clock (now?),
maps roster rows through effectiveHealth, carries rosterHealth (raw) and
now through to the model. Self-row and canonical-server are EXEMPT.

Existing tests preserved via pinned clock in test input() helper.
…1375)

Layer 3: deviceTooltip now shows relative age (formatAge) instead of raw
ISO timestamps when now is available, and annotates staleness-derived
health changes with 'degraded (no heartbeat)' / 'down (no heartbeat)'.
renderDeviceRow passes model.now through.
Layer 4: 60s setInterval in resolveWebviewView re-pushes fleet status so
display health transitions (reachable → degraded → down) even when the
roster file is static. Cleaned up in onDidDispose.
Layer 5: FleetHeartbeat periodically POSTs this machine's own roster row
with health: 'reachable' and a fresh last_report to POST /amicode/roster.
Full DI seams for testability. Guards: no-op when resolveIdentity returns
null. Errors swallowed silently (next tick is the retry).
…tures (#1375)

Layer 6: FleetHeartbeat started after sidebar setup in activate(), with
lazy service endpoint resolution. Disposed in deactivate() and via
ctx.subscriptions.

Also fixes sidebar_view.test.ts test fixtures: deviceRow helper now uses
Date.now() for last_report so effectiveHealth staleness doesn't falsely
degrade reachable rows in the test harness.
- lint-skills-known.txt: add create-a-fleet companion exemption for
  tools/fleet/README.md (a repo-root cross-reference, same pattern as
  the other known entries)
- amicode_service_runner.test.ts: use a stub engine binary for the
  'no app dist' test so it doesn't depend on the gitignored vendored
  binary (absent in worktrees and CI without a build step)
@coderabbitai

coderabbitai Bot commented Sep 21, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: b6ae7dc6-4130-4255-b181-20f77bd6a599

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jeonghun-jj-lee
jeonghun-jj-lee merged commit 268b898 into feature/free-tier-fleet Sep 21, 2026
5 checks passed
@jeonghun-jj-lee
jeonghun-jj-lee deleted the wt/live-fleet-health-1375 branch September 21, 2026 17:33
jeonghun-jj-lee added a commit that referenced this pull request Sep 23, 2026
…1389)

* feat(fleet): effectiveHealth + formatAge + staleness integration in buildFleetSectionModel (#1375)

Layer 1: effectiveHealth pure function with DEGRADED_AGE_MS (180s) and
DOWN_AGE_MS (300s) staleness thresholds. formatAge helper for tooltips.

Layer 2: buildFleetSectionModel now accepts an injectable clock (now?),
maps roster rows through effectiveHealth, carries rosterHealth (raw) and
now through to the model. Self-row and canonical-server are EXEMPT.

Existing tests preserved via pinned clock in test input() helper.

* feat(fleet): enhanced tooltip with formatAge + staleness annotation (#1375)

Layer 3: deviceTooltip now shows relative age (formatAge) instead of raw
ISO timestamps when now is available, and annotates staleness-derived
health changes with 'degraded (no heartbeat)' / 'down (no heartbeat)'.
renderDeviceRow passes model.now through.

* feat(fleet): staleness sweep timer in sidebar view (#1375)

Layer 4: 60s setInterval in resolveWebviewView re-pushes fleet status so
display health transitions (reachable → degraded → down) even when the
roster file is static. Cleaned up in onDidDispose.

* feat(fleet): FleetHeartbeat class — periodic roster self-report (#1375)

Layer 5: FleetHeartbeat periodically POSTs this machine's own roster row
with health: 'reachable' and a fresh last_report to POST /amicode/roster.
Full DI seams for testability. Guards: no-op when resolveIdentity returns
null. Errors swallowed silently (next tick is the retry).

* feat(fleet): wire FleetHeartbeat in extension.ts + fix stale test fixtures (#1375)

Layer 6: FleetHeartbeat started after sidebar setup in activate(), with
lazy service endpoint resolution. Disposed in deactivate() and via
ctx.subscriptions.

Also fixes sidebar_view.test.ts test fixtures: deviceRow helper now uses
Date.now() for last_report so effectiveHealth staleness doesn't falsely
degrade reachable rows in the test harness.

* fix(test): resolve pre-existing test failures in worktree builds (#1375)

- lint-skills-known.txt: add create-a-fleet companion exemption for
  tools/fleet/README.md (a repo-root cross-reference, same pattern as
  the other known entries)
- amicode_service_runner.test.ts: use a stub engine binary for the
  'no app dist' test so it doesn't depend on the gitignored vendored
  binary (absent in worktrees and CI without a build step)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant