Skip to content

[Goal by Claude Opus 5.5] Add Agent Tank Usage History Charts to ProPR - #3218

Merged
integry merged 8 commits into
mainfrom
goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4
Oct 20, 2026
Merged

integry merged 8 commits into
mainfrom
goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Conversation

@propr-dev

@propr-dev propr-dev Bot commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Goal Implementation Summary

✅ Goal completed successfully.

Goal: Agent Tank has received a significant new update - different/unified JSON data structure, support for Gemini 4 Argon (separately tracked value) and historical data, which would also allow plotting graphs in ProPR to show the usage change line for different agents/metrics. We could show a unified usage chart in Analytics (with options to show only certain agents/metrics or all of them). In addition when hovering (or tapping on mobile), a specific metric in the usage section in the sidebar it would show a chart overlay showing the changes in usage for the last 2 periods (for example for a 5h session, it would be a 10h chart, for a weekly limit it would be a 2 week chart, etc)
Branch: goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4
Goal ID: e0d6a5d6-fd83-43c1-ba9e-45254c61b1e6

Summary of Changes

Everything the goal asked for is built and published; the last checkpoint is commit 851e99d. The charts have only been tested and screenshotted against mocked data. They haven't run against a real Agent Tank 0.10 daemon or a rebuilt agent image.

  • Agent Tank 0.10.0: the bundled image now ships 0.10.0. ProPR reads the new { "providers": [...] } format and still accepts the old 0.9.x map, so an external daemon can be upgraded before or after ProPR. ProPR's local fixes still weren't upstream, so I rebased the patch onto 0.10.0.
  • Gemini 4 Argon: it appears in the sidebar under its own "Gemini 4 Argon" group with a "Weekly" row, and has its own history line.
  • History: bundled mode throws away Agent Tank's own history after every run, so ProPR now records a point per metric each time it reads Agent Tank and keeps 15 days. In external mode it uses the daemon's own history when the daemon keeps one, and falls back to ProPR's record otherwise. The data is served at GET /api/config/agent-tank/history.
  • Analytics chart: one chart plots every agent's metrics on a 0–100% scale. You can pick a range from 24 hours to 14 days and toggle providers and individual metrics. A table shows each line's latest, lowest and highest value. The pane is hidden when Agent Tank is off or the viewer can't read usage.
  • Sidebar overlay: hovering a metric on desktop, or tapping it on touch screens and in the mobile usage sheet, opens a chart of its last two periods. That's 10 hours for a 5-hour session and 14 days for a weekly limit, with a dashed marker where the current period began.

Results:

  • UI unit tests: the full suite passes, 2,879 tests.
  • End-to-end: the new Playwright spec passes 4 of 4. The existing related specs pass 63 of 63.
  • Backend: the Agent Tank suites pass, including new ones for the new format, history storage and the history endpoint.

Things you might trip over:

  • Gaps in bundled-mode history: ProPR's own history only gets points while something is reading usage, for example an open ProPR tab. Expect gaps when nobody has ProPR open.
  • More than 8 metrics: the Analytics chart draws at most 8 lines, one per available color. Any extra metrics are listed as "not plotted" rather than drawn in a repeated color.
  • Duplicate tooltips: sidebar rows keep their existing native tooltip. On a long hover it shows alongside the new overlay.

The previews are attached to the PR.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Time: 24m 49s
  • Tokens: 14,978,570 (14,920,588 in / 57,982 out)
  • Cost: $14.57

💡 Need changes?

Comment on this PR to request refinements — the AI agent monitors comments and will update the implementation based on your feedback.


This PR description was updated automatically by ProPR after the goal completed.


Visual preview

Analytics: unified quota usage chart

Analytics: unified quota usage chart

Every agent's session, weekly and per-model quota (including Antigravity's Gemini 4 Argon) on one 0-100% chart over the last 7 days. Provider chips and per-metric chips toggle lines, with the crosshair tooltip open. Mocked history data.

Original unavailable: managed storage is unavailable or the upload has expired.

Analytics usage chart on a phone

Analytics usage chart on a phone

The same pane at 390px over 3 days: filters wrap under each provider, and the chart fits above the bottom navigation.

Original unavailable: managed storage is unavailable or the upload has expired.

Sidebar metric hover overlay

Sidebar metric hover overlay

Hovering Claude's Session row opens a chart of the last 10 hours (two 5-hour sessions), with a dashed marker where the current session started.

Original unavailable: managed storage is unavailable or the upload has expired.

Tapping a weekly metric on mobile

Tapping a weekly metric on mobile

In the mobile API & quota usage sheet, tapping Antigravity's Gemini 4 Argon weekly quota shows the last 14 days (two weekly periods) in a full-width card with a close button.

Original unavailable: managed storage is unavailable or the upload has expired.

@propr-dev propr-dev Bot added the AI label Oct 18, 2026
@integry
integry marked this pull request as ready for review October 18, 2026 09:30
@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

11 similar comments
@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

❌ Failed to resolve merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4

Existing worktree retained; branch is in use

System-triggered merge conflict resolution

Repository owner deleted a comment from propr-dev Bot Oct 18, 2026
@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

🔀 Resolved merge conflicts from main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4 in commit a327ce6

Conflicting Files

  • docs/static/openapi/propr-api.yaml

Resolution Summary

I resolved the one merge conflict, in docs/static/openapi/propr-api.yaml. No other file in the repo has conflict markers.

What the conflict was: both branches changed the route-coverage counts in the spec's info.x-route-coverage block. The PR side said total: 304, documented: 68, undocumented: 236; main said total: 304, documented: 69, undocumented: 235. Neither side was right for the merged code, because each counted only its own branch's routes. main documented one more route (from the recent follow-up/review-outcome work), and the PR registers routes main doesn't have.

How I resolved it: this spec is generated from the route registry, so I reran npm run gen:openapi against the merged sources instead of picking one side. The result is total: 305, documented: 69, undocumented: 236. That keeps main's newly documented route and counts the PR's routes too. The counts block is the only part of the file that changed; the rest of the spec was already the same on both sides.

Why: editing a generated file by hand would likely fail the gen:openapi:check CI gate, and both hand-picked versions had the wrong total.

Checks:

  • No conflict markers left anywhere.
  • npm run gen:openapi:check passes: the spec and client types are current and valid (305 routes, 69 documented, 236 undocumented).
  • The route-coverage test (packages/api/test/openapiRouteCoverage.test.ts) passes, 16 of 16.

🤖 Resolution Details

  • Model: Claude Opus 5.5
  • Time: 2m 33s

View Task Execution


System-triggered merge conflict resolution

…-agent-tank-has-received-a-20261017-2303-az4

Automatically resolved merge conflicts after merging target branch into PR branch.
Resolved conflicts in:
- docs/static/openapi/propr-api.yaml

PR: #3218
Model: Claude Opus 5.5
@integry

integry commented Oct 18, 2026

Copy link
Copy Markdown
Owner

/merge

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

🔀 Auto-merged main into goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4 (clean merge) in commit a327ce6

No conflicts were found — the merge was verified by an AI agent.


🤖 Verification Details

  • Model: Claude Opus 5.5
  • Time: 1m 53s

View Task Execution


System-triggered merge conflict resolution

Repository owner deleted a comment from mcptestio Oct 18, 2026
@integry

integry commented Oct 18, 2026

Copy link
Copy Markdown
Owner

/review

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR adds compatible status parsing, persistent usage history, an Analytics chart, and sidebar history overlays. It needs changes before merge: some metrics are permanently inaccessible, downsampling makes summary statistics inaccurate, and failed writes can suppress later retries.

✅ Backward compatibility — Both canonical provider arrays and legacy status maps pass through shared parsing used by bundled and external reads.

✅ Scoped history access — The new endpoint reuses the existing usage-access guard and validates timestamp ordering.

✅ Interaction coverage — Added tests cover hover intent, touch interaction, cancellation, metric filtering, and history persistence. Current head checks report 28 passed and no failures.

This assessment is based on static inspection of the supplied code; no commands were run.

Merge blockers

Every finding below was introduced by this PR and must be resolved before merging.

F1: 🔴 Metrics beyond eight cannot be selected

  • Required behavior: Analytics must allow users to select particular agents and metrics; limiting simultaneous plotted lines must not permanently exclude available metrics.

  • Evidence: propr-ui/src/components/Analytics/AgentUsageHistory.tsx:116–120 — selection is restricted before user filters are applied.

    1. A history response contains nine or more series.
    2. all.slice(0, MAX_USAGE_SERIES) permanently excludes the ninth and subsequent series from colored.
    3. Both metric controls and chart/table contents derive from that truncated array.
    4. Hiding the first eight metrics or their providers never makes the excluded metrics selectable. Users cannot inspect those metrics even individually.

    The overflow message acknowledges missing metrics but offers no recovery; “Show all” only clears filters. The same restriction affects the table. static trace: followed all → colored → offered → visible and the controls rendering offered.

  • Minimum fix: Offer selection controls for every series and apply the eight-line limit to the selected plotted series. Allow users to replace selected lines with previously excluded metrics, and keep all selected metrics accessible in the table.

F2: 🔴 Downsampling changes reported extrema

  • Required behavior: The table’s lowest and highest readings over the selected range must reflect recorded data, rather than only points retained for drawing.

  • Evidence: packages/core/src/services/agentTankHistoryService.ts:downsampleHistoryPoints, propr-ui/src/components/Analytics/usageHistoryView.ts:toPlottedSeries — extrema are calculated after lossy sampling.

    1. A series contains 1,200 evenly spaced readings, all zero except the second reading at 100%.
    2. With the default 600-point cap, the second and third readings fall in the same bucket. Keeping the bucket’s last point discards the 100% reading.
    3. The endpoint returns only the downsampled points.
    4. toPlottedSeries calculates max from those points, so the table reports “Highest 0%” despite a recorded 100% reading.

    Preserving the first and last points does not preserve interior extrema. Existing sampling tests assert only length and endpoints. static trace: evaluated the bucket calculation and traced the returned points into the table’s statistics.

  • Minimum fix: Calculate range statistics before downsampling and return them separately, or preserve the original extrema in the sampled output so the displayed minimum and maximum remain accurate.

F3: 🔴 Failed writes suppress snapshot retries

  • Required behavior: History deduplication must acknowledge successfully persisted samples, not discard samples merely because a write was attempted.

  • Evidence: packages/core/src/services/agentTankUsageHistory.ts:rowsToRecord and recordAgentTankUsageHistory — the deduplication baseline advances before persistence succeeds.

    1. A fresh snapshot reaches rowsToRecord, which updates lastRecorded for each metric.
    2. The awaited database insert rejects, for example during temporary database unavailability. The catch returns zero, but retains those updated baselines.
    3. Storage recovers and an aggregate read returns the same cached snapshot.
    4. capturedAtMs <= previous.capturedAtMs skips every affected metric, so the snapshot is never retried. A subsequent fresh snapshot with unchanged values is also suppressed until the heartbeat threshold.

    The catch preserves usage-read availability but does not restore recording eligibility. The heartbeat cannot recover the lost capture, and repeated reads of that capture remain suppressed indefinitely. static trace: followed baseline mutation, insert rejection, catch, and the subsequent deduplication checks; no fault-injection test was executed.

  • Minimum fix: Commit deduplication baselines only after a successful insert. Serialize recording attempts or otherwise protect concurrent baseline updates so failure recovery does not overwrite a newer successful baseline.

Suggestions

These are optional follow-ups and are not sent to /fix.

S1: 🟢 Validate the actual daemon contract

Run a smoke test against Agent Tank 0.10 and the rebuilt image, including /history/:id, metric filtering, and fallback behavior. The supplied coverage validates constructed payloads, while the implementation summary explicitly identifies live integration as untested. This is additional confidence work rather than a demonstrated compatibility defect.

S2: 🟢 Refresh open Analytics charts

Consider refreshing history on usage-update events or a bounded interval. useUsageHistoryRead currently fetches only on mount and range changes, so an open chart retains its original endpoint and values. Automatic refresh would improve monitoring, although the objective does not explicitly require live Analytics updates.

Score

The implementation has substantial coverage and clean current checks, but three localized correctness issues remain in metric access, summary accuracy, and persistence recovery.

Score: 6/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 55s
  • Tokens: 99,419 (97,664 in / 1,755 out)
  • Cost: $0.95

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix F1 F2 F3 S1 S2

🤖 Review by ProPR

@integry

integry commented Oct 18, 2026

Copy link
Copy Markdown
Owner

/ultrafix

@propr-dev propr-dev Bot added the ultrafix label Oct 18, 2026
@propr-dev

