docs: History — чистка legacy-upload + сводка сессии 2026-08-26
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# Чистка: удалён мёртвый legacy-код загрузки напрямую (2026-08-26)
|
||||
|
||||
## Контекст
|
||||
|
||||
При разборе стресс-тестов выяснилось: я (AI) гонял HTTP-стресс через `POST /upload`
|
||||
(прямой multipart), тогда как реальная загрузка в проде идёт через **ВМ-буфер**
|
||||
(`PUT` на ВМ WebDAV → `POST /api/upload_refs` → `contracts_upload_sink`).
|
||||
Прямой `/upload` — мёртвый legacy-эндпоинт, который фронт не вызывает.
|
||||
|
||||
## Что удалено (коммит `aa58522`, −176 строк)
|
||||
|
||||
- `site/routes/upload_bp.py`:
|
||||
- эндпоинты `POST /upload` и `POST /unzip-upload`;
|
||||
- функции `_check_ext`, `_unzip`, константа `ALLOWED`;
|
||||
- пустой blueprint `upload_bp`.
|
||||
- `site/routes/__init__.py`: регистрация `upload_bp`.
|
||||
- `site/static/app.js`: мёртвые константы `UPLOAD_URL`, `CONVERT_URL`, `UNZIP_URL`.
|
||||
- `tests/test_upload_security.py` — целиком (тестировал удалённые `_check_ext`/`_unzip`).
|
||||
- `tests/test_routes.py`: классы `TestUpload`, `TestUnzipUpload`.
|
||||
|
||||
## Что оставлено (рабочее)
|
||||
|
||||
- `contracts_upload_sink` + `_store_and_parse` + `_convert` — sink для `/api/upload_refs` (VM-буфер).
|
||||
- `pages_bp /upload/<path:filename>` — отдача ES-модулей `upload/frontend` (клиентский ZIP).
|
||||
|
||||
## Почему ревью Sonnet не заметило
|
||||
|
||||
Ревью искало сломанное (трассировки ошибок), а не мёртвый код. `/upload`/`/unzip-upload`
|
||||
не падали и не давали 500 — просто не вызывались. Обнаруживаются только аудитом
|
||||
«какие эндпоинты фронт реально дёргает».
|
||||
|
||||
## Проверки
|
||||
|
||||
- `py_compile` + `node -c app.js` — OK.
|
||||
- `import app` — OK, 24 роута; `/upload` (POST) и `/unzip-upload` отсутствуют,
|
||||
`/api/upload_refs` и `/upload/<path>` на месте.
|
||||
- Юнит-тесты: 92 passed (было 102).
|
||||
|
||||
## Хвост
|
||||
|
||||
`tests/load/stress_http.py` всё ещё бьёт по удалённому `/upload` — нужен
|
||||
переписывание на `/api/upload_refs` (PUT на ВМ → refs).
|
||||
@@ -0,0 +1,60 @@
|
||||
# Сводка сессии 2026-08-26 — contracts-flask (тесты + чистка + стресс)
|
||||
|
||||
## 1. Фикс логики сверки (v2.0.15 → v2.0.16)
|
||||
|
||||
- **`full_replace` дублировал строки**: `reset()` чистил `spec_current` только на старте
|
||||
пайплайна, а `full_replace` (все ADD) применялся поверх старых строк → дубли.
|
||||
- Фикс: `db/spec_events.py::clear_current()` (чистит только `spec_current`, история
|
||||
`spec_events` сохраняется) + вызов в `process.py` при `mode == "full_replace"`.
|
||||
- Коммит `021c925`, запушено, прод передеплоен → `2.0.16`.
|
||||
- Детали: `History/2026-08-26-full-replace-fix.md`.
|
||||
|
||||
## 2. Документация
|
||||
|
||||
- Архитектура: `DOC/architecture-contracts-flask.md` (актуальная, VM-буфер, клиентский ZIP).
|
||||
- Корневой `README.md` — подробный, со ссылкой на архитектуру.
|
||||
|
||||
## 3. Тесты
|
||||
|
||||
### Удалены старые (коммит `9a8ae0a`)
|
||||
- `deploy/tests/` (unit/pipeline/integration + `test_drhider.py`), `deploy/conftest.py`,
|
||||
`deploy/tests.js` — ссылались на старую `compare/`-архитектуру.
|
||||
|
||||
### Новые юнит/интеграционные (коммиты `8f8fabf`, `3b259cf`)
|
||||
- 13 файлов в `contracts-flask/tests/` + `conftest.py` (изоляция БД) + `README.md`.
|
||||
- Покрытие: metrics, grouping, llm_client, llm, classify, parse, connection,
|
||||
spec_events, spec_current, process_pipeline, routes.
|
||||
- **92 passed** (после чистки legacy; было 102).
|
||||
|
||||
### Нагрузочные (маркер `load`, коммиты `b7d60e1`, `08f7e3f`, `6fcbbdd`)
|
||||
- `tests/load/test_load_pipeline.py` — 100 контрактов × 20 допников × 10 услуг.
|
||||
- `tests/load/test_load_apply_ops.py` — 5000 ADD/UPDATE/DELETE.
|
||||
- `tests/load/test_load_concurrency.py` — конкурентная запись SQLite.
|
||||
- `tests/load/stress_http.py` — standalone HTTP-стресс.
|
||||
- Полный прогон: not-load 102 passed, load 3 passed (~3 мин).
|
||||
|
||||
### Находка №1: SQLite `database is locked` (коммит `08f7e3f`)
|
||||
- 16 конкурентных писателей → `database is locked`; 8 — нестабильно; **4 — стабильно**
|
||||
(= `MAX_WORKERS` приложения). Для текущего сценария (один пользователь) некритично.
|
||||
- `History/2026-08-26-load-sqlite-locked.md`.
|
||||
|
||||
## 4. Стресс-тест прода (коммит `08e8e3a`)
|
||||
|
||||
- Прод: `contractor.pythonk8s.dev.nubes.ru`, под `pythonk8s` (cpu 1, mem 1Gi).
|
||||
- Прямой POST 100KB → **83% таймаутов** (шлюз рвёт >64KB) — подтверждён предел платформы,
|
||||
поэтому и существует VM-буфер.
|
||||
- Реальный файл 30KB → 200/200 ok (rps 10), под CPU 899m / MEM 520Mi, без OOM.
|
||||
- `History/2026-08-26-stress-100kb-gateway.md`.
|
||||
|
||||
## 5. Чистка мёртвого legacy-кода (коммит `aa58522`)
|
||||
|
||||
- Удалены `POST /upload`, `POST /unzip-upload`, `_check_ext`, `_unzip`, `ALLOWED`,
|
||||
пустой blueprint, константы фронта `UPLOAD_URL`/`CONVERT_URL`/`UNZIP_URL`.
|
||||
- Загрузка теперь ТОЛЬКО через ВМ (`/api/upload_refs` → `contracts_upload_sink`).
|
||||
- `History/2026-08-26-cleanup-legacy-upload.md`.
|
||||
|
||||
## Хвосты / открытые вопросы
|
||||
|
||||
1. `tests/load/stress_http.py` бьёт по удалённому `/upload` — переписать на `/api/upload_refs`.
|
||||
2. Прод-риск `database is locked` при конкурентных сверках — отложен (нет мультитенантности).
|
||||
3. E2E с реальным LLM (`gpt-oss-120b`) на проде — не проверялся автоматически (тесты на Fake LLM).
|
||||
Reference in New Issue
Block a user