388 lines
19 KiB
Markdown
388 lines
19 KiB
Markdown
# 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 direct
|
|
detail-change verification 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 current-vs-IK-traineddata comparison proof is now captured. On 2026-07-08,
|
|
`npm run scan:goal:compare:validated` passed with
|
|
`outputs/live-soak/2026-07-08T18-38-35/scan-performance-assessment.json`.
|
|
At `limit=100`, `current` won the qualified comparison with `100/100` parsed,
|
|
`0` review, `0` misses, `378 ms/artifact` active average, and `37800 ms`
|
|
projected time for 100 artifacts. `ik-traineddata` was not qualified at
|
|
`limit=100` because it parsed `97/100`, had `5` review and `3` misses. The
|
|
separate 3 artifacts/second target is still not proven.
|
|
|
|
## 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, main-stat value crop, crop images, full-frame payloads, and
|
|
inventory preview payloads. The equipped footer remains in real artifact-read
|
|
captures when its marker is visible, because ownership now matters for phase 1
|
|
validation. Preflight and poll captures still skip OCR/crops/lock-state work.
|
|
The slot crop remains in the fast path because it materially improved
|
|
real-read quality.
|
|
- 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 duplicate skipping is disabled in the hottest path; duplicate
|
|
handling now primarily uses parsed artifact signatures so OCR is not skipped
|
|
solely from a crop fingerprint collision.
|
|
|
|
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`
|
|
- `npm run scan:goal:compare:validated`
|
|
- `npm run scan:goal:compare:validated:wait`
|
|
- `npm run scan:iterate:compare:validated`
|
|
- `npm run scan:iterate:compare:validated:wait`
|
|
- `npm run scan:live:preflight`
|
|
- `npm run scan:live:preflight:wait`
|
|
- `scan-performance-assessment.json` ranks runs by quality first and speed
|
|
second, and records whether the 100-artifact result is a complete
|
|
current-vs-IK comparison through `goal100Decision` and
|
|
`goal100.comparisonComplete`.
|
|
|
|
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.
|
|
- Detail-change verification now uses the artifact OCR capture itself instead
|
|
of a separate card-ready capture before OCR.
|
|
- Scroll readiness uses inventory fingerprint polling:
|
|
max 760 ms, 80 ms polls, changed pages may proceed after 100 ms.
|
|
- Store/review writes are held out of the click/capture/OCR hot path. The
|
|
latest source batches artifact store writes before the final summary instead
|
|
of issuing one save/reload cycle per artifact.
|
|
- Auto-scan artifact captures skip Electron source enumeration in the hot path
|
|
and call the GDI capture helper directly.
|
|
- 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:
|
|
|
|
- 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.
|
|
- On 2026-07-08, `/scanner/start?entry=visible-inventory&limit=50&engine=current`
|
|
completed `50/50` parsed and stored, `0` review, `0` duplicates, `0` misses,
|
|
`2` pages, `61765 ms` elapsed, `1235 ms/artifact`, `averageCaptureMs: 186`,
|
|
and `averageOcrMs: 162`.
|
|
- A deferred single-write flush experiment also completed `50/50`, but regressed
|
|
to `63616 ms` because `writeFlushMs` was `8163`; the source now uses batch
|
|
persist instead, pending a fresh elevated live measurement.
|
|
- After direct GDI hot-path optimization, a 20-artifact run completed
|
|
`20/20` parsed, `19` stored, `0` review, `1` duplicate, `0` misses,
|
|
`7966 ms` elapsed, `398 ms/artifact`, `averageCaptureMs: 193`, and
|
|
`averageOcrMs: 167`.
|
|
- A 45-artifact direct-GDI run completed `45/45` parsed, `42` stored,
|
|
`0` review, `3` duplicates, `0` misses, `2` pages, `18625 ms` elapsed,
|
|
`414 ms/artifact`, `averageCaptureMs: 187`, and `averageOcrMs: 162`.
|
|
- A 100-artifact direct-GDI run on signature
|
|
`2026-07-08-direct-gdi-hotpath` completed `100/100` parsed, `97` stored,
|
|
`0` review, `3` duplicates, `0` misses, `4` pages, `42064 ms` elapsed,
|
|
`421 ms/artifact`, `averageCaptureMs: 179`, and `averageOcrMs: 154`.
|
|
- `npm run eval` passed after the speed work with `23/23` exact-match cases,
|
|
`100%` field accuracy, and `100%` critical fields.
|
|
- The 3 artifacts/second target is now prepared in code but not live-proven:
|
|
artifact hot-path captures omit detail preview payloads, and stats expose
|
|
capture roundtrip/overhead timing. A qualifying 20-artifact run must finish in
|
|
`<= 6667 ms` with 0 misses and no silent OCR quality regression.
|
|
- Follow-up 3/s attempts on 2026-07-08 fixed the false review trigger caused by
|
|
omitted detail previews. The best clean `limit=20` run reached `7285 ms`
|
|
(`364 ms/artifact`, about `2.75 artifacts/second`) with `20/20` parsed,
|
|
`0` review, and `0` misses. The final stable run on
|
|
`2026-07-08-direct-gdi-reviewfix` completed `20/20` with `0` review,
|
|
`0` misses, and `7973 ms` elapsed (`399 ms/artifact`). Detail-region capture,
|
|
5 OCR workers, DataURL buffer decode, and substat `PSM.SINGLE_COLUMN` were
|
|
tested and rejected as slower than the direct-GDI baseline.
|
|
- Final current-vs-IK-traineddata comparison on 2026-07-08:
|
|
`npm run scan:goal:compare:validated` passed. Evidence file:
|
|
`outputs/live-soak/2026-07-08T18-38-35/scan-performance-assessment.json`,
|
|
`createdAt: 2026-07-08T18:41:11.6120957+02:00`. `goal100Decision` was
|
|
`qualified-comparison: winner=current`; `goal100.comparisonComplete` was true.
|
|
`current` completed `100/100` parsed, `97` stored, `0` review, `0` misses,
|
|
`4` pages, `378 ms/artifact` active average. `ik-traineddata` completed
|
|
`97/100` parsed, `92` stored, `5` review, `3` misses and was rejected for
|
|
parsing fewer artifacts than requested.
|
|
- The review queue now has a bounded corpus-growth workflow:
|
|
`npm run eval:review-candidates` writes a deduplicated, Git-ignored worklist
|
|
to `outputs/review-eval-candidates/`. This separates complete modern OCR
|
|
samples from stale captures and prevents the parser's own guess from being
|
|
promoted to ground truth without human confirmation. After manual checking,
|
|
`npm run eval:prepare-confirmed` turns one candidate plus explicit expected
|
|
labels into a paste-ready confirmed corpus snippet.
|
|
|
|
Current live limitation:
|
|
|
|
- The fast path and current-vs-IK-traineddata 100-artifact comparison are proven
|
|
in the current live environment. 3 artifacts/second is not proven; remaining
|
|
speed work needs a larger OCR or capture-pipeline change, not more click
|
|
tuning.
|
|
- The visible-inventory ownership/lock extension is also live-proven in this
|
|
environment: equipped footer reads for `Citlali` and `Linnea`, unlocked
|
|
`locked: false`, positive locked `locked: true`, and locked/equipped
|
|
persistence all passed on 2026-07-09.
|
|
|
|
## 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 | No separate wait capture; OCR capture verifies changed detail |
|
|
| 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 |
|
|
| Capture hot path | Direct window/screen capture without source-list scan per item | Direct GDI capture in auto-scan artifact loop |
|
|
| 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 | Qualified current-vs-IK comparison captured; `current` won with `100/100`, 0 review, 0 misses, 37.8s projected |
|
|
|
|
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.
|
|
- 3 artifacts/second is not proven.
|
|
- Native Inventory Kamera outside this app was not re-run in the same session;
|
|
the completed comparison is against the bundled `ik-traineddata` scan engine.
|
|
|
|
## Theoretical Runtime Flow
|
|
|
|
For short iteration while tuning:
|
|
|
|
1. Start current elevated app with `npm run dev:admin` and confirm UAC.
|
|
2. Run `npm run scan:iterate:compare:validated:wait` from a visible artifact inventory
|
|
when starting directly after UAC, or `npm run scan:iterate:compare:validated`
|
|
if preflight already passes.
|
|
3. Inspect `scan-performance-assessment.json`, review samples, and timings if the
|
|
20-artifact comparison fails quality gates.
|
|
|
|
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:validated:wait` directly after UAC, or
|
|
`npm run scan:goal:compare:validated` if preflight already passes.
|
|
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. Keep `current` as the default OCR engine for now; it won the qualified
|
|
current-vs-IK-traineddata live comparison.
|
|
2. If pursuing 3 artifacts/second, focus on capture/OCR pipeline changes rather
|
|
than click timing.
|
|
3. Grow the eval corpus with confirmed real review samples before tightening
|
|
parser thresholds further.
|
|
4. Repeat equipped/locked live samples in later sessions if confidence or UI
|
|
behavior changes, but the first positive locked proof has passed.
|
|
5. Keep recommendations secondary until scanner quality remains stable across
|
|
repeated live sessions and the result rail, artifact inventory, and detail
|
|
evaluation flow are implemented.
|
|
6. Treat current speed as acceptable for the next product phase; prioritize
|
|
artifact content extraction and review-safe value scoring before another
|
|
broad speed pass.
|
|
|
|
## 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.
|