Skip to content

feat(observatory): stale-claim badge on the fleet view (#133)#1433

Merged
jaylfc merged 2 commits into
devfrom
feat/observatory-stale-badge
Jun 25, 2026
Merged

feat(observatory): stale-claim badge on the fleet view (#133)#1433
jaylfc merged 2 commits into
devfrom
feat/observatory-stale-badge

Conversation

@jaylfc

@jaylfc jaylfc commented Jun 25, 2026

Copy link
Copy Markdown
Owner

What

Adds a board-only staleness signal to GET /api/observatory/fleet. Each working agent now carries held_seconds (age of its claimed card) and stale (true past STALE_CLAIM_SECONDS = 1800s). Idle agents keep the same shape (held_seconds: null, stale: false).

Why

First non-gated slice of #133 (Observatory probe/badges). A hung or wedged lane holding a claim with no progress is exactly what the pause switch hides; the badge surfaces it. This is the board-only half of the decision-30 stale-claim signal (the no-trace-progress half needs the lane to trace-slug mapping and is phase 2).

Scope

Purely additive to the fleet endpoint; pause/throttle untouched. claimed_at is guarded (missing/None never breaks the view).

Tests

3 new (fresh claim not stale, backdated claim stale, idle uniform shape); full observatory route + taosctl suites green (17 + 13).

Summary by CodeRabbit

  • New Features
    • The Observe fleet view now includes how long each agent has been holding its current task.
    • Claimed tasks are flagged as stale once the hold time exceeds the threshold.
    • Idle agents now return a consistent payload format (including held_seconds: null and stale: false), with claim-age handling resilient to clock skew.
  • Tests
    • Added integration coverage for fresh claims, stale claims, idle agents, and future-dated (clock-skew) claims in the fleet endpoint.

Enrich each fleet agent with held_seconds and a stale flag derived from the
claimed_at on its held card, so a hung or wedged lane that the pause switch
would otherwise hide is visible at a glance. Board-only signal (claim age);
threshold STALE_CLAIM_SECONDS = 1800. Idle agents keep the same shape
(held_seconds null, stale false). A richer no-trace-progress check is phase 2
once the lane to trace-slug mapping is wired.
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 401836c8-42f6-45b4-bf5f-6c1a340acd8d

📥 Commits

Reviewing files that changed from the base of the PR and between 8859d4a and b800a9c.

📒 Files selected for processing (2)
  • tests/test_routes_observatory.py
  • tinyagentos/routes/observatory.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/test_routes_observatory.py
  • tinyagentos/routes/observatory.py

📝 Walkthrough

Walkthrough

Adds held_seconds and stale to /api/observatory/fleet for claimed and idle agents, and adds integration tests for fresh, stale, idle, and clock-skew cases.

Changes

Fleet stale badge update

Layer / File(s) Summary
Fleet response fields
tinyagentos/routes/observatory.py
get_fleet adds claim-age calculation and returns held_seconds and stale on working and idle agent records.
Fleet badge tests
tests/test_routes_observatory.py
Async integration tests cover a fresh claim, a backdated stale claim using STALE_CLAIM_SECONDS, an idle registered agent, and a future-skewed claim.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

A bunny hopped through observatory light,
Counting claim-age by moonbeam bright.
Fresh ears bounce, stale ones softly glow,
Idle paws still in the roster show.
🐇✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding stale-claim signaling to the observatory fleet view.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/observatory-stale-badge

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.

@gitar-bot

gitar-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

Note

Your trial team has used its Gitar budget, so automatic reviews are paused. Upgrade now to unlock full capacity. Comment "Gitar review" to trigger a review manually.
Learn more about usage limits

Code Review ✅ Approved

Integrates stale-claim status into the fleet API response by surfacing claim age and staleness triggers for active agents. No issues found in the implementation or test coverage.

Options

Display: compact → Showing less information.

Comment with these commands to change:

Compact
gitar display:verbose         

Important

Your trial ends in 2 days — upgrade now to keep code review, CI analysis, auto-apply, custom automations, and more.

Was this helpful? React with 👍 / 👎 | Gitar

claimed_at = t.get("claimed_at")
held_seconds = int(now - claimed_at) if claimed_at else None
agents.append({
"handle": handle,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

WARNING: Clock-skew edge cases for held_seconds

Two related edge cases on this line:

  1. Negative held_seconds under clock skew. int(now - claimed_at) can produce a negative value if the agent's clock was ahead of the server when the claim was written (or if the row's claimed_at is from a different host). A negative age will be returned to the client and will also defeat the stale check (>= STALE_CLAIM_SECONDS is false for negatives). Clamp with max(0, int(now - claimed_at)) so the UI never shows a negative age and a freshly-claimed-but-clock-skewed agent can't accidentally appear unstuck.

  2. claimed_at == 0 is treated as missing. if claimed_at is falsy for the Unix epoch (1970-01-01). The comment says the guard is for missing/None, but a literal 0 would also be coerced to None here and the field would silently lose its badge. Use if claimed_at is not None so the guard matches the stated intent.

Suggested change
"handle": handle,
held_seconds = max(0, int(now - claimed_at)) if claimed_at is not None else None

Reply with @kilocode-bot fix it to have Kilo Code address this issue.

@kilo-code-bot

kilo-code-bot Bot commented Jun 25, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

The previous review's clock-skew edge cases (int(now - claimed_at) going negative and if claimed_at treating epoch-0 as missing) have both been resolved in commit b800a9c:

  • claimed_at is not None now correctly preserves an epoch-0 timestamp
  • max(0, int(now - claimed_at)) clamps any future-stamped claim to a non-negative age

The new test_fleet_clamps_held_seconds_under_clock_skew test exercises the future-claimed_at path and verifies held_seconds == 0, which matches the production behavior.

Files Reviewed (2 files)
  • tinyagentos/routes/observatory.py - 0 issues (previous issue resolved)
  • tests/test_routes_observatory.py - 0 issues
Previous Review Summary (commit 8859d4a)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 8859d4a)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
tinyagentos/routes/observatory.py 217 Clock-skew edge cases: int(now - claimed_at) can go negative, and if claimed_at treats the Unix epoch (0) as missing instead of None only.
Files Reviewed (2 files)
  • tinyagentos/routes/observatory.py - 1 issue
  • tests/test_routes_observatory.py - 0 issues

Fix these issues in Kilo Cloud


Reviewed by minimax-m3 · Input: 28.6K · Output: 1.5K · Cached: 111.4K

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tinyagentos/routes/observatory.py`:
- Around line 212-215: The held age calculation in the observatory view can go
negative when claimed_at is in the future or the clock skews, so clamp the
computed age to zero in the route logic that sets held_seconds. Update the age
handling in the observatory response builder (where claimed_at is read and
held_seconds is derived) to keep the “age in seconds” value non-negative while
still leaving missing/None values as None.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 58bfac27-0753-41d8-a547-86ee4ba064c4

📥 Commits

Reviewing files that changed from the base of the PR and between 00116e9 and 8859d4a.

📒 Files selected for processing (2)
  • tests/test_routes_observatory.py
  • tinyagentos/routes/observatory.py

Comment thread tinyagentos/routes/observatory.py Outdated
Fold gitar edge-case: use 'claimed_at is not None' so an epoch-0 timestamp is
not read as missing, and max(0, ...) so clock skew (a claim stamped slightly in
the future) cannot report a negative age. Adds a clock-skew test.
@jaylfc jaylfc enabled auto-merge (squash) June 25, 2026 11:37
@jaylfc jaylfc merged commit b95bb9b into dev Jun 25, 2026
8 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in TinyAgentOS Roadmap Jun 25, 2026
jaylfc added a commit that referenced this pull request Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

1 participant