Skip to content

Bind asynchronous clipboard capture to its generation - #18

Open
MiMoHo wants to merge 1 commit into
haad:masterfrom
MiMoHo:bind-clipboard-capture-generation
Open

Bind asynchronous clipboard capture to its generation#18
MiMoHo wants to merge 1 commit into
haad:masterfrom
MiMoHo:bind-clipboard-capture-generation

Conversation

@MiMoHo

@MiMoHo MiMoHo commented Aug 31, 2026

Copy link
Copy Markdown

Problem

The asynchronous clipboard path mixed generations, UI threads, and privacy states:

  • it captured changeCount, but later re-read content and pasteboard types independently, allowing content from one generation to be classified with types from another
  • completion compared the latest global pbCount, not the generation associated with that read job
  • a slow read could still commit after the user paused capture
  • Remote Desktop progress reused the user-controlled pause-icon toggle and mutated AppKit from a worker thread
  • “save data types instead of content” also fell through to save the payload and mutated the clipping store off the main thread
  • dispatch_queue_create received an NSString object instead of the required C-string label

The off-main image update is consistent with the AppKit worker-thread crash class reported in TermiT#262, although that historical crash log alone cannot identify one exact Flycut line.

Change

  • serialize blocking clipboard reads on a dedicated queue
  • capture the observed generation, advertised types, and Flycut-blocked generation for each job
  • compare the observed generation with the generation immediately after the payload read
  • commit on the main thread only when the generation stayed stable, was not Flycut-authored, and capture is still enabled
  • keep shouldSkip side-effect-free
  • implement diagnostic mode in the main-thread commit path so it stores only the type and never the payload
  • remove the Remote Desktop progress toggle from clipboard polling so it cannot conflict with the logical pause state
  • use a valid C-string queue label and declare the existing shouldSkip selector

Verification

  • initial RED: four focused safety tests failed for the missing policy, mixed generations, worker UI update, diagnostic fallthrough, and queue-label type

  • a first hash-bound dual review correctly failed the candidate because in-flight reads could bypass a later pause and queued Remote Desktop toggles could invert the pause/status state

  • added the current pause state to the native commit policy, removed polling progress toggles, and moved diagnostics behind the same main-thread gate

  • final focused suite: 4/4 passed, including changed generation, blocked generation, paused-at-commit, side-effect-free diagnostics, and source-thread invariants

  • native arm64 link comparison: base and candidate each link the same 20 PBX sources with 0 errors; no new warning signature and two existing warnings removed

  • Clang analyzer comparison for AppController.m and FlycutOperator.m: 15 identical existing diagnostics and 0 errors

  • final independent concurrency/state review of diff SHA-256 a58cd6bd19c2cb849a4a3f3d413dc57bc570f30fde996c459a6ad7ba309a40e5: PASS, no findings

  • final independent security/privacy/MRC review of the same diff: PASS, no findings

Interaction with PR #5

PR #5 changes the same privacy-filter method. When combining them, retain PR #5’s independent concealed/password-type filtering while keeping diagnostic recording in this PR’s generation- and pause-validated main-thread commit path.

Limitation

A full signed Xcode release build, Thread Sanitizer app run, and live delayed Remote Desktop transfer were unavailable in this Command Line Tools environment. The candidate links the complete app target and uses a native C policy test plus source-level queue/thread invariants.

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