Skip to content

feat(engine): summarize the active rented-loop fleet for internal ops - #6130

Merged
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
luciferlive112116:feat/active-loop-fleet-summary
Jul 15, 2026
Merged

feat(engine): summarize the active rented-loop fleet for internal ops#6130
loopover-orb[bot] merged 1 commit into
JSONbored:mainfrom
luciferlive112116:feat/active-loop-fleet-summary

Conversation

@luciferlive112116

Copy link
Copy Markdown
Contributor

Summary

Closes #4808

No dashboards or alerts exist for the internal ops team to monitor active rented loops. The issue's acceptance criterion is that an internal operator can see every currently active rented loop and its status at a glance.

This adds that view's pure decision core. buildActiveLoopFleetSummary(loops) takes the fleet as ops currently knows it and returns:

  • activeCount — loops still running, the number an operator reads first (plus totalCount for the whole set).
  • byStatus / byHealth — the breakdown by run status and health tier.
  • needingAttention — the loops misbehaving badly enough to need a human right now, worst-severity first.
  • loops — every loop, in a stable order.

That is what a dashboard panel renders and what an alert rule fires on, computed once, the same way, for both.

It reuses the escalation path rather than restating it. The vocabulary (LoopRunOutcome, LoopHealthTier) is loop-escalation.ts's (#4806) already-merged types, and needsAttention is not a second opinion — each row's flag is evaluateEscalation's own shouldEscalate for that loop. So the fleet view and the per-loop escalation path can never disagree about what "needs a human" means: one rule, called once per loop, not a second copy that drifts. A test asserts row.escalation equals evaluateEscalation(facts) exactly.

Scope — what this deliberately does not do

