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
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
ecef030699
commit
d7d4ea74b6
@@ -40,5 +40,7 @@ type ArticlePreviewRequest struct {
|
||||
Items models.ConfigItems `json:"items"`
|
||||
ServerModel string `json:"server_model"`
|
||||
SupportCode string `json:"support_code,omitempty"`
|
||||
PricelistID *uint `json:"pricelist_id,omitempty"`
|
||||
// PricelistID is accepted for backward compatibility but ignored: article
|
||||
// categories come from the component universe (world ∪ estimate), not one pricelist.
|
||||
PricelistID *uint `json:"pricelist_id,omitempty"`
|
||||
}
|
||||
|
||||
@@ -70,13 +70,18 @@ func (s *LocalConfigurationService) Create(ownerUsername string, req *CreateConf
|
||||
|
||||
if strings.TrimSpace(req.ServerModel) != "" {
|
||||
articleResult, articleErr := article.Build(s.localDB, req.Items, article.BuildOptions{
|
||||
ServerModel: req.ServerModel,
|
||||
ServerPricelist: pricelistID,
|
||||
ServerModel: req.ServerModel,
|
||||
})
|
||||
if articleErr != nil {
|
||||
return nil, articleErr
|
||||
}
|
||||
req.Article = articleResult.Article
|
||||
if len(articleResult.Warnings) > 0 {
|
||||
slog.Warn("article generation degraded",
|
||||
"server_model", req.ServerModel,
|
||||
"article", articleResult.Article,
|
||||
"warnings", articleResult.Warnings)
|
||||
}
|
||||
}
|
||||
|
||||
total := req.Items.Total()
|
||||
@@ -166,13 +171,18 @@ func (s *LocalConfigurationService) Update(uuid string, ownerUsername string, re
|
||||
|
||||
if strings.TrimSpace(req.ServerModel) != "" {
|
||||
articleResult, articleErr := article.Build(s.localDB, req.Items, article.BuildOptions{
|
||||
ServerModel: req.ServerModel,
|
||||
ServerPricelist: pricelistID,
|
||||
ServerModel: req.ServerModel,
|
||||
})
|
||||
if articleErr != nil {
|
||||
return nil, articleErr
|
||||
}
|
||||
req.Article = articleResult.Article
|
||||
if len(articleResult.Warnings) > 0 {
|
||||
slog.Warn("article generation degraded",
|
||||
"server_model", req.ServerModel,
|
||||
"article", articleResult.Article,
|
||||
"warnings", articleResult.Warnings)
|
||||
}
|
||||
}
|
||||
|
||||
total := req.Items.Total()
|
||||
@@ -216,13 +226,10 @@ func (s *LocalConfigurationService) Update(uuid string, ownerUsername string, re
|
||||
|
||||
// BuildArticlePreview generates server article based on current items and server_model/support_code.
|
||||
func (s *LocalConfigurationService) BuildArticlePreview(req *ArticlePreviewRequest) (article.BuildResult, error) {
|
||||
pricelistID, err := s.resolvePricelistID(req.PricelistID)
|
||||
if err != nil {
|
||||
return article.BuildResult{}, err
|
||||
}
|
||||
// Categories for the article come from the component universe (world ∪ estimate),
|
||||
// not from a specific pricelist, so req.PricelistID is no longer needed here.
|
||||
return article.Build(s.localDB, req.Items, article.BuildOptions{
|
||||
ServerModel: req.ServerModel,
|
||||
ServerPricelist: pricelistID,
|
||||
ServerModel: req.ServerModel,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -527,13 +534,18 @@ func (s *LocalConfigurationService) UpdateNoAuth(uuid string, req *CreateConfigR
|
||||
|
||||
if strings.TrimSpace(req.ServerModel) != "" {
|
||||
articleResult, articleErr := article.Build(s.localDB, req.Items, article.BuildOptions{
|
||||
ServerModel: req.ServerModel,
|
||||
ServerPricelist: pricelistID,
|
||||
ServerModel: req.ServerModel,
|
||||
})
|
||||
if articleErr != nil {
|
||||
return nil, articleErr
|
||||
}
|
||||
req.Article = articleResult.Article
|
||||
if len(articleResult.Warnings) > 0 {
|
||||
slog.Warn("article generation degraded",
|
||||
"server_model", req.ServerModel,
|
||||
"article", articleResult.Article,
|
||||
"warnings", articleResult.Warnings)
|
||||
}
|
||||
}
|
||||
|
||||
total := req.Items.Total()
|
||||
|
||||
Reference in New Issue
Block a user