mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-11 14:00:29 +00:00
8d33986b5e
A systematic audit of all model-bound paths (not just the ones touched reactively) found a leak: SummarizeSession (internal/ai/chat/session_compaction.go) sent the PERSISTED chat transcript to the chat model via provider.Chat WITHOUT the dial-aware model-boundary sanitizer. The transcript is built from persisted messages — original user prompts and tool outputs — which carry raw resource identifiers (hostnames/IPs/names) regardless of how the live turns were redacted. On a cloud chat model at redacted/local_only, that shipped identifiers to the provider, contradicting the cloud_context_privacy dial. (Secrets were already redacted at transcript-build time via safety; resource identifiers were not.) Fix: run the compaction ChatRequest through modelboundary.RequestSanitizerForModel with the same dial resolution as a normal turn — fail closed to redacted when no config snapshot, RedactLocalOnlyResourcesOnly() at full, nil (no-op) for local Ollama. Mirrors the interactive seam exactly. Audit also checked: report/fleet narrators, quick analysis, ExecuteAgentic(Stream), discovery analysis, and Patrol all already install the sanitizer (verified). The Patrol preflight self-test sends a fixed payload with no resource content, so it needs no sanitizer (verified static, not trusted from the audit summary). agentcontext output flows through the sanitized agentic loop. So compaction was the one gap. Contract: ai-runtime gains a UNIVERSAL backstop rule — every model-bound path that carries infrastructure-derived content must install the dial-aware sanitizer; session compaction named explicitly; static no-identifier probes exempted. Proof: TestServiceSummarizeSessionRedactsResourceIdentifiersForCloud (a transcript hostname is stripped in the captured compaction request at the redacted dial); existing compaction tests stay green (fix is additive — empty-model path unchanged). Full internal/ai/... suite green (23 packages).