12 Commits
Author SHA1 Message Date
Mikhail ChusavitinandClaude Sonnet 5 d7d4ea74b6 fix: артикул — категории из component universe + видимость нераспознанных токенов
Генерация артикула резолвила lot_category из одного прайслиста конфигурации
(GetLocalLotCategoriesByServerPricelistID), поэтому world-only LOT (напр.
GPU_NV_RTX_PRO_6000D_SERVER_84GB_PCIE, есть только в world) молча выпадал из
артикула. Теперь категории берутся через GetLocalComponentCategoriesByLotNames
(тот же world ∪ estimate, что и весь конфигуратор). BuildOptions.ServerPricelist
убран; preview-article принимает pricelist_id, но игнорирует.

Нераспознанные токены больше не пишутся как UNK: в артикул идёт lot_category как
плейсхолдер (4xGPU, 2xCPU), сегмент помечается Recognized=false, добавляется
warning с именем LOT. Конфигуратор подсвечивает такие сегменты (amber) и выводит
список предупреждений; сохранение/обновление/откат логируют WARN. Без каталога
вендоров в репо детектируется только структурный сбой формы имени.

parseGPUModel: принимает суффикс-букву в номере модели (6000D → RTX6000D),
раньше терял её и схлопывал до RTX_84GB.

ADL bible-local/decisions/2026-09-01-article-category-from-component-universe.md,
2026-09-01-article-degraded-token-visibility.md; раздел «Article generation» в
02-architecture.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RAhfF4P1ySRZ67yyUUeVw2
2026-09-01 09:01:56 +03:00
Mikhail ChusavitinandClaude Sonnet 5 4d7b0e13ef refactor: устранить дублирование кода (Go-хендлеры, JS-автокомплит)
Найдено статическим анализом (dupl/jscpd) + проверено вручную:

Go:
- appstate/path.go: ResolveDBPath/ResolveConfigPath → общий resolvePath()
- handlers/respond.go: дженерик BindJSON[T] для bind+422-ошибки
- article/generator.go: buildNetSegment/buildPSUSegment → buildProfileSegment()
- cmd/qfs/main.go (+respond.go): 8 повторяющихся switch{case errors.Is(...)}
  → respondByErrCase(c, err, errCase{...}, ...)

Frontend (index.html):
- 5 идентичных обработчиков клавиатурной навигации автокомплита
  → handleAutocompleteKeyGeneric(event, onSelect)
- 4 функции сборки нового элемента корзины из автокомплита
  → buildNewCartItem()/commitCartChange()

Также: PricingMarkup — единая точка правды для аплифт-коэффициента
в JS (render + export), с cross-reference комментариями к Go-константам
в export.go (defaultSaleMarkup/stockCompetitorMarkupFactor).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 20:13:27 +03:00
Mikhail ChusavitinandClaude Sonnet 5 7edb80e498 feat: расчёт стоимости платного тестирования/аренды GPU-серверов
Новая вкладка «Аренда» в конфигураторе (доступна для проектов с флагом
rental_enabled): расчёт по методичке "Регламент расчёта стоимости
платного тестирования и аренды GPU-серверов" — Разовый + Еженедельный
платёж по каждому компоненту (New/БУ чекбоксом), с аплифтом к Estimate.

Заодно: поддержка (support_code) в Base-вкладке теперь добавляется как
обычный LOT в спеку (SVC_{срок}y{уровень}_{платформа}) через
autocomplete-пикер вместо выпадающего списка — партномер собирается
тем же lot_name-based механизмом, что и для GPU/CPU/памяти, справочная
цена по регламенту техподдержки хранится в qt_settings.support_pricing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-22 13:34:07 +03:00
Mikhail ChusavitinandClaude Sonnet 4.6 f24584f65c fix: лоты без категории в прайслисте не блокируют сборку артикула
ResolveLotCategoriesStrict переименован в ResolveLotCategories и лишён
строгости: лоты, отсутствующие в прайслисте или с пустой lot_category,
просто пропускаются — партномер из них не собирается. Ранее любой
«незнакомый» лот возвращал ошибку и блокировал сохранение конфига.

Удалены ErrMissingCategoryForLot, MissingCategoryForLotError и
fallback через local_components (противоречил cc72052).

resolvePricelistID: если прайслист отсутствует локально после синка —
fallback на последний активный вместо ошибки.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-29 16:21:45 +03:00
mchusandClaude Sonnet 4.6 7d190cc7a8 fix: регистронезависимый поиск lot_name и удаление мёртвого кода
- SQLite-запросы по lot_name теперь используют UPPER(lot_name) IN/= для
  совместимости с легаси-данными, синхронизированными до нормализации регистра
- Удалена таблица local_components и весь связанный код синхронизации;
  источник данных для компонентов — local_pricelist_items
- Удалена функция getCategoryFromLotName из JS: категория берётся только
  из прайслиста, без инференса из имени лота
- Регистронезависимые сравнения lot_name в JS (warehouse stock set,
  addedLots, cartLots, allComponents.find, _bomLotValid)
- В support bundle добавлены: latest_pricelist_items.json, local.db,
  autocomplete_lots.json для диагностики

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-26 08:52:22 +03:00
Mikhail ChusavitinandClaude Sonnet 4.6 e1f34ae81b fix: compressArticle used hard-coded indices, PSU rendered as NIC when GPU absent
compressArticle assumed a fixed segment layout [model,cpu,mem,gpu,disk,net,psu,support].
Build() skips empty segments, so without GPU the PSU slot shifted to index 5. Step 2 of
compression called compressNetSegment on the PSU value ("2x1kW") which returned "2xNIC".

Replace positional indexing with namedSeg{group,value} tagged segments; compressArticle
now looks up each segment by group name via findSegGroup(), regardless of array length.

Regression test TestBuild_CompressArticle_NoGPU_PSUNotNIC reproduces the exact config
from OPS-2445 (NF5280M6 + 2xPSU, no GPU) that triggered the bug.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-19 12:36:55 +03:00
Mikhail ChusavitinandClaude Sonnet 4.6 89ce001906 fix: abbreviate GPU architecture suffixes in article token
Ampere, Hopper, Blackwell now produce AMP/HOP/BWL suffixes (like ADA)
so RTX cards across generations are distinguishable: RTX6000ADA vs
RTX6000BWL. LOVELACE remains a skip token as it duplicates ADA info.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 15:08:47 +03:00
Mikhail ChusavitinandClaude Sonnet 4.6 6a41c957cc fix: include model number and ADA suffix in GPU article token
RTX 6000 ADA and A6000 are distinct cards — RTX_4000_ADA_SFF now
produces RTX4000ADA instead of RTX, avoiding visual ambiguity with
the segment separator (10xRTX4000ADA vs 10xRTX-1x…).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-09 15:07:25 +03:00
Mikhail ChusavitinandClaude Sonnet 4.6 08a8113949 Fix article generator producing 1xINTEL in GPU segment
MB_ lots (e.g. MB_INTEL_..._GPU8) are incorrectly categorized as GPU
in the pricelist. Two fixes:
- Skip MB_ lots in buildGPUSegment regardless of pricelist category
- Add INTEL to vendor token skip list in parseGPUModel (was missing,
  unlike AMD/NV/NVIDIA which were already skipped)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-06 10:53:31 +03:00
Mikhail Chusavitin 4f6a62f5dc Fix article category fallback for pricelist gaps 2026-02-12 16:47:49 +03:00
Mikhail Chusavitin 3ab9ca1e73 Refine article compression and simplify generator 2026-02-11 19:24:25 +03:00
Mikhail Chusavitin 92bca0d0be Add article generation and pricelist categories 2026-02-11 19:16:01 +03:00