Fix dropped clicks and late screenshots in fast recording
Root cause of 'I clicked many times but only got two screenshots':
finishing/pausing a session called backend.stop(), which cancelled every
in-flight frame request to null. Clicks whose PNG had not finished
encoding yet were then dropped — only the first few survived.
Fixes:
- Stream backend now *drains* on stop: it stops accepting new requests but
keeps the worker alive until frames already selected for queued clicks
finish encoding. stop({ immediate: true }) keeps the old abandon-now
behavior for an unhealthy worker.
- Two-stage worker reply: a fast 'frame-selected' ack pins the pairing and
proves liveness; the slow PNG payload follows. A slow encode (seconds on
software-rendered hosts) is no longer mistaken for a dead worker, which
had been forcing the post-click fresh-shot fallback (late screenshots).
- Queued clicks carry their guide id and are stored even if the session
ends while they wait in the queue.
- The tray gesture that stops a session is discarded by matching its
recorded screen position, not a time window — a fast workflow click near
the stop is no longer collateral damage. (Replaces the earlier grace
window, which dropped whole bursts.)
- A click on a display with no ready stream resolves null so the caller
fresh-shots the correct monitor instead of returning another screen.
- STEPFORGE_CAPTURE_LOG=1 prints one line per click decision; the
second-instance handler now surfaces the running window instead of
exiting silently.
- Self-test gains a fast-burst-then-finish scenario (8/8 saved) and the
marker/coordinate checks remain at 0.00% offset.
Tests: 133 unit + all repo checks passing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+24
-1
@@ -134,8 +134,31 @@ click position. Three pieces make that hold:
|
||||
click-time screen. Storing is serialized per click; pairing is not, so
|
||||
slow encodes never skew later clicks.
|
||||
|
||||
Reliability rules that keep "one click → one step" true under load:
|
||||
|
||||
- **The worker reply is two-stage.** It acknowledges frame *selection*
|
||||
within milliseconds (proving liveness and pinning the pairing), then
|
||||
ships the PNG whenever the encode finishes — seconds later on
|
||||
software-rendered hosts. A slow payload is never mistaken for a dead
|
||||
worker; only a missing ack degrades the backend.
|
||||
- **Stopping drains.** Finishing or pausing a recording keeps the worker
|
||||
alive until frames already selected for queued clicks finish encoding.
|
||||
Without this, ending a session right after a fast click burst cancelled
|
||||
every still-encoding frame and those clicks vanished (the "I clicked ten
|
||||
times but only got two screenshots" bug).
|
||||
- **Queued clicks outlive the session.** A click registered while recording
|
||||
carries its guide id and still becomes a step if the session ends while it
|
||||
waits in the store queue. The lone exception is the tray gesture that
|
||||
stopped the session, discarded by matching its recorded screen position.
|
||||
- **A click is never served another monitor's frame.** If the clicked
|
||||
display has no ready stream the backend returns null and the caller
|
||||
fresh-shots the correct screen, rather than circling a point on the wrong
|
||||
one.
|
||||
|
||||
`STEPFORGE_CLICK_SELFTEST=1 npm start` exercises the whole pipeline in a
|
||||
real Electron session and reports steps-per-click and marker offsets.
|
||||
real Electron session: it reports steps-per-click and marker offsets, then
|
||||
runs a fast-burst-then-finish scenario that must save every click.
|
||||
`STEPFORGE_CAPTURE_LOG=1` prints one diagnostic line per click decision.
|
||||
|
||||
## Security Rules
|
||||
|
||||
|
||||
Reference in New Issue
Block a user