propr-dev Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

🔄 Ultrafix loop started (goal: 8/10, max cycles: 10)

First action: /fix

💡 Tip: Remove the ultrafix label from this PR to stop further ultrafix cycles.

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit c3765b2

Addressed 1 AI review comment (IDs: 6254069330)

Addressed findings F1, F2, F3

Summary of Changes

F1, F2 and F3 are fixed, each with regression tests. Every new backend and UI unit test failed against the old code and passes now.

F1: metrics past eight can now be selected (AgentUsageHistory.tsx, usageHistoryView.ts)

  • Every series gets a chip. The eight-line limit now applies only to what the chart draws: the first eight selected series. The table lists every selected series.
  • A new helper, planPlottedSeries, picks which series are drawn and their colors. Drawn series keep their usual color, so nothing changes when there are eight or fewer. A series past the palette takes the color of a line you've hidden, so hiding one metric lets an extra one onto the chart without recoloring the rest.
  • A selected series that isn't drawn shows a hollow dot and a "not plotted" label. The message now reads "N selected metrics are not plotted… hide one to plot another, or see them all in the table".
  • Tests: a component test with 10 series (all chips present, swapping a line in, table shows all selected), a test for the color rule, and a new Playwright case.

F2: lowest and highest readings now match the recorded data (downsampleHistoryPoints)

  • Thinning now keeps the lowest and highest reading in each time bucket, in time order, plus the first and last points. It stays within the point limit.
  • Every recorded extreme reaches the client, so the table's lowest and highest values are exact. Short spikes also stay visible on the chart.
  • Points with no percentage are never picked as an extreme. Points that all share one timestamp are handled too.
  • Test: your example (1,200 readings, a 100% spike at the second reading) now keeps 100%, plus an interior minimum and the same-timestamp case.

F3: a failed write no longer blocks retries (agentTankUsageHistory.ts)

  • The duplicate check no longer updates its record of the last stored reading per metric while scanning. It saves those values only after the database insert succeeds. If the insert fails, nothing is saved, so the same cached snapshot is retried later.
  • Recording attempts now run one at a time. A later attempt waits for the one in progress, so it never deduplicates against a write that hasn't succeeded yet, and a failed attempt can't overwrite a newer successful one.
  • Tests: a database that rejects inserts, then recovers and stores the same snapshot; and two concurrent attempts where the first fails, the second succeeds, and the failed older snapshot isn't stored afterwards.

Checks run:

  • History storage suite: 11/11 pass.
  • History endpoint suite: 14/14 pass (it needs --experimental-test-module-mocks).
  • Analytics and usage-history UI tests: 62/62 pass.
  • The Playwright spec: 5/5 pass in Chromium.
  • tsc passes for core and the UI, and eslint with zero warnings passes on the changed core, UI and e2e files. The root test/ file isn't covered by any eslint config.

Separate issue, not fixed: the cleanup of rows older than 15 days records its run time before the delete runs. If the delete fails, it won't retry for an hour. That's outside F3, which is about the duplicate check.

I attached a preview of the Analytics pane with ten series, after one line was swapped for an extra metric. It uses mocked data.

Visual preview

Analytics: more than eight metrics

Analytics: more than eight metrics

Ten series with mocked data. Every metric has a chip. After Claude · Fable is hidden, Gemini 4 Flash takes its line and color. GPT-OSS stays selected with a hollow dot and is marked not plotted, and the note explains how to swap lines or use the table.

Original unavailable: managed storage is unavailable or the upload has expired.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Requested By: @integry
  • Time: 8m 0s
  • Tokens: 1,743,764 (1,725,277 in / 18,487 out)
  • Cost: $1.07
  • Subscription usage: Session +1%, Weekly +1%

Undo Changes • View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR
Processing comment ID: 6254080496✓

…new backend and UI unit test failed against the old code and passes now.

F1, F2 and F3 are fixed, each with regression tests. Every new backend and UI unit test failed against the old code and passes now.

**F1: metrics past eight can now be selected** (`AgentUsageHistory.tsx`, `usageHistoryView.ts`)
- Every series gets a chip. The eight-line limit now applies only to what the chart draws: the first eight selected series. The table lists every selected series.
- A new helper, `planPlottedSeries`, picks which series are drawn and their colors. Drawn series keep their usual color, so nothing changes when there are eight or fewer. A series past the palette takes the color of a line you've hidden, so hiding one metric lets an extra one onto the chart without recoloring the rest.
- A selected series that isn't drawn shows a hollow dot and a "not plotted" label. The message now reads "N selected metrics are not plotted… hide one to plot another, or see them all in the table".
- Tests: a component test with 10 series (all chips present, swapping a line in, table shows all selected), a test for the color rule, and a new Playwright case.

**F2: lowest and highest readings now match the recorded data** (`downsampleHistoryPoints`)
- Thinning now keeps the lowest and highest reading in each time bucket, in time order, plus the first and last points. It stays within the point limit.
- Every recorded extreme reaches the client, so the table's lowest and highest values are exact. Short spikes also stay visible on the chart.
- Points with no percentage are never picked as an extreme. Points that all share one timestamp are handled too.
- Test: your example (1,200 readings, a 100% spike at the second reading) now keeps 100%, plus an interior minimum and the same-timestamp case.

**F3: a failed write no longer blocks retries** (`agentTankUsageHistory.ts`)
- The duplicate check no longer updates its record of the last stored reading per metric while scanning. It saves those values only after the database insert succeeds. If the insert fails, nothing is saved, so the same cached snapshot is retried later.
- Recording attempts now run one at a time. A later attempt waits for the one in progress, so it never deduplicates against a write that hasn't succeeded yet, and a failed attempt can't overwrite a newer successful one.
- Tests: a database that rejects inserts, then recovers and stores the same snapshot; and two concurrent attempts where the first fails, the second succeeds, and the failed older snapshot isn't stored afterwards.

**Checks run:**
- History storage suite: 11/11 pass.
- History endpoint suite: 14/14 pass (it needs `--experimental-test-module-mocks`).
- Analytics and usage-history UI tests: 62/62 pass.
- The Playwright spec: 5/5 pass in Chromium.
- `tsc` passes for core and the UI, and eslint with zero warnings passes on the changed core, UI and e2e files. The root `test/` file isn't covered by any eslint config.

**Separate issue, not fixed:** the cleanup of rows older than 15 days records its run time before the delete runs. If the delete fails, it won't retry for an hour. That's outside F3, which is about the duplicate check.

I attached a preview of the Analytics pane with ten series, after one line was swapped for an extra metric. It uses mocked data.

PR: #3218
Comment by: @integry (ID: 6254080496)
Model: Claude Opus 5.5
@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @propr-ultrafix

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR adds compatibility parsing, persistent usage history, Analytics charts, and sidebar overlays. It needs changes before merge, primarily to preserve the demo-data access boundary.

✅ Backward compatibility — Both canonical provider envelopes and legacy status maps pass through a shared parser.

✅ Recoverable history writes — Recording is serialized, and failed inserts leave snapshots eligible for retry.

✅ Accessible numeric alternative — The Analytics table includes every selected metric, including those beyond the chart’s eight-line limit.

This review uses static analysis of the supplied code; no commands were run. Current checks report 20 passed, six pending, and no failures.

Merge blockers

Every finding below was introduced by this PR and must be resolved before merging.

F4: 🔴 Demo access exposes real usage history

  • Required behavior: Demo access must expose synthetic usage data, not real installation usage.

  • Evidence: packages/api/routeRegistry.ts:119, packages/api/routes/configRoutesAgentTank.ts:getAgentTankHistory

    1. A request authenticated with authorization source demo reaches the new history endpoint on an instance with Agent Tank enabled.
    2. requireAgentTankUsageAccess explicitly lets demo requests through without requiring agent-management permission.
    3. The new handler unconditionally calls readAgentTankUsageHistory, which reads the installation’s persisted history and, in external mode, its configured daemon.
    4. The demo caller receives real provider quota history.

    The guard’s documented exception is justified by synthetic demo data, but this handler has no demo-data substitution or refusal. Time and metric filtering do not enforce that boundary. static trace: the supplied guard, new route registration, handler, and history service establish this path.

  • Minimum fix: Return synthetic history for demo requests, or require agent-management permission for this endpoint until a synthetic history response exists.

F5: 🔴 Disabling history permanently disables sidebar triggers

  • Required behavior: Sidebar history must become available again when Agent Tank is re-enabled.

  • Evidence: propr-ui/src/components/usageHistory/useUsageMetricHistory.ts:historyDisabled, propr-ui/src/components/usageHistory/UsageMetricHistoryOverlay.tsx:UsageMetricHistoryTrigger

    1. With usage rows already rendered, Agent Tank is disabled and a row’s history request returns { enabled: false }.
    2. The hook sets the module-level historyDisabled flag to true.
    3. Agent Tank is subsequently re-enabled and usage rows render again.
    4. Every closed history trigger renders as an inert wrapper because the flag remains true; hovering or tapping cannot issue a request that discovers recovery.

    The cache’s 60-second TTL does not apply to this flag. Only the test-only reset function clears it, so even component unmounting and remounting cannot recover without reloading the application. static trace: flag assignment, exported reset function, and trigger early return.

  • Minimum fix: Expire the disabled state or clear it when enabled usage becomes available, allowing a subsequent interaction to retry.

F6: 🔴 Analytics exposes raw model identifiers

  • Required behavior: Newly visible model names, tooltips, and accessibility labels must use human-readable display names, as required by the supplied repository naming contract.

  • Evidence: propr-ui/src/components/usageHistory/usageHistoryModel.ts:usageMetricLabel, propr-ui/src/components/Analytics/AgentUsageHistory.tsx:series chip rendering

    1. A supported Antigravity usage entry contains a model identifier such as gemini-2.5-pro.
    2. agentTankUsageMetrics.ts:antigravityMetrics persists that identifier unchanged as the history series label.
    3. usageMetricLabel only strips quota suffixes, so the identifier becomes the Analytics chip text, chart/table label, and accessible name.
    4. The chip’s title also directly exposes series.label.

    The existing sidebar model path uses getModelDisplayName, but the new Analytics path bypasses that protection. static trace: metric extraction through history serialization and Analytics label rendering; no regression test was executed.

  • Minimum fix: Apply the shared model display helpers to model-derived history labels, including tooltips and accessibility text, while preserving quota-group wording and internal series keys.

Suggestions

These are optional follow-ups and are not sent to /fix.

S3: 🟢 Refresh open Analytics history

The Analytics reader fetches only on mount or range changes, despite existing usage-update events. Subscribing to those events would keep an open chart current. This is an optional freshness improvement; the existing response still represents its captured time range.

S4: 🟢 Validate the actual daemon contract

Add integration coverage against Agent Tank 0.10.0 and the rebuilt image. The supplied tests exercise mocked canonical responses and local storage, while daemon-history parsing and source selection lack equivalent end-to-end evidence. This would strengthen confidence beyond the mocked previews.

Score

The implementation has useful compatibility and storage coverage, but the demo-data disclosure and two UI regressions require correction. Pending checks are not treated as failures.

Score: 6/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 1m 19s
  • Tokens: 103,800 (102,163 in / 1,637 out)
  • Cost: $0.99

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix F4 F5 F6 S3 S4

🤖 Review by ProPR

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit 3455113

Addressed 1 AI review comment (IDs: 6254228265)

Addressed findings F4, F5, F6

Summary of Changes

I fixed F4, F5 and F6. Each new unit test failed on the previous code and passes now.

F4: demo access exposed real usage history

  • GET /api/config/agent-tank/history now requires the agent-management permission (packages/api/routeRegistry.ts:121). I didn't find any synthetic history to return, so refusing demo viewers was the safe choice. Demo viewers can still read the synthetic usage feed.
  • The UI side: in demo mode the sidebar metric rows no longer open a history overlay, so demo viewers don't get a 403 error inside it. The Analytics pane already hides itself when the request is refused.
  • Regressions: the route test now expects a 403 for demo viewers on the history endpoint, includes it in the member-denied and admin-allowed lists, and a UI test covers the demo sidebar.

F5: disabling history switched sidebar triggers off for good

  • The "history is off" flag now:
    • turns off by itself after 60 seconds, the same as the cache.
    • clears as soon as the sidebar reads usage with Agent Tank enabled.
    • clears when any history response comes back enabled.
  • Clearing it also drops cached "off" answers, so the next hover or tap really asks the server again.
  • Rows now update straight away when the flag changes. Before, closed rows only noticed on their next render.
  • Regressions cover rows going inactive while history is off, coming back after re-enabling (with a fresh request), and the 60-second expiry for rows outside the sidebar.
  • One timing gap remains and I left it: if an older "enabled" usage read lands after history was reported off, the flag clears early. The only cost is one extra request when someone next hovers a row.

