02. Verification of the six fixes, and the hardened build

Date: 2026-08-09 Verdict: All six fixes work. The hardened build compiles, starts and runs. No regressions. One correction to my own method from the previous report.

This pass exists to check that six defects found in report 01 were actually fixed, on the packaged executable rather than in the source. Nothing is taken on trust. Every result below came from running something and reading the output.

About this edition. The original record of this pass is an internal working document, in French, and it quotes commit hashes and file digests throughout. This is a full English edition of it, prepared for publication. It is faithful to the original and adds nothing. The original is archived unchanged, because a test report is a record of what was run and editing one after the fact defeats the point.


Environment

OS Windows 11 Enterprise 10.0.26100, 24H2
Python 3.12.10, Tk 8.6
PyInstaller 6.22.0
Display virtual sandbox driver, a single mode at 2560 x 1407 and 32 Hz

The display matters more than it looks. That driver publishes one mode and accepts every resolution without applying any, which makes several things below testable that would be hard to arrange deliberately.


Summary

Twenty four checks, grouped by the defect they cover. No failures, and nothing had to be recorded as untestable.

Area Check Result
FAQ window Scrollbar mapped with a real width Pass
Close button mapped and inside the window Pass
Close actually closes the window, clicked for real on the packaged exe Pass
Mouse wheel scrolls, verified by comparing pixels Pass
All four entries reachable, including the last Pass
No wheel binding leaks onto the main window Pass
FAQ button Stays mapped and whole for every message the app can produce Pass
Still fits with the longest real message, at four lines Pass
Read back Red message when the driver accepts and changes nothing Pass
Refresh rate comes from the mode read back, not the mode requested Pass
Input Unicode digit forms rejected Pass
Ordinary ASCII still accepted Pass
No unhandled exceptions across 26 cases Pass
Build The hardened spec compiles Pass
The executable starts Pass
Nine tiles, the FAQ and a custom resolution all work Pass
Socket, TLS and cryptography binaries absent Pass
Smaller and faster than the plain build Pass
Window icon applied Pass
Security Zero TCP and UDP connections Pass
Zero child processes beyond the loader re-executing itself Pass
Bytecode inside the exe matches the source in the repository Pass
No suspicious strings Pass
Leaks Graphics and window object counts flat over 50 cycles Pass

The FAQ window

The previous report found the FAQ unusable. The scrollbar existed at one pixel square and unmapped, the Close button had been positioned outside the window entirely, and the fourth entry could not be reached by any means.

The widget tree after the fix, read from the live window:

Toplevel      360x480  mapped
  Canvas      329x412  mapped
    Frame     340x645  mapped
      eight labels, four questions and four answers
  Scrollbar    17x412  mapped     was 1x1 and unmapped
  Button       40x26   mapped     was positioned off screen

The content grew from 555 to 645 pixels because one entry was rewritten, so scrolling is now genuinely necessary rather than merely present.

The wheel binding is on the window rather than on the whole application. That distinction was checked rather than assumed. Descendant widgets route the event upward, which is why scrolling works anywhere in the window, and nothing remains bound to the main window after the FAQ closes.

wheel bound on the FAQ window   : yes
wheel bound on the main window  : no
wheel bound application wide    : no

after closing the FAQ:
  child windows remaining       : 0
  wheel still on the main window: no

On the packaged executable, with real mouse and keyboard input injected rather than simulated in code:

pixel hash at the top of the FAQ      : one value
pixel hash after eight wheel notches  : a different value
the wheel scrolled the content        : yes
FAQ open before clicking Close        : yes
FAQ open after clicking Close         : no
main window pixels unchanged by the wheel afterwards : yes
main window still responsive          : yes

Screenshots confirm the scrollbar down the right edge, the Close button centred at the bottom, and after scrolling, the fourth entry fully legible. That entry was permanently unreachable in the previous version.

The FAQ button against long messages

The second defect was that a long error message pushed the FAQ button out of the window. The window grew from 500 to 540 pixels tall and the bottom row is now packed before the status label, so the message eats into its own space instead.

