Fix document retention and helper retry regressions

Keep failed cursor trials and native recapture anchored to the original document, and restore the requested cached root before LRU eviction. Base braille retry resets on established connection time rather than stalled startup. Poll private AT-SPI daemon ownership without triggering service activation and clean up partial startup failures. Add focused regressions and update browser testing notes.
This commit is contained in:
Storm Dragon committed 2026-11-03 11:37:36 -05:00
1 parent a4d427099e
commit 4da61465b0
11 files changed
+282 -132

No files matched your search

+27 -19
View File
@@ -45,8 +45,13 @@ func (worker *brailleWorker) run(ctx context.Context, done chan struct{}) {
backoff := time.Duration(0)
lastError := ""
for ctx.Err() == nil {
started := time.Now()
err := worker.session(ctx)
connectedFor, err := worker.session(ctx)
// Only a healthy, established connection resets retry history. Waiting
// for the helper's ready message can itself take several minutes.
if connectedFor > 10*time.Second {
backoff = 0
lastError = ""
}
if err != nil && ctx.Err() == nil {
if err.Error() != lastError {
worker.logger.Warn("braille helper disconnected", "error", err)
@@ -55,12 +60,6 @@ func (worker *brailleWorker) run(ctx context.Context, done chan struct{}) {
worker.logger.Debug("braille helper still unavailable", "error", err)
}
}
// A session that stayed up a while was a real connection; do not
// keep growing the delay after it ends.
if time.Since(started) > 10*time.Second {
backoff = 0
lastError = ""
}
backoff = nextBrailleBackoff(backoff)
select {
case <-ctx.Done():
@@ -70,23 +69,31 @@ func (worker *brailleWorker) run(ctx context.Context, done chan struct{}) {
}
}
func (worker *brailleWorker) session(ctx context.Context) (result error) {
// connectedFor excludes startup waits so the supervisor can distinguish an
// established connection from a slow failed handshake.
func (worker *brailleWorker) session(ctx context.Context) (connectedFor time.Duration, result error) {
var connectedAt time.Time
defer func() {
if !connectedAt.IsZero() {
connectedFor = time.Since(connectedAt)
}
}()
defer func() { worker.mu.Lock(); worker.connected = false; worker.mu.Unlock() }()
childCtx, cancel := context.WithCancel(ctx)
defer cancel()
command := exec.CommandContext(childCtx, worker.path, "--client")
stdin, err := command.StdinPipe()
if err != nil {
return err
return 0, err
}
stdout, err := command.StdoutPipe()
if err != nil {
return err
return 0, err
}
var stderr bytes.Buffer
command.Stderr = &stderr
if err := command.Start(); err != nil {
return err
return 0, err
}
waitDone := make(chan struct{})
var waitErr error
@@ -154,17 +161,18 @@ readyWait:
select {
case err := <-ready:
if err != nil {
return err
return 0, err
}
break readyWait
case <-notice.C:
worker.logger.Info("waiting for braille display")
case <-giveUpTimer.C:
return errors.New("braille helper connection timed out")
return 0, errors.New("braille helper connection timed out")
case <-ctx.Done():
return nil
return 0, nil
}
}
connectedAt = time.Now()
worker.logger.Info("braille helper connected")
worker.mu.Lock()
worker.connected = true
@@ -198,15 +206,15 @@ readyWait:
for {
select {
case <-waitDone:
return waitErr
return 0, waitErr
case err := <-writeError:
return err
return 0, err
case err := <-readErrors:
return err
return 0, err
case event := <-routes:
worker.route(childCtx, event)
case <-ctx.Done():
return nil
return 0, nil
}
}
}