F6: Analytics showed raw model identifiers

  • A new readableSeriesLabel in usageHistoryModel.ts puts model-derived labels through getModelDisplayName, the same helper the sidebar uses. gemini-2.5-pro now shows as "Gemini 2.5 Pro".
  • The same fix covers Codex per-model limits, which had the same raw-name problem.
  • Quota pool names such as "Claude and GPT · Weekly" and "Gemini 4 Argon Weekly" keep their wording. Series keys, colors and URL filters are unchanged.
  • The display name is now used for the chip text, accessible name, tooltip, chart legend and table.

Verification

  • UI: typecheck and lint are clean, and 302 tests pass across the usage-history, Analytics, sidebar and Settings suites.
  • Backend: the route authorization, OpenAPI route coverage and history route suites pass (35 tests).
  • End-to-end: agent-tank-usage-history.pw.ts passes 5 of 5.

Something else I ran into: the end-to-end spec's shared fixture signs in as a demo user. Its two sidebar-overlay tests only passed because of the F4 leak, so with the fix they failed. I changed that spec to sign in as a user with agent-management permission.

I didn't attach previews. With the mocked data, none of these fixes changes anything you'd see on screen.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Requested By: @propr-ultrafix
  • Time: 12m 10s
  • Tokens: 3,968,008 (3,943,285 in / 24,723 out)
  • Cost: $1.81
  • Subscription usage: Session +1%

View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR

…vious code and passes now.

I fixed F4, F5 and F6. Each new unit test failed on the previous code and passes now.

**F4: demo access exposed real usage history**
- `GET /api/config/agent-tank/history` now requires the agent-management permission (`packages/api/routeRegistry.ts:121`). I didn't find any synthetic history to return, so refusing demo viewers was the safe choice. Demo viewers can still read the synthetic usage feed.
- The UI side: in demo mode the sidebar metric rows no longer open a history overlay, so demo viewers don't get a 403 error inside it. The Analytics pane already hides itself when the request is refused.
- Regressions: the route test now expects a 403 for demo viewers on the history endpoint, includes it in the member-denied and admin-allowed lists, and a UI test covers the demo sidebar.

**F5: disabling history switched sidebar triggers off for good**
- The "history is off" flag now:
  - turns off by itself after 60 seconds, the same as the cache.
  - clears as soon as the sidebar reads usage with Agent Tank enabled.
  - clears when any history response comes back enabled.
- Clearing it also drops cached "off" answers, so the next hover or tap really asks the server again.
- Rows now update straight away when the flag changes. Before, closed rows only noticed on their next render.
- Regressions cover rows going inactive while history is off, coming back after re-enabling (with a fresh request), and the 60-second expiry for rows outside the sidebar.
- One timing gap remains and I left it: if an older "enabled" usage read lands after history was reported off, the flag clears early. The only cost is one extra request when someone next hovers a row.

**F6: Analytics showed raw model identifiers**
- A new `readableSeriesLabel` in `usageHistoryModel.ts` puts model-derived labels through `getModelDisplayName`, the same helper the sidebar uses. `gemini-2.5-pro` now shows as "Gemini 2.5 Pro".
- The same fix covers Codex per-model limits, which had the same raw-name problem.
- Quota pool names such as "Claude and GPT · Weekly" and "Gemini 4 Argon Weekly" keep their wording. Series keys, colors and URL filters are unchanged.
- The display name is now used for the chip text, accessible name, tooltip, chart legend and table.

**Verification**
- UI: typecheck and lint are clean, and 302 tests pass across the usage-history, Analytics, sidebar and Settings suites.
- Backend: the route authorization, OpenAPI route coverage and history route suites pass (35 tests).
- End-to-end: `agent-tank-usage-history.pw.ts` passes 5 of 5.

**Something else I ran into:** the end-to-end spec's shared fixture signs in as a demo user. Its two sidebar-overlay tests only passed because of the F4 leak, so with the fix they failed. I changed that spec to sign in as a user with agent-management permission.

I didn't attach previews. With the mocked data, none of these fixes changes anything you'd see on screen.

PR: #3218
Comment by: @propr-ultrafix (ID: 0)
Model: Claude Opus 5.5
@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @propr-ultrafix

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR adds compatible status parsing, persistent usage history, an Analytics chart, and sidebar overlays. It needs a localized change before merge: the chart cannot display all selected metrics as requested.

✅ Backward compatibility — Both canonical provider arrays and legacy status maps use shared parsing, with focused tests for both formats.

✅ Reliable recording retries — History writes serialize baseline updates and preserve failed snapshots for retry; tests cover concurrent and failed inserts.

✅ History authorization — The new endpoint requires agent-management permission and excludes the synthetic demo exception.

Current checks show 27 passed, none failed, and one pending. This review used static analysis only; no commands were run.

Merge blockers

Every finding below was introduced by this PR and must be resolved before merging.

F7: 🔴 Allow plotting all selected metrics

  • Required behavior: The original objective explicitly requests a unified usage chart with options to show selected agents/metrics “or all of them.”

  • Evidence: propr-ui/src/components/Analytics/usageHistoryView.ts, planPlottedSeries; propr-ui/src/components/Analytics/AgentUsageHistory.tsx, chart rendering.

    1. History returns more than eight metrics, as explicitly exercised by the new ten-series tests.
    2. With every metric selected, planPlottedSeries takes only selected.slice(0, MAX_USAGE_SERIES), where the maximum is eight.
    3. AgentUsageHistory passes only drawn to the chart. “Show all” clears filters but retains this limit.
    4. Users therefore cannot compare all metrics on the unified chart; plotting an omitted metric requires hiding another.

    The table and “not plotted” notice explain the omission but do not provide the requested all-metrics chart. Existing tests affirm the restriction rather than prevent it. static trace: verified through selection, planning, and rendering in the supplied diff.

  • Minimum fix: Permit all selected series to render, extending visual differentiation beyond eight colors, for example with additional colors or dash patterns. Preserve the existing filtering controls.

Suggestions

These are optional follow-ups and are not sent to /fix.

S5: 🟢 Validate the real daemon contract