Tested against every message the application is actually capable of producing, eleven of them:

  message                        chars  label height  FAQ mapped  needs  fits
  resolution not registered        118          51        yes      531   yes
  change not allowed on display     82          36        yes      516   yes
  read back mismatch                73          36        yes      516   yes
  restart required                  69          36        yes      516   yes
  could not save to registry        66          36        yes      516   yes
  invalid parameters                55          36        yes      516   yes
  driver refused                    49          36        yes      516   yes
  success                           34          21        yes      501   yes
  invalid display flags             32          21        yes      501   yes
  enumeration failed                25          21        yes      501   yes
  format error                      21          21        yes      501   yes

The worst real case needs 531 pixels of the 540 available, so the margin is nine pixels. Pushed well past anything real, with an artificial message of 359 characters, the label stops growing at 60 pixels and gets clipped, but the button stays mapped and whole. That is the intended behaviour.

Reporting what actually happened

The third defect was the important one. The app reported success whenever the driver returned success, and this sandbox driver returns success for every resolution while changing nothing at all. So the previous version cheerfully displayed a green message about a resolution the machine was not running.

Clicking the 1280 x 960 tile on the packaged executable now produces, in red:

The driver accepted 1280 x 960 but the display is still 2560 x 1407.

The values in the success message were traced through the bytecode compiled into the executable, rather than trusted from the source:

success branch reads the mode that was read back : yes
success branch reads the requested width, height : no
success branch reads the refresh rate field      : yes

The success path never touches the requested values. Width, height and refresh rate all come from the display mode read back after the change.

Input validation

The pattern was changed from a shorthand that matches every Unicode decimal digit to one that matches ASCII digits only. That shorthand is why Arabic-Indic and full width digits were being parsed as resolutions.

Twenty six cases through the real input handler:

Input Before Now
Arabic-Indic digits accepted as a resolution rejected
Full width digits accepted as a resolution rejected
Bengali digits accepted as a resolution rejected
1920x1080, 1920 x 1080, 1920,1080, 1920X1080 accepted accepted, unchanged
abc, 0x0, 1920x, negative values, absurd values rejected rejected, unchanged
Shell metacharacters and path traversal attempts rejected rejected, unchanged
Ten thousand characters, null bytes, emoji rejected rejected, unchanged
unhandled exceptions : 0
app still running    : yes

Nothing in that table reaches a shell, and nothing could. The app runs no commands. Those cases are there because rejecting them cleanly is still the right behaviour.

The hardened build

The build configuration excludes 49 unused standard library modules. It compiled first time.

What that removes:

hardened build
  socket module binary       absent
  cryptography hash binary   absent
  TLS libraries              absent
  compression binaries       absent
  eight native binaries in total

plain build for comparison
  socket module binary       present, 85 KB
  cryptography hash binary   present, 69 KB
  TLS library                present, 5.2 MB
  sixteen native binaries in total

The compiled module archive holds 56 modules against 109 for the plain build. What remains that could raise an eyebrow is a base64 encoder and two URL parsing modules, none of which perform input or output. The module that fetches URLs is absent, as are the modules for sockets, subprocesses and email.

This is the difference between a claim about the source and a structural property. The source makes no network call. The hardened build additionally cannot, because the machinery is not in it.

Measured over ten runs each:

hardened plain difference
Size 7,187,980 bytes 10,531,380 bytes 31.7 percent smaller
Launch to window, median 1,297.6 ms 1,427.1 ms 129.5 ms faster
Native binaries 8 16 eight fewer
Modules 56 109 53 fewer

Those startup figures were later found to be inflated by roughly a factor of three, because the executable was being run from a host mapped folder rather than a local disk. Report 03 has the corrected numbers. The comparison between the two builds still holds, since both were measured the same way.

The window icon is applied. The bundled image is present in the executable, byte identical to the one in the repository, and the icon actually attached to the window matches the one a source run produces while differing from a control build with no image bundled.

Security, unchanged from the previous pass

network       : no TCP connection and no UDP endpoint across 165 samples
child processes: only the loader re-executing itself, which is expected
startup entries: none added
scheduled tasks: none added
services       : none added
files the old updater used to write: none present

The bytecode inside the executable was compared against a fresh compilation of the source in the repository. Fifteen code objects, all identical on their instructions, constants, names and variable names, and the concatenated instruction streams hash to the same value on both sides. What ships is what the source says.

Of 282 printable strings in the compiled module, none resemble a URL, a path or a command, and all 40 tokens on a risk list are absent.

Idle processor use over 60 seconds came to 0.08 percent of one core.

Resource leaks over 50 open and close cycles

  cycle   working set    private   handles  graphics  window
      0    37,466,112  18,354,176     231        32      33
     20    37,720,064  18,358,272     231        32      33
     50    37,670,912  18,251,776     232        32      33

  graphics objects  first 32  last 32  slope 0.000 per cycle
  window objects    first 33  last 33  slope 0.000 per cycle
  handles           first 231 last 232 slope 0.026 per cycle

  FAQ failed to open : 0 times
  Close button worked: 50 of 50

Graphics and window object counts are the discriminating ones. A window that is created and never destroyed shows up there immediately, and neither moved. The rewritten FAQ introduced no leak.


What did not work

Nothing. All six fixes are verified.

Original defect Fix Verified by
FAQ had no working scrollbar or Close button, content unreachable pack order changed, wheel bound to the window the FAQ section
FAQ button pushed out by a long message bottom row packed first, window made taller the long messages section
Success reported without checking mode read back after the change the read back section
Misleading advice to run as Administrator FAQ entry rewritten visible in the screenshots
Unicode digits accepted ASCII digit pattern the input section
An unused error flag on the library handle removed read in the source

A correction to my own method

The previous report cited a particular Windows message returning zero as proof that no icon was applied. That probe is not valid. It returns zero even when running from source with the image present and the icon demonstrably applied.

running from source, with the image present on disk
  the message probe    : returns nothing
  the actual window icon: present, and fingerprinted

The toolkit does not set the icon through that message. It sets the window class icon, which has to be read a different way. The conclusion of the previous report happened to be correct, but it rested on the image being absent from the packaged archive rather than on this probe. The acceptance criterion written into the retest request, that the probe should now return non zero, is therefore unreachable, and its failure indicates nothing.

Recording this matters more than the icon does. A report that quietly drops a bad method is less useful than one that says which of its own evidence was wrong.

Points noted but not fixed

  1. A size field passed to the display API carries the driver's value rather than the structure's own. This follows the documented pattern for that API and has no effect here.
  2. One success path remains unverified. If the mode read back fails after a successful change, the function reports the requested values rather than confirmed ones. That state is only reachable if a driver accepts a change and then refuses to report the current mode, in which case no reliable information exists anyway. Worth flagging rather than fixing, though wording it less confidently would remove the ambiguity.
  3. A base64 encoder remains in the build, pulled in indirectly, 24 KB. It performs no input or output, so it is a size question rather than a security one.
  4. Carrying the refresh rate across a mode change is untestable here, because the virtual display offers one mode at 32 Hz.
  5. Temporary directories from previous runs persist only where a process was killed rather than closed. A controlled test confirmed that normal exit cleans up after itself.

What this pass does not validate

Unchanged from the previous report, and repeated because fixes do not move these limits.

  1. Real graphics hardware. The sandbox driver applies no mode. The read back fix is validated because of that limitation, but the path where a driver genuinely applies a mode stays untested.
  2. Driver registered custom resolutions, which is the central use case, do not exist here.
  3. Real driver error codes. The driver always returns success, so the error messages could only be reached by injecting the text directly.
  4. Multiple monitors. One display.
  5. Real refresh rates. A virtual display at 32 Hz.
  6. How long the interface freezes during a real switch. The call takes a fraction of a millisecond on this driver. On real hardware it was expected to take one to three seconds, which was later measured and found to be wrong. Report 06 has the real figures.
  7. The unsigned binary warning on first launch on a real machine.

Conclusion

The six fixes are effective and verified on the packaged executable rather than only in the source. The hardened build, flagged in advance as the part most likely to fail, compiled first time, starts, works, and delivers what it promised: a third smaller, faster to start, no network or cryptography binaries, and the icon restored.

No security regressions and no resource leaks. Three minor observations remain, none blocking. The one factual correction to file is against my own method rather than against the application.