Improve L2 market parsing and data handling
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
# Store Icon Progress Overlay Evidence
|
||||
|
||||
## Implemented
|
||||
|
||||
- `data/fixtures.json` describes every one of the 17 committed JPG files exactly once, including clean/tooltip sequence state and reviewed merchant/item/slot expectations.
|
||||
- Live capture and the browser harness call the same `src/frame-analyzer.js#analyzeFrame`; no second OCR pipeline was added.
|
||||
- Calibration supports optional independent Sell and Buy 6 × 3 grid regions. The calibration canvas is displayed at 2× while stored coordinates remain source pixels.
|
||||
- A clean recognized shop frame records occupied cells as `pending`; a unique icon match above the absolute threshold and second-best margin changes only that cell to `found`.
|
||||
- Active-shop changes and three consecutive missing sale anchors clear grid/slot progress without deleting parsed historical items.
|
||||
- The selected source preview expands to at least 640 CSS px and draws pending slots yellow, found slots green, followed by transient diagnostics and a parsed/total counter.
|
||||
- Slot thumbnails and the grid-captured marker are runtime-only and are excluded from clipboard JSON and the market outbox payload.
|
||||
|
||||
## Verification run (2026-08-11)
|
||||
|
||||
- `node --test`: **30 passed, 0 failed**.
|
||||
- `vite build`: **passed**. Existing OpenCV browser-externalization and large-chunk warnings remain.
|
||||
- `git diff --check`: **passed**; only the repository's expected LF-to-CRLF conversion warnings were printed.
|
||||
- Playwright screenshot lane: **17/17 cases executed** through production OpenCV/Tesseract/parser, but the semantic assertion currently reports **42 mismatches**. The lane is intentionally red and must not be represented as acceptance-complete.
|
||||
|
||||
Useful browser evidence despite the red aggregate:
|
||||
|
||||
- Clean `sell-gnumli` detected exactly pending slots `[0,1]`.
|
||||
- Clean `buy-rakot` detected exactly pending slots `[0,1,2]`.
|
||||
- In the Gnumli sequence, the Blessed Spiritshot catalog crop uniquely matched slot `1`, producing `pending=[0]`, `found=[1]`.
|
||||
- A targeted rerun wrote `sell-gnumli-clean-overlay.jpg` with both occupied cells yellow and `sell-gnumli-blessed-spiritshot-overlay.jpg` with slot 0 yellow / slot 1 green under the ignored Playwright result directory.
|
||||
- The contextual `buy-kapayji` tooltip-only case produced no reported mismatch, including its pending-to-found slot transition.
|
||||
- The remaining failures are dominated by low-resolution Lineage font OCR (for example `Domestos` → `Domastos`, `Gnumli` → `Enumli`) and lost tooltip quantities/names. Raising the occupancy threshold from `0.15` to `0.18` removed the observed false-positive `shotD` slot 16 on the final full-corpus rerun.
|
||||
- The fixture failure output now contains `fixture-report.json`, one annotated overlay and per-stage crops for every failing case under ignored `test-results/`.
|
||||
- Desktop and 600 px narrow source-card states were rendered from the production CSS contract and visually inspected during implementation. The preview measured at least 640 px on desktop and collapsed to one column without horizontal overflow at 600 px, but those synthetic-layout screenshots were not retained as durable goal artifacts and do not prove the live renderer/canvas call path.
|
||||
|
||||
## Unproven / blocked evidence
|
||||
|
||||
- Fixture catalog PNGs are reviewed screenshot crops, not bytes returned by the real `/api/l2/items` `iconUrl`. They prove the matching path and ambiguity guard, but not live catalog artwork compatibility.
|
||||
- The local host returns no usable real catalog/calibration endpoints, so hosted calibration PUT→GET preservation and a real catalog icon score remain unverified.
|
||||
- Manual OS display capture was not exercised; the CSS layout screenshots do not prove the real `getDisplayMedia` source or the actual `drawSourceOverlay` canvas call path.
|
||||
|
||||
Acceptance remains partial until the 17-case semantic lane is green and one real API icon is paired with an occupied live slot.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Goal: Store Icon Progress Overlay
|
||||
|
||||
Use Krypton Execution to execute `docs/goals/store-icon-progress/PLAN.md` after the required Buy-store fixture and catalog icon URL evidence are available.
|
||||
|
||||
Core rules:
|
||||
- Treat PLAN.md as the source plan.
|
||||
- Create `data/fixtures.json` from the reviewed 17-file corpus before changing recognition behavior.
|
||||
- Keep fixture expected data human-owned; tests may report actual values but must never bless or rewrite expectations automatically.
|
||||
- Keep fixture calibration, templates, catalog JSON/icon bytes and sequence pending/found states human-owned and versioned.
|
||||
- Run fixtures through the single `src/frame-analyzer.js#analyzeFrame` path used by live capture; remove the inline implementation from `main.js` and do not create a test-only parser.
|
||||
- Use real production OpenCV/Tesseract/parser in the Playwright lane; substitute only catalog transport with committed fixture assets.
|
||||
- Preserve the active result as slot-state truth owner.
|
||||
- Keep old six-field calibration readable and operational.
|
||||
- Do not infer the parsed slot from tooltip position or hover order.
|
||||
- Mark a slot green only for a unique best visual match above both the absolute threshold and second-best margin; ties remain yellow.
|
||||
- Do not send runtime images or slot state to the backend.
|
||||
- Make the active source preview readable at the real source-card scale before accepting overlay evidence.
|
||||
- Verify optional grid calibration survives the hosted PUT-to-GET round trip.
|
||||
- Capture yellow-to-green browser evidence and record it in EVIDENCE.md.
|
||||
- Finish with one `npm run check` gate covering unit tests, all fixture screenshots, the production build and `git diff --check`.
|
||||
- Say `implemented but unproven` if Buy/Sell or catalog-icon matching cannot be demonstrated.
|
||||
@@ -0,0 +1,167 @@
|
||||
# Store Icon Progress Overlay Implementation Plan
|
||||
|
||||
**Intent:** Показывать прогресс обхода открытого магазина прямо поверх захваченного игрового кадра: занятые иконки ожидают tooltip в жёлтой рамке и становятся зелёными после успешного распознавания и привязки к слоту.
|
||||
**Current Behavior:** Overlay показывает только служебные области текущего кадра и общий статус одного tooltip; приложение не знает список занятых слотов и не хранит прогресс по каждой иконке.
|
||||
**Expected Outcome:** После распознавания магазина приложение находит занятые слоты его Buy/Sell-сетки, показывает их жёлтыми, сохраняет чистый снимок сетки без tooltip и переводит точный слот в зелёный после OCR предмета и совпадения его каталоговой иконки.
|
||||
**Target-Perspective Output:** В развёрнутом превью выбранного окна (не уже 640 CSS px на desktop, когда позволяет viewport) виден реальный магазин с компактным чек-листом поверх его иконок: жёлтый означает «наведи курсор», зелёный — «этот слот уже прочитан»; рядом показан счётчик `2/5 иконок`.
|
||||
**Truth Owner:** Активный `result` источника владеет текущим магазином и его `iconSlots`; `src/vision.js` владеет определением занятых ячеек и сравнением визуальной иконки, а `drawSourceOverlay` только рисует состояние.
|
||||
**Contract Boundary:** Калибровка хранит необязательные `sellItemGridRegion` и `buyItemGridRegion` относительно найденного маркера магазина. `detectOccupiedSlots(frame, absoluteGridRect)` возвращает `{slotId,row,column,frameRect,score}[]`. После `resolveCatalogItem` `matchCatalogIconToSlot(slots, icon)` возвращает ровно один `slotId` только при прохождении абсолютного порога и отрыва от второго результата; иначе возвращает `null`.
|
||||
**Cutover:** Существующие diagnostics boxes продолжают показывать pipeline, но прогресс иконок рисуется из отдельного устойчивого `result.iconSlots`; общий статус «Предмет ожидает» заменяется счётчиком слотов, когда сетка доступна.
|
||||
**Displaced Path:** Не использовать ближайший к tooltip слот, порядок наведения или «первый жёлтый» как источник истины — эти эвристики могут покрасить не ту иконку.
|
||||
**Value Density:** Две необязательные области калибровки, один лёгкий пиксельный проход по 18 ячейкам при открытии магазина и одно сравнение с pending slots после нового предмета; без OCR всех иконок и без нового backend-контракта.
|
||||
**Evidence Gate:** Все 17 кадров из `data/` описаны в human-reviewed manifest и прогоняются тем же analyzer path, что live capture; на полном Sell-кадре занятые слоты выделены, пустые не выделены; на полном Buy-кадре работает отдельная область; после связанного tooltip ровно соответствующий слот меняет жёлтый на зелёный, а остальные остаются жёлтыми.
|
||||
**Acceptance Evidence:** `npm run test:fixtures` сравнивает merchant/side/occupied slots/tooltip item с manifest для каждого файла и проверяет связанные store sequences; browser screenshots до/после tooltip для Sell и Buy при фактическом размере source card; unit tests occupied-slot classifier, unique-best/tie и active-shop reset; production build; calibration PUT→GET round-trip; отсутствие slot-данных в clipboard export/outbox.
|
||||
**Evidence Lane:** Human-reviewed `data/fixtures.json`, локальный browser fixture runner, `node --test`, production build.
|
||||
**Kill Criteria:** Нет второго overlay canvas, нет позиционного угадывания hovered slot, нет обязательной миграции старой калибровки, нет отправки thumbnail/data URL в backend; inline `analyzeFrame` удалён из `main.js`, и live capture/fixture runner импортируют один `analyzeFrame` из `src/frame-analyzer.js`.
|
||||
**Architecture Slice:** `data/*.jpg`, `data/fixtures.json`, `index.html`, `src/main.js`, выделяемый production analyzer seam, `src/vision.js`, `src/parser.js`, fixture tests, `package.json`, `README.md`, `src/style.css`.
|
||||
**Plan Review Gate:** Requires PRE review before execution.
|
||||
|
||||
## Product Direction
|
||||
|
||||
- Domain: private store, Buy/Sell grid, occupied slot, tooltip, catalog icon, captured frame, scan progress.
|
||||
- Color world: тёмный игровой кадр, приглушённый amber ожидания, зелёный подтверждения, красный ошибки, нейтральный синий diagnostics.
|
||||
- Signature: живой чек-лист непосредственно на слотах Lineage II, а не отдельный dashboard со списком.
|
||||
- Rejected defaults: отдельная карточка каждого pending slot; анимированные пульсирующие рамки; окрашивание всех пустых клеток сетки.
|
||||
- Direction: сохранить реальный кадр главным слоем и добавить только семантические рамки и компактный счётчик.
|
||||
|
||||
## Component Checkpoint
|
||||
|
||||
- Intent: владелец инструмента быстро видит, какие предметы в конкретном магазине ещё нужно обойти; интерфейс остаётся спокойным и утилитарным.
|
||||
- Hierarchy: сам кадр и рамки слотов — focal point; textual status вторичен.
|
||||
- Palette: существующие `pending` amber и `found` green; новые декоративные цвета не добавляются.
|
||||
- Depth: borders-only поверх видео, без теней и glow.
|
||||
- Surfaces: существующее preview surface; новый контейнер не создаётся.
|
||||
- Typography: существующий маленький overlay status с tabular counter.
|
||||
- Spacing: существующая плотность 4/8 px; рамка не перекрывает содержимое иконки.
|
||||
- Readability: активное source preview разворачивается минимум до 640 CSS px на desktop; на узком viewport занимает доступную ширину без отдельного уменьшенного дубликата.
|
||||
|
||||
## Architecture Slice
|
||||
|
||||
- Files to create: `data/fixtures.json`, `data/fixture-calibration.json`, reviewed template/catalog assets under `data/fixture-assets/`, `src/frame-analyzer.js`, Playwright fixture regression spec and browser evidence images.
|
||||
- Files to modify: `index.html`, `src/main.js`, `src/vision.js`, `src/parser.js`, fixture/unit tests, `package.json`, `README.md`, `src/style.css`; hosted calibration endpoint/schema добавляется в scope только если round-trip отбрасывает optional regions.
|
||||
- Files to avoid: `src/market-outbox.js`, import proxy, backend payload, catalog API contract.
|
||||
- Source of truth: `data/fixtures.json` владеет reviewed expected result/initial state/slot transitions каждого screenshot sequence; `data/fixture-calibration.json` и `data/fixture-assets/` владеют reviewed test geometry/templates/catalog bytes; production analyzer владеет фактическим результатом кадра; `result.activeShopKey` + `result.iconSlots` владеют live progress.
|
||||
- Read path: fixture JPG + fixture calibration → тот же production analyzer, что live frame → actual result → semantic comparison with manifest; live frame → sale anchor → header side/merchant → side-specific grid → occupied slots → yellow overlay; tooltip → parsed item → catalog icon → saved grid snapshot → matched slot → green overlay.
|
||||
- Write path: fixture manifest/calibration/assets редактируются только при добавлении или ручной перепроверке screenshots; тесты не переписывают expected values автоматически; calibration дополняется двумя optional regions; runtime slot state остаётся только в памяти источника.
|
||||
- Contract boundary: `src/frame-analyzer.js` экспортирует единственный `analyzeFrame({frame,result,calibration,templates,source,services}) -> Promise<result>`; production OCR/OpenCV/parser импортируются внутри этого модуля или передаются только через production adapters, а `services.catalog` является единственной fixture substitution; `detectOccupiedSlots(frame, absoluteGridRect) -> [{slotId,row,column,frameRect,score}]`; `matchCatalogIconToSlot(slots, icon) -> slotId|null`; canvas wrappers live in `vision.js`.
|
||||
- Integration points: fixture manifest loader/schema, production `analyzeFrame`, `emptyCalibration`, calibration UI/addRegion/rendering, `resolveCatalogItem` result, `drawSourceOverlay`, package verification scripts.
|
||||
- Migration/cutover: existing v4 calibration is read unchanged; missing grid region disables only icon progress for that side.
|
||||
- Displaced path: общий item status остаётся fallback только при отсутствии grid calibration.
|
||||
- Acceptance evidence gate: full-window Buy and Sell fixtures plus tooltip/item catalog icon.
|
||||
|
||||
## Fixture Corpus and Ground Truth
|
||||
|
||||
Все кадры имеют размер 1560 x 1360 и сняты персонажем `Deela`. `merchant` ниже — персонаж открытого магазина. Номер slot считается с нуля слева направо по верхней строке. Значения `unknown` не угадываются по иконке: такой fixture проверяет заголовок и занятость слота, но не название предмета.
|
||||
|
||||
| File | Scene | Expected store | Visible/hovered contents |
|
||||
| --- | --- | --- | --- |
|
||||
| `Discord_2KrJ9GGjCP.jpg` | Buy + tooltip | `buy:KapayJI`, occupied `[0]` | slot 0: `Ancient Adena`, quantity `0`, each `2` Adena |
|
||||
| `Discord_7xmx8OSuCH.jpg` | Sell, clean | `sell:Domestos`, occupied `[0]` | slot 0: `unknown` |
|
||||
| `Discord_ARWzEIaayl.jpg` | Sell + tooltip | `sell:Gnumli`, occupied `[0,1]` | slot 0: `Soulshot: C-grade`, quantity `36,370`, price `20` Adena |
|
||||
| `Discord_dxpCzaJEWD.jpg` | Sell + tooltip | `sell:Boroda4`, occupied `[0,1]` | slot 1: `Brigandine Helmet`, quantity `1`, price `800,000` Adena |
|
||||
| `Discord_ezvlzpNHRg.jpg` | Sell + tooltip | `sell:shotD`, occupied `[0,1]` | slot 1: `Dimensional Fragment`, quantity `687`, price `3,500` Adena |
|
||||
| `Discord_fb9f61z8Ek.jpg` | Sell + tooltip | `sell:shotD`, occupied `[0,1]` | slot 0: `Tutorial Guide`, quantity `1`, price `5,000,000` Adena |
|
||||
| `Discord_fFbzX9vDhW.jpg` | Sell + tooltip | `sell:1SHOP`, occupied `[0]` | slot 0: `Ancient Adena`, quantity `1,793,000`, price `3` Adena |
|
||||
| `Discord_ikzA9VhROZ.jpg` | Buy + tooltip | `buy:RAKOT`, occupied `[0,1,2]` | slot 2: `Coarse Bone Powder`, quantity `0`, each `1` Adena |
|
||||
| `Discord_K9RkTrU6B2.jpg` | Sell, clean | `sell:Crom`, occupied `[0,1]` | slots 0–1: `unknown` |
|
||||
| `Discord_KL0fnDcvr7.jpg` | Sell + tooltip | `sell:Boroda4`, occupied `[0,1]` | slot 0: `Spellbook: Prominence`, quantity `2`, price `50,000` Adena |
|
||||
| `Discord_qy3EYIEcMV.jpg` | Sell + tooltip | `sell:Gnumli`, occupied `[0,1]` | slot 1: `Blessed Spiritshot: D-Grade`, quantity `7,245`, price `58` Adena |
|
||||
| `Discord_sSJAGZLHvm.jpg` | Sell, clean | `sell:Boroda4`, occupied `[0,1]` | paired contents: `Spellbook: Prominence`, `Brigandine Helmet` |
|
||||
| `Discord_tJFxvFi7DM.jpg` | Sell, clean | `sell:1SHOP`, occupied `[0]` | paired content: `Ancient Adena` |
|
||||
| `Discord_TxbA20ZOQB.jpg` | Buy + tooltip | `buy:RAKOT`, occupied `[0,1,2]` | slot 0: `Scroll: Enchant Weapon (D)`, quantity `0`, each `200,000` Adena |
|
||||
| `Discord_uqGcQhxIWc.jpg` | Sell, clean | `sell:shotD`, occupied `[0,1]` | paired contents: `Tutorial Guide`, `Dimensional Fragment` |
|
||||
| `Discord_w3Smu4bOQK.jpg` | Sell, clean | `sell:Gnumli`, occupied `[0,1]` | paired contents: `Soulshot: C-grade`, `Blessed Spiritshot: D-Grade` |
|
||||
| `Discord_wQc5FDayAK.jpg` | Buy, clean | `buy:RAKOT`, occupied `[0,1,2]` | slot 0: `Scroll: Enchant Weapon (D)`; slot 1: `unknown`; slot 2: `Coarse Bone Powder` |
|
||||
|
||||
Manifest records both human-facing `displayName` and parser-facing normalized `name`, for example `Spellbook: Prominence` → `Spellbook Prominence`. It also records `viewerCharacter`, `groupId`, `scene`, standalone vs contextual assertion mode, `side`, `merchant`, `occupiedSlots`, optional `hoveredSlot`, optional reviewed `initialState`, `expectedPendingSlots`, `expectedFoundSlots`, `catalogAssetId`, and optional `{displayName,name,quantity,priceAdena,priceMode}`. Every `data/*.jpg` must appear exactly once; missing files and stale manifest entries fail before OCR starts.
|
||||
|
||||
`data/fixture-calibration.json` is human-reviewed versioned truth for this 1560 x 1360 corpus: sale anchor, store header, tooltip search/anchor, name/price regions and Buy/Sell grid regions. Template images are committed as explicit files under `data/fixture-assets/`; runner never derives calibration from actual results. Catalog mappings point to committed API JSON plus original icon bytes by `catalogAssetId/path`, not to manifest-derived generated icons.
|
||||
|
||||
Sequence groups:
|
||||
|
||||
- `sell-gnumli`: clean → Soulshot tooltip → Blessed Spiritshot tooltip.
|
||||
- `sell-boroda4`: clean → Spellbook tooltip → Brigandine Helmet tooltip.
|
||||
- `sell-shotd`: clean → Tutorial Guide tooltip → Dimensional Fragment tooltip.
|
||||
- `sell-1shop`: clean → Ancient Adena tooltip.
|
||||
- `buy-rakot`: clean → Scroll tooltip → Coarse Bone Powder tooltip; middle slot intentionally remains unknown/pending.
|
||||
- `sell-domestos`, `sell-crom`: standalone clean frames guarding the confirmed header and occupancy fields.
|
||||
- `buy-kapayji`: tooltip-only partial group with human-reviewed `initialState` for `buy:KapayJI` and slot 0 pending; it validates tooltip parsing/transition only and does not claim standalone header/grid recognition.
|
||||
|
||||
## Fixture Test Contract
|
||||
|
||||
- Unit/schema lane (`node --test`): manifest validity, exact JPG coverage, unique ids, slot ranges, paired group consistency, normalization and pure state transitions.
|
||||
- Screenshot lane (`npm run test:fixtures`): `@playwright/test` starts the Vite fixture page in bundled Chromium, loads real JPGs, applies committed fixture calibration, calls `src/frame-analyzer.js#analyzeFrame`, and compares only declared expected fields. It uses real production OpenCV/Tesseract/parser; only `/api/l2/items` transport is fulfilled from committed catalog JSON/icon bytes.
|
||||
- Sequence lane: feed group frames in manifest order and assert remembered `side:merchant`, item aggregation and explicit `expectedPendingSlots`/`expectedFoundSlots` after every frame. Contextual-only fixtures start from their reviewed `initialState`; they are never reported as standalone full-frame passes.
|
||||
- Diagnostics on failure: write an actual-vs-expected JSON report plus crop/overlay artifacts under an ignored test-output directory; never overwrite the manifest or source JPGs.
|
||||
- Stable assertions: exact semantic merchant/side/name/quantity/price and slot ids; no pixel-perfect full-screen snapshots and no assertion on OCR confidence unless a threshold regression is specifically under test.
|
||||
- Three-miss reset stays in the pure state-transition unit lane because the current corpus has no three-frame no-store sequence.
|
||||
- Verification command: add `npm run check` for unit tests, all 17 fixture cases, production build and `git diff --check`; hosted calibration PUT→GET remains a separately recorded environment evidence gate because it requires the deployed backend.
|
||||
|
||||
## Runtime Invariants
|
||||
|
||||
- Buy и Sell используют разные calibrated grid regions; side выбирается только из распознанного заголовка.
|
||||
- Grid region делится на фиксированную Interlude-сетку 6 x 3; пользователь выделяет внешний прямоугольник клеток без заголовка и scroll buttons.
|
||||
- Пустые ячейки не получают рамку; занятые начинаются как `pending`.
|
||||
- Occupancy считается только внутри фиксированного inset каждой ячейки, исключающего border; метрика и порог выбираются по измеренному разрыву между occupied/empty примерами обоих типов магазина и фиксируются константой с fixture-тестом.
|
||||
- Grid snapshot обновляется только на кадре с распознанным заголовком и без найденного tooltip, чтобы tooltip не закрыл иконки.
|
||||
- Смена `side:merchant` полностью сбрасывает runtime slots, но не исторические parsed items.
|
||||
- Зелёный статус ставится только если лучший visual match превышает измеренный threshold и опережает второй результат не меньше чем на измеренный margin; tie/identical icons возвращают `null`, остаются жёлтыми и получают статус «неоднозначно».
|
||||
- Повторный OCR того же предмета не перекрашивает другой одинаковый slot без нового однозначного совпадения.
|
||||
- Slot thumbnails, grid snapshots и match scores не попадают в outbox или exported JSON.
|
||||
- После трёх последовательных кадров без `saleAnchor`/нижнего маркера магазина (существующий `result.misses`) очищаются `activeShopKey`, grid snapshot и slots; отсутствие header OCR при видимом маркере, в том числе из-за tooltip, прогресс не сбрасывает; повторное открытие того же merchant строит состояние заново.
|
||||
|
||||
## Tasks
|
||||
|
||||
1. Зафиксировать corpus в `data/fixtures.json` и добавить schema/coverage tests.
|
||||
- Allowed scope: существующие 17 JPG остаются неизменными; expected values вводятся вручную по таблице выше; unknown fields остаются явно unknown.
|
||||
- Expected output: каждый JPG описан ровно один раз, связанные кадры объединены `groupId`, human display и parser-normalized item names разделены.
|
||||
- Verification: `node --test` validates schema, coverage and group consistency.
|
||||
- Parallel: no; establishes regression truth.
|
||||
2. Выделить `src/frame-analyzer.js#analyzeFrame` и добавить Playwright browser fixture runner без дублирования pipeline.
|
||||
- Allowed scope: перенести только ownership анализа кадра из DOM-heavy `main.js`; удалить inline implementation; live capture и fixtures импортируют один symbol; runner использует production OCR/OpenCV/parser, подменяя только внешний catalog transport committed fixture-ответом.
|
||||
- Expected output: `npm run test:fixtures` обрабатывает JPGs, сравнивает только declared fields и сохраняет понятные failure artifacts.
|
||||
- Verification: source search находит одно определение `analyzeFrame`; намеренно испорченный expected field даёт targeted diff; после возврата manifest corpus проходит.
|
||||
- Parallel: no; establishes executable evidence lane.
|
||||
3. Добавить optional Sell/Buy grid calibration в `index.html`, `src/main.js`, `src/parser.js`.
|
||||
- Allowed scope: два поля относительно sale anchor; существующие шесть остаются обязательным минимумом.
|
||||
- Expected output: старые сохранения работают; grid fields можно выбрать, удалить, сохранить и увидеть на calibration canvas.
|
||||
- Verification: parser/calibration tests, browser selection smoke и hosted PUT→GET round-trip; если поля теряются, минимально расширить серверную схему.
|
||||
- Parallel: no; extends the contract.
|
||||
4. Добавить в `src/vision.js` минимальные slot helpers: 6 x 3 geometry, occupied-cell classifier и unique-best matching catalog icon к pending slots.
|
||||
- Allowed scope: локальная grid image analysis; использовать существующий OpenCV loader/matcher.
|
||||
- Expected output: provided Sell fixture returns exactly its occupied cells; empty grid returns none.
|
||||
- Verification: Node tests для geometry/classifier seam, absolute threshold, second-best margin, identical-icon tie и browser fixture for canvas wrapper.
|
||||
- Parallel: no; consumes tasks 1-3 contracts and uses both Sell/Buy fixture corpus.
|
||||
5. Интегрировать runtime state в `src/main.js`.
|
||||
- Allowed scope: active-shop reset, clean grid snapshot, slot match after `resolveCatalogItem`, no backend writes.
|
||||
- Expected output: stable pending/found slots persist across frames and reset on shop change/close.
|
||||
- Verification: focused state-transition tests, three-miss close/reset, reopening same merchant and two-frame browser flow; assert no slot/snapshot fields in clipboard export and outbox.
|
||||
- Parallel: no; consumes tasks 3-4.
|
||||
6. Развернуть активное live-превью и расширить существующий `drawSourceOverlay`/status copy.
|
||||
- Allowed scope: selected source preview минимум 640 CSS px на desktop; draw slot rects before transient diagnostics; reuse `boxColor(pending/found)`.
|
||||
- Expected output: игровые слоты читаемы в карточке источника, yellow/green outlines и `parsed/total` counter; no new canvas or motion.
|
||||
- Verification: desktop screenshot именно при фактическом размере source card, narrow viewport screenshot, squint/token/state checks.
|
||||
- Parallel: can start after runtime contract is fixed.
|
||||
7. Обновить `README.md`, добавить единый `npm run check`, прогнать tests/build/diff-check и записать browser evidence в `EVIDENCE.md`.
|
||||
- Acceptance evidence: manifest coverage report `17/17`, Sell and Buy yellow states, exact green transition, shop reset.
|
||||
- Parallel: no.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Автоматически кликать или наводить курсор в игровом окне.
|
||||
- OCR названий прямо с 32 px icon.
|
||||
- Сохранять slot progress между перезапусками приложения.
|
||||
- Менять каталог, import payload или исторический список результатов.
|
||||
- Угадывать слот по положению tooltip или порядку обхода.
|
||||
|
||||
## Required Input Before Execution
|
||||
|
||||
- Реальный ответ `/api/l2/items` для одного известного предмета из Sell fixture, включая `iconUrl`, и доступные по этому URL bytes (либо контролируемый локальный/hosted fixture). Same-origin сам по себе не доказывает, что catalog artwork, alpha и размер совпадают с игровой иконкой.
|
||||
- Buy fixture теперь есть: `Discord_wQc5FDayAK.jpg`; по нему и clean Sell fixtures во время исполнения измерить occupied/empty metric gap и только затем зафиксировать cell inset/threshold.
|
||||
- По реальной паре slot crop ↔ catalog icon измерить absolute match threshold и best-vs-second margin; до этого зелёная привязка считается непроверенной.
|
||||
|
||||
## Risks
|
||||
|
||||
- Кастомный клиент может изменить размер/число slot cells; фиксированная 6 x 3 геометрия тогда потребует отдельной настройки.
|
||||
- Catalog icon может отличаться рамкой, альфой или масштабом от клиентского asset; evidence должен зафиксировать реальный match score до выбора порога.
|
||||
- Одинаковые иконки в нескольких слотах требуют дополнительного различителя; до него неоднозначные совпадения должны оставаться жёлтыми.
|
||||
Reference in New Issue
Block a user