Commit Graph

114 Commits

Author SHA1 Message Date
rcourtman 482b84e219 Remove Assistant pre-model context heuristics 2026-05-15 16:28:17 +01:00
rcourtman a0b3bc7ed3 Record user-chat token usage to the cost ledger
chat.Service.ExecuteStream was a long-standing cost-ledger gap: the
agentic loop accumulated token counts via stream callbacks (see
GetTotalInputTokens / GetTotalOutputTokens in agentic_control.go)
and surfaced them in the SSE done envelope to the frontend, but
nothing on the server side recorded a cost.UsageEvent. Patrol,
discovery, QuickAnalysis, and the report narrators all record; only
chat — the bulk of AI token spend — did not. The operator's AI
usage dashboard was therefore understating cost dramatically.

Found while extending the cost-recording mindset across subpackages
after fixing QuickAnalysis (08491b9f4). Initially spawned as a
separate task but the right shape and scope became clear, so landing
it directly here.

Pipeline:
- Service.CostStore() exposes the per-tenant cost store handle.
- chat.Config gains optional CostStore *cost.Store field, threaded
  into chat.Service.costStore at NewService time.
- chat.Service.recordChatTurnCost records a UsageEvent with
  UseCase="chat" after every loop.ExecuteWithTools return (success
  OR error — operator was billed regardless of clean response).
  Skips when costStore is nil or zero tokens accumulated.
- ai_handler.go's two chatCfg construction sites populate CostStore
  via h.resolveCostStore(ctx).
- router wires the resolver to AISettingsHandler.GetAIService(ctx).CostStore()
  with no Enabled gate — even brief chat usage while AI was being
  configured should appear in the dashboard.

ExecutePatrolStream is deliberately not changed. It creates a
separate tempLoop and its caller (patrol_ai.go) records cost via
its own helper at line 887. Recording in ExecuteStream only avoids
double-counting on the patrol-via-chat path.

Tests in chat/cost_recording_test.go cover: recording when store
configured, no-op when store nil, no-op on zero tokens (early
failures), graceful handling of model strings missing the
provider prefix.
2026-05-10 23:15:53 +01:00
rcourtman 08491b9f48 Fix QuickAnalysis cost recording and audit the pattern
Service.Narrate (b84b87d8d) and Service.NarrateFleet (d4463a615)
fixed missing cost-record calls in the report-narrative path. Auditing
the rest of internal/ai for the same bug class found one more:
Service.QuickAnalysis. It is used for alert auto-resolve and similar
lightweight decisions, so production token spend on auto-resolve
analysis was invisible in the AI usage dashboard.

Mirror the same fix: capture costStore under the read lock alongside
provider/cfg, and after provider.Chat returns, record a UsageEvent
labelled with the request's UseCase (defaulting to "quick_analysis"
when the caller leaves it blank). Recording happens before the
empty-content guard so failed-but-billed calls are still visible.

Adds cost_recording_audit_test.go: an AST-level audit that walks
internal/ai/*.go (excluding _test.go and sub-packages), finds every
function calling .Chat() on a providers.Provider value, and asserts
each function body also references .Record() on a cost store.
Exemption is allowed via a //cost-recording-exempt: <reason> doc
comment. RunPatrolToolPreflight is annotated as exempt — it is a
connectivity self-test, not user workload, and should not pollute
the operator's cost dashboard.

The audit is intentionally local (function-scoped, not
interprocedural). A passthrough wrapper that calls a recording
function rather than calling Record itself would need an explicit
exemption naming the wrapped callee. Keeping the scan local makes
new Chat callers loud rather than letting silent gaps creep in via
indirection.

Future Chat callers must either record cost or carry the exemption
marker. The audit fails CI otherwise, so the regression that shipped
in b2bd9d114 (Narrate) and would have shipped again in d4463a615
(fleet) cannot recur silently.
2026-05-10 21:57:39 +01:00
rcourtman add1096ec8 Cache Patrol preflight outcome and hydrate UI on settings load
The Verify Patrol button reset its result to empty on every
page load — the operator had to re-click to see the verified
state, even though nothing had changed. This commit adds the
observability layer of the auto-preflight plan: every
RunPatrolToolPreflight result is now cached on the AI Service
and surfaced through /api/settings/ai as patrol_preflight, so
the inline result panel rehydrates on page load with the
most-recent outcome and a "last verified Xs ago" indicator.

Backend: patrolPreflightCache (mutex-guarded) on Service with
defensive-copy CachedPatrolPreflight() accessor; every
RunPatrolToolPreflight branch (success, soft warning, classified
failure, validation early-return) records into the cache.
PatrolPreflightSnapshot projects the cached result onto the
AI settings response. Tests cover both success-then-failure
supersession and the defensive-copy invariant.

Frontend: PatrolPreflightSnapshot type mirrors the wire shape;
hydratePatrolPreflightFromSettings(data) projects the snapshot
into the same response shape the manual button writes;
loadSettings and updateSettings flows call it. The result
panel renders a "last verified Xs ago" line under the
provider/model row when recorded_at_unix is present.

End-to-end smoke verified against deepseek-v4-flash: panel
rehydrates as green "Tool calling verified · last verified
just now" after page reload.

Auto-preflight on save (the trigger half of the resilience
plan) follows in the next commit.

Contracts: ai-runtime, api-contracts, agent-lifecycle (dep),
storage-recovery (dep), frontend-primitives all updated to
reflect the new patrol_preflight surface and hydration
contract. Verification artifacts: settingsArchitecture +
patrolPreflight client tests.
2026-05-10 14:58:26 +01:00
rcourtman fb293169f7 Make will_fix_later an operational commitment, not silent shut-up
Before this change, all three dismissal reasons funnelled through the same
"swallow re-detection at same/lower severity" path in FindingsStore.Add, so
will_fix_later was functionally identical to expected_behavior — Pulse stayed
quiet forever despite the dismiss_finding tool literally telling the LLM
"Pulse Patrol will continue to monitor this issue."

Now will_fix_later sets Finding.RemindAt (default 7 days) at dismissal time.
Once RemindAt has passed, the next re-detection clears the dismissal and emits
a `reminded` lifecycle event so the operator sees their lapsed commitment
instead of a swallowed finding. expected_behavior keeps acknowledged-forever
semantics; not_an_issue keeps Suppressed=true. The LLM tool response now
surfaces the remind-at date so Patrol's conversational explanations stay
aligned with the contract.
2026-05-09 10:19:28 +01:00
rcourtman d5735a1b92 Keep direct DeepSeek Patrol models selectable 2026-05-08 11:57:04 +01:00
rcourtman d2625c4dfb Persist Patrol settings with readiness handoff
Refs #1463
2026-05-07 19:26:00 +01:00
rcourtman 9d1fabef03 Gate Patrol readiness across runtime entrypoints
Refs #1463
2026-05-07 18:24:47 +01:00
rcourtman ad61b6c19f Require approval for backend alert investigation commands 2026-05-07 01:24:57 +01:00
rcourtman 53838d8f93 Fix RC3 backend release blockers 2026-05-01 21:36:28 +01:00
rcourtman ded190dcab Retire hosted AI quickstart runtime 2026-04-28 16:11:27 +01:00
rcourtman b1e179479d Retire self-hosted AI quickstart surfaces 2026-04-28 15:49:18 +01:00
rcourtman ecf8fd4299 Keep self-hosted Pro prompts opt-in 2026-04-28 11:23:49 +01:00
rcourtman 94a5ab1b59 Enforce data policy at AI model boundary 2026-04-25 21:13:53 +01:00
rcourtman 3ec2c0779e Harden agent command and deploy trust boundaries 2026-04-21 23:50:34 +01:00
rcourtman a170692683 Align AI discovery lifecycle with discovery settings
Refs #1425
2026-04-21 16:06:49 +01:00
rcourtman 3e09fd4493 Bound discovery AI response size 2026-04-15 14:51:50 +01:00
rcourtman 12c30da168 Own quickstart state and bill Patrol per run 2026-04-03 19:45:38 +01:00
rcourtman 830215e4c3 Bill quickstart by Patrol execution 2026-04-03 19:00:40 +01:00
rcourtman 7062f556dc Resolve BYOK models from live provider catalogs 2026-04-03 11:33:03 +01:00
rcourtman 0d25939921 Use a Pulse-owned alias for hosted quickstart models 2026-04-03 10:44:58 +01:00
rcourtman 57cc212f34 Replace Patrol quickstart with server bootstrap 2026-04-02 23:15:06 +01:00
rcourtman 73597f8b1a Forward-port Ollama runtime auth continuity 2026-04-01 14:38:39 +01:00
rcourtman ff0362d9f6 Clarify Patrol trigger sources and activity breakdown 2026-03-29 14:34:35 +01:00
rcourtman da20a171dd Project incident timelines from canonical history 2026-03-20 11:42:26 +00:00
rcourtman abc4b1a62a Canonicalize incident timeline events 2026-03-20 11:30:16 +00:00
rcourtman 42e472e9f7 Clarify canonical timeline ownership 2026-03-20 11:05:08 +00:00
rcourtman db4a02eced Rename resource graph context to relationships 2026-03-19 14:32:27 +00:00
rcourtman bdaa2bd525 Normalize relationship terminology 2026-03-19 14:30:45 +00:00
rcourtman c4c154efcf Route correlations through intelligence facade 2026-03-19 04:15:26 +00:00
rcourtman 2523b62379 Centralize memory change formatting 2026-03-19 02:58:28 +00:00
rcourtman 399f5d64dc Share recent change section formatting 2026-03-19 02:53:50 +00:00
rcourtman 85914c21b9 Centralize resource change summary formatting 2026-03-19 02:50:55 +00:00
rcourtman 064f2d2baa Move resource graph formatting into unified resources 2026-03-19 02:45:44 +00:00
rcourtman 8f499b13d3 Centralize correlation summary formatting 2026-03-19 02:42:45 +00:00
rcourtman 7bb7b16ac5 Add canonical resource graph context 2026-03-19 00:46:00 +00:00
rcourtman 7f7b84e621 Share backend resource change presentation 2026-03-19 00:38:08 +00:00
rcourtman 27dc24b6fd Use canonical resource timelines in incident context 2026-03-18 23:51:22 +00:00
rcourtman 749b0c46e5 Use canonical resource timelines in AI context 2026-03-18 23:49:48 +00:00
rcourtman e864682e33 Audit unified AI exports 2026-03-18 17:22:24 +00:00
rcourtman 778a2577b6 feat: Pulse v6 release 2026-03-18 16:06:30 +00:00
rcourtman d852964696 fix(ai): record patrol and QuickAnalysis token usage in cost store for budget enforcement
Patrol runs, evaluation passes, and QuickAnalysis calls were consuming
LLM tokens without recording them in the cost store. This made the
cost_budget_usd_30d budget setting ineffective since enforceBudget()
never saw patrol spend.

- Add RecordUsage() to ai.Service for thread-safe cost recording
- Add recordPatrolUsage() helper to PatrolService, called on both
  success and error paths for main patrol and evaluation pass
- Record QuickAnalysis token usage in cost store
- Return partial PatrolResponse (with token counts) on error instead
  of nil, so callers can always record consumed tokens
- Propagate partial response through chat_service_adapter on error
2026-03-01 19:19:47 +00:00
rcourtman 24f5b1cb31 fix(patrol): cap per-run tokens and reset patrol session history 2026-02-24 11:29:47 +00:00
rcourtman 60f9e6f07f security: fix multiple vulnerabilities (SAML, SSRF, Auth)
Addressed several security findings:
- SAML: Sanitized RelayState to prevent open redirects
- SAML: Fixed logout to properly invalidate server-side sessions
- Auth: Added auth, rate limiting, and logout checks to password change endpoint
- AI: Added admin/scope gating (ai:execute) for command execution
- AI: Blocked private IP ranges in fetch_url to prevent SSRF
- Config: Enforced settings:read/write scopes for export/import
- Agent: Added agent:exec scope requirement for WebSockets
2026-02-03 18:39:15 +00:00
rcourtman 935326ebb7 fix(api/ai): resolve critical auth, agent download, and lifecycle issues
- Fix API-only mode to accept Bearer tokens and query params
- Fix data race in API token validation using fine-grained locking
- Fix unified agent download serving wrong binary for invalid arch
- Fix AI infra discovery running when AI disabled and missing stop mechanism
2026-02-03 16:35:12 +00:00
rcourtman 0c802e7083 fix(patrol): improve service lifecycle, graceful shutdown, and concurrency 2026-02-01 16:27:25 +00:00
rcourtman 95a0d7a6bd feat(backend): implement AI Patrol, Investigation, and system-wide refactors 2026-01-30 19:02:14 +00:00
rcourtman 03b5586ac8 refactor(ai): update patrol and service to use chat service adapter
- Update patrol.go to use chat service for AI execution
- Update service.go with chat service provider integration
- Add patrol streaming endpoint to router
2026-01-28 21:24:34 +00:00
rcourtman e194e17159 Update AI core services and adapters
AI module improvements:

Patrol System:
- Better trigger handling
- Improved history persistence
- Enhanced coverage testing

Knowledge Store:
- Extended functionality
- Better test coverage

Adapters:
- Discovery adapter updates
- Investigation adapter improvements

Unified Bridge:
- Setup improvements
- Better test coverage

Alert handling and service updates.
2026-01-28 16:51:53 +00:00
rcourtman 7f7edfceb4 test: expand backend coverage 2026-01-25 21:08:44 +00:00