The reported validation uses mocked data, and the new tests do not exercise history retrieval against a real Agent Tank 0.10 daemon. A focused integration check covering history-enabled, history-disabled, and bundled execution would strengthen confidence in the upstream response assumptions. This is additional verification, not a demonstrated code defect.

S6: 🟢 Refresh Analytics history while open

useUsageHistoryRead fetches only on mount or range changes, so its latest values remain fixed while sidebar usage continues updating. Consider subscribing to usage updates or adding a refresh control. Automatic Analytics refresh is not explicitly required, so this is optional.

Score

The implementation has substantial focused coverage and sound compatibility and recording logic, but its deliberate plotting limit leaves an explicit objective unmet. Real-daemon validation also remains outstanding.

Score: 6/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 45s
  • Tokens: 105,074 (103,930 in / 1,144 out)
  • Cost: $0.99

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix F7 S5 S6

🤖 Review by ProPR

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit bd54fe9

Addressed 1 AI review comment (IDs: 6254528632)

Addressed finding F7

Summary of Changes

I fixed F7: the Analytics usage chart now draws every selected metric. The eight-line limit is gone.

What changed

  • Line styles (usageHistoryModel.ts): the first eight series stay solid in the existing colors. Each further group of eight reuses those colors with a dash pattern (long dash, then dotted, then dash-dot), so up to 32 series all look different. After 32 the styles repeat, but the labels on the metric buttons still tell them apart. As before, each metric's style comes from its position in the whole history, so hiding one never restyles the others.
  • Rendering (usageHistoryView.ts, AgentUsageHistory.tsx, AgentUsageHistoryChart.tsx): the chart now gets every selected series. I removed planPlottedSeries, the grey "not plotted" color, the "not plotted" labels on the metric buttons and the notice under the filters. The provider and metric toggles and "Show all" work as before.
  • Matching samples: a new UsageSeriesSwatch.tsx shows a short sample of each line, in its color and dash, on the metric buttons, in the chart tooltip and in the table. A dashed line's sample is dashed too, so they all match the chart.

Same limit elsewhere: nothing else had it. The cap was only in the Analytics chart; the sidebar overlay draws a single line and was never capped.

Tests

  • I replaced the unit tests that enforced the cap:
    • With ten metrics, all ten lines are drawn, each with a different color and dash pair.
    • The 9th metric's button shows the same dash as its line.
    • Hiding a metric removes only its line and leaves the others' styles unchanged.
    • The table still lists every selected metric.
    • The first 32 series all get different styles.
  • To make the chart draw lines in the unit tests, I gave it a fixed size in that test file. The new ten-line test would fail on the old code, which drew only eight; I didn't run it against the old code to confirm.
  • The Playwright test for more than eight metrics now expects all ten lines, with the last two dashed.
  • Results:
    • The Analytics, usage-history and Analytics page unit suites pass, 66 tests.
    • All 5 tests in the usage-history Playwright spec pass.
    • tsc --noEmit and ESLint with zero warnings allowed are clean on the changed folders.

I captured a preview of the desktop chart with all ten metrics drawn, using mocked data. The two extra lines are dashed, and their buttons and tooltip rows show the same dash.

Visual preview

Analytics usage chart plotting all ten metrics

Analytics usage chart plotting all ten metrics

With ten metrics selected, every one is drawn. The ninth and tenth lines reuse a hue with a dashed stroke, and their chip swatches and tooltip rows show the same dash. Mocked history data.

Original unavailable: managed storage is unavailable or the upload has expired.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (medium)
  • Requested By: @propr-ultrafix
  • Time: 5m 10s
  • Tokens: 1,136,259 (1,123,770 in / 12,489 out)
  • Cost: $0.78

View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR

…ted metric. The eight-line limit is gone.

I fixed F7: the Analytics usage chart now draws every selected metric. The eight-line limit is gone.

**What changed**
- **Line styles** (`usageHistoryModel.ts`): the first eight series stay solid in the existing colors. Each further group of eight reuses those colors with a dash pattern (long dash, then dotted, then dash-dot), so up to 32 series all look different. After 32 the styles repeat, but the labels on the metric buttons still tell them apart. As before, each metric's style comes from its position in the whole history, so hiding one never restyles the others.
- **Rendering** (`usageHistoryView.ts`, `AgentUsageHistory.tsx`, `AgentUsageHistoryChart.tsx`): the chart now gets every selected series. I removed `planPlottedSeries`, the grey "not plotted" color, the "not plotted" labels on the metric buttons and the notice under the filters. The provider and metric toggles and "Show all" work as before.
- **Matching samples:** a new `UsageSeriesSwatch.tsx` shows a short sample of each line, in its color and dash, on the metric buttons, in the chart tooltip and in the table. A dashed line's sample is dashed too, so they all match the chart.

**Same limit elsewhere:** nothing else had it. The cap was only in the Analytics chart; the sidebar overlay draws a single line and was never capped.

**Tests**
- I replaced the unit tests that enforced the cap:
  - With ten metrics, all ten lines are drawn, each with a different color and dash pair.
  - The 9th metric's button shows the same dash as its line.
  - Hiding a metric removes only its line and leaves the others' styles unchanged.
  - The table still lists every selected metric.
  - The first 32 series all get different styles.
- To make the chart draw lines in the unit tests, I gave it a fixed size in that test file. The new ten-line test would fail on the old code, which drew only eight; I didn't run it against the old code to confirm.
- The Playwright test for more than eight metrics now expects all ten lines, with the last two dashed.
- Results:
  - The Analytics, usage-history and Analytics page unit suites pass, 66 tests.
  - All 5 tests in the usage-history Playwright spec pass.
  - `tsc --noEmit` and ESLint with zero warnings allowed are clean on the changed folders.

I captured a preview of the desktop chart with all ten metrics drawn, using mocked data. The two extra lines are dashed, and their buttons and tooltip rows show the same dash.

PR: #3218
Comment by: @propr-ultrafix (ID: 0)
Model: Claude Opus 5.5
@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @propr-ultrafix

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR adds compatible Agent Tank parsing, persistent usage history, and charts in Analytics and the sidebar. It needs a localized correction before merge: the Analytics history never refreshes while the page remains open.

✅ Backward compatibility — Both aggregate and individual status reads normalize the canonical and legacy response shapes.

✅ Resilient recording — History writes are serialized, and failed inserts leave samples eligible for retry.

✅ Authorization boundary — The history endpoint requires agent-management permission and excludes the synthetic-demo exception.