It summarizes only: no dashboard, no alert delivery, no IO, no clock read. Wiring panels and alert rules into the self-host observability stack is the integration this issue is blocked on #4793, so this core carries no opinion about Grafana or Alertmanager and stays correct whatever renders it. This is the same pure-decision-core shape the sibling Rent-a-Loop issues merged as (#4801, #4800, #4806, #4796, #4792).

  • Conventional Commit title (feat(engine): …).
  • Focused: one new pure module + its barrel export + its test. No existing behavior changed.
  • Follows CONTRIBUTING.md; no site//CNAME/lovable; no changelog edit.
  • Linked open issue (Closes Internal ops observability & alerting #4808, above).

Validation

  • git diff --check clean.
  • npm run build:miner — exit 0 (the engine package compiles + emits).
  • npm run typecheck — exit 0.
  • npx vitest run test/unit/loop-fleet-summary.test.ts test/unit/loop-escalation.test.ts19 tests passed (the sibling suite is included to prove the reused rule still holds).
  • Coverage on packages/loopover-engine/src/loop-fleet-summary.ts (in Codecov's coverage.include): 100% statements (17/17), 100% branch (4/4), 100% functions (6/6), 100% lines (15/15).
  • Rebased onto current main.

Invariants an operator's view must not get wrong — each tested:

Invariant Why it matters
Every status/tier key is always present (0 when none) A panel binds to a fixed set of keys and never renders a hole
Worst-severity first, loopId as tie-break A watched panel must not reshuffle between renders; input order cannot change the output
The caller's array is never mutated A summary must not reorder the fleet its caller still holds
No computed health tier reads as unknown, never healthy An operator must tell "nothing is wrong" from "nothing has checked yet"
Each row's decision is evaluateEscalation's The fleet view can't drift from the escalation path it summarizes
Each loop stays attributed to its own tenant Ops needs to see whose loop is misbehaving

Safety

  • No secrets, wallets, hotkeys, trust scores, rewards, private rankings, or private maintainer evidence. Rows carry only loop/tenant identifiers and status — no customer content, no payout or scoring value.
  • No auth/cookie/CORS/GitHub App/session change.
  • Additive and inert: a new module plus its barrel export. Nothing imports it yet, so runtime behavior is byte-identical until the (blocked) integration wires it up.
  • Pure and side-effect-free: no IO, no storage, no Date.now(), so it is deterministic and trivially testable.
  • This is an internal ops view spanning tenants by design (that is the issue's ask); it exposes nothing a tenant-facing surface would leak, since it carries only ids and status enums.
  • No API/OpenAPI/MCP change; no schema change; no generated artifact affected.
  • No UI changes; no changelog edit.

No dashboards or alerts exist for the internal ops team to monitor active
rented loops (JSONbored#4808). Its acceptance criterion is that an operator can
see every currently active rented loop and its status at a glance.

Add that view's pure decision core: buildActiveLoopFleetSummary takes the
fleet as ops currently knows it and returns how many loops are live, how
they break down by run status and health tier, and which ones need a
human right now -- what a dashboard panel renders and what an alert rule
fires on, computed once, the same way, for both.

It reuses loop-escalation.ts's (JSONbored#4806) already-merged vocabulary instead
of restating it, and calls evaluateEscalation itself per loop rather than
re-deciding what "needs a human" means. So the fleet view and the
per-loop escalation path cannot drift apart: there is one rule, called
once per loop, not a second copy. A test asserts each row's decision IS
evaluateEscalation's own output for that loop.

Summarizes only: no dashboard, no alert delivery, no IO, no clock read.
Wiring panels and alert rules into the self-host observability stack is
the integration this issue is blocked on (JSONbored#4793), so this core has no
opinion about Grafana or Alertmanager and stays correct whatever renders
it.

Invariants an operator's view must not get wrong, all tested: every
status/tier key is always present (0 when none) so a panel never renders
a hole; ordering is worst-severity-first with loopId as a deterministic
tie-break, so a watched panel never reshuffles between renders and input
order cannot change the output; the caller's array is never mutated; and
a loop with no computed health tier reads as "unknown" rather than being
assumed healthy -- an operator must be able to tell "nothing is wrong"
from "nothing has checked yet".

Closes JSONbored#4808
@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 15, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.32%. Comparing base (f825c9c) to head (b6b5d78).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #6130   +/-   ##
=======================================
  Coverage   95.32%   95.32%           
=======================================
  Files         596      597    +1     
  Lines       47117    47133   +16     
  Branches    15024    15026    +2     
=======================================
+ Hits        44914    44930   +16     
  Misses       1477     1477           
  Partials      726      726           
Flag Coverage Δ
shard-1 43.98% <18.75%> (-0.01%) ⬇️
shard-2 36.78% <18.75%> (+0.11%) ⬆️
shard-3 32.20% <100.00%> (-0.06%) ⬇️
shard-4 33.88% <18.75%> (-0.01%) ⬇️
shard-5 31.63% <18.75%> (-0.01%) ⬇️
shard-6 44.89% <18.75%> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
packages/loopover-engine/src/loop-fleet-summary.ts 100.00% <100.00%> (ø)

@loopover-orb loopover-orb Bot added the gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier. label Jul 15, 2026
@loopover-orb

loopover-orb Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Tip

🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-15 11:54:42 UTC

3 files · 1 AI reviewer · no blockers · readiness 100/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This adds a pure `buildActiveLoopFleetSummary` function that aggregates rented-loop facts into status/health breakdowns and a needs-attention list, delegating the escalation decision entirely to the existing `evaluateEscalation` (no restated logic). The counting, breakdown initialization (`byStatus`/`byHealth` fully populated to 0), and severity/loopId sort are all correctly implemented and traced through the visible test cases (converged-but-healthy count, unknown-health-not-healthy, stable tie-break by loopId). The test suite directly asserts `row.escalation` equals a fresh `evaluateEscalation(facts)` call, which is the right way to guarantee the two paths can't drift.

Nits — 4 non-blocking
  • loop-fleet-summary.ts: the `loops` field is documented as 'every loop, in a stable order' but is actually sorted by severity/loopId rather than preserving input order — worth clarifying the doc comment so a future caller doesn't assume insertion order is kept.
  • index.ts: the new export block duplicates re-export comment style already used for loop-escalation.js above it — fine, but consider consolidating the barrel comments if more fleet-summary-style modules get added.
  • Consider adding a test where `byStatus`/`byHealth` values are asserted with a mixed fleet that includes an 'unknown' health tier alongside a 'critical' one to fully exercise the `?? "unknown"` branch in combination with sorting.
  • The 109-line file's top-of-file comment block is fairly long relative to the code — could be trimmed since the JSDoc on `buildActiveLoopFleetSummary` already repeats most of the same rationale.
Signal Result Evidence
Code review ✅ No blockers 1 reviewer
Linked issue ✅ Linked #4808
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 120 registered-repo PR(s), 62 merged, 35 issue(s).
Contributor context ✅ Confirmed Gittensor contributor luciferlive112116; Gittensor profile; 120 PR(s), 35 issue(s).
Gate result ✅ Passing No configured blocker found.
Improvement ✅ Minor risk: clean · value: minor · LLM: moderate
Linked issue satisfaction

Partially addressed
This delivers a well-tested pure summarization core that computes the data an operator view would need, but the issue explicitly asks for a live internal dashboard panel and alert rules wired into the observability stack, and the PR itself states it deliberately does no dashboard, no alert delivery, and no IO, deferring that integration to #4793.

Review context
  • Author: luciferlive112116
  • Role context: outside_contributor
  • Public audience mode: oss maintainer
  • Lane context: Repository is configured for direct PR review.
  • Public profile languages: Python, JavaScript, MDX, Rust, TypeScript
  • Official Gittensor activity: 120 PR(s), 35 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Keep the PR focused and include validation evidence before maintainer review.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://gittensory.aethereal.dev/docs/loopover-commands

🧪 Experimental — new and may change.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit e9ecca2 into JSONbored:main Jul 15, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gittensor:feature Gittensor-scored feature linked to a feature issue — scores a 0.25x multiplier.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Internal ops observability & alerting

1 participant