Commit Graph

14 Commits

Author SHA1 Message Date
AzuTear 7930e369a7 feat(ocr): substat-roll validation + rarity inference for GOOD export
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>
2026-07-06 16:21:28 +02:00
AzuTear b8309af377 fix(input): inject a no-op input event so force-foreground actually works
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>
2026-07-06 16:13:25 +02:00
AzuTear c8ae0dd7bf fix(input): force Genshin foreground via AttachThreadInput (auto-scan no longer aborts)
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>
2026-07-06 16:07:30 +02:00
AzuTear 113601f031 fix(electron): point main + preload + index paths at the real build layout
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>
2026-07-06 08:11:34 +02:00
AzuTear 39691fd40b feat(good): wire GOOD import/export UI into the Diagnose view
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>
2026-07-06 07:56:31 +02:00
AzuTear 8d4d24f0bb feat(ui): separate dev info into a Diagnose view, declutter the scan workspace
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>
2026-07-06 07:46:31 +02:00
AzuTear b8a38ba547 docs: scanner rework status (done vs remaining live-calibration items)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 21:57:23 +02:00
AzuTear dcac155887 feat(store): GOOD interop, rescan-merge, data staleness, lock detection
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>
2026-07-05 21:55:20 +02:00
AzuTear 6ea3d9e714 feat(scan): card-ready gating replaces the fixed settle delay
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>
2026-07-05 21:47:03 +02:00
AzuTear 2c6c1a8b31 feat(ocr): resolution-anchored layout module + crop preprocessing
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>
2026-07-05 21:42:16 +02:00
AzuTear c7138b541d feat(native): C# input/capture sidecar replacing the PowerShell helper
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>
2026-07-05 21:33:26 +02:00
AzuTear 92345ef51a fix(scan): repair pre-existing tsc errors so the build is green
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>
2026-07-05 21:25:34 +02:00
AzuTear b7dbc618b3 feat(eval): add field-level OCR accuracy harness + seed corpus
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>
2026-07-05 20:41:30 +02:00
AzuTear e76d88e0c7 chore: initialize repository baseline
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>
2026-07-05 20:31:01 +02:00