Skip to content

Refuse a run that lost sight of EC, instead of blaming EC - #101

Merged
amrali-eg merged 3 commits into
masterfrom
fix/ec28-fresh-window-probe
Sep 10, 2026
Merged

Refuse a run that lost sight of EC, instead of blaming EC#101
amrali-eg merged 3 commits into
masterfrom
fix/ec28-fresh-window-probe

Conversation

@amrali-eg

Copy link
Copy Markdown
Owner

Closes EC-28. No production code changes; MainForm
was read and not edited.

What this does: the smoke suite stops blaming EC when it loses access to the
GUI. What it does not do: prevent access from being lost.

Reproduced

Thirty bounded full-suite runs were started on the final master build, stopping at
the first failure with its workspace preserved. Run 5 failed - in phase C, not
phase A, so the finding was never phase-specific.

The preserved workspace shows EC did the work correctly: french.txt
converted 39 to 45 bytes with a .bak and a sidecar, russian.txt left in
KOI8-R exactly as the phase requires. The application finished; the driver then
spent thirty seconds blind to it and reported that as EC failing.

Sending EC's window to a non-active virtual desktop reproduces the fingerprint on
demand. The excursion was verified with
IVirtualDesktopManager::IsWindowOnCurrentVirtualDesktop rather than assumed - an
early attempt read the state too soon after the hotkey and got the pre-switch
answer, which would have made the experiment a control that could not fail.

The standing theory was wrong

It is not a stale automation object. The held element answered
NativeWindowHandle without throwing, and looking the window up again from the
desktop found nothing either (window found afresh: no). Reacquisition, the
theory this branch set out to test, would not have helped. IsOffscreen is no
signal either - it reads false for a window on another desktop.

The fix

When a wait expires, the driver asks whether EC is still running and whether its
window can be found at all. Process alive and window unreachable is refused, not
failed: GuiEnvironmentException says the phase could not be verified and no
verdict about EC is reported - it may already have converted files - Program
returns exit 2 beside the other refused prerequisites, and no phase verdict is
printed.

The check began on the idle wait alone and that was not enough: an excursion
timed during phase C's source confirmation expired in a control lookup instead, so
it never ran and EC was blamed again. Every timeout is built in one place, so the
question is asked there and covers every wait. Startup keeps its own meaning -
before the window has ever been found, not finding it means EC failed to show one.

Controls

Control Result
Hidden past the timeout, during source confirmation exit 2, environment message, no phase verdict - previously [FAIL] C
Hidden briefly, returned inside the wait Phase passes; access returns with the window
Active desktop, 6 full runs All pass, no spurious refusal
Unit tests 756

Two earlier runs of the widened control passed and proved nothing, because the
desktop verification had been dropped from the script and the switch had not taken
effect. Recorded in the commit: an unverified control cannot fail.

Unproven

The original occurrence had nobody switching desktops, so its trigger is still
unknown; a locked session or lost interactive desktop would look identical. The
fix does not depend on which - any occurrence now becomes a refusal rather than a
false accusation, which is the harm that mattered on a required gate.

Setup this settles: the suite must run on the active desktop of an interactive
Windows session. Unattended runs need a dedicated interactive session.

🤖 Generated with Claude Code

amrali-eg and others added 3 commits September 10, 2026 08:58
Two of the four original leads were acted on in PR #98 and neither explained the
failure. WaitForMainReady no longer accepts any final conversion status - each
caller names the headline its own action produces - and the timeout now records
whether the process is alive, the main-window handle reads, the review is gone,
and the status bar can be found and read. Both were real weaknesses in the
failing path; removing them makes the next occurrence legible rather than mute,
which is not the same as finding the cause.

The entry also cited EC-26 as still open. It is fixed.

What remains is one untested theory - that the AutomationElement held for the
main window from startup goes stale, which would match a diagnostic that saw
window chrome and nothing inside it - and the observation that reproduction needs
the whole ten-phase suite rather than phase A alone. The theory's test is to
compare the held object against a freshly found one at the moment of failure;
reacquisition is worth adding only if they disagree.

The entry now also says how this closes: a cause reproduced and controlled closes
it as fixed, and a stress run without recurrence is recorded as not reproduced
and left under watch. Passing runs are not a fix.

Two paragraphs leaned on twelve phase-A-only runs to support a conclusion the
entry itself calls the wrong shape of evidence. They now rest on the code
argument, which is what actually carries them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
EC-28 reproduced. Sending EC's window to a non-active virtual desktop produces
the fingerprint exactly: the process lives, the conversion completes and writes
correct files, and every control inside the window becomes unreachable - the
held element answers but its subtree holds only the title bar. The suite then
reported a phase failure, which says EC did not finish work it had finished.

The standing theory was a stale automation object. It is wrong: looking the
window up again from the desktop finds nothing either, so reacquisition would
not have helped. IsOffscreen is no use as a signal - it reads false for a window
on another desktop - so the check is that the window cannot be found from the
desktop at all while the process is still alive.

That case is now refused rather than failed. GuiEnvironmentException says nothing
about EC was measured and names the likely causes, Program reports it with exit 2
beside the other refused prerequisites, and a phase deliberately does not absorb
it, because a phase result would be a verdict the run never earned.

Controls: hidden past the timeout, the suite exits 2 and prints no phase verdict,
where the previous build printed a phase failure. Hidden briefly and returned
inside the wait, the phase passes, so access returns with the window. On the
active desktop, six consecutive full runs passed with no spurious refusal.

The excursion was verified with IVirtualDesktopManager rather than assumed. A
first attempt read the desktop state too soon after the hotkey and got the
pre-switch answer, which would have made the experiment a control that could not
fail.

What this does not establish: the original occurrence had nobody switching
desktops, so the trigger that time is still unknown. A locked session or a lost
interactive desktop would look the same. The fix does not depend on which.

EC is unchanged, and was never at fault.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three corrections plus a widening the corrections uncovered.

The refusal no longer claims nothing was measured or that the run never took
place. EC may already have converted files; what is missing is the ability to
check. It now says the phase could not be verified and that no verdict about EC
is reported.

The fresh-window lookup is itself an automation call, and it was unwrapped: a
throw would have escaped and become the phase failure this exists to prevent. It
is now caught and reported inside the refusal.

Narrowing the ledger title to the idle wait exposed the real problem. A desktop
excursion timed during phase C's source confirmation expired in RequireById, not
in the idle wait, so the check never ran and EC was blamed again. Every timeout
in this driver is built by Expired, so the question is asked there and now covers
every wait. Startup keeps its own meaning: before the window has ever been found,
not finding it means EC failed to show one, so a flag set when it is first seen
separates that from losing it later.

Controls, each with the excursion verified through IVirtualDesktopManager rather
than assumed: hidden past the timeout during the source confirmation, the suite
exits 2 with the environment message and prints no phase verdict, where it
previously printed a phase failure. On the active desktop, six consecutive full
runs pass with no spurious refusal, and the unit suite is unchanged at 756.

Two earlier runs of this control passed and told me nothing, because I had
dropped the desktop verification from the script and the switch had not taken
effect. An unverified control cannot fail.

EC is unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@amrali-eg
amrali-eg merged commit 51c54b0 into master Sep 10, 2026
3 checks passed
@amrali-eg
amrali-eg deleted the fix/ec28-fresh-window-probe branch September 10, 2026 08:04
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