Skip to content

fix(privacy): stop persisting dictated content to the disk log - #403

Closed
postoso wants to merge 2 commits into
altic-dev:mainfrom
postoso:fix/privacy-no-transcript-in-disk-logs
Closed

fix(privacy): stop persisting dictated content to the disk log#403
postoso wants to merge 2 commits into
altic-dev:mainfrom
postoso:fix/privacy-no-transcript-in-disk-logs

Conversation

@postoso

@postoso postoso commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

DebugLogger persists every log line to ~/Library/Logs/Fluid/Fluid.log unconditionally: FileLogger.append runs before the loggingEnabled guard, so the "Enable debug logs" toggle only gates the in-memory UI panel, not the disk file. As a result, on release builds the dictated transcript, spoken prompts/instructions, selected text, and LLM request/response bodies were written to that log in plaintext. The dictation prompt-trace path was also on by default, so it logged the transcript + prompt + AI answer on every AI-enhanced dictation.

This redacts user content to metadata only (lengths, byte counts, model/provider names, status, response field names) at every affected site, keeping diagnostics useful. Full prompt traces are still available on the console behind FLUID_PROMPT_TRACE=1, but are never persisted to disk.

Scope

28 logging sites across 9 files (LLMClient, AIProvider, FunctionCallingProvider, ASRService, the two Apple speech providers, ContentView, RewriteModeService, TypingService). Includes LLMError.httpError's description, which embedded the raw provider error body and escaped to the log via downstream error.localizedDescription calls.

Testing

  • xcodebuild build: succeeds
  • swiftlint --strict: 0 violations
  • Completeness cross-checked (a remaining-leak re-grep + a cross-model review). No regression test added: the project has no SwiftPM test target and these surfaces are private, so a dedicated Xcode test target would be disproportionate; the completeness review is the gate.

DebugLogger.log() writes every line to a persistent plaintext file
(~/Library/Logs/Fluid/Fluid.log) unconditionally: FileLogger.append
runs before the `guard loggingEnabled` check, so the EnableDebugLogs
toggle only gates the in-memory UI panel, not the disk file. As a
result, multiple log call sites persisted the user's dictated
transcript, spoken prompts/instructions, selected text, and the
AI-processed result to disk in plaintext on release builds.

Redact user content at every leak site, logging metadata (lengths,
byte counts, model/provider names, status, response field names)
instead of the content itself, while keeping diagnostics useful:

- LLMClient: redact the cURL request body, the request-body debug
  log, the full streaming delta (now logs field names only), the
  streamed content chunk, and the non-streaming HTTP-error body.
- LLMClient: LLMError.httpError.errorDescription no longer embeds the
  raw provider error body, which callers persist via
  error.localizedDescription; expose status code and body size only.
- AIProvider / FunctionCallingProvider: redact request body, response
  body, error bodies, and tool-call arguments.
- ASRService: redact the final transcript, post-processed transcript,
  streaming partial, and boosted-term logs.
- AppleSpeechAnalyzerProvider / AppleSpeechProvider: redact
  recognized-speech logs.
- ContentView / RewriteModeService: the prompt-trace sinks
  (logDictationPromptTrace, logPromptTrace) persist only a redacted
  metadata line; the full trace remains available on the console
  behind the explicit FLUID_PROMPT_TRACE=1 env var.
- TypingService: drop the typed-text content previews; the adjacent
  length logs are retained.
@postoso
postoso force-pushed the fix/privacy-no-transcript-in-disk-logs branch from c89b16d to 5a9753f Compare August 16, 2026 04:54
@greptile-apps

greptile-apps Bot commented Aug 16, 2026

Copy link
Copy Markdown

Greptile Summary

This PR prevents dictated, selected, prompted, and AI-generated content from being persisted in the plaintext diagnostic log while retaining metadata useful for debugging.

  • Replaces transcript, prompt, response, tool-argument, and typed-text previews with lengths, byte counts, field names, and status metadata.
  • Restricts full prompt traces to console output explicitly enabled through FLUID_PROMPT_TRACE=1.
  • Redacts provider response bodies from persisted HTTP-error descriptions and adds regression coverage for that behavior.

Confidence Score: 5/5

The PR appears safe to merge, with no concrete blocking or independently actionable non-blocking defects identified.

The changes consistently replace sensitive persisted content with metadata, preserve explicitly enabled console tracing, and add coverage for the shared HTTP-error redaction path without altering the underlying transcription, AI-processing, or text-insertion behavior.

Reviews (1): Last reviewed commit: "test(privacy): assert dictated content i..." | Re-trigger Greptile

@postoso

postoso commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

Closing this out. On reflection the scattered shape here isn't something a narrower version fixes: the content gets interpolated at ~20 call sites, so any correct fix touches at least as many files as this PR, and the version with a real regression test comes out larger. Rather than leave a stale diff adding to the queue, I'm withdrawing. Happy to revisit if logging privacy gets picked up on the roadmap.

@postoso postoso closed this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant