Improve IK-style artifact scanner pipeline

This commit is contained in:
AzuTear
2026-07-07 22:02:24 +02:00
parent 8ebbe91c39
commit f791d1464c
70 changed files with 7408 additions and 445 deletions
+19 -1
View File
@@ -55,6 +55,9 @@ flowchart LR
| `src/App.tsx` | Main app shell, scan view, triage view, build view, overlay preview |
| `src/lib/artifactOcrParser.ts` | Converts OCR output into a parsed artifact candidate with confidence and notes |
| `src/lib/fuzzyMatch.ts` | Generic fuzzy string matching for OCR text against known game data |
| `src/lib/genshinLookup.ts` | Pure lookup and validation API for generated Genshin data |
| `src/lib/autoScanEntry.ts` | Pure entry-mode planning and auto-scan preflight validation |
| `src/lib/cardReadyGate.ts` | Detail/page fingerprint readiness gate for scan timing |
| `src/lib/scoring.ts` | Recommendation and build scoring logic |
| `src/lib/demoData.ts` | Temporary local demo snapshot |
| `src/data/genshinGameData.json` | Generated local dictionary of characters, artifact sets, slots, and stats |
@@ -131,6 +134,17 @@ sequenceDiagram
[AUTOMATION_LIVE_SCAN.md](AUTOMATION_LIVE_SCAN.md).
- Click verification: after each click the parsed detail-panel signature should change. An unchanged signature is a soft miss (it can also mean two OCR-identical neighbor pieces, common among +0 artifacts), so it is retried once with a small offset, logged with the stuck artifact name, and then skipped - never fatal on its own. The scan aborts only when the first ~6 clicks of page 1 produce nothing new (diagnosis hint: elevated Genshin blocks SendInput via UIPI, or grid coordinates are wrong) or a later page yields zero new artifacts.
- Scan stats separate clicked (click attempts), parsed (readable captures), stored (persisted), review (review samples), duplicates, and misses, so "scanned" cannot be mistaken for "successfully read".
- Artifact grid automation uses Inventory Kamera's 32-target full-page model
(`8 x 4` safe click targets). The apparent lower fifth row sits in the
bottom control band on 16:9 captures and is not clicked automatically.
- Guided auto-entry is state gated. The normal scan button first performs a
lightweight no-OCR preflight; OCR/store/review work starts only after the
artifact inventory grid and artifact detail card are visually confirmed.
- The entry path tries direct inventory (`B`) first and uses the IK-style
ESC/B fallback only when direct entry does not reach an artifact detail card.
- Card and page waits are fingerprint based. The scanner can proceed as soon as
the expected visual state changes and stabilizes, while still accepting IK-like
200 ms item and 100 ms scroll readiness points.
- Scrolling sends one wheel notch per grid row with the cursor anchored over the inventory (assumption: roughly one row per notch; overlap is absorbed by dedupe, and a page without new artifacts stops the scan).
- The scan never deletes, enhances, feeds, locks, or spends anything; it only selects tiles to read them.
@@ -156,4 +170,8 @@ Parsed artifacts from both modes are persisted into `artifact-store.json` keyed
## Performance
Current OCR is prototype-grade and may be slower than the target scanner. Two batch-scan bottlenecks were removed: input/capture no longer spawn a PowerShell process (and recompile Win32 interop) per action, and the Tesseract worker is created once and reused across captures. The eventual batch scanner should still move expensive capture/OCR/build work into workers or a native sidecar.
Current OCR is still measured against the IK target rather than assumed good.
The app keeps a Tesseract.js worker pool, can use the Inventory-Kamera
`genshin_fast_09_04_21.traineddata` path for comparison, and reports capture,
OCR, card-ready, scroll-ready, active-scan, and projected-100 timings. A default
engine change requires a same-capture benchmark and a qualified live soak result.
+282 -1
View File
@@ -23,6 +23,12 @@ Validated live on 2026-07-07 with Genshin open in the artifact inventory at
This proves that the current elevated app plus helper path can deliver mouse
movement and click input to the focused Genshin client in this environment.
Latest-source timing is not proven while `/health.appBuild.signature` differs
from the `APP_RUNTIME_SIGNATURE` in `electron/main.ts`. On 2026-07-07 the port
was still owned by an older elevated runtime, so goal scans were intentionally
blocked by the stale-build gate. Restart the elevated app through
`npm run dev:admin` and confirm UAC before collecting new 100-artifact evidence.
## Elevation And UAC
Use:
@@ -98,6 +104,66 @@ For live validation, prefer a bounded scan first:
Invoke-RestMethod "http://127.0.0.1:17317/scanner/start?limit=2"
```
The visible-inventory path remains the safest first check. The normal guided
entry tries the read-only direct world path first:
`B -> artifact tab -> first artifact tile`. If that does not produce a visible
artifact detail card, it falls back to the Inventory Kamera-compatible sequence:
`ESC -> B -> artifact tab -> first artifact tile`.
The normal Auto-Scan button uses a guided start. It first takes one lightweight
preflight capture without OCR, full-frame payload, review scoring, or storing.
If an artifact detail card is already visible, it starts the visible-inventory
scan. Otherwise it runs the guided entry above. OCR/review/store work starts
only after the artifact-detail preflight passes.
Guided entry uses short state polling for the Inventory screen, artifact grid,
and first detail card instead of waiting the full fixed delay every time; if the
state never appears, the same timeout budget returns the last diagnostic capture.
```powershell
Invoke-RestMethod "http://127.0.0.1:17317/scanner/start?entry=paimon-menu&limit=2"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/start?entry=auto-entry&limit=2"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/start?entry=visible-inventory&limit=2&engine=ik-traineddata"
```
Those paths send only read-only navigation. `ESC` is not a universal "go to
world" command: from the world it opens the Paimon menu, while from the
already-open Paimon menu it returns to the world. This is why the normal
`auto-entry` path first tries `B` directly and uses the IK-style `ESC -> B`
fallback only when direct entry did not reach an artifact detail card.
The scan starts only after a valid lookup package, supported 16:9 layout,
detected artifact grid, Genshin-client capture, and visual artifact-detail
markers are all present. If any preflight check fails, keep using the
visible-inventory path while tuning the entry step.
The visual preflight also classifies the Paimon menu. The Paimon profile/card
grid can look like an inventory grid if only fixed 16:9 coordinates are used, so
the scanner must reject `paimonMenu.present` before any artifact OCR, review
sample creation, store write, or grid scan starts. The guided entry may still
take lightweight skip-OCR captures while navigating, but those captures are only
state evidence.
The same guard also runs inside the scan loop. If the app is on the main game
screen, a Paimon/menu screen, a generic primary-screen capture, or any screen
without an artifact detail card, auto-scan must block instead of clicking tiles
or trying OCR.
After each click the loop polls the detail fingerprint with a short bounded
budget instead of sleeping blindly. The current budget is 420 ms with 60 ms
polls; if the card changes and stabilizes earlier, OCR starts earlier, and if it
does not change the loop retries or stops through the normal miss guards. If the
card changed but remains animated, the loop now proceeds after 200 ms, matching
Inventory Kamera's select-next-item wait more closely without removing the
detail-change guard.
The outer scan start focuses Genshin once; hot-loop fingerprint/OCR captures do
not re-run the focus helper before every tile, which avoids an OS focus ping on
each artifact while still relying on click readback, foreground checks, and the
detail-card guard for safety.
After a scroll, the loop now uses the same cheap fingerprint polling model for
the inventory pane: it proceeds as soon as the next page fingerprint changed and
stabilized instead of always sleeping the old fixed 760 ms settle delay. Changed
but still animated inventory pages may proceed after 100 ms, again matching IK's
fast-scroll wait while still blocking unchanged pages.
Then poll:
```powershell
@@ -105,10 +171,221 @@ Invoke-RestMethod "http://127.0.0.1:17317/scanner/status" |
ConvertTo-Json -Depth 12
```
Before live timing, verify that the endpoint is the current app instance:
```powershell
Invoke-RestMethod "http://127.0.0.1:17317/health" |
ConvertTo-Json -Depth 6
```
The response must include `appBuild.signature` and
`appBuild.expectedOcrWorkerPoolSize`. If `appBuild` is missing, or
`/scanner/status` still reports the old OCR warmup start time, the local port is
still owned by a stale elevated Electron process. Close the old Administrator
window/app and restart with `npm run dev:admin` before running scanner probes.
Use the status `stats` timing fields for IK comparisons: `elapsedMs`,
`activeScanMs`, `writeFlushMs`, `averageMsPerParsed`,
`activeAverageMsPerParsed`, `averageCaptureMs`, `averageOcrMs`,
`artifactsPerMinute`, and `projectedMsFor100`. `elapsedMs` is end-to-end
including queued writes; `activeScanMs` is the click/capture/OCR loop before
the final store/review flush. A run only counts as speed
evidence when `parsed`, `stored`, `review`, `duplicates`, and `misses` are read
together; raw click count alone is not scanner throughput. If `averageOcrMs`
dominates `averageMsPerParsed`, the next speed lever is an IK-style OCR worker
queue. If `averageCaptureMs` dominates, crop payload/capture work is the
bottleneck.
The `/scanner/start?limit=N` endpoint sends a renderer command payload with a
temporary scan limit. It does not change the normal UI setting. The normal
hotkeys and buttons still use the UI's configured scan limit.
Lookup and benchmark utility endpoints:
```powershell
Invoke-RestMethod "http://127.0.0.1:17317/scanner/lookup/status"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/lookup/regenerate"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/ocr/warmup"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/ocr/warmup?engine=ik-traineddata"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/benchmark-ocr?limit=5"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/benchmark-ocr?limit=5&engine=ik-traineddata"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/benchmark-ocr?limit=5&engine=compare"
Invoke-RestMethod "http://127.0.0.1:17317/scanner/benchmark-ocr?limit=5&profile=full"
```
The benchmark endpoint measures the current Tesseract.js engine and the
Inventory-Kamera-traineddata Tesseract.js path against the artifact crop set and
returns timing/field counts, min/p50/p90/max timing, OCR p50/p90 timing,
20/45/100-artifact projections, skipped-OCR count, and the active OCR worker
pool size. It also returns per-field OCR timings under
`ocrFieldAverages`, which is the first place to look before changing crop or
parser behavior. Individual captures also report whether the artifact was
detected as `sanctified`; level/substat crops are shifted in that state to match
Inventory Kamera's crop model. By default it uses the auto-scan `fast` OCR profile,
which omits the low-value set-effect crop, the slot crop that can be derived
from the matched artifact piece name, and the main-stat-value crop that can be
derived from slot, main-stat label, and level. The fast profile also uses
Inventory Kamera's tighter substat crop height; full/manual captures keep the
larger recovery crop for debugging difficult samples. Auto-scan also omits per-crop diagnostic Base64 images from hot-loop OCR
captures while keeping the detail screenshot, OCR text, crop rect metadata, and
timings. OCR crops are passed to Tesseract as PNG buffers internally, not as
Base64 DataURLs, to avoid encode/decode overhead in batch scans. When
`skipOcrUnlessArtifactDetail` blocks OCR because no artifact detail card is
visible, OCR crop preprocessing is skipped too. Auto-scan readiness and scroll
checks use native detail/inventory fingerprints and omit preview DataURLs in
poll captures. Fast preflight/poll captures also omit crop list construction, crop images, and lock-state
detection unless a caller explicitly overrides that option; add
`profile=full` to OCR every artifact detail crop for debugging. It uses the same
artifact-detail guard as auto-scan: if the current screen is not a confirmed artifact detail view, OCR is
skipped and the response shows `skippedOcrCaptures` instead of burning time on
invalid crops.
For speed, the fast auto-scan profile also skips the optional Equipped footer
OCR. Name, level, main-stat label, and substats remain in the OCR hot path;
slot, set, and main-stat value are derived when the lookup/parser can validate
them. Use a full/manual capture when equipped ownership or every debug crop matters.
Local store/review writes are serialized through an internal queue but no longer
block the next inventory click. The scan still flushes the queue before it
returns its final summary, so `stored` and `review` counts remain final-state
numbers.
The app warms the default OCR worker pool in the background after startup; check
`/scanner/status` -> `ocrWarmup.current` before timing the first artifact. Use
`/scanner/ocr/warmup?engine=ik-traineddata` before comparing Inventory
Kamera-traineddata timings so the benchmark is not dominated by worker creation.
`engine=ik-traineddata` uses Inventory Kamera's local
`genshin_fast_09_04_21.traineddata` through Tesseract.js when the file is found
in `data/tessdata`, `IK_TESSDATA_DIR`, `work/Inventory_Kamera`, `work/refs`,
or the local `_ik_ref*` folders.
`engine=compare` runs `current` and `ik-traineddata` against the same visible
artifact detail state. The auto-scan default must stay `current` until the IK
traineddata path wins on the same captures. For a controlled live comparison,
start the scanner with `engine=ik-traineddata`; this only changes the OCR
worker language for that run and leaves the default UI/hotkey path on
`current`.
The OCR pool defaults to four workers because the fast artifact crop set has
four useful OCR parameter groups; set `GAA_OCR_WORKERS=1..8` before startup to
benchmark a different worker count. Inventory Kamera's native engine pool is
still the reference design, but the current app path remains Tesseract.js until
native OCR is integrated and measured. Crops are scheduled across the whole
worker pool and each worker caches its last Tesseract parameter profile; this is
closer to Inventory Kamera's multi-engine field OCR than the earlier
parameter-group-serial scheduler.
## Diagnostic Evidence
The Diagnose page contains a compact evidence timeline for scanner work. It logs
runtime pings, focus attempts, key presses, entry captures, artifact-tab clicks,
preflight failures, grid/count metadata, detail fingerprints, and detail/inventory
screenshots. The same last events are also published through:
```powershell
Invoke-RestMethod "http://127.0.0.1:17317/scanner/status" |
ConvertTo-Json -Depth 18
```
Use this before changing scanner behavior: run the smallest failing action, read
the evidence timeline, then decide whether the failure is focus/input, entry
navigation, grid detection, capture quality, OCR, or parser validation.
If Paimon entry shows `entry key ESC` or `entry key B` with `eventsSent: 0`, the
running `InputHelper.exe` probably predates keyboard support or is blocked. Stop
the elevated app/helper, run `npm run helper:build`, then restart with
`npm run dev:admin` so the app loads the rebuilt helper.
## Soak-Test Helper
After the elevated app is running and Genshin is open on the artifact inventory,
the non-elevated terminal can drive the local dev-control endpoints and save a
full evidence bundle:
```powershell
npm run scan:soak
```
The helper writes timestamped JSON snapshots and a transcript to:
```text
outputs/live-soak/<timestamp>/
```
Default sequence:
1. `/health`
2. `/scanner/status`
3. `/capture/smart?skipOcr=1`
4. `/automation/probe-click?index=1`
5. `/automation/probe-click?index=3`
6. `/scanner/start?limit=2`
7. `/scanner/start?limit=5`
8. `/scanner/start?limit=10`
9. `/scanner/start?limit=20`
10. `/review/samples?limit=30`
For the actual Inventory-Kamera speed target, use the explicit goal run after
`/health` shows the current `appBuild`:
```powershell
npm run scan:goal
npm run scan:goal:current
npm run scan:goal:ik
npm run scan:goal:compare
```
That run first warms/benchmarks `current` vs. `ik-traineddata`, then scans
limits `2, 5, 20, 45, 100` with the selected scan engine, and writes
`scan-run-summary.json` plus `scan-run-summary.csv`. `npm run scan:goal`
uses the default `current` scan engine; use `scan:goal:ik` for a native
IK-traineddata scan pass. Use `scan:goal:compare` to run both scan engines
back-to-back with the same limits and one combined CSV. The CSV is the quickest evidence for
`averageMsPerParsed`, `activeAverageMsPerParsed`, `averageCaptureMs`,
`captureP50Ms`, `captureP90Ms`, `averageOcrMs`, `ocrP50Ms`, `ocrP90Ms`,
`averageCardReadyMs`, `averageScrollReadyMs`, `artifactsPerMinute`, and
`projectedMsFor100`.
The run also writes `scan-performance-assessment.json`, which groups results by
limit, picks the best qualified engine, and labels the dominant bottleneck as
OCR, capture, card-ready, or scroll-ready. A qualified winner must finish the
run, parse the requested count, keep miss rate under 2%, and keep review rate
at or below 15%; review and miss rates are penalized before active average speed
is used as the tie-breaker.
The assessment ranking can be verified without Genshin or the Electron app:
```powershell
npm run scan:assessment:test
```
This self-test rejects synthetic runs that are fast but have too many misses or
too many review samples, so the final IK comparison cannot be won by speed alone.
For the current implementation summary and IK comparison rationale, see
[scanner-ik-progress-report.md](scanner-ik-progress-report.md).
Use the readiness timings to compare against Inventory Kamera's fixed waits:
IK waits about 200 ms after selecting the next inventory item and about 100 ms
after fast scrolls. If `averageCardReadyMs` or `averageScrollReadyMs` dominates
the active average while OCR is already low, tune the fingerprint gate before
touching OCR again.
The runner reads `APP_RUNTIME_SIGNATURE` from `electron/main.ts` and refuses
to run against a stale Electron process when `/health.appBuild.signature` does
not match the current source. Use `-AllowStaleBuild` only for deliberate
debugging of an older instance.
Current dev builds also expose `/dev/shutdown` on localhost. The start cleanup
script calls it before falling back to `Stop-Process`, so a previous elevated
app can shut itself down cleanly even when the caller cannot terminate an
administrator process directly. Older builds without that endpoint still need
manual close or a confirmed `npm run dev:admin` restart.
Review samples are saved as a compact summary by default so Vite does not try to
watch large Base64 payloads under `outputs/`. Full review payloads can be saved
with `-SaveFullReviewSamples` when needed.
It stops on a failed probe, blocked scan, stopped scan, or timeout unless
`-ContinueAfterBlocked` is supplied directly:
```powershell
powershell -NoProfile -ExecutionPolicy Bypass -File scripts\live-soak.ps1 -Limits 2,5 -ContinueAfterBlocked
```
## Anti-Cheat And Safety Boundary
Do not describe the current implementation as bypassing anti-cheat. The app
@@ -133,7 +410,9 @@ The current 16:9 layout profile is calibrated from a 1920x1080 English
artifact-inventory capture:
- detail rect approximately `x=1308`, `y=120`, `width=492`, `height=838`
- inventory grid: `8 x 5`
- inventory grid: `8 x 4` safe automated targets, matching Inventory Kamera's
32-artifact full-page model. The apparent lower fifth row is in the bottom
control band and is intentionally not clicked during auto-scan.
- first tile center: `x=179`, `y=254`, `row=0`, `col=0`
- second tile center: `x=325`, `y=254`, `row=0`, `col=1`
- inventory count crop successfully read `2059/2400` in the live session
@@ -152,3 +431,5 @@ Before marking an automation change done:
5. If Genshin is available, run `/automation/probe-click?index=1`.
6. For scan-loop changes, run `/scanner/start?limit=2` before any broader scan.
7. Record new live findings in this file and in `docs/scanner-rework-status.md`.
8. For IK-target claims, attach or cite `scan-performance-assessment.json` from
a non-stale `npm run scan:goal:compare` run.
+13
View File
@@ -4,6 +4,7 @@
- [ ] The expected crop or capture behavior is clear.
- [ ] Genshin is not accessed through memory reads, hooks, injection, or game files.
- [ ] Auto-scan starts only from confirmed artifact inventory plus visible detail card, or blocks with a reason.
- [ ] Capture failures are shown to the user.
- [ ] OCR uncertainty remains inspectable in Details.
- [ ] Parser output does not silently trust low-confidence text.
@@ -12,6 +13,18 @@
- [ ] `npm run build` passes.
- [ ] Manual Smart Capture is tested when possible.
## IK-Speed Or OCR-Engine Claim
- [ ] `/health.appBuild.signature` matches the current `APP_RUNTIME_SIGNATURE`.
- [ ] `npm run scan:assessment:test` passes.
- [ ] The run includes `scan-performance-assessment.json`.
- [ ] The 100-artifact run finishes cleanly.
- [ ] Parsed count is at least the requested count.
- [ ] Miss rate is at or below 2%.
- [ ] Review rate is at or below 15%.
- [ ] Speed comparison uses active scan timing plus quality, not click count alone.
- [ ] The default OCR engine is changed only after same-capture benchmark evidence.
## UI Change
- [ ] The main workflow remains visible without unnecessary scrolling.
+47
View File
@@ -16,6 +16,7 @@ This document contains Architecture Decision Records.
| ADR-008 | Replace the PowerShell input/capture helper with a C# sidecar | Accepted | 2026-07-05 |
| ADR-009 | Resolution-anchored layout profiles and OCR preprocessing over color detection | Accepted | 2026-07-05 |
| ADR-010 | Elevated dev runner and bounded live automation probes | Accepted | 2026-07-07 |
| ADR-011 | Quality-gated Inventory Kamera comparison before OCR default changes | Accepted | 2026-07-07 |
## ADR-001: Build A Local Electron App First
@@ -286,3 +287,49 @@ Document the workflow in [AUTOMATION_LIVE_SCAN.md](AUTOMATION_LIVE_SCAN.md).
- The implementation remains inside the allowed safety boundary: no memory
reads, hooks, injection, game-file modification, deleting, feeding, enhancing,
locking/unlocking, or spending resources.
## ADR-011: Quality-Gated Inventory Kamera Comparison Before OCR Default Changes
### Status
Accepted
### Context
The product target is not merely to click through 100 artifacts quickly. It is
to scan the first 100 artifacts with accuracy at least as good as Inventory
Kamera and speed equal to or better than Inventory Kamera. A faster scan that
creates too many misses, review samples, or false positives is worse than a
slower qualified run.
The app can now compare the current OCR path with Inventory Kamera's
`genshin_fast_09_04_21.traineddata` through the same visible crop set. It also
has hot-loop timing fields for capture, OCR, card readiness, scroll readiness,
active scan time, and projected 100-artifact time.
### Decision
Use a quality-gated live soak and benchmark before changing the default OCR
engine or claiming IK parity. A qualified scan result must:
- finish cleanly,
- parse at least the requested count,
- keep miss rate at or below 2%,
- keep review rate at or below 15%,
- report active scan timing and bottlenecks,
- come from a runtime whose `/health.appBuild.signature` matches the current
source.
`scripts/live-soak.ps1` writes the evidence bundle and
`scan-performance-assessment.json`. `npm run scan:assessment:test` verifies that
the ranking logic rejects fast but low-quality synthetic runs without needing
Genshin.
### Consequences
- Speed claims cannot be based on click count or elapsed time alone.
- A new OCR engine cannot become the default just because it is theoretically
closer to IK; it must win the same-capture benchmark and a qualified live run.
- Stale elevated Electron instances are treated as invalid evidence, not as a
harmless warning.
- The goal remains open until the 100-artifact qualified comparison is captured.
+14 -2
View File
@@ -3,6 +3,8 @@
This document is the source of truth for project intent, scope, runtime facts, and operational expectations.
For implementation structure, see [ARCHITECTURE.md](ARCHITECTURE.md). For engineering standards, see [CONVENTIONS.md](CONVENTIONS.md).
For the latest Inventory-Kamera comparison work, see
[scanner-ik-progress-report.md](scanner-ik-progress-report.md).
## Project Identity
@@ -58,6 +60,7 @@ The app is not intended to replace deep min-max tools. It prioritizes time savin
| --- | --- | --- |
| Safety | Never perform irreversible in-game actions. | Code review and manual test |
| Performance | Single artifact read should feel interactive and batch scan should not stall on false progress. | Capture latency monitored manually; auto-scan stops on blocked verification |
| IK target | First 100 artifacts should scan with accuracy at least as good as Inventory Kamera and equal or better speed. | `npm run scan:goal:compare` quality-gated report |
| Privacy | Captures and parsed data stay local by default. | No remote upload in scanner path |
| Reliability | Uncertain OCR must be visible to the user. | Confidence and details view |
| Learning loop | Scanner mistakes should become reusable local review samples. | `review-samples.jsonl` |
@@ -95,6 +98,9 @@ The app is not intended to replace deep min-max tools. It prioritizes time savin
- The parser already uses known sets, pieces, slots, stat aliases, set aliases, character aliases, and derived slot/set mapping.
- Review samples, learned replacements, parser notes, and stored artifacts already persist locally.
- The auto-scan loop is no longer a naive click spammer: it has preflight, verification, miss handling, page fingerprinting, and stop conditions.
- The scanner now has an Inventory-Kamera comparison path: 32 safe artifact
targets per page, lookup-derived fields, fast OCR crop profile, current vs.
IK-traineddata benchmark endpoint, and a quality-gated live soak runner.
- Elevated live automation is validated in the current dev environment:
`/automation/probe-click?index=1` changed the selected artifact and
`/scanner/start?limit=2` completed with 2/2 verified reads and 0 misses.
@@ -108,6 +114,9 @@ The app is not intended to replace deep min-max tools. It prioritizes time savin
- Learned fixes currently focus on text replacements; they do not yet update crop offsets, UI profile variants, or scanner targeting rules in a structured way.
- The scan page is cleaner than before, but it still exposes too much operator/debug state in the main flow.
- Recommendations and build logic exist, but the scanner is not yet reliable enough to make them the core focus.
- The latest source has not yet completed the final 100-artifact live comparison
because the current dev-control port is still owned by a stale elevated
Electron process. Live timing must wait for a UAC-approved restart.
### Current product conclusion
@@ -233,8 +242,11 @@ Status:
2. Tighten the game data generator and parser contract, then backfill regression tests from real bad samples.
3. Continue moving auto-scan behavior out of `App.tsx` and into isolated scanner modules.
4. Soak-test the elevated C# helper automation path with gradually larger scan limits and page scroll transitions.
5. Extend the learning system from text-only fixes into crop/UI profile tuning.
6. Resume recommendation work only when scan accuracy is consistently trustworthy.
5. Run `npm run scan:goal:compare` after `/health.appBuild.signature` matches
the current source and use the quality-gated 100-artifact report as the IK
target evidence.
6. Extend the learning system from text-only fixes into crop/UI profile tuning.
7. Resume recommendation work only when scan accuracy is consistently trustworthy.
## Open Questions
+3
View File
@@ -2,12 +2,15 @@
Field-level accuracy measurement for the artifact OCR parser. This is the gate
every OCR, crop, layout, or parser change runs against (see ADR-007).
It is necessary but not sufficient for the IK target: live scan speed and
review/miss rates are measured by `npm run scan:goal:compare`.
## Run it
```powershell
npm run eval # full accuracy report for the seed corpus
npm test # runs the eval gate alongside the rest of the suite
npm run scan:assessment:test # verifies quality-first scan ranking logic
```
The report prints exact-match rate, overall field accuracy, a per-field
+301
View File
@@ -0,0 +1,301 @@
# Scanner IK Progress Report - 2026-07-07
This report summarizes the scanner/OCR work toward the current target:
scan the first 100 artifacts with accuracy at least as good as Inventory Kamera
and speed equal to or better than Inventory Kamera, without memory reads, hooks,
injection, game-file modification, or unsafe in-game actions.
## Executive Summary
The scanner has moved from a fragile OCR-first prototype toward an
Inventory-Kamera-style artifact scanner:
- Artifact scan is now the first-class path.
- Auto-scan starts only after a validated artifact inventory/detail preflight.
- Main-game, Paimon-menu, primary-screen, unsupported-layout, missing-grid, and
missing-detail states block before OCR/store/review work.
- OCR uses a fast artifact profile that skips low-value fields and derives
slot, set, and main-stat value through lookup constraints when safe.
- The OCR worker pool, field crop split, page model, scroll model, and readiness
waits now mirror the relevant IK design choices more closely.
- Diagnostics now preserve state evidence, timings, screenshots where useful,
entry events, focus/input events, preflight failures, and scan-loop reasons.
- A live soak runner now measures throughput and quality, compares current vs.
IK-traineddata engines, and refuses to run against stale Electron builds.
The requested final goal is not proven complete yet. The current live dev port is
still owned by an older elevated Electron instance, so the latest code cannot be
truthfully benchmarked against IK until the app is restarted with UAC approval
and `npm run scan:goal:compare` completes a qualified 100-artifact run.
## What Changed
### Lookup and validation
- `scripts/generate-genshin-data.cjs` was extended into a stricter lookup
package generator.
- `src/lib/genshinLookup.ts` provides pure matching and validation for sets,
pieces, slots, stats, characters, aliases, GOOD keys, source version, and
validation summaries.
- Auto-scan preflight blocks if the lookup package is invalid.
Why this matters:
IK succeeds partly because raw OCR is not trusted by itself. The app now follows
the same principle: OCR text is normalized, matched, constrained, and derived
against a canonical package before it is accepted.
### OCR and parser pipeline
- Artifact detail crops are split into field-specific regions:
name, slot, main-stat label, main-stat value, level, substats, set effects,
equipped/footer, lock, and rarity.
- Fast auto-scan profile skips lower-value OCR work:
set effects, slot crop, main-stat value crop, equipped footer, crop images,
full-frame payloads, and inventory preview payloads.
- Slot, set, and main-stat value are derived when lookup, slot rules, and level
constraints make that safe.
- Field-specific Tesseract PSM/whitelist cleanup and preprocessing are used.
- OCR crops are passed as PNG buffers internally instead of Base64 DataURLs.
- Exact visual duplicates are skipped before OCR.
Why this matters:
The fast path spends OCR only on fields that materially change the artifact
identity or review decision. That is closer to IK's queued crop model than a
manual-debug capture that OCRs every visible thing.
### Engine comparison and benchmark path
- `/scanner/ocr/warmup?engine=current|ik-traineddata` warms OCR workers.
- `/scanner/benchmark-ocr?engine=current|ik-traineddata|compare` benchmarks the
same visible artifact crops.
- Auto-scan accepts `ocrEngine: "current" | "ik-traineddata"`.
- `scripts/live-soak.ps1` supports:
- `npm run scan:goal`
- `npm run scan:goal:current`
- `npm run scan:goal:ik`
- `npm run scan:goal:compare`
- `scan-performance-assessment.json` ranks runs by quality first and speed
second.
Important rule:
A fast engine cannot win if it has too many misses or too much review. A
qualified winner must finish cleanly, parse the requested count, keep miss rate
at or below 2%, and keep review rate at or below 15%.
### Auto-scan entry and safety
- The normal auto button runs a guided start:
1. focus Genshin,
2. run a lightweight no-OCR preflight,
3. if artifact detail is visible, use visible-inventory mode,
4. otherwise try direct `B -> artifact tab -> first artifact tile`,
5. if needed, fall back to the IK-style ESC/B inventory sequence,
6. start OCR only after artifact grid and detail card pass preflight.
- Entry captures are state evidence only. They do not create review samples,
store artifacts, or run artifact OCR before the detail preflight passes.
- Entry waits now poll for state readiness instead of always sleeping the full
fixed delay.
- Scan loop also rechecks the same safety boundary after each click and scroll.
Why this matters:
The previous failure mode was dangerous from a product-quality point of view:
when the game was not in artifact inventory, the scanner could still take
screenshots and try to read artifacts. The current path is explicitly blocked
outside the artifact inventory/detail state.
### Scan loop and speed
- Grid model uses IK's 32-artifact visible page concept (`8 x 4`) instead of
clicking the risky lower band.
- Last/partial page planning bottom-aligns like IK, avoiding unnecessary
duplicate reads after scroll.
- Card readiness uses detail fingerprint polling:
max 420 ms, 60 ms polls, changed cards may proceed after 200 ms.
- Scroll readiness uses inventory fingerprint polling:
max 760 ms, 80 ms polls, changed pages may proceed after 100 ms.
- Store/review writes are queued so the next tile can be clicked before disk
writes finish. The queue is still flushed before final summary.
- Focus is done once at scan start; hot-loop captures do not refocus every tile.
Why this matters:
IK uses fixed waits around 200 ms after selecting inventory items and 100 ms
after fast scrolls. The app now keeps those as safety ceilings/acceptance points
while allowing earlier continuation when visual evidence is ready.
### Diagnostics and logging
- Scanner diagnostics now capture timeline events for runtime, focus, keypress,
entry captures, tab clicks, first-tile clicks, preflight, OCR/skips, grid,
counts, detail/page fingerprints, and failure reasons.
- `/scanner/status` publishes recent diagnostic evidence.
- Review sample output is compact by default so Vite does not watch large Base64
payloads during live soak runs.
- The live runner writes timestamped JSON snapshots, CSV summaries, transcript,
benchmark data, and performance assessment files under `outputs/live-soak/`.
Why this matters:
Future scanner bugs can be debugged from captured evidence instead of relying
only on a human description of what appeared on screen.
## Vorgehensweise
1. Read the local Inventory Kamera reference under `work/Inventory_Kamera`.
2. Copy the proven concepts, not the entire implementation:
32 artifact targets per page, fixed coordinate ratios, queued OCR work,
short item/scroll waits, read-only inventory navigation, and Tesseract
traineddata comparison.
3. Harden the app's own architecture around those concepts:
pure lookup API, parser derivation, renderer scan orchestration,
Electron capture/OCR boundary, sidecar input helper, and diagnostics.
4. Add tests before trusting behavior:
lookup validation, parser derivation, auto-entry planning/preflight,
card-ready gates, page planning, scan-loop blocking, OCR eval corpus.
5. Add live tooling before claiming performance:
bounded probes, stale-build gate, benchmark endpoint, soak runner, CSV/JSON
assessment, and quality-first comparison.
## Tests and Evidence
Latest repo validation after the recent changes:
| Check | Result |
| --- | --- |
| PowerShell parse for `scripts/live-soak.ps1` | Passed |
| `npm run scan:assessment:test` | Passed |
| `npm run lint` | Passed |
| Focused scanner tests | Passed |
| `npm test` | Passed, 171 tests |
| OCR eval seed corpus | 100% exact match, 100% field accuracy, 100% critical fields |
| `npm run build` | Passed |
| `git diff --check` | Passed |
Live evidence already collected earlier on 2026-07-07:
- Probe click changed artifact detail successfully.
- Limit 2 live auto-scan completed with 2/2 parsed and 0 misses.
- Limit 20 live soak completed on the first visible page.
- Limit 45 live soak crossed into a scrolled page.
Current live limitation:
- `/health` still reports an older elevated build:
`2026-07-07-ocr-pool4-hotloop-no-refocus`.
- Current source expects:
`2026-07-07-ik32-fastsubstats-active-timing`.
- The live soak runner correctly refuses to benchmark the stale runtime.
- A UAC restart attempt was canceled, so the latest code is not yet live.
## Inventory Kamera Comparison
| Area | Inventory Kamera | Current app status |
| --- | --- | --- |
| Safe scope | Reads inventory through screen/click automation | Same safety boundary: screen capture and read-only input only |
| Entry | ESC/B inventory navigation and tab click | Direct `B` path plus IK-style fallback, with preflight guards |
| Page model | 32 artifact items per page | 32 safe targets (`8 x 4`) implemented |
| Last page | Bottom-aligned partial page after scroll | Implemented in page planner |
| Item wait | About 200 ms fixed wait | Fingerprint polling, accepts changed card after 200 ms |
| Scroll wait | About 100 ms fast wait after scroll | Fingerprint polling, accepts changed page after 100 ms |
| OCR model | Native Tesseract worker queue and custom traineddata | Tesseract.js pool with current and IK-traineddata comparison path |
| Field parsing | OCR plus game-data lookup | OCR plus generated lookup, GOOD keys, aliases, slot/stat constraints |
| Quality gate | Mature behavior by design and user history | Explicit benchmark/soak quality gates added |
| Diagnostics | Logs/screenshots in IK flow | Diagnostics timeline plus JSON evidence bundle |
| 100-artifact proof | Reference target | Not yet proven on latest app build |
What is theoretically better than before:
- The app no longer spends OCR on invalid screens.
- It no longer treats click count as scanner success.
- It can prove whether `current` or `ik-traineddata` wins on the same capture
set instead of changing engines blindly.
- It can reject fast-but-wrong results automatically.
- It can identify whether the bottleneck is OCR, capture, card readiness, or
scroll readiness.
What is not yet proven better than IK:
- Native Tesseract speed is not integrated as the default.
- The latest code has not completed the 100-artifact live run.
- Review rate and miss rate on the user's real inventory still need the new
live report.
## Theoretical Runtime Flow
For the intended 100-artifact comparison:
1. Start current elevated app with `npm run dev:admin` and confirm UAC.
2. Verify `/health.appBuild.signature` matches `electron/main.ts`.
3. Warm current and IK-traineddata OCR workers.
4. Run a small bounded probe from the artifact inventory.
5. Run `npm run scan:goal:compare`.
6. For each engine and limit (`2, 5, 20, 45, 100`):
- focus Genshin once,
- verify lookup and layout,
- verify artifact grid and detail card,
- click one safe grid target,
- poll detail fingerprint,
- skip duplicate visuals,
- OCR only the fast artifact crop set,
- parse through lookup constraints,
- queue store/review writes,
- scroll with inventory fingerprint polling,
- stop on repeated pages, invalid surfaces, blocked input, OCR timeout, or
repeated misses.
7. Write CSV, JSON snapshots, transcript, benchmark report, and performance
assessment.
8. Declare a winner only if the 100-artifact run is qualified by quality.
Expected bottleneck sequence:
- If OCR dominates, compare `current` vs `ik-traineddata`, crop count, and
worker pool size.
- If capture dominates, reduce payload construction and preview/crop image work.
- If card-ready dominates, tune the detail fingerprint gate.
- If scroll-ready dominates, tune page fingerprint polling and scroll notches.
## What Is Better Than Before
- Auto-scan is artifact-detail gated; no more blind OCR from main gameplay or
menu screens.
- Paimon/menu detection blocks before scan-loop OCR or writes.
- The normal button is one coherent guided flow instead of a separate "get to
inventory first, then scan" workflow.
- The app has a real lookup layer instead of raw OCR plus scattered hardcoded
assumptions.
- The scanner can compare OCR engines without changing the default blindly.
- Performance reports now include quality decisions, not just elapsed time.
- Diagnostics are concrete enough for later self-troubleshooting.
- Stale elevated runtime is detected before live soak, avoiding false evidence.
## Risks and Remaining Work
1. Restart with UAC and run the latest build live.
2. Run `npm run scan:goal:compare` from a visible artifact inventory.
3. If the 100-artifact winner is not qualified, inspect:
`scan-performance-assessment.json`, review samples, diagnostic timeline, and
field timings.
4. If `ik-traineddata` wins but Tesseract.js is still slow, evaluate native
Tesseract integration.
5. Grow the eval corpus with confirmed real review samples before tightening
parser thresholds further.
6. Validate a positive locked-artifact sample.
7. Keep recommendations secondary until scanner quality is proven.
## Definition of Done for the IK Target
The goal is complete only when current evidence proves all of these:
- The app is running the latest runtime signature.
- The 100-artifact scan finishes cleanly.
- Parsed count is at least 100.
- Miss rate is at or below 2%.
- Review rate is at or below 15%.
- The run is equal to or faster than the recorded IK reference or the selected
IK-traineddata/native baseline on the same machine and inventory setup.
- The evidence bundle is saved under `outputs/live-soak/`.
- Any chosen default OCR engine is backed by the same-capture benchmark.
+89 -2
View File
@@ -5,6 +5,22 @@ Progress on the approved scanner/OCR rework. See ADR-007/008/009/010 in
live automation runbook, see
[AUTOMATION_LIVE_SCAN.md](AUTOMATION_LIVE_SCAN.md).
## Current IK-Speed Target Status
See [scanner-ik-progress-report.md](scanner-ik-progress-report.md) for the full
report.
Current status:
- The scanner architecture now follows the relevant Inventory Kamera model:
32 artifact targets per page, lookup-derived fields, fast artifact OCR profile,
short readiness gates, page-overlap planning, and queued OCR/store work.
- The live runner can compare `current` and `ik-traineddata` engines and rejects
runs that are fast but fail miss/review quality thresholds.
- The final 100-artifact IK target is not proven yet. The dev-control port is
currently owned by an older elevated Electron build, and the runner correctly
refuses stale timing evidence until the app is restarted with UAC approval.
## Done (implemented, unit-tested, build green)
- **OCR eval harness** — `src/eval/`, `npm run eval`, gate in `npm test`. See
@@ -37,6 +53,62 @@ live automation runbook, see
- **Bounded auto-scan validation** — `/scanner/start?limit=2` completed live
with 2 clicks, 2 verified detail views, 2 parsed artifacts, 2 stored records,
2 review samples, and 0 misses.
- **Auto-scan OCR performance pass** - auto-scan captures now use an artifact
OCR mode that skips inventory-count OCR on each tile, keeps equipped-character
OCR, raises the substat crop to catch artifact level, stores automatic review
samples without full-screen/inventory screenshots, reads only the tail of large
JSONL files, avoids review noise when only level/equipped is missing, starts
the scan with an OCR-free preflight capture, skips exact visual duplicates
before OCR, prevents repeated startup review reprocessing, omits full-frame
and inventory-preview Base64 payloads from tile captures, and applies
crop-specific Tesseract page-segmentation/whitelist parameters.
- **Visible-page live soak helper** - `scripts/live-soak.ps1` now drives the
dev-control health/status, smart-capture, probe-click, bounded scan, and
review-tail endpoints and writes evidence to `outputs/live-soak/`. On
2026-07-07 it completed probes at indices 1 and 3 plus scan limits 2, 5, 10,
and 20 against the elevated running app. The limit 20 run finished `done` with
20 attempted, 20 verified, 18 parsed, 18 stored, 1 review, 1 duplicate, 1
miss, and 1 page.
- **Scroll/page-transition live soak** - after the helper and loop fixes,
`scripts/live-soak.ps1 -Limits 45 -ProbeIndices 1 -SkipSmartCapture`
completed `done` on 2026-07-07 with 45 attempted, 45 verified, 35 parsed, 35
stored, 9 review, 1 duplicate, 9 misses, and 2 pages. This validates that the
scanner can cross from the first visible page into a scrolled page in the live
1920x1080 setup.
- **Lookup package layer** - `scripts/generate-genshin-data.cjs` now emits
normalized lookup keys, GOOD keys, piece/set/slot links, aliases, source
version metadata, generated time, and validation summary. `src/lib/genshinLookup.ts`
provides pure matching and validation APIs, and the scanner status/dev-control
path exposes lookup validity. Auto-scan preflight blocks when the lookup package
is invalid.
- **Inventory-Kamera-style field split** - artifact detail crops now separate
name, slot, main-stat label, main-stat value, level, substats, set effects, and
footer. OCR uses field-specific PSM/whitelist cleanup, and the parser derives
slot/set/main-stat through lookup constraints before falling back to review.
- **Paimon-menu auto-entry scaffold** - auto-scan supports
`scanEntryMode: "paimon-menu"` and `/scanner/start?entry=paimon-menu&limit=N`.
The entry sends only read-only navigation (`ESC`, `B`, artifact-tab click),
then requires a valid lookup, supported layout, and detected artifact grid
before the scan loop starts. The existing visible-inventory start remains the
fallback/debug path.
- **OCR benchmark endpoint scaffold** - `/scanner/benchmark-ocr?limit=N` captures
identical artifact crops with the current engine and returns timing/field counts.
`/scanner/benchmark-ocr?engine=compare` can also compare the local
Inventory-Kamera-traineddata Tesseract.js path when
`genshin_fast_09_04_21.traineddata` is present in `data/tessdata`, `work/`, or
`IK_TESSDATA_DIR`. The OCR worker pool defaults to four workers and can be
tuned with `GAA_OCR_WORKERS=1..8`. Native Tesseract is still not the default
and should only replace `tesseract.js` after the benchmark proves it faster
and more accurate on the same crops.
- **Quality-gated live comparison** - `scripts/live-soak.ps1` now supports
goal runs for `current`, `ik-traineddata`, and `compare`, writes CSV/JSON
summaries, groups results by limit, identifies timing bottlenecks, and rejects
winners that miss the requested count, exceed 2% misses, or exceed 15% review.
`npm run scan:assessment:test` verifies this ranking logic without Genshin.
- **State-polled guided entry** - the guided auto-entry waits for Inventory,
artifact grid, and first detail card evidence instead of sleeping the full
fixed delay every time. OCR/review/store work still starts only after artifact
detail preflight passes.
## Remaining — needs the live environment or a UI pass
@@ -46,12 +118,27 @@ resolution or without UI work best tested live:
1. **Validate/tune OCR preprocessing** on more real captures — confirm invert +
threshold + upscale factor help (not hurt) actual Tesseract reads. The
text-level eval harness cannot measure image preprocessing.
2. **Validate locked=true** against a known locked artifact — unlocked/grey lock
2. **Wire and benchmark native IK-traineddata OCR** against the same crop set.
The current benchmark can use IK-traineddata through Tesseract.js; native
Tesseract integration remains the next implementation step before any engine
default changes.
3. **Validate guided entry live** from world, visible inventory, and Paimon/menu
states with limits 2, 20, and 45. Confirm the artifact-tab coordinate in the
user's current 16:9 layout and keep `visible-inventory` as fallback if the
menu path is blocked.
4. **Validate locked=true** against a known locked artifact — unlocked/grey lock
was live-checked; a gold locked icon still needs a positive sample.
3. **Broader scan soak test** — after the bounded two-item live scan passed,
5. **Broader scan soak test** — after the bounded two-item live scan passed,
the next automation validation should increase the limit gradually and watch
for repeated pages, scroll behavior, duplicate handling, and OCR review rate.
6. **100-artifact IK comparison** — after `/health.appBuild.signature` matches
current source, run `npm run scan:goal:compare` and compare qualified
100-artifact results.
Visible-page limits up to 20 and a scroll/page-transition limit of 45 have
passed. The remaining soak work is now OCR accuracy, review-rate reduction, and
larger runs after the review corpus has grown.
## Grow the eval corpus