Adds the accuracy check yas / Genshin Optimizer use: a substat value is only
legitimate if it equals round(sum of 1..6 rolls) from that stat's roll table.
Values that fit no combination at either rarity are guaranteed OCR misreads.
- src/lib/substatRolls.ts: 5-star roll tables (+ 4-star %/crit tables to tell
rarities apart), pure isPlausibleSubstat/implausibleSubstats, and inferRarity
(level > 16 or roll-table fit; conservative, defaults to 5). Validates against
the union of rarities so valid 4-star pieces are not false-flagged.
- Wired in: shouldFlagArtifactForReview routes implausible substats to review;
the parser adds an explanatory note; goodInterop export replaces the hardcoded
rarity:5 with inferRarity (fixes wrong 4-star exports to GO/IK).
- 10 new unit tests; 131 total green; eval still 100%.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Follow-up to the AttachThreadInput change: verified against an isolated repro
(a foreground-stealing window + the helper spawned exactly like the app) that
AttachThreadInput + clearing the foreground-lock timeout was NOT sufficient on
this Windows build - SetForegroundWindow still returned false and Genshin stayed
in the background.
The missing condition is "the calling process received the last input event".
Injecting a benign no-op input (a 0,0 relative mouse move, no cursor movement, no
menu-mnemonic side effect) right before SetForegroundWindow satisfies it. With the
nudge the repro now returns focused:true / setForegroundResult:true from a
background process while another app holds the foreground - the exact auto-scan
start scenario. Applied to both the C# sidecar and the PowerShell fallback.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Auto-scan aborted immediately with "Genshin konnte nicht in den Vordergrund
geholt werden". Root cause: the focus call runs in the background input/capture
helper process, and Windows' foreground lock silently refuses SetForegroundWindow
from a process that is neither foreground nor the last input source. When the user
clicks "Auto-Scan starten" the Electron window is foreground, so the helper's plain
SetForegroundWindow is dropped and focus stays false.
Fix (both the C# sidecar and the PowerShell fallback): before SetForegroundWindow,
attach our thread's input queue to the target (and current-foreground) window
thread with AttachThreadInput and clear SPI_..FOREGROUNDLOCKTIMEOUT, then restore.
This is the same technique Inventory Kamera and other reliable automators use; it
is what our helper was missing after the old ALT-tap workaround was removed on the
wrong assumption that equal integrity level is sufficient (that only covers UIPI
input injection, not foreground changes).
Sidecar recompiled + republished; electron build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
npm run dev failed with ERR_MODULE_NOT_FOUND for dist-electron/services/inputHelper.
Root cause: the electron program includes src runtime files (repositories,
layoutProfile, ocrPreprocess), so tsc's inferred rootDir is the project root and
it emits the entry at dist-electron/electron/main.js (with src at
dist-electron/src). package.json "main" still pointed at a stale flat
dist-electron/main.js fossil from an older build layout, whose extensionless
imports don't resolve under NodeNext ESM.
- package.json main -> dist-electron/electron/main.js.
- predev/build copy preload.cjs into dist-electron/electron/ (next to main.js,
where main.ts resolves it via __dirname).
- main.ts loads ../../dist/index.html (one level deeper now) for the packaged
window + overlay.
Verified: clean electron build emits only the nested layout; electron . loads the
main process past module resolution (only ERR_CONNECTION_REFUSED for the dev
server, expected standalone); npm run build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Completes the GOOD interop point end-to-end (the conversion engine landed earlier
in goodInterop.ts). No new IPC needed - reuses the existing artifacts:load /
artifacts:saveMany / good:export bridge.
- Scan controller gains exportGoodFromStore (loadArtifacts -> storedArtifactsToGood
-> exportGood) and importGoodArtifacts (saveMany + snapshot refresh), plus a
canGoodInterop flag.
- DiagnosticsView adds a GOOD Interop card: export the scan store as GOOD, or
import a GOOD file. The file is read in the renderer via a file input +
goodDatabaseToStoredArtifacts, so no file-dialog IPC is required.
Verified in the browser preview after a clean restart: the Diagnose view renders
all cards (Status, Last scan, GOOD Interop, Automation log, Crops/OCR), the
Scan<->Diagnose switch works with no console errors (the earlier hook-order
warnings were stale-HMR artifacts from deleting files mid-session). 120 tests +
build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reworks the UI so the Scan tab shows only core actions and all developer /
diagnostic surfaces live in one dedicated view.
- New "Diagnose" nav view. ScanView stays mounted for scan|diagnose (the scan
controller state persists across the switch) and renders either the clean
workspace or the new DiagnosticsView by mode.
- DiagnosticsView consolidates runtime/rights, grid detection, learning + data
staleness, fingerprint, auto-scan counters, the automation log, the dev-output
toggle, the Demo-Daten action, and the raw crops/OCR/confidence dump. Reuses
the existing diagnostics/details model hooks.
- Scan workspace decluttered: removed the Scanner Diagnose button and the Details
button, dropped the rules/grid/mode dev fields from the result brief and capture
meta, shortened the topbar headline, and moved Demo-Daten out of the topbar.
- Removed the now-dead ScanDiagnosticsModal / ScanDetailsModal components (their
content moved into the view); metrics grid hidden on the Diagnose view.
- Added dev:web script + .claude/launch.json for browser preview.
Verified in the browser preview (both views render, no console errors); 120
tests + build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Task #5 building blocks, each a pure + unit-tested module:
- goodInterop.ts: GOOD (Genshin Optimizer / Inventory Kamera / Akasha) import and
export for scanned StoredArtifactRecords - slot/stat/set key maps both ways,
substat string <-> { key, value }, main-value reconstruction on import
(ADR-003). Export is lossless; import is best-effort (GOOD lacks piece names).
- artifactMerge.ts: rescan-merge (ADR-006 follow-up). Level-independent identity
(set + slot + main + substat NAME set) collapses leveled re-scan duplicates,
keeping the higher-level/stronger record and summing timesSeen. Conservative:
differing substat lineups never merge.
- dataPackageStatus.ts: warns when the genshin-db package is older than ~45 days
(a patch cycle) so new sets/characters aren't silently missed; surfaced in the
Scanner Diagnose data-package line. Adds dataGeneratedAt to genshinData.
- lockDetection.ts: EXPERIMENTAL read-only lock-status heuristic (gold-pixel
ratio in a top-right icon crop). Pure + tested but not wired into capture; crop
position and threshold need calibration against a reference 16:9 screenshot.
120 tests + build green. Remaining wiring (needs UI / live calibration): GOOD
import/export buttons and live lock detection.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds src/lib/cardReadyGate.ts: after a tile click, poll the detail fingerprint
until it has both changed from the previous artifact and stabilized across
consecutive samples, instead of waiting a hardcoded 280ms and hoping.
- Faster on quick machines (proceeds as soon as the card is stable), correct on
slow ones (waits up to the budget).
- Robust to particle/hover-glow animation: requiring two consecutive equal
samples ignores single-frame noise, and if the card never fully stabilizes it
still proceeds once the content has changed rather than looping on an animated
frame.
- ESC/stop abort is honored between polls via checkAbort.
autoScanLoop now uses waitForCardReady for both the initial read and the one
retry; CLICK_SETTLE_MS removed. 6 new unit tests; 94 total green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements ADR-009 (structure + preprocessing; exact IK fixed coordinates still
need calibration against a reference 16:9 screenshot).
- src/lib/layoutProfile.ts: pure, unit-tested geometry for the artifact screen -
detail rect, the four detail crops, inventory rect/count crop, 5-col grid,
16:9 detection, aspect label, and an off-16:9 support warning. Single source of
truth; electron/main.ts now delegates all crop/grid geometry to it and keeps
colour detection only as the detail-rect fallback.
- src/lib/ocrPreprocess.ts: pure, unit-tested Otsu binarization with inversion
(artifact text is the bright foreground) over a BGRA bitmap.
- main.ts: OCR now reads an upscaled + binarized copy of each crop; the original
crop is retained for the diagnostics UI. CaptureResult carries layout info
{ aspect, isSixteenNine, warning }.
NOTE: image preprocessing changes the OCR input and cannot be validated by the
text-level eval harness; it needs a live Genshin 16:9 capture to confirm/tune
(threshold, invert, upscale factor). 88 tests + build green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Implements ADR-008. native/input-helper is a self-contained .NET 9 console exe
speaking the identical JSON-over-stdin/stdout protocol as the old PowerShell
helper (ping/cursor/runtime/focus/click/scroll/bounds/capture), so the
InputHelperService interface is unchanged.
- Win32 interop compiled once (native exe), not per call.
- PerMonitorV2 DPI via manifest so click/capture coordinates stay correct on
mixed-DPI multi-monitor setups.
- capture returns base64 PNG bytes inline (imageBase64) instead of writing a
temp file per frame; the client handles both base64 and the PowerShell path.
- InputHelperClient prefers the exe and falls back to the embedded PowerShell
helper when the exe is absent, so the app still runs without the .NET build.
- main.ts resolves the exe (INPUT_HELPER_EXE env -> packaged resources/input-helper
-> native/input-helper/bin/publish). electron-builder ships it via extraResources.
- npm run helper:build; README documents the build + fallback.
Verified end-to-end through the compiled client: sidecar spawns, runtime info
and a base64 primary-screen capture return correctly. Build stays green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The scan feature had 16 tsc errors from refactor drift; npm run build failed.
- modals/hooks/* are five levels deep but imported ../../../../lib (four);
corrected to ../../../../../lib.
- useScanDiagnosticsModalModel / useScanReviewQueueModalModel picked
saveReviewSample / canSaveReviewSample / loadReviewQueue from the modal Props,
but the components wire those through from controller.*; source them from the
controller type instead (fixes the downstream unknown-type errors).
- useScanResultCardModel let its field-row tuple array widen to
(string | ParsedField)[][]; annotate it Array<[string, ParsedField]> like the
sibling hook.
- ScanTopControlsModel was missing autoScanRunning (destructured by the
component); add it. useScanTopControlsModel does not use refreshCaptureSources,
so its input is Omit<...,"refreshCaptureSources">.
tsc, vite build, and the electron build all pass; 74 tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a measurement gate for the artifact OCR parser (ADR-007), the prerequisite
for the layout-profile and preprocessing rework. runOcrEval feeds labeled OCR
text through the real parseArtifactCandidate and scores per-field / per-case
accuracy.
- src/eval/ocrEvalHarness.ts: pure metrics (per-field, critical-field, exact).
- src/eval/corpus/seedCorpus.ts: 23 cases transcribed from the verified parser
test assertions; runs at 100%.
- src/eval/reviewSampleCorpus.ts: converts review samples into label *candidates*
(never ground truth) so the review queue can grow the corpus.
- src/eval/ocrEval.test.ts + reviewSampleCorpus.test.ts: gate (must stay 1.0) and
converter unit tests.
- npm run eval script; docs/ocr-eval.md; ADR-007/008/009.
Also records the agreed rework direction: C# input/capture sidecar (ADR-008) and
resolution-anchored layout profiles + OCR preprocessing (ADR-009).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Import the existing Electron + React + TypeScript app as the version-control
baseline before the scanner rework (C# input/capture sidecar, resolution-anchored
layout profiles, OCR preprocessing, eval harness, rescan-merge, GOOD interop).
Housekeeping in this commit:
- Remove orphaned temp_inputhelper_block.ts (duplicate of the input-helper script).
- Ignore .claude/scheduled_tasks.lock local session state.
- Add .gitattributes to normalize line endings (LF in repo).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>