Skip to content

[Latent Audit] P2 · Medium · PRIVACY.md claims the shipped default involves no clipboard; the shipped default capture mode is Clipboard, so every read does a synthetic ⌘C round-trip #83

Description

@latent-variable

Severity: Medium · stale_docs · confidence high
Location: docs/PRIVACY.md:113

Impact: The privacy document tells a reader two things about the shipped configuration that the code contradicts: that Yap "ships in Selected text mode, which reads a live selection and nothing else" and that "Read source → Selected text, the shipped default, has no clipboard involvement at all." On a factory install the separate Capture-method setting defaults to Clipboard, so under Read source = Selected text every ⌘⇧R press saves the whole pasteboard, posts a synthetic ⌘C, reads whatever landed, and writes the saved items back — which is the exact behaviour the document assigns only to the opt-in Auto mode, and which is why the same document earlier says Accessibility is needed for "Simulating ⌘C for the clipboard fallback". A privacy doc that is confidently wrong about which path runs by default is worse than no doc: a user decides they are safe on the strength of that sentence.

Evidence: Doc claims, docs/PRIVACY.md: :99 "Yap ships in Selected text mode, which reads a live selection and nothing else." and :113-114 "Read source → Selected text, the shipped default, has no clipboard involvement at all." Code: app/Sources/Yap/Prefs.swift:162 sets the Capture-method default to clipboard — captureMode = CaptureMode(rawValue: d.string(forKey: "captureMode") ?? "") ?? .clipboard — while :163 defaults readSource to .selection, so the shipped pair is (.selection, .clipboard). The read pipeline passes captureMode straight through for .selection: app/Sources/Yap/AppState.swift:423-424case .selection: capture = await TextCapture.capture(mode: prefs.captureMode). app/Sources/Yap/TextCapture.swift:29-30 routes that to await viaClipboardAsync(), and TextCapture.swift:134+ is the pasteboard round-trip: await waitForModifiersToClear(), let saved = snapshot(pb), defer { restore(pb, saved) }, three attempts at sendCopyHeld() posting ⌘C to .cghidEventTap, then reading pb.string(forType: .string). So the default path touches, and temporarily replaces, the general pasteboard on every read, and needs Accessibility to do it. Only Capture method = Accessibility (TextCapture.swift:26-27) reads a live selection with no clipboard involvement. AGENTS.md corroborates the code, not the doc: "Default capture mode is clipboard, not Accessibility" and it glosses selection as "(AX + ⌘C only, strict — keeps the no-stale-clipboard invariant)". The section heading itself ("The Auto read source and your clipboard") plus the bullet "Yap never overwrites your clipboard doing this. The synthetic-⌘C path saves and restores it" describe the ⌘C path as an Auto-only affair, which the defaults disprove. Not a plan or design doc — it is live reference text; last touched 2026-08-31 per git, and the mismatch is a specific claim plus the code that refutes it, not an age argument.

Recommendation: Rewrite the two sentences; do not delete the document, it is load-bearing privacy text and the rest of it holds. Say what the shipped configuration actually does: Read source defaults to Selected text, Capture method defaults to Clipboard, so a read posts a synthetic ⌘C, reads the pasteboard, and restores what was there — which is precisely why the Accessibility grant is requested. State that only Capture method → Accessibility reads a live selection with no clipboard involvement, and that Read source → Clipboard skips capture entirely and reads what you copied yourself. Keep the existing guarantee that the pasteboard is restored, and keep the iTerm copy-on-select note, which is accurate.

Cross-validated by: codex — PRIVACY.md claims Yap ships in Selected text mode with "no clipboard involvement at all," but Prefs.swift defaults captureMode to .clipboard and readSource to .selection. AppState.swift passes that mode to TextCapture.capture, whose .clipboard path executes viaClipboardAsync(), including synthetic ⌘C and pasteboard snapshot/restore, so the documented default behavior is contradicted by the code.

Filed automatically by latent-git-agents (auditor, agent: pi). Dedupe token: latent-audit-fp-195adcbe13471184

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Scheduled, not urgentcleanupRemovable code: dead paths, unused deps, tests that cannot fail

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions