Repository navigation
[compass] Fix: a seat_type call Windows refuses partway loses the count of what was typed - #23
Merged
Conversation
TextTyping.Type called typist.Send with no catch. InputInjector.Send throws
when the seat's input is blocked or SendInput accepts fewer events than it was
given, for example once a typed Enter opened a UAC prompt or an elevated window.
The exception left Type, and the pipe handler turned it into a bare
"{type}: {message}" reply with no typed, total or nextIndex, so an agent could
not tell how much of the text had reached the field before it retried.
A refusal now ends the call like the other stops, with the exact count,
errorCode typing_stopped and partlySent: true, since the refused character
(an Enter pressed but not released, say) may have arrived in part. Other
exceptions still surface as before.
The docs no longer say a stopping seat ends typing with typing_stopped
(B-020): the daemon's shutdown waits behind the running input.text on the
shared seat connection, so the caller sees the connection close, and the
sign-out closes the program anyway.
Reported in Compass's Anode inbox as B-021 and B-020 (the second review of #18).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Review follow-up. Typing catches only TextTyping.Refused now, which the typing path in InputInjector throws: TypingStep sends one step, and a block or a short SendInput count becomes Refused, with PartlySent when an earlier part of the step (an Enter's press) or some of its events went out. Any other exception, ObjectDisposedException included, still surfaces as a fault. The docs no longer name an elevated window as a refusal: Windows drops input an elevated window doesn't take without reporting it, which TROUBLESHOOTING and PROTOCOL now say. A seat that stops during a call may answer with a lost connection or typing_stopped; either way the program is closed. The cancel reason names the request's time, which is what cancels typing in practice. The check covers refusals at the first character, at an ordinary one and at a key whose release was refused, and that the reply never repeats the text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Second review follow-up (P3s): Windows may drop input to an elevated window without an error, rather than always does; the cancel reason names the request's time or a stopping seat, since a shutdown on another connection cancels the same token; a stop at the first character says "Nothing was sent."; and the SeatHost comment names the request's deadline, not the lease's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
Author
|
Compass review: ready to merge Tested by compass-merge on 2026-10-07 on head
Not merged tonight only because of the five-merges-per-run cap (#20, #21, #22 and PixelForge #4 and #5 were older). The next compass-merge run merges it if nothing changes. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The report
Compass's Anode inbox (
ANODE-BUGS.md), from compass-merge's second review of #18:SendInputfailure partway throughseat_typeloses the count of what was typed.seat_typewithtyping_stopped, which in practice it doesn't.B-021: root cause and fix
Cause.
TextTyping.Typecalledtypist.Sendwith no catch.InputInjector.Sendthrows in two cases:InvalidOperationExceptionwhen the seat's input is blocked (WindowAccess.InputBlockReason());Win32ExceptionwhenSendInputaccepts fewer events than it was given.The exception left
Type, and the seat pipe's handler turned it into a bare"{type}: {message}"reply, with noerrorCode,typed,totalornextIndex. The agent couldn't tell how much text had reached the field before retrying, and a retry could type it twice. #18's 45-second calls made the window wider.Fix.
InputInjector.TypingStepsends each step of typing: a character's events, or an Enter's or Tab's press and release.SendInputcount becomes aTextTyping.Refused.PartlySentwhen part of the step went out first: an Enter whose press went out but whose release was refused, or some of a character's events.Sendand its errors unchanged.SendCountedis the shared part, and it still reads the Win32 error right afterSendInput.TextTyping.Typecatches onlyRefused. It ends the call like the other stops:ok: false,errorCode: "typing_stopped", and the exacttyped,totalandnextIndex.partlySent: trueonly when part of that character went out. The message then says it may already have taken effect, as a pressed Enter does.HeldKeys, and Anode releases it when the lease ends, as before.ObjectDisposedExceptionincluded, is a fault in Anode and still surfaces.Not every refusal can be reported. Windows may drop input that an elevated window doesn't accept without an error. TROUBLESHOOTING and PROTOCOL now say so, instead of offering an elevated window as an example.
B-020: docs only
The daemon sends
shutdownon its one shared seat connection. A runninginput.textholds that connection, soshutdowntimes out unsent after 1.5 s. The daemon then closes the pipe, and the sign-out ends the seat host.The docs now say a seat that stops during a call ends it with a lost connection or
typing_stopped. The viewer disconnects first, so input may be refused before the pipe closes. Either way the sign-out closes the program, so don't send the rest.The cancel reason now names the request's time first, which is what cancels typing in practice, and still mentions a stopping seat. #18's CHANGELOG entry and a
SeatHost.cscomment are corrected too.How I tested it
scripts\build.ps1 -QuickTest -OutputDirectory artifacts\pkg-build): 91/91 quick checks pass, on 8a58f77, 371437c and fd2356c. The documentation check is consistent.partlySent) and at an ordinary character;nextIndex, nothing sent after it, the reason in the message, and no text in the reply;partlySenton the other stops;InvalidOperationExceptionand anObjectDisposedExceptionfromSendstill propagate.selftest --quick, each file restored byte for byte):partlySenton every refusal;partlySentnever; and the refused character counted as typed.TypingStep's own counting calls the realSendInput, so quick checks can't reach it. A seat run can (below).git merge-tree) with [compass] Anode Business, ready to switch on: the terms and a README line that it isn't on sale yet #19, [compass] Fix: seat_observe fails on File Explorer windows ("Object reference not set to an instance of an object") #20, [compass] Fix: a packaged app's daemon keeps its state in the app's package folder, which the docs and rendering --restore missed #21, [compass] Before the launch: the README's "Known issues in 0.11.1" #22 and [compass] Fix: a request queued behind a long seat operation loses its reply and detaches the seat #24: all clean.anode-controlpipe.Second review
Codex is at its usage limit until 9 October, so fresh read-only Claude subagents reviewed.
First pass, on 8a58f77: problems found. All fixed in 371437c:
typing_stopped. The docs are hedged.partlySentwas true on every refusal. It is now computed where the events are sent, and onlyRefusedis caught.Second pass, on 371437c: no P1 or P2. It confirmed several points:
SendInput;partlySentflag is right in every case: a block, a refused press, a refused release, and 0 or some of a character's or surrogate pair's events;Its P3s were fixed in fd2356c: the elevated-window note now says "may", the cancel reason names both causes, a stop at the first character says "Nothing was sent.", and a
SeatHostcomment is corrected. One P3 is left: the checks passRefusedwith a preset flag, soTypeUnit's own flag logic (pressed,sent > 0) runs only in a seat. It is listed below.CI: green on 8a58f77, 371437c and fd2356c.
All four open fix PRs merged together on
main(#20, #21, #23, #24, locally): 95/95 quick checks, documentation consistent.Still to check in a real seat
TypeUnit's flag logic). For example, have a typed Enter open something that takes the input desktop, such as a UAC prompt. The reply should betyping_stoppedwith the right count, andpartlySentonly when an Enter was cut off.okwith the text lost, ortyping_stopped. The docs say it may be either.🤖 Generated with Claude Code