feat(desktop): add harness to NIP-AM agent-usage breakdown#2790
Merged
wpfleger96 merged 3 commits intoJul 25, 2026
Conversation
Group the per-agent model breakdown by (harness, model) instead of model alone, so the same model running under two different harnesses (e.g. claude-sonnet via goose vs claude-code) produces two distinct rows rather than collapsing into one. Changes: - agent_metric_index: add nullable TEXT harness column; schema migration (M1) does ADD COLUMN + index rebuild via the shared backfill parser so all existing rows get harness populated from retained raw_json — no data loss, ingest/backfill remain in sync - AgentMetricIndexRow: parse harness from AgentTurnMetricPayload (REQUIRED field), write/read through all store paths - AgentScope.models: widen key from Option<String> to (Option<String>, Option<String>) i.e. (harness, model); sort tiebreak is harness-ascending then model-ascending, None last in each - ModelUsage wire type: add harness: Option<String> field - AgentUsageFocusedView: render harness as a dimmed sub-label on each model row; null harness (pre-migration or unknown) renders no label so single-harness data is visually unchanged except for the label - tauriArchive.ts / bridge.ts: add harness to AgentUsageModel type - agentUsage.ts: update sortModelsByKnownTotal tiebreak for (harness, model) compound key - Tests: collapse-fix integration test (same model / two harnesses → two rows), migration test (old-shape rows get harness after rebuild), harness sort tests, E2E fixture + assertion updates Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
wpfleger96
force-pushed
the
duncan/agent-usage-harness
branch
from
July 25, 2026 00:13
0945825 to
7d11593
Compare
- M1 atomicity: wrap ALTER TABLE, full DELETE, per-scope rebuild, and archive_migrations marker in one unchecked_transaction so a crash before commit leaves no orphaned marker and the next open re-runs the whole migration from scratch. - M1 worklist: derive (identity, relay) pairs from archived_events (kind 44200) instead of surviving index rows so an empty index cannot cause M1 to silently declare success with scopes missing. - ALTER error handling: replace blanket let _ = ... with a PRAGMA table_info check; ALTER runs only when the harness column is absent and every other error propagates. - New Rust tests via open_archive_db: legacy-file reopen populates harness + records marker, second open is idempotent, rolled-back mid-migration state re-runs to completion on next open. - TS sort: replace localeCompare with ordinal < / > comparators so frontend ordering is locale-independent and matches Rust String::cmp. - e2eBridge.ts: add harness: string | null to RawAgentUsageModel so the tauriArchive.ts mirror contract is accurate. - Rust comparator: extract cmp_known_total + cmp_option_str_none_last helpers and ModelSortKey struct to eliminate the duplicated None-last ladder; also fixes the clippy type_complexity lint on the 4-tuple. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Split the M1 harness-migration tests from store_tests.rs into a new store_migration_tests.rs so store_tests.rs falls back under the 1000- line limit without a ratchet override; store_tests.rs is now ~858 lines (checker: 858). The store_tests.rs override is removed; store.rs gains one line for the new #[path] include (checker: 1044). Add a one-line comment at sortModelsByKnownTotal noting the identifier ordering domain is ASCII in practice so UTF-16 vs UTF-8 scalar divergence for astral code points is accepted. Co-authored-by: Will Pfleger <pfleger.will@gmail.com> Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Member
Author
wpfleger96
pushed a commit
that referenced
this pull request
Jul 25, 2026
wpfleger96
marked this pull request as ready for review
July 25, 2026 16:04
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.




Stack: #2035 → this PR
What
Group the per-agent model breakdown by
(harness, model)instead ofmodelalone, so the same model running under two different harnesses (e.g.claude-sonnetviagoosevsclaude-code) produces two distinct rows rather than collapsing into one.Changes
Rust / SQLite
agent_metric_index: add nullableharness TEXTcolumn. Schema migration M1:ALTER TABLE ... ADD COLUMN+ delete-then-backfill rebuild so all existing rows getharnesspopulated from retainedarchived_events.raw_json— no data loss; ingest and backfill share the samefrom_payloadparser (frozen-plan requirement preserved).AgentMetricIndexRow: parseharnessfromAgentTurnMetricPayload.harness(REQUIRED field per NIP-AM), write/read through all store paths (ROW_COLUMNS, INSERT,row_from_sql).AgentScope.modelsgrouping key widened fromOption<String>to(Option<String>, Option<String>)i.e.(harness, model). Sort tiebreak: harness ascending → model ascending,Nonelast in each.ModelUsagewire type: addharness: Option<String>field.Frontend
tauriArchive.ts/bridge.ts: addharnesstoAgentUsageModeltype.AgentUsageFocusedView: renderharnessas a dimmed sub-label next to each model name on breakdown rows.nullharness (pre-migration data or unknown) renders no label — single-harness data is visually unchanged.agentUsage.tssortModelsByKnownTotal: tiebreak updated for compound(harness, model)key.Tests
sortModelsByKnownTotalharness tiebreak tests, same-model two-harness sort test.bridge.tsfixture type updated,agent-usage.spec.tsharness assertion,agent-usage-screenshots.spec.tsshot 02 harness-label visibility check.Gates
All green locally:
just desktop-check✓just desktop-typecheck✓just desktop-build✓just desktop-test(3487 pass, 0 fail) ✓cargo testindesktop/src-tauri(1575 pass, 0 fail) ✓