You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The generic Ctrl+Insert probe timed out for Firefox, then the explicit Firefox Ctrl+C fallback produced a new external clipboard generation and advanced to grab-capture-result. Failure therefore occurred while materializing the newly advertised MIME object, not while invoking application Copy.
Root design defect
The current external-offer materializer treats a multi-MIME clipboard object as a serial list of blocking byte streams:
request one MIME;
wait up to the fixed transfer_timeout_ms for EOF;
only after completion start the next MIME;
on the first receive error/timeout, free the entire partially captured item and return the error.
read_pipe_capped() uses one absolute deadline created at transfer start. Receiving bytes does not extend that deadline. Consequently:
one stalled representation creates head-of-line blocking and prevents later good representations from being requested;
a healthy large/slow representation that continuously makes progress can be falsely failed merely for taking longer than the fixed wall-clock timeout;
one MIME failure destroys already completed sibling representations;
current logs do not identify the advertised MIME manifest, which representation failed, which completed, byte counts, or what good data was discarded;
the timeout is per representation rather than a coherent whole-capture bound, so worst-case operation duration scales with advertised MIME count.
The outgoing path has the same architectural smell: source_send() writes an entire requested representation synchronously inside the Wayland callback using the same fixed absolute timeout, which can block Wayland dispatch for a large/slow consumer.
This conflicts with docs/architecture.md: timeouts bound waiting; observable protocol/data progress is the synchronization authority.
Violated invariants
Independent MIME representations must not head-of-line block one another.
Data progress and transfer completion are distinct: bytes arriving prove liveness; EOF proves protocol completion.
A healthy transfer may exceed a nominal duration while making bounded progress; inactivity and whole-transaction bounds are separate concerns.
A failed grab never overwrites the prior register.
Partial success must never be silently presented as a complete register.
Any discarded representation must be explainable without logging clipboard payload bytes.
Wayland callbacks must not perform potentially long blocking clipboard I/O.
Target transfer model
Use one nonblocking event-driven transfer manager inside the existing user daemon. Keep Wayland, command socket, transaction state, incoming MIME pipes, outgoing consumer pipes, and timers under one reactor; do not add another daemon/process merely for transfer I/O.
Incoming representations should be independently materialized with bounded concurrency so one bad MIME does not prevent siblings from progressing. Outgoing source_send callbacks should enqueue nonblocking writes and return immediately rather than draining the consumer FD synchronously.
Use distinct bounds for:
first progress;
idle/no-progress after transfer has begun;
whole capture/transaction lifetime;
total payload bytes.
Do not add user-facing tuning knobs until live/synthetic evidence demonstrates which bounds need configuration.
Failure policy
For the current register model, remain strict by default: if any representation classified as required/persistable fails, continue enough sibling work to produce complete diagnostics, preserve the prior register, and report object-level failure. Do not silently degrade to plain text or treat timeout as an accidental MIME filter.
If live evidence proves that a class of advertised MIME is intentionally non-persistable/non-materializable, make that an explicit documented policy with regression coverage rather than skipping whatever happens to fail.
Required observability
Permanent metadata-only diagnostics at the materialization boundary should make a failure self-explaining, for example:
Identify the exact Firefox representation and transfer state that triggered the original failure.
Add lowest-layer synthetic regressions for: independent sibling progress, zero-byte stall, partial-progress stall, a transfer that takes longer than the old 3 s bound while continually progressing, total payload cap, whole-capture bound, selection generation change, old-register preservation, and atomic all-success commit.
Ensure outgoing large/slow consumer transfers no longer block the Wayland event loop.
Observed
Live rich-content qualification under #8 failed on Firefox at the first Browser -> Writer capture step.
Build/runtime:
mainat87b4822829aea8d8285867b6378282976e47c670ClipReg 0.2.0-beta.1+g87b4822829aeactive/running,NRestarts=0Transaction evidence:
The generic
Ctrl+Insertprobe timed out for Firefox, then the explicit FirefoxCtrl+Cfallback produced a new external clipboard generation and advanced tograb-capture-result. Failure therefore occurred while materializing the newly advertised MIME object, not while invoking application Copy.Root design defect
The current external-offer materializer treats a multi-MIME clipboard object as a serial list of blocking byte streams:
transfer_timeout_msfor EOF;read_pipe_capped()uses one absolute deadline created at transfer start. Receiving bytes does not extend that deadline. Consequently:The outgoing path has the same architectural smell:
source_send()writes an entire requested representation synchronously inside the Wayland callback using the same fixed absolute timeout, which can block Wayland dispatch for a large/slow consumer.This conflicts with
docs/architecture.md: timeouts bound waiting; observable protocol/data progress is the synchronization authority.Violated invariants
Target transfer model
Use one nonblocking event-driven transfer manager inside the existing user daemon. Keep Wayland, command socket, transaction state, incoming MIME pipes, outgoing consumer pipes, and timers under one reactor; do not add another daemon/process merely for transfer I/O.
For each representation track at least:
no-first-progress,no-progress,payload-cap,selection-changed, FD/protocol error, whole-capture bound, etc.).Incoming representations should be independently materialized with bounded concurrency so one bad MIME does not prevent siblings from progressing. Outgoing
source_sendcallbacks should enqueue nonblocking writes and return immediately rather than draining the consumer FD synchronously.Use distinct bounds for:
Do not add user-facing tuning knobs until live/synthetic evidence demonstrates which bounds need configuration.
Failure policy
For the current register model, remain strict by default: if any representation classified as required/persistable fails, continue enough sibling work to produce complete diagnostics, preserve the prior register, and report object-level failure. Do not silently degrade to plain text or treat
timeoutas an accidental MIME filter.If live evidence proves that a class of advertised MIME is intentionally non-persistable/non-materializable, make that an explicit documented policy with regression coverage rather than skipping whatever happens to fail.
Required observability
Permanent metadata-only diagnostics at the materialization boundary should make a failure self-explaining, for example:
Never log clipboard payload bytes.
Acceptance
v0.2.0-rc.1promotion.This blocks
v0.2.0-rc.1through #8.