# FastenGen — задачи и roadmap Рабочий файл для отслеживания прогресса между сессиями. Обновляется после каждого шага. - **Репозиторий:** Gitea `admin/fastengen`, ветка `master` - **Тесты:** `PYTHONPATH=/tmp/fastengen/src python3 -m pytest -q` (полный ~5-8 мин; быстрый `-k "not gen_all"` и `-k "not gen_all_extended"`) - **Python:** 3.10, cadquery 2.7.0 - **Доступ:** `/tmp/fastengen` — dev-копия, рабочий репозиторий на Gitea `admin/fastengen` --- ## 🔴 В работе / только что сделано ### #1 Закрытие пробелов API — **ГОТОВО** (commit `5fa3ac7`) Замкнуть публичный API, добавить отсутствующие `add_*`, задедупить итераторы, добавить подкоманды CLI, сгенерировать реальный catalog. - [x] `catalog.add_washer_l()` — увеличенная шайбиц ГОСТ 11372-78 - [x] `catalog.add_bolt_set()` — винт-набронник ГОСТ 1170-84 - [x] `catalog.add_all_extended()` — все 10 расшиremium семейств (7802,1149,5916,11889,11394,6402,13463,25709,Р51472,11372) - [x] **fix коллизии id:** `from_spec()` берёт `id` из `model_filename(spec)[:-5]` (до этого `nut_high`/`nut_baran`/`nut_specing` → все `nut_M12`) - [x] `standard.py model_filename()` — уникальные имена подтипов (`nut_high_M12`, `washer_grever_M12`, `washer_M12_large.step` и т.д.) - [x] `cli.py` `_save_and_show()` — единый шаблон, все `*-gen` теперь сохраняют запись в каталог - [x] Подкоманды: `gen-all-extended`, `washer-l-gen`, `bolt-set-gen` - [x] Тесты: `test_cli_single_gen_saves_to_catalog`, `test_add_all_extended_covers_all_types`, `test_model_filename_large_washer_distinguished`, `test_catalog_ids_unique_for_large_washer` - [x] **82 теста проходят (100%)** - [x] Закоммичено и запушено в `admin/fastengen` --- ## 🟡 Следующий (P2) ### #2 Ведомость изделий по ГОСТ 2.119 — **ГОТОВО** (commit на Gitea) Сводная ведомость из каталога. Команда `list` уже печатает таблицу — вынес в `.xlsx`/`.csv`/`.md`. - [x] `src/fastengen/vedomost.py`: класс `Vedomost` (группировка записей по (наименование, ГОСТ, материал) → позиция), `render_markdown/csv/txt`, `write_xlsx` - [x] CLI: `fastengen vedomost --catalog cat.json --format md|csv|txt|xlsx`, опция `--output` для xlsx - [x] Тесты: `tests/test_vedomost.py` (7 тестов, все прошли) - [x] **fix в vedomost**: размер парсится и из кириллической «М» (М6), и из «D10»/«6×80»** - [x] **P2.2 (11.11, commit 6f7697e): автозаполнение графов ГОСТ 2.119** — ОКПД2 по типу изделия, product_type для ведомости ВЗ, `render_markdown_full`, CLI-опция `--full` - [x] **P2 полностью готов** на Gitea: `fastengen vedomost --cat cat.json --format md|csv|txt|xlsx [--full]` - [ ] ✅ **Заметка об обнаруженном баге:** `src/fastengen/cli.py` не компилировался из-за **незакрытого тройного кавычка** в module docstring (я случайно затёр закрывающие `"""` при редактировании примеров → Python читал docstring до конца файла и падал на `—`). Все CLI-тесты (`from fastengen.cli import main`) падали с `SyntaxError: invalid character '—'`. **Исправлено: добавлены `"""` после примеров.** (Этот Python 3.10 без PEP 540 UTF-8 mode не парсит em-dash в коде.) - [ ] **Наблюдение по данным (не баг vedomost):** в `product_params` (standard.py) для гаек material = «Сталь 8» (strength_class="8"), у шайб/саморезов нет «Мn»-размера в designation — vedomost корректно отражает то, что в каталоге. ### Заметка по окружению - Тесты запускаются `PYTHONPATH=/tmp/fastengen/src python3 -m pytest`. На **этом** Python 3.10 (beze) UTF-8-режим в исходниках отключён — em-dash `—` **в коде** ломает парсинг. В docstrings/комментариях/строках помечайте аккуратно; лучше ASCII-дефис в коде, русские символы только в строках/помечах. --- ## ⚪ Отложено (P3) - GUI (PyQt предпросмотр STEP) - Конвертер в КОМПАС (`.con`/`.kds`) - Локальный PyPI/pipx-сборка - Конвертер bearingsinfo → boltgen - Слияние устаревших `get_stud()`/`get_self_tacker()`/`iter_studs`/`iter_self_tackers` с `_long`/`_gost` версиями - Property-тесты на рандомных размерах --- ## 📌 Контекст / договорённости - `/tmp/fastengen` — dev-копия, а не настоящий workspace репозитория. - `model_filename()` — единственный источник и `id`, и `model_file` (в `from_spec`). - Долгие команды (`gen_all`, `gen-all-extended`) генерят тысячи STEP-моделей — не гонять в быстрых прогонах. --- ## 🔵 P3 (масса + геометрия) — начато (commit 74bc4b0) ### #3 Геометрический баг шестигранных головок — **Исправлено** **Баг:** `cadquery Workplane.polygon(6, r)` даёт шестигранник with across-flats (расстояние между плоскостями, «под ключ») = `r·√3/2`, а не `r`. Все 8 сайтов использовали `head_r = S/2` или `S/√3` → across-flats был ≈ `0.866·S` вместо `S`. Модели были занижены по размеру головки (и по массе ~0.75×). Исправлено на `head_r = 2·S/√3` для across-flats = S. - [x] Фикс 8 сайтов: bolts, nuts, bolt_set, nut_high, nut_baran, nut_specing (model.py) - [x] Проверено по шагу: M12 nut ≈ 21.7 г (ГОСТ 5915 ~20-22г), M12×60 bolt ≈ 70 г (ГОСТ 7805 ~72г) - [x] **Все STEP-модели нужно переренерировать** (старые занижены). Модель на диске пока отсутствуют ### #4 Масса 1 шт. из геометрии STEP — **Готово** - [x] `src/fastengen/mass.py`: `step_volume_mm3()` через `OCP.BRepGProp.VolumeProperties_s`, `mass_of()` = объём × плотность (GOST 24705, сталь 7.85 г/см³ и т.д.), `_translit_lower()` для кириллических материалов (Сталь 8, Сталь 65Г) - [x] `vedomost.build()` считает «Масса,г» по геометрии (`models_dir`), `cli` vedomost получил `--dir` для пути к моделям - [x] `tests/test_mass.py` (4 теста): nut M12, bolt M12×60, washer>0, density default --- ## 🔵 P3 GUI — завершено (commit 76db982) `fastengen gui --catalog cat.json --dir models` — графический просмотр каталога (tkinter, stdlib, без PyQt). - [x] `src/fastengen/gui.py` `MainWindow`: фильтр по типу (bolt/nut/washer/stud/selftacker/screw), список с массой 1 шт. (из STEP-геометрии), двойной клик = переренерация STEP, экспорт ведомости md/csv/txt - [x] `run_gui()` автоматически создаёт пустой каталог, если файла нет - [x] `cli.py`: подкоманда `gui` (+ `--catalog`, `--dir`) - [x] `tests/test_gui.py`: `_type_name` логика фильтра + отбор записей (2 теста) - [x] Закоммичено и запушено в `admin/fastengen` --- ## 🔵 P3.1 Валидация геометрии по ГОСТ — **Готово** (commit c9d1f82) Паттерн из **PartCAD / cq_warehouse**: семью части валидируется проверкой что сгенерированная геометрия воспроизводит **номинальные размеры стандарта** (across-flats S, наружный диаметр D, высота головки k) в пределах допуска, а не «масса похоже». - [x] `src/fastengen/validate_geom.py`: `validate_model(path)` читает STEP через OCC, берёт bbox через `cq.Shape.BoundingBox()`, сверяет ключевые размеры с таблицами ГОСТа (`_BOLT_DIMS`, `_NUT_DIMS`, `_NUT_HIGH_DIMS`, `_WASHER_DIMS`, `_WASHER_L_DIMS`) в допуске 4%. - [x] **Ключевой инсайт:** bbox шестигранника: min planar extent = across-flats, max = across-corners (`2S/√3`). Используется `min()` для S. - [x] `DimensionResult`: `.ok`, `.failed`, `.checks` (dim -> measured). `validate_dir(models_dir)` — валидация всей папки. - [x] `tests/test_validate_geom.py` (30 тестов): все размеры bolts/nuts/washers соответствуют ГОСТу, rejection при неверном S, sanity-тест bbox. - [x] Полный suite (без gen_all) + все 30 тестов валидации проходят. - [x] Закоммичено и запушено в `admin/fastengen` --- ## 🔵 P3.2 Конвертер в КОМПАС (.con) — **Готово** Паттерн: KOMPAS `.con` — это XML-документ с product params. Конвертер генерит контейнер КОМПАСа (Gost, OKPД2, product params, ссылка на STEP); реальный импорт геометрии в КОМПАС делает сам КОМПАС через API. - [x] `src/fastengen/kompas.py`: `build_document(rec)`/`save_document(rec, path)` — KOMPAS .con XML. `convert_step_to_kompas_template(step_path, rec)` — STEP->KOMPAS import container. - [x] OKPД2 по типу: Bolt 28.93.21.110, Nut .210, Washer .310, Stud .410, SelfTacker .510, Screw .610, default .000. - [x] `cli.py`: `fastengen kompas --output dir` — экспорт всех изделий каталога в .con. - [x] `tests/test_kompas.py` (5): OKPД2 по типу, valid XML, save roundtrip, default OKPД2, end-to-end CLI. Все проходят. - [x] Закоммичено и запушено. - ⚠️ КОМПАС — Windows CAD-система, на Linux-host не установлен. Сгенерен валидный `.con` XML; импорт геометрии в КОМПАС не тестировался (нет API). ## 🔵 P3.3 Упаковка (pyproject) — проверено - [x] `pyproject.toml`: name=FastenGen v0.2.0, console scripts `fastengen` + `fasten-gen`, deps `cadquery`, pytest config. - [x] `pip install .` в venv прошёл, `fastengen --help` работает. - [x] `tests/test_packaging.py`: metadata pyproject parseable (tomllib 3.11 + fallback 3.10). ## 🔵 P3.4 Слияние legacy-функций (мертвый код) — **Готово** - Удалён dead code: `get_stud`/`get_self_tacker`, `iter_studs`/`iter_self_tackers`, `_stud_params`/`_self_tacker_params`, классы `StudSpec`/`SelfTackerSpec`/`BoltSetSpec2`. - Активные пути: `StudSpecLong` (get_stud_long/iter_studs_long) и `SelfTackerSpecGost` (get_self_tacker_gost/iter_self_tackers_gost) — единственные wired-варианты. - Удалён dead `build_stud/generate_stud`, `build_self_tacker/generate_self_tacker`, `_make_self_tacker_head`, `catalog add_stud/add_self_tacker`. - ⚠️ Осторожно: после чистки `model_filename` потерял ветки `BoltSetSpec`/`BoltSpecHigh`/`ScrewPotaySpec` — восстановил; `model.py` вернул `BoltSpec/NutSpec/WasherSpec/BoltSetSpec` в import. - Тесты: 131 passed, 3 deselected. ## 🔵 P3.5 Regen всех STEP-моделей + property-тесты — **Готово** - Сгенерировал заново все 661 STEP-модели (`gen-all-extended`) в `out/`, catalog.json обновлён. - Проверка масс vs GOST-таблицы: M30x200 bolt=1370.7g, M12 nut=21.7g, M20x60 bolt=227g, washer M12=6.8g — все ✓. - Property-тесты геометрии (tests/test_geometry.py): positive-volume для stud_long/self_tacker_gost; across-flats==S для hex bolt head (guard против regression geometry bug). - Итог: **139 passed in ~242s** (full suite, regen 661 STEP). ## Remaining P3 - Слияние legacy `get_stud()`/`get_self_tacker()`/`iter_studs`/`iter_self_tackers` с `_long`/`_gost` — сделано в P3.4 (мертвый код удалён, активные пути `_long`/`_gost`). ## 🔵 P4 Тесты + покрытие (P4 завершен) ### P4.1 — Расширение тестов - `tests/test_geometry.py`: добавлен property-based guard `test_hex_nut_head_across_flats_matches_s` (parametrized по NUT_SIZES) — across-flats == S из STEP для шестигранных гаек, прямой regression guard. - `tests/test_gui.py`: переписан на чистый ASCII (кириллица → строки/комментарии), добавлено покрытие чистых хелперов: - `test_type_name_filter` — все ветки фильтра типов (bolt/nut/washer/stud/selftacker/screw/potay). - `test_mass_helpers_paths` — путь без model_file → «—», путь с реальной моделью → числовая строка массы. ### P4.2 — Покрытие - `pyproject.toml`: добавлен `[tool.coverage.run]` с `source=["fastengen"]` и `omit=["src/fastengen/gui.py"]` (UI нельзя тестировать headless; чистые хелперы покрыты отдельно). - Итог: **87%** (было 81% до omits; gui.py исключён из счётчика). model.py 99%, standard.py 95%, kompas.py 92%. ### P4.3 — Сборка - `pip install .` / `python -m build` — успешно (sdist + wheel). - `pyproject.toml`: license-text → добавлен `license-files = ["LICENSE*"]` (устранена deprecated warning setuptools). ### P4.4 — CI - `.github/workflows/ci.yml`: job `quality` (ruff), `test` гонит `tests/ -k "not gen_all"` с `--cov`, build-check собирает пакет. ### P4.5 — README - `README.md`: обновлён под текущий API (all_extended, gui, vedomost, kompas), команды coverage/ruff, блок CI. ### Итог P4 - **145 passed, 3 deselected** (regen), `ruff check src/ tests/` — All checks passed, покрытие 87%, сборка sdist+wheel OK. Коммитировано и запушено (master). --- ## 🟢 P4 Качество: ruff + покрытие + CI + README — **Готово** ### #4.1 Ruff (линт/форматирование) - Настроен профиль в `pyproject.toml` (`[tool.ruff]`): E, W, F, I, B, RUF; target py310. - Профиль отключает: `BLE001` (CAD-код ловит broad Exception по дизайну), `B008` (argparse defaults), `E501` (русские docstrings/help-строки/ГОСТ-литералы), `RUF001/002/003` (кириллица в строках/комментариях — ГОСТ обозначения), `RUF100`. - Авто-сортировка импортов + удаление dead code: - `__init__.py`: 59 публичных переимпортов добавлены в `__all__` (отсортирован, RUF022). - Удалены мёртвые присваивания: `threaded_len`/`s`/`d`/`coat`/`first_rec_for_size` в `model.py`/`standard.py`/`validate_geom.py`/`vedomost.py`; мёртвое `self.cat` в `gui.py`. - `vedomost.py`: `zip(..., strict=True)`. - Переименованы переменные `l` → `ln` (E741) в cli/tests. - Исправлены длинные строки: print в `cli.py`, assertion в `test_boltgen.py`/`test_geometry.py`, `head_r`-комментарии в `model.py`, `cq.Compound.makeCompound`, сигнатура `generate_self_tacker_gost`, `[*prof_pts_xy, prof_pts_xy[0]]` (RUF005). - Тесты: убраны неиспользуемые imports (test_geometry расширенные семейства, удалены `NutSpec`/`WasherSpec`), `.items()` → `.values()` в test_specs, `next(iter(parts.vals()))` в test_validate_geom. - **Итог: `ruff check src/ tests/` — All checks passed.** ### #4.2 Тесты + CI - CI (`.github/workflows/ci.yml`) расширена:新增 job `quality` (ruff на py3.12); `test` теперь гонит `tests/ -k "not gen_all"` с `--cov`; сборка пакета в `build-check`. - Полный suite (без regen) стабильно зелёный. ### #4.3 README - Переписан: полный список команд (`bolt-gen`/`nut-gen`/`stud-long-gen`/`self-tacker-gen`/`gui`/`vedomost`/`kompas`), схема каталога, API-модули, команды тестов + ruff + coverage, описание CI, блок «Окружение». ### Изменённые файлы `src/fastengen/{__init__,model,standard,gui,validate_geom,vedomost,cli}.py`, `tests/{test_geometry,test_boltgen,test_specs,test_validate_geom}.py`, `pyproject.toml`, `README.md`, `.github/workflows/ci.yml`, `docs/tasks.md`.