Repository navigation
Changelog
Home ← # Changelog
-
All handlers now return structured JSON instead of hardcoded
"ok"—verifiedResult()helper and ~50+ handler functions setContent: []mcp.Content{&mcp.TextContent{Text: "ok"}}which blocked the MCP SDK from auto-populating with the structured second return value. WhenContent == nil, the SDK marshals the second value and sets bothStructuredContentandContent(as JSON text). FixedverifiedResult()to returnnilContent when extra data is present, and changed every handler that returned explicit"ok"Content to return&mcp.CallToolResult{}, map[string]any{"ok": true}, nil(no-data tools) or&mcp.CallToolResult{}, result, nil(data tools). Verified live post-reboot:list_windows,get_system_info,get_active_window,ocrall return their structured JSON payloads instead of"ok".
-
roUninitializenever called on shutdown — COM WinRT apartment initialized byensureRo()was never cleaned up. AddedCloseWinRT()inocr_com.gowired intomain.go's signal handler soRoUninitializeruns on graceful shutdown. -
statusinitializer unreachable inverifiedResult—status := "ok"was always overwritten by the if/else branches before use. Changed to single defaultstatus := "ok (verified)"with negation on!vr.Passed. -
klMouseDownandwinEventHookProcdead code — leftover scaffolding from keylogger refactor.winEventHookProctype was unused (callback usessyscall.NewCallbackinline);klMouseDownwas shadowed by local vars inpollLoop. Removed. -
Unused
stateparams inexecVerifyandexecPoll— both functions received*chainStatebut never used it. Renamed to_ *chainStateto match the pattern already used byexecWaitandexecTool. Keeps call-site interface compatibility withexecIf/execLoopwhich do need state. -
Inefficient string concatenation in
WriteStringcalls — three spots inreadXlsxandreadPdfconcatenated strings before passing tobuf.WriteString(...), allocating intermediate strings. Changed tofmt.Fprintf(&buf, ...)which avoids the extra allocation.
-
uia_set_textMCP tool — writes text into a UI element via UI Automation'sValuePattern.SetValue. The COM plumbing (uiaElement.setValue) existed but was never wired. AddedUIASetText()inuia.go, handler and registration inserver.go. Fills a backlog item fromdocs/meta/backlog.md. -
Prior-based coordinate prediction in
FindUIElement—priors.gotracked element frequency and position per window butFindUIElementnever consulted them. AddedFindPriorPrediction()that returns predicted coordinates for high-confidence priors (frequency >= 70%, sample_count >= 5, StdX/StdY <= 2.0). Inserted as step 1.5 in the cascade: memory → prior → ONNX → OCR. A prior hit avoids ONNX (no GPU/CPU inference) and OCR (no PowerShell launch). -
ONNX/OCR failure logging in
FindUIElement— when ONNX detection failed, the function silently fell through to OCR with no trace of the error. Same for OCR failure. Addedlog.Printfcalls in both paths so server logs record when these subsystems are unavailable, distinguishing "not found" from "can't detect." -
Competitive intelligence gathered from landscape survey — cross-referenced 12 open-source and commercial projects in
docs/comparison-vs-alternatives.mdand extracted features worth adopting. Added a "Competitive Intelligence" section todocs/meta/plan.mdwith prioritized steals (quick wins → medium → high effort). Fleshed outdocs/meta/backlog.mdwith 3 new sections (Memory & ML, Transport & Server, Browser Automation, Linux & Container) and enhanced Security & Identity, Vision, Mouse, Screen, and Processes sections — totaling ~41 new backlog items. Shout out to Cua, Agent-S, Bytebot, MS Magentic-UI, Windows-MCP, DesktopCtl, Windows MCP Server, Computer Control MCP, Browser Use, and Microsoft Windows Recall for the reference implementations and design inspiration.
-
Double screenshot in
FindUIElementOCR fallback — when ONNX failed,OCRScreen("")captured the screen again even thoughCaptureScreen()had already been called at step 2. Changed OCR fallback to callocrFromBase64(b64, "")directly, reusing the existing screenshot. Also performspushRecentOCR/tryCompletePair/LogOCRSnapshotside effects thatOCRScreennormally handles. -
Fragile memory deserialization in
FindUIElement— the memory fast path used 4 levels of nested type assertions (any → map → float64 → int32) with silent fall-through on any mismatch. Extracted intomemoryToElement()helper that returnsnilon any parse failure, keeping it clear and testable.
-
Training pair pipeline died permanently after a single missed OCR window —
LogToolCallonly calledOCRScreen("")(the auto-capture that completes a pending pair and refreshesrecentOCRfor the next action) inside theif ocrBefore != ""branch. If one action'sfindRecentOCRBeforecall missed thebridgeWindow— entirely plausible under normal agent round-trip latency between an explicitocr()call and the action that follows it — the buffer never refreshed again. Every subsequent action would also find nothing, permanently starvingtraining_pairsuntil something called an OCR tool manually to re-seed it. Moved theOCRScreen("")auto-capture out of the conditional so it now runs after every action regardless of whether that action found a prior snapshot, making the bridge self-healing instead of a single point of failure.
-
bridgeWindowwidened 30s → 60s — 30s was tight for realistic agent-driven latency between an OCR call and the action that follows it. Combined with the self-healing refresh above, 60s gives headroom without letting stale context linger indefinitely.
Live end-to-end test through the MCP server (ocr → click → type → key_press → click → type): before this fix, 5 real actions produced 0 training_pairs rows (the bridge had already gone dark from an earlier missed window). After the fix and a rebuild/restart, the same kind of sequence produced 5/5 pairs, with agent_train/agent_analyze showing populated timing_stats, success_rates, and top_sequences with counts correctly bounded by total_commands.
-
agent_analyze: timing_stats/success_rates resetting on restart — Stats were purely in-memory (map[string]*ToolTiming,map[string]*ToolSuccess), so every server restart wiped them, leavingagent_analyzewith empty timing_stats/success_rates until new commands arrived. Addedadaptive_statsSQLite table andSaveAdaptiveStat()/LoadPersistedStats()/HydratePersisted(). On startup,EnsureAdaptive()callsHydratePersisted()to seed in-memory stats from the durable table, and everyRecordResult()call persists the aggregate asynchronously viago SaveAdaptiveStat(...). -
Training token inflation:
uniqueTokens()dedup —tokenize()on raw OCR text produced duplicate word entries per row (same word appearing multiple times in the OCR dump contributed multiple hits to the (word, command) pair). This causedCountintop_sequencesto exceedtotal_commands/total_sequences(which count rows, not word occurrences). AddeduniqueTokens()to dedupe before insert, so each (word, command) pair gets at most 1 hit per row regardless of how many times the word appears in the OCR context. -
OCR context scoped to nearby words —
findRecentOCRBefore()used to pass the ENTIRE screen's OCR dump asocr_beforefor every command, so common on-screen words ("the", bullet points, news headlines, unrelated UI labels) all got associated with whatever command followed — producing noise-dominated predictions. Now:- For coordinate-based tools (click, move_mouse, drag, hover), it uses word bounding boxes (
words []OCRWord) to scope context to words within 200px of the target coordinates, nearest-first, capped at 20 words. - For non-coordinate tools, it falls back to
capAndDedupeText()which returns at most 40 unique words from the full dump instead of the raw dump.
- For coordinate-based tools (click, move_mouse, drag, hover), it uses word bounding boxes (
-
LogToolCallno longer double-counts timing/success —LogToolCallpreviously calledAdaptive.RecordResult(tool, 0, errVal == nil)with a phantom 0ms duration. Callers (Click, TypeText, etc.) already callAdaptive.RecordResultwith the real elapsed duration. Removed the call fromLogToolCallto avoid every action being double-counted with a fake 0ms sample alongside the real one.
-
pushRecentOCR()signature — Now accepts*OCRResult(with word bounding boxes) instead of juststring, enabling spatial scoping infindRecentOCRBefore. -
findRecentOCRBefore()signature — Now takestool string, argsJSON stringto enable tool-specific OCR scoping. - Datalog query limit relaxed — From clamped 50–200 range to 1–5000 range (default 50).
-
chaintool startup panic — shared sub-schema pointers —chainInputSchema()reused the same*jsonschema.Schemaforthen,else, andstepsfields. The MCP SDK'sAddTool()requires schemas to form a tree (not a DAG) and panics on duplicate pointers. Changed to factory functions that return unique instances per call. -
Module path mismatch —
go.moddeclaredgithub.com/user/go-mcp-computer-usebut the repo lives atgithub.com/coff33ninja/go-mcp-computer-use. Updated module path and all 7 import references across the codebase. (User was lazy to update this.) -
Adaptive engine:
timing_statsandsuccess_ratesnever populated —RecordCommand(which callsRecordResult→RecordTiming+RecordSuccess) was defined but never called. AddedAdaptive.RecordResult(tool, 0, errVal == nil)toLogToolCallso runtime success/failure is tracked per tool. Previouslyagent_analyzealways showed emptytiming_stats: {}andsuccess_rates: {}. -
Adaptive engine:
rebuildSequencesmerge corruptsCountand never updatesFreq— When merging duplicate (word, command) entries, Count was overwritten instead of accumulated, and Freq (success ratio) was set at creation and never recalculated on merge. Added internalSuccessCount/FailCountfields toSequenceExample, fixed merge to accumulate correctly and recalculateFreq.
-
Chain integration tests — 7 tests build-tagged
//go:build integrationthat start the mcp-server binary and validate chain tool end-to-end via stdio MCP protocol. Covers: simple steps, capture, loop, if/else branching, unknown tool error, timeout, and structured data output. Run withgo test -tags=integration -v -count=1 -timeout 120s ./internal/actions/ -run 'TestChain_'. -
CI:
chain-testsjob — runs chain integration tests after lint in.github/workflows/ci.yml. - README badges — Go version, release, CI status, Windows, MCP, last commit, PRs welcome.
-
All 60+ query/result handlers now return structured data instead of "ok" — Every handler that returns meaningful data (get_volume, get_battery, list_windows, get_system_info, get_uptime, get_clipboard, get_pixel_color, list_displays, get_disk_usage, get_network_info, ocr, find_image, find_all_images, list_audio_devices, list_processes, uia_find, uia_get_text, memory_get/search/list, template_find/list/store/forget, training_, onnx_, datalog_status, chain, launch_and_wait, write_file, delete_file, find_files, list_directory, set/get_working_directory, bridge_debug, set_config, task_begin, and more) now return their structured JSON data instead of the placeholder
"ok"text. The SDK auto-populates tool results from structured output when no explicitTextContentis set, so tools likeget_screen_sizenow show{"width":1920,"height":1080}instead of"ok". -
get_screen_size,get_cursor_position— same fix applied (noticed during audit). -
chaintool schema — no longer rejected by Gemini —IfConfig.Then/ElseandLoopConfig.Stepschanged from[]anyto[]ChainStep, which produceditems: trueandtype: ["null", "array"]in the auto-generated JSON schema (both rejected by Gemini's MCP schema validator). The chain tool now uses a manually craftedInputSchemathat avoids the recursive type cycle injsonschema-goand produces clean schema output.
-
Windows icon embedded in mcp-server.exe — app.ico compiled into a COFF
.sysoresource viarsrc(github.com/akavel/rsrc), so the binary shows a custom icon in File Explorer, taskbar, and title bar. Icon sizes: 16, 32, 48, 64, 256px with SVG source inicons/app.svg. -
icons/directory — app.svg source, generated PNGs at 5 sizes, app.ico multi-res icon, app.rc resource script. -
scripts/gen-icons.ps1— PowerShell script that runsrsrcto compileapp.icointocmd/mcp-server/rsrc_windows.syso, auto-installingrsrcif missing. Called frombuild.ps1,lint.ps1, and CI release workflow.
-
Bump
golang.org/x/netv0.54.0 → v0.55.0 — dependency update from Dependabot patching a security vulnerability in thego_modulesgroup. -
.github/dependabot.yml—package-ecosystemwas empty""; set to"gomod"so Dependabot properly scansgo.modfor vulnerabilities.
-
write_file—overwriteis now optional — changedOverwrite boolto*Overwrite *boolwithomitempty. No longer required in tool schema, defaults tofalsewhen omitted. -
get_file_info— returns metadata instead of "ok" — handler now returns actual file info JSON (name,size,is_dir,mod_time,mode).
-
File System tools — 11 new tools for navigating and manipulating files:
-
list_directory— list files/dirs at path (name, size, is_dir, mod_time, mode) -
read_file— read file with automatic type detection + native format parsing -
write_file— write/overwrite files with format-aware creation and editing -
find_files— recursive glob search (e.g.*.go,**/*.md) -
copy_file— copy file or directory (recursive) -
move_file— move/rename file or directory -
delete_file— delete file/dir to Recycle Bin via SHFileOperationW (not permanent) -
create_directory— mkdir -p (recursive directory creation) -
get_file_info— file/dir metadata (size, mod_time, is_dir, mode) -
set_working_directory— set working directory for relative path resolution -
get_working_directory— get current working directory
-
-
Format-aware
read_file— auto-detects mime type by magic bytes + extension; parses:- Plain text (txt, json, csv, yaml, toml, md, source code, configs, etc.) via
io.ReadAll -
.docxvianguyenthenguyen/docxlibrary, extracting text from<w:t>XML elements -
.xlsxviaxuri/excelize/v2, all sheets rendered as TSV -
.pdfvialedongthuc/pdf, all pages with separators - Images (png, jpg, gif, bmp, tiff, webp) via native WinRT COM OCR (
ocrNative) - Pagination:
pageandpage_sizeparams (default 8000 chars), returns page/totalPages/truncated
- Plain text (txt, json, csv, yaml, toml, md, source code, configs, etc.) via
-
Format-aware
write_file— detects target extension and creates/edits:- Plain text — raw write via
os.WriteFile -
.docx— new file creates from scratch (ZIP+XML); overwrite preserves existing headers/footers/images by swapping<w:body>content, writes to temp + rename -
.xlsx— new file viaexcelize.NewFile(); overwrite opens existing, repopulates cells from TSV content -
.pdf— new file creates from text viago-pdf/fpdf; overwrite triespdfcpu.FillFormFilewith JSON form field data, falls back tocreatePdf
- Plain text — raw write via
-
File verification —
FilePreCheck/FilePostVerifywired into all 5 action file tool handlers (write, copy, move, delete, create_directory) usingExpConfig/VerifyArgspattern from v0.2.28 -
Recycle Bin delete —
delete_fileusesSHFileOperationWwithFOF_ALLOWUNDOto move items to the Recycle Bin instead of permanentos.RemoveAll -
Working directory — all file tools resolve relative paths against a configurable working directory (defaults to process CWD, changeable via
set_working_directory) -
New dependencies —
nguyenthenguyen/docx,ledongthuc/pdf,xuri/excelize/v2,go-pdf/fpdf,pdfcpu/pdfcpufor native document parsing and creation
-
internal/actions/filesystem.go— EnhancedReadFilewith format dispatch + pagination; enhancedWriteFilewith format-aware creation/editing (docx, xlsx, pdf); file verification helpers; Recycle Bin via SHFileOperationW; working directory support. -
internal/server/server.go— UpdatedReadFileArgs{Path, Page, PageSize}, updatedwrite_filetool description; file verification handlers. -
internal/actions/chain.go— UpdatedchainReadFilewith page/page_size params. -
VERSION— bumped to 0.2.29.
Now at 131 total MCP tools (+11).
-
Auto-verify on 5 remaining high-value tools —
open_url,launch_app,find_text_and_click,select_all_and_type,click_menu_itemnow supportauto_verifyandexpectedparameters with OCR-based post-action verification, matching the existing 6 tools. -
TrainingCatLaunchcategory — New"launch"training category for app launch snapshots. -
Pre-action validation (
pre_expected) — All 11 verification-enabled tools now acceptpre_expectedwith the sameExpConfigshape (text/not_text/change). Runs OCR before the action and fails fast if precondition not met — action is never executed. -
VerifyArgsembeddable struct — Replaced duplicateAutoVerify/Expected/PreExpectedfields across all 11 arg structs with a singleVerifyArgsembed, reducing 22 lines of redundancy. -
preVerifyCheckhelper — Common pre-verify logic extracted to server.go. -
Region-of-typing OCR —
type,type_and_submit,select_all_and_typenow capture cursor position (GetCursorPosition) before typing and restrict verification OCR toSmartRegionAround(cursor, 400px)instead of full-screen scan. -
Window-aware OCR for
click_menu_item— Verification scans only within the target window bounds (found byFindWindowByTitle+GetWindowState) instead of full screen. -
Coordinate-reuse for
find_text_and_click—FindTextAndClicknow returns click coordinates(int32, int32, error). The handler usesSmartRegionAround(click_pos, 400px)for post-verify instead of full-screen OCR. Pre-verify uses the specified search region.
-
internal/actions/chained.go—FindTextAndClicksignature changed fromerror→(int32, int32, error). Callers updated:server.go,chain.go,cmd/benchmark/main.go. -
internal/actions/training.go— AddedTrainingCatLaunch. -
internal/server/server.go— All 11 verification handlers updated with cursor-aware region (type tools), window-bounds region (click_menu_item), coordinate-reuse region (find_text_and_click), and pre-verify checks.VerifyArgsstruct replaces repetitive fields.
-
find_image/find_all_imagesONNX + OCR fallback — When NCC template matching fails (no match, degenerate template), both tools now cascade through ONNX YOLO object detection → Windows OCR.find_imagereturns the highest-confidence ONNX element (or first OCR word if ONNX is empty).find_all_imagesreturns all ONNX elements + all OCR words. The fallback captures a fresh screenshot if no screenB64 was provided (ensureScreenB64), making it robust against degenerate templates. -
findImageONNXFallback/findAllONNXFallbackhelpers — Extracted fallback logic with full cascade (ONNX → OCR) and screen capture self-healing. -
ensureScreenB64helper — Captures screen on demand when the passed-inscreenB64is empty, fixing the edge case where degenerate templates bypass screen decode. -
ocr_languagestool — NewOcrLanguages()function inocr.go:145queries WinRT COM (IOcrEngineStatics.get_AvailableRecognizerLanguages) and returns every installed OCR language with tag, display name, and native name. -
Middle mouse button —
Clicknow supportsbutton: "middle"viamouseEventMiddleDown/mouseEventMiddleUp(0x0020/0x0040). -
Horizontal scroll —
Scrollnow takeshorizontal boolparameter; usesmouseEventHWheel(0x1000) flag when horizontal.chainScrollpasses it through from args.
-
internal/actions/template.go—FindImageandFindAllImagesrestructured: degenerate templates (zero-dim, no-variance) skip NCC entirely and go straight to ONNX+OCR fallback. Template-larger-than-screen still errors (unrecoverable).FindAllImagesadded as new NCC implementation with non-maximum suppression (overlap >50% suppressed). -
internal/actions/window_ext.go—GetWindowStatenow returnsfullscreenboolean field. AddedisFullscreen()helper that checksMonitorFromWindow+GetMonitorInfoW+WS_CAPTIONstyle. -
internal/actions/window_ext.go— AddedmonitorFromWindowproc,MONITORINFOstruct,WS_CAPTIONconstant. -
docs/tools.md→docs/reference/tools.md— auto-regenerated (2 new tools, 120 total) -
Doc audit & reorganization — Audited 20 files across
docs/,dev/,.github/instructions/. Deleteddocs/todo.md(dead) anddev/models-setup.md(duplicate ofdocs/models-setup.md). Deduplicated privacy table, accessibility block, inline tool listing (80 lines), and inline release cycle (8 steps) into cross-references. Reorganized flatdocs/into subdirs:adr/,reference/,guides/,meta/. Moved 15 files to new locations. Updated all cross-references in README.md and all 18 docs files. -
CI/CD path updates —
ci.ymlreferencesdocs/tools.md→docs/reference/tools.md;release.ymlreferencesdocs/CHANGELOG.md→docs/meta/CHANGELOG.md;scripts/gen-tools-doc.gowrites todocs/reference/tools.md;scripts/push-and-release.ps1referencesdocs/meta/CHANGELOG.md. -
scripts/gen-tools-doc.go—MkdirAll("docs")→MkdirAll("docs/reference"), output path changed fromdocs/tools.mdtodocs/reference/tools.md. -
New reference docs —
docs/reference/windows-dll-ref.md(every syscall proc, DLL, COM interface used),docs/reference/uipi.md(UIPI elevation detection logic + call sites),docs/reference/com-patterns.md(COM/WinRT patterns: vtable dispatch, async polling, HSTRING/BSTR lifecycle, threading model, UIA tree traversal) -
Cross-reference updates —
README.md,codebase-map.md,windows-dll-ref.mdall updated with links to the 3 new reference docs -
docs/reference/windows-dll-ref.md— Fixed inaccurate advapi32.dll proc names (removedCheckTokenMembership/AllocateAndInitializeSid/FreeSidthat were never used inuipi.go) -
docs/reference/vtable-verification.md— New doc covering COM vtable stability guarantees, SDK header verification procedure, CI/CD plan, and complete test table (13 tests, 16 unique vtbl indices, all verified)
-
find_image/find_all_imagesno longer error on degenerate templates — Previously a constant-color or 0×0 template returned an unrecoverable error. Now falls through to ONNX + OCR object/text detection.
-
36 vtblMethod() call sites annotated — Every COM/WinRT vtable dispatch in
uia_com.go,ocr_com.go,ocr.go,winrt.gotagged with inline// N = MethodName (verified 2026-06-30, Win11 26200)and block-level// Verified YYYY-MM-DD — WinBuild SDKheaders above each interface definition. -
internal/actions/vtable_test.go— 13 smoke tests with build tag//go:build vtable && windows. Covers all 16 unique vtbl indices used in production: UIA GetRootElement (vtbl 5), BoundingRect (43), FindFirst (5, 21), Conditions (21, 23, 25), GetPropValue (10), GetCurrentPattern (16), ValuePattern/Invoke/Array (3, 4, 6, 21), OCR GetLanguages (7, 6), OCR TryCreate (10), OCR TryCreateFromLanguage (9), StorageFile async pipeline (6, 8, 14, 0, 7), HSTRING round-trip, vtblMethod nil guard. All pass (~8s). -
scripts/verify-vtable-docs.go— Parses all 36 vtblMethod() call sites from source, cross-references each unique index againstcom-patterns.mdandvtable-verification.mddoc tables, checks test coverage via// vtbl:annotations. Rungo run ./scripts/verify-vtable-docs.go. Confirms all 16 unique indices are documented and tested. -
CI:
vtable-checkjob —.github/workflows/ci.ymlrunsgo test -v -tags=vtable ./internal/actions/ -run 'TestVtable'after build, plusgo run ./scripts/verify-vtable-docs.goto catch doc drift. -
go vetpasses — zero warnings across all vtable code. -
scripts/verify-iid-usage.go— New Go script that parseswinrt.go, scansinternal/actions/for IID references, categorizes each asused(referenced outside winrt.go),internal(only within winrt.go), orunused. Cross-references against the Status column incom-patterns.mddocs. With-update, rewrites the Status column. Run:go run ./scripts/verify-iid-usage.goorgo run ./scripts/verify-iid-usage.go -update. -
scripts/discover-winrt-iids.ps1-UpdateDocs mode — Added-UpdateDocsswitch that auto-generates the 51-entry IID table indocs/reference/com-patterns.mdfrom discovered values, replacing the content between<!-- IID_TABLE_START -->/<!-- IID_TABLE_END -->markers. Includes fallback pass for statics discovered under flat keys. Now also callsverify-iid-usage.go -updateto set correct usage statuses. CI runs-UpdateDocsthengo run verify-iid-usage.gothengit diffto catch drift. -
ci.ymlvtable-check job — AddedVerify WinRT IID docs are in sync with sourcestep: runspowershell -File scripts\discover-winrt-iids.ps1 -UpdateDocs+go run ./scripts/verify-iid-usage.go, fails ifdocs/reference/com-patterns.mdhas uncommitted changes. -
docs/reference/scripts.md— New reference doc cataloging all 8 scripts with purpose, invocation, uniqueness, and cross-references to docs and CI. -
docs/reference/com-patterns.md— VTable dispatch section (§2) updated withIUnknown basecolumn in all index tables. IID table wrapped in<!-- IID_TABLE_START/END -->markers with new Status column (used/internal/unused). Inline-UpdateDocsflag in both "run the script" instructions. -
docs/reference/vtable-verification.md— Expanded from "proposed plan" to actual test table withvtbl Indices+Verifiedcolumns, Performance note documenting whyFindAllon desktop root is slow by design, and CI/CD integration reference. -
uia.goandConditiondead code fixed —CreateAndCondition(vtbl 25) was called frombuildConditionbut not tested; now exercised byTestVtable_IUIAutomation_Conditions. -
internal/actions/uia_ctrltype_test.go— 3 tests validating the UIA ControlTypeId map covers all 41 constants (50000–50040), no duplicates, no out-of-range values, and unknown names return nil. -
Cross-references updated —
README.md,docs/reference/codebase-map.md,docs/reference/windows-dll-ref.md,docs/ci-cd-pipeline.mdall linked to new vtable docs. -
VTable indices are hard-won — Every index was researched against SDK headers (UIAutomationClient.h, windows.data.h, windows.storage.h) and verified at runtime on Windows 11 (build 26200). These are the most fragile part of the codebase: an incorrect vtbl index silently calls the wrong method or crashes. The verification script and test suite exist because even a single off-by-one error can take days to diagnose. Microsoft freezes these indices for published interfaces, but when upgrading to a new Windows build, run
go test -tags=vtableandgo run ./scripts/verify-vtable-docs.gobefore shipping.
... older versions omitted.