The supplied checks show 27 passed, no failures, and one pending. This review used static analysis only; no commands were run.

Merge blockers

Every finding below was introduced by this PR and must be resolved before merging.

F8: 🔴 Refresh Analytics history after new samples

  • Required behavior: The new usage chart must reflect collected usage changes; an open Analytics page must not remain permanently empty or display indefinitely stale latest values.

  • Evidence: propr-ui/src/components/Analytics/AgentUsageHistory.tsx, useUsageHistoryRead

    1. Open Analytics in bundled mode before any local history has been recorded. The history request returns an enabled response with no series.
    2. Subsequent sidebar or watcher reads record samples through the new getAllStatuses recorder.
    3. Keep Analytics open with the same range. Its request effect depends only on range; it has no timer, usage-event subscription, or refresh control.
    4. The pane continues displaying “No usage history yet” despite available history. With existing history, its chart and “Latest” values similarly remain frozen.

    The backend watchers collect samples but cannot update this component’s stored response. Provider and metric toggles only change filtering and do not trigger another request. static trace: verified from the effect dependencies, rendering branches, aggregate recorder, and supplied watcher callers; no execution was performed.

  • Minimum fix: Refresh the mounted history reader periodically or through the existing live-resource mechanism, advancing its time bounds and retaining abort cleanup. Ensure an initially empty response becomes populated without navigation or changing ranges.

Suggestions

These are optional follow-ups and are not sent to /fix.

S7: 🟢 Verify the real daemon contract

The supplied tests cover parsing, storage, and mocked UI responses, but do not exercise readDaemonHistory against the pinned daemon. A contract test using actual 0.10.0 history output would strengthen confidence in query bounds, metric filtering, and fallback behavior. This is additional verification, not a demonstrated code blocker.

S8: 🟢 Preserve history across source transitions

agentTankHistoryService.ts replaces an agent’s entire local history with daemon series whenever any daemon series exist. Consider merging non-overlapping local observations when a newly started daemon has less history than ProPR. The current per-agent preference is explicitly documented, so improving continuity is an optional follow-up.

Score

The implementation has substantial coverage and sound compatibility and storage handling, but the Analytics refresh defect leaves a central new feature stale during normal use. The correction should be localized.

Score: 6/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 44s
  • Tokens: 105,460 (104,360 in / 1,100 out)
  • Cost: $0.97

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix F8 S7 S8

🤖 Review by ProPR

@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ Applied the requested follow-up changes in commit 3460119

Addressed 1 AI review comment (IDs: 6254771853)

Addressed finding F8

Summary of Changes

F8 is fixed: an open Analytics page now picks up new usage history by itself, with no navigation and no range change. Before, it read history once when it opened and never again. The full UI unit suite passes (2,957 tests), as does the history Playwright spec (5 of 5), with lint and typecheck clean.

How it works now (propr-ui/src/components/Analytics/AgentUsageHistory.tsx)

  • The history read now goes through the app's existing useLiveResource mechanism, the same one the sidebar's usage section uses.
  • It reads again whenever the server sends a usage-changed event. The backend writes the new sample before it sends that event, so the re-read always includes it.
  • Even without an event, it reads again every 5 minutes while connected, or every 30 seconds while disconnected.
  • Each read asks for the selected range ending at that moment, so the chart and "Latest" values move forward.
  • While a refresh is in flight the current chart stays on screen.
  • If a refresh fails, the last good data stays up. An error only shows when nothing has loaded yet.
  • Changing the range still cancels the old request, and closing the page stops the listening.

Same problem in the sidebar overlay (useUsageMetricHistory.ts): the metric chart overlay read once when opened. Pinned open by a tap, it could stay stale or say "Not enough history yet" forever. It now reads again, skipping its 60-second cache, on each usage-changed event while open, and stops listening when closed. Settings' agent cards show this overlay without a live connection, so there it keeps its single read.

Tests

  • Analytics: three new tests. An empty history fills in after a usage event, with the same 7-day range ending later. The latest value updates (17% → 44%) while the chart stays up. A failed refresh keeps the last good data.
  • Overlay: one new test. A pinned overlay fills in after a usage event and stops reading once closed.
  • Checked against the old code: all four of these fail on the previous code and pass now. A fifth new test (an error on the first read with nothing to keep, and no listeners left after closing) is a guard, not a regression test.
  • Test mocks: the socket mocks in AnalyticsPage.test.tsx, AgentTankSidebar.test.tsx and MobileBottomNavigation.test.tsx gained the socket functions the new code calls. These are mock-only changes.

What can't be avoided: a sample recorded between the server's usage checks (for example, during a sidebar refresh) with no value change sends no event. It shows up at the next 5-minute re-read at the latest.

I didn't add a preview: the change is the chart updating over time, which a screenshot can't show.

Visual preview

Analytics usage all metrics

Analytics usage all metrics

Original unavailable: managed storage is unavailable or the upload has expired.

Analytics usage desktop

Analytics usage desktop

Original unavailable: managed storage is unavailable or the upload has expired.

Analytics usage mobile

Analytics usage mobile

Original unavailable: managed storage is unavailable or the upload has expired.

Sidebar usage overlay desktop

Sidebar usage overlay desktop

Original unavailable: managed storage is unavailable or the upload has expired.

Sidebar usage overlay mobile

Sidebar usage overlay mobile

Original unavailable: managed storage is unavailable or the upload has expired.


🤖 Implementation Details

  • Model: Claude Opus 5.5 (high)
  • Requested By: @propr-ultrafix
  • Time: 18m 39s
  • Tokens: 2,229,271 (2,210,843 in / 18,428 out)
  • Cost: $1.19

View Task Execution


💡 ProPR Slash Commands
Command Description Example
/merge Merge target branch into this PR and resolve conflicts /merge
/review Request an AI code review /review or /review claude-sonnet
/fix Address review blockers, or blockers and suggestions with /fix all /fix, /fix all, or /fix F3 S5
/switch Change the AI model for this PR /switch claude-opus
/use Override the model for a single follow-up run /use claude-sonnet
/ultrafix Loop review→fix cycles until score goal is met /ultrafix or /ultrafix goal=8 max=10

🤖 Generated by ProPR

…history by itself, with no navigation and no range change. Before, it read history once when it opened and never again. The full UI unit suite passes (2,957 tests), as does the history Playwright spec (5 of 5), with lint and typecheck clean.

F8 is fixed: an open Analytics page now picks up new usage history by itself, with no navigation and no range change. Before, it read history once when it opened and never again. The full UI unit suite passes (2,957 tests), as does the history Playwright spec (5 of 5), with lint and typecheck clean.

**How it works now** (`propr-ui/src/components/Analytics/AgentUsageHistory.tsx`)
- The history read now goes through the app's existing `useLiveResource` mechanism, the same one the sidebar's usage section uses.
- It reads again whenever the server sends a usage-changed event. The backend writes the new sample before it sends that event, so the re-read always includes it.
- Even without an event, it reads again every 5 minutes while connected, or every 30 seconds while disconnected.
- Each read asks for the selected range ending at that moment, so the chart and "Latest" values move forward.
- While a refresh is in flight the current chart stays on screen.
- If a refresh fails, the last good data stays up. An error only shows when nothing has loaded yet.
- Changing the range still cancels the old request, and closing the page stops the listening.

**Same problem in the sidebar overlay** (`useUsageMetricHistory.ts`): the metric chart overlay read once when opened. Pinned open by a tap, it could stay stale or say "Not enough history yet" forever. It now reads again, skipping its 60-second cache, on each usage-changed event while open, and stops listening when closed. Settings' agent cards show this overlay without a live connection, so there it keeps its single read.

**Tests**
- **Analytics:** three new tests. An empty history fills in after a usage event, with the same 7-day range ending later. The latest value updates (17% → 44%) while the chart stays up. A failed refresh keeps the last good data.
- **Overlay:** one new test. A pinned overlay fills in after a usage event and stops reading once closed.
- **Checked against the old code:** all four of these fail on the previous code and pass now. A fifth new test (an error on the first read with nothing to keep, and no listeners left after closing) is a guard, not a regression test.
- **Test mocks:** the socket mocks in `AnalyticsPage.test.tsx`, `AgentTankSidebar.test.tsx` and `MobileBottomNavigation.test.tsx` gained the socket functions the new code calls. These are mock-only changes.

**What can't be avoided:** a sample recorded between the server's usage checks (for example, during a sidebar refresh) with no value change sends no event. It shows up at the next 5-minute re-read at the latest.

I didn't add a preview: the change is the chart updating over time, which a screenshot can't show.

PR: #3218
Comment by: @propr-ultrafix (ID: 0)
Model: Claude Opus 5.5
@propr-dev

propr-dev Bot commented Oct 18, 2026 •

Copy link
Copy Markdown
Contributor Author

✅ AI Code Review Complete requested by @integry

Posted 1 review:

View Task Details

@propr-dev

propr-dev Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

⚠️ Ultrafix stopped before reaching its goal. Requested goal: 8/10. Last score: unknown. Max cycles were exhausted, so manual review and merge are now required.

@integry

integry commented Oct 18, 2026

Copy link
Copy Markdown
Owner

/ultrafix

@propr-dev

propr-dev Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

🔄 Ultrafix loop started (goal: 8/10, max cycles: 10)

First action: /review

💡 Tip: Remove the ultrafix label from this PR to stop further ultrafix cycles.

@propr-dev

propr-dev Bot commented Oct 18, 2026

Copy link
Copy Markdown
Contributor Author

🔍 AI Code Review — codex:gpt-6-astra

Overall Evaluation

The PR implements the requested history storage, Analytics chart, sidebar overlays, and Gemini 4 Argon grouping with a reasonably clear separation between parsing, persistence, and presentation. It is merge-ready based on the supplied code review, with runtime integration verification remaining a useful follow-up.

✅ Backward-compatible parsing — Both canonical provider envelopes and legacy status maps pass through shared parsers, with tests covering bundled and external entry points.

✅ Recoverable history writes — Recording is serialized, and deduplication baselines advance only after successful insertion, allowing failed writes to be retried.

✅ Permission boundary preserved — The history endpoint requires agent-management permission, and demo sidebar rows do not offer access to real history.

The authoritative checks report 28 passed, none failed or pending, and 17 neutral/skipped. This review used static analysis only; no commands were run.

Merge blockers

No merge blockers.

Suggestions

These are optional follow-ups and are not sent to /fix.

S9: 🟢 Exercise the actual daemon contract

Add integration coverage for agentTankHistoryService.ts against Agent Tank 0.10.0, including history-enabled, history-disabled, and unreachable cases. The supplied tests cover parsing and local persistence extensively, but do not exercise the daemon history adapter. This would strengthen release confidence without implying a demonstrated incompatibility.

S10: 🟢 Make singleton series visible

AgentUsageHistoryChart.tsx disables dots, so a newly recorded series containing only one point has no visible line segment. Consider showing a dot for singleton series or an explicit collecting-history message. The chips and table already expose the reading, making this a presentation improvement rather than a blocker.

S11: 🟢 Preserve history across source transitions

readAgentTankUsageHistory chooses daemon history for an entire agent whenever any daemon series exists. Consequently, switching to a newly initialized daemon can temporarily hide older local history or locally available sibling metrics. Consider filling missing series or earlier intervals from local records. The current behavior follows the stated source-preference policy, so this is an optional continuity improvement.

Score

The implementation substantially satisfies the objective, has broad targeted coverage, and has no verified merge blocker in the supplied diff. Actual daemon and rebuilt-image integration remain less thoroughly validated than the mocked paths.

Score: 8/10


🤖 Review Details

  • Model: GPT-6 Astra
  • Time: 40s
  • Tokens: 107,847 (106,587 in / 1,260 out)
  • Cost: $1.02

View Task


💡 Next step: Comment /fix to address every F# merge blocker, /fix all for every pending blocker and suggestion, or name records explicitly, as in /fix F3 S5.
F# and S# IDs increment across review comments and remain permanent, so selectors such as /fix F3 F5 stay unambiguous across cycles. S# suggestions stay optional: they are implemented only when you name them or request /fix all, and they never relax a merge blocker.

Copy and edit to choose records from this review:

/fix S9 S10 S11

🤖 Review by ProPR

@propr-dev propr-dev Bot removed the ultrafix label Oct 18, 2026
@integry
integry merged commit ae7badb into main Oct 20, 2026
48 checks passed
@integry
integry deleted the goal-e0d6a5d6/claude-opus-5-5-agent-tank-has-received-a-20261017-2303-az4 branch October 20, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant