From eaa4a567088ae6979277c5f6c6d2ce0459c48d85 Mon Sep 17 00:00:00 2001 From: Shahovalov MIkhail Date: Wed, 27 May 2026 17:25:41 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20drawing=5Ffill=5Ftitle=5Fblock=20?= =?UTF-8?q?=E2=80=94=20=D1=83=D0=BF=D1=80=D0=BE=D1=87=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=D0=B8=D0=B5=20=D0=BF=D0=BE=20=D1=80=D0=B5=D0=B2=D1=8C=D1=8E=20?= =?UTF-8?q?Codex=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #3/#6: доступ к графе через RequireStampCell(stamp,columnId) — null-check ячейки + единое место валидации (запись и чтение). #4: проверка columnId>0 в helper (защищает и ReadStampCellAsync). #2/#5: нетранзакционность записи зафиксирована комментарием (откат при Update()==FALSE спекулятивен, не делаем). RCW — долг v2-2. Тесты без изменений в числе: 123 unit + 65 integration = 188 зелёных. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-27-drawing-title-block-design.md | 13 ++++++++++++- src/Kompas.Mcp.Core/Drawings/DrawingService.cs | 16 ++++++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md b/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md index ef10d9e..d8057b4 100644 --- a/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md +++ b/docs/superpowers/specs/2026-05-27-drawing-title-block-design.md @@ -1,7 +1,18 @@ # Дизайн: основная надпись чертежа (drawing_fill_title_block) через API7 **Дата:** 2026-05-27 -**Статус:** реализовано и проверено (4 интеграционных + 7 unit, всего 188); ревью Codex спека учтено +**Статус:** реализовано и проверено (4 интеграционных + 7 unit, всего 188); ревью Codex спека и реализации учтено + +## Правки по ревью реализации Codex + +- **null-check ячейки** (#3): доступ к графе через `RequireStampCell(stamp, columnId)` — проверяет + `columnId > 0` и `Text[columnId] != null` с диагностикой; используется в записи и чтении (единое + место валидации, #6). +- **`columnId <= 0`** (#4): валидируется в `RequireStampCell` (защищает и `ReadStampCellAsync`). +- **Нетранзакционность** (#2/#5): записываем все графы, затем один `Update()`; при `Update()==FALSE` + откат старых значений не делаем — зафиксировано комментарием как осознанное поведение (откат + спекулятивен, сценарий невоспроизводим). +- **RCW** — осознанный долг (v2-2), точечный release не вводим. ## Находка спайка: `Str` ПЕРЕЗАПИСЫВАЕТ (Clear не нужен) diff --git a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs index a0b3d9f..7a2d6b8 100644 --- a/src/Kompas.Mcp.Core/Drawings/DrawingService.cs +++ b/src/Kompas.Mcp.Core/Drawings/DrawingService.cs @@ -46,8 +46,11 @@ public sealed class DrawingService throw new ArgumentException("Укажите хотя бы одно поле основной надписи (designation/name/material)."); var stamp = RequireActiveStamp(); + // Нетранзакционно: все графы записываются, затем один Update() фиксирует. При Update()==FALSE + // (на практике не воспроизводится) откат старых значений не делаем — он спекулятивен (Str уже + // на in-memory объектах графы, повторный Update мог бы тоже упасть); сообщаем об ошибке. foreach (var (columnId, text) in fields) - stamp.Text[columnId].Str = text; // Str замещает содержимое (Clear не нужен) + RequireStampCell(stamp, columnId).Str = text; // Str замещает содержимое (Clear не нужен) if (!stamp.Update()) throw new InvalidOperationException("IStamp.Update вернул FALSE — основная надпись не обновлена."); return fields.Count; @@ -58,9 +61,18 @@ public sealed class DrawingService => _dispatcher.InvokeAsync(() => { var stamp = RequireActiveStamp(); - return stamp.Text[columnId]?.Str ?? string.Empty; + return RequireStampCell(stamp, columnId).Str ?? string.Empty; }, ct); + /// Получить графу основной надписи по номеру с диагностикой (номер > 0, ячейка != null). + private static IText RequireStampCell(IStamp stamp, int columnId) + { + if (columnId <= 0) + throw new ArgumentOutOfRangeException(nameof(columnId), "Номер графы основной надписи должен быть > 0."); + return stamp.Text[columnId] + ?? throw new InvalidOperationException($"Графа {columnId} основной надписи недоступна (Text[{columnId}] == null)."); + } + private IStamp RequireActiveStamp() { var doc2d = RequireActiveDrawing();