Repository navigation
Surface 3 (client): report harness inventory to the server - #632
Conversation
Attaches a per-machine coding-agent inventory to the two client→server carriers
so the server can raise the "installed but not configured" notification and (PR 3)
the machine-went-quiet backstop. This is PR 2 of the new-harness-detection spec;
PR 3 (kcap-server) consumes it.
- Core: HarnessInventory { machine_id, vendors: { <id>: { detected, wired } },
declined[] } + a pure Evaluate (shared by both carriers), registered in
CapacitorJsonContext. machine_id is MachineId.Get() — the same id the daemon
sends on DaemonConnect — so the server correlates a machine's connect record,
status-report inventory, and hook-ingest inventory.
- Daemon: additive nullable field on DaemonStatusReport; AgentOrchestrator caches
the inventory and recomputes on a 6h in-memory cadence (never claims the on-disk
nudge throttle stamp, so surfaces 1–2 aren't starved). BuildStatusReport stays
pure (reads the cache); the send path refreshes.
- Hook ingest: SessionStartInventory.Stamp serializes the same HarnessInventory
(via the same context → byte-identical wire shape) onto each vendor's SessionStart
body; wired into all 9 hook commands (session-start only for Claude/Cursor).
- Additive/down-level-safe: an old server ignores the field; an old client never
sends it.
Tests: Core Evaluate (mapping + declined); daemon status report carries the
inventory; hook session-start body carries it (integration, CI-gated). AOT clean.
AI-2118
PR Summary by QodoClient: report harness inventory via daemon status reports and hook session-starts
AI Description
Diagram
High-Level Assessment
Files changed (16)
|
Code Review by Qodo
1.
|
…Claude spool path - RefreshHarnessInventoryIfStale now runs check-evaluate-publish under one lock (single-flight): overlapping report calls can't each probe, and a slower probe can't overwrite a newer one and reset the TTL to stale content. Eval is a few dir/PATH stats + a small JSON read, so holding the gate across it is cheap; a probe failure no longer advances the timestamp (retries next report). (Codex P2 #1) - Claude's degraded arm spools the session-start body via NormalizeForSpool and bypasses HandleCore's stamp, so a replayed session-start never carried the inventory. Stamp session-start bodies in NormalizeForSpool too, so the hook-ingest carrier works even for auth/URL-outage replays. (Codex P2 #2) AI-2118
…bose docs - RefreshHarnessInventoryIfStale now advances the timestamp on failure too (and logs at Debug), so a persistently-failing environment backs off to the 6h TTL instead of re-probing on every 60s send. (qodo #2) - Trimmed the HarnessInventory / SessionStartInventory / status-report-cache doc comments to the load-bearing "why" per the repo's comment guideline. (qodo #1) AI-2118
PR 2 of the new-harness-detection spec (surfaces 1–2 shipped in #626). Attaches a per-machine coding-agent inventory to the two client→server carriers so the kcap-server side (PR 3) can raise the "installed but not configured" UI notification and the machine-went-quiet backstop. This PR is client-only and additive — inert until the server consumes it.
What's here
Core —
HarnessInventory { machine_id, vendors: { <vendorId>: { detected, wired } }, declined: [vendorId] }with a pureEvaluate(shared by both carriers), registered inCapacitorJsonContext(snake_case wire shape).machine_idisMachineId.Get()— the same id the daemon already sends onDaemonConnect— so the server correlates a machine's connect record, status-report inventory, and hook-ingest inventory to one machine.Carrier A — daemon status report: additive nullable field on
DaemonStatusReport.AgentOrchestratorcaches the inventory and recomputes on a 6h in-memory cadence, deliberately never claiming the on-disk nudge throttle stamp (so it can't starve the hook/CLI nudge surfaces).BuildStatusReportstays pure (reads the cache); the send path refreshes.Carrier B — hook ingest:
SessionStartInventory.Stampserializes the sameHarnessInventorythrough the same context (→ byte-identical wire shape) onto each vendor's SessionStart body. Wired into all 9 hook commands (guarded to session-start for the shared-injection Claude/Cursor paths). Computed fresh — current-state metadata on an already-happening POST, so no throttle; never throws.Down-level: additive/nullable — an old server ignores the field; an old client never sends it (the server treats an absent inventory as "unknown", never "nothing detected").
Testing
Evaluate: vendor→entry mapping +declinedlist.DaemonStatusReportcarries the inventory (9 vendors + machine id).harness_inventory(integration test, CI-gated like itsSessionStartVisibilityTestssiblings).AI-2118
🤖 Generated with Claude Code