Переносит архив `audits/2026-10-11/` (19 файлов) из codex/audit-remediation-2026-10-11 в develop и добавляет точечный allowlist в .gitignore.
79 KiB
Аудит 10 — Custom Scripts & Tooling
1. Audit metadata
- Audit ID: 10 / Custom Scripts & Tooling.
- Дата: 2026-10-11.
- Workspace:
/Users/ksv741/Project/vibe/WealthLedger. - Задание:
audit-prompts/10-custom-scripts-and-tooling.md. - Результат:
audit-results/10-custom-scripts-and-tooling.md. Имя без суффикса-reportвыбрано по прямому указанию пользователя. - Режим: read-only для исследованных репозиториев; единственная подготовленная запись в workspace — этот отчёт.
- Skill: установленный
ponytail-auditпрочитан и применён к сложности инструментов. Его complexity-pass отделён от проверки побочных эффектов и границ гарантий. Исправления не применялись. - Graphify: инструкции прочитаны; существующий
graphify-out/graph.jsonв workspace не найден. Extraction/install не запускались: они создают дополнительные артефакты, не предусмотренные read-only контрактом аудита. - Прежний аудит:
audit-results/technical-audit-2026-10-11.mdпрочитан как реестр гипотез. Findings этого отчёта получены из текущих файлов и callers независимо.
Репозитории и состояние
Пути в таблице относительны к workspace; evidence далее использует тот же префикс.
| Repo path | HEAD SHA | git status --short при исследовании |
Охват |
|---|---|---|---|
. |
dc030f84c979cedb2628ef4bd97c62d6c63a9256 |
Пустой вывод | Workspace manifest, release config, CI и allowlist |
frontend |
c8821200ce699dab1ce65360d1968d5877a2e78b |
Пустой вывод | Полный инвентарь custom tooling |
backend |
0ad84ff4f0b4712abc7e69dc299856f14af6eadd |
Пустой вывод | Полный инвентарь custom tooling |
specs |
fcdc805f6c1b3be6a20a7e858e3e80cbd83a9121 |
Пустой вывод | Полный инвентарь custom tooling |
docs |
e6fd4f64b81dd73b33959b845a1babcfac1891c8 |
Пустой вывод | Полный инвентарь custom tooling |
deploy |
a56ed85230ae27c1e7155f0cc74ecb33fb9d5644 |
Пустой вывод | Только обнаружение layout и Git metadata; вне четырёх явно перечисленных targets |
deploy — дополнительный самостоятельный checkout, а не root-owned каталог. В нём обнаружен deploy.sh, но его реализация и tests/ не исследовались. Утверждение о полном инвентаре ниже относится к четырём targets промпта, а не ко всем возможным deployment-инструментам workspace.
Root исключает audit-results/ из tracking через .gitignore:1–7; чистый root status сам по себе не подтверждает наличие или качество нового отчёта. Файл проверяется отдельно.
Что запускалось
-
git rev-parse HEAD,git status --short,git ls-filesв указанных checkout. -
Статические чтения manifests, hooks, workflows, конфигураций и всех найденных custom tooling files;
rg --files --hidden --no-ignoreи адресные content searches. -
Context7 для актуальной семантики
openapi-typescript --check, release-it Git checks и npm/npx fallback; установленные реализации генератора и release-it проверены отдельно. -
Две небольшие read-only проверки установленного генератора из
frontend:source "$HOME/.nvm/nvm.sh" && nvm use --silent && node node_modules/openapi-typescript/bin/cli.js src/shared/api/spec/openapi.json -o src/shared/api/generated/schema.d.ts --check source "$HOME/.nvm/nvm.sh" && nvm use --silent && node node_modules/openapi-typescript/bin/cli.js src/shared/api/spec/openapi.json -o packages/icons/src/types.ts --checkПервая завершилась успешно и вывела
openapi-typescript 7.13.0. Вторая намеренно сравнивала результат с другим существующим файлом и получилаGenerated types are not up-to-date!— ветвь отказа с exit 1. Это проверка отрицательного исхода без изменения snapshot или generated types, а не симуляция обновления backend schema. После запусков frontend status оставался пустым.Первоначальный вызов
nvm use --silentне выполнился: shell не загрузил функциюnvm. Node-команда тогда не запускалась. Проблема устранена загрузкой существующего$HOME/.nvm/nvm.sh; установка Node не потребовалась.
Не запускались: npm ci/install/audit, custom scripts, release preview/prepare, codegen без --check, Prisma migration/generate, E2E/SQLite/durability/container runners, full verify, сборки, публикация images, broker/bank API, OpenSpec CLI и новые исполняемые инструменты. Runtime поведение этих runners оценено по коду, не воспроизведено.
Проверки сохранённого отчёта:
source "$HOME/.nvm/nvm.sh" && nvm use --silent && node docs/node_modules/markdownlint-cli/markdownlint.js --config docs/.markdownlint.json -- audit-results/10-custom-scripts-and-tooling.md— PASS, без--fix. Первый запуск выявил только MD029 в нумерации двух списков; нумерация исправлена, повторный запуск прошёл.git diff --no-index --check -- /dev/null audit-results/10-custom-scripts-and-tooling.md— PASS; проверяет и новый ignored report, который обычный diff не охватывает.git diff --checkв root и четырёх targets — PASS;git status --shortво всех пяти — пустой вывод.git status --short --ignored -- audit-results/10-custom-scripts-and-tooling.mdподтвердил ожидаемый ignored-каталог.- Семантически сверены inventory totals, callers, scope, evidence и различие confirmed/UNVERIFIED. Boy Scout review ограничен новым отчётом: конкурирующие отчёты/инструкции не создавались, исходники и прежние audit files сохранены.
2. Executive verdict
- Факт: основной tooling уже делегирует штатным ESLint, TypeScript, Vitest/Jest, dependency-cruiser, npm, Prisma и release-it. Biome сейчас отсутствует; возвращать его ради сокращения scripts не обосновано.
- Подтверждённое упрощение: frontend
check-openapi.mjsповторяет имеющийсяopenapi-typescript --check. Можно убрать один 45-строчный файл, сохранивnpm run openapi:checkи ту же гарантию сравнения generated types с локальным snapshot — TOOL-001. - Подтверждённая возможность нежелательного side effect: pre-commit использует
npx lint-stagedбез отказа от установки отсутствующего пакета. При корректномnpm ciиспользуется локальный пакет; при неполной установке команда допускает registry/cache fallback. Фактическая установка во время commit UNVERIFIED — TOOL-002. - Непроверенная эксплуатационная гипотеза: у
backend/test/runtime-check.cjsиfrontend/scripts/check-image-publication.cjsне найдены локальные исполняющие callers. Этоpossible unused, не доказанный dead code. У второго есть полезный recovery-инвариант, поэтому автоматическое удаление особенно неуместно — TOOL-003/004. - KEEP: SQLite isolation/cleanup, crash-process fixture, durability checks, offline backend schema generator и release version guards имеют самостоятельную ответственность. Ни обычный Jest, ни
git diff --exit-code, ни базовые release-it checks полностью её не заменяют. - Граница доказательства: локальная freshness-проверка generated types не подтверждает свежесть предоставленного snapshot относительно текущего backend. Сравнение backend offline document с configured runtime document принадлежит отдельной backend suite; это правильное разделение ownership.
Подтверждённых проблем уровня P0–P2 в исследованном tooling не установлено. Рекомендации ниже — небольшие P3 улучшения и проверки ownership. Экономия runtime/CI minutes не измерялась.
3. Inventory & coverage
3.1. Метод и воспроизводимые границы подсчёта
Инвентарь построен по tracked tree каждого repo и независимому filesystem scan со скрытыми папками. Исключены .git, node_modules, dist, dist-dev, generated, coverage, storybook-static и generated .husky/_.
Пример команды обнаружения физических JS/shell-инструментов:
rg --files --hidden --no-ignore frontend backend specs docs -g '*.sh' -g '*.mjs' -g '*.cjs' -g '*.js' -g '*.py' -g '!**/node_modules/**' -g '!**/.git/**' -g '!**/dist/**' -g '!**/dist-dev/**' -g '!**/coverage/**' -g '!**/generated/**' -g '!**/storybook-static/**' -g '!**/.husky/_/**'
Hooks без расширения и TS config entrypoints добавлены из git ls-files и manifest/config references. Ранние широкие searches включали lockfile/generated шум; он не использован для подсчёта custom scripts или findings. Установленные library files читались только для проверки семантики замены, в инвентарь project-owned code не включены.
Определение метрики: custom tooling file — project-owned CLI/test runner либо загружаемый helper с собственной validation/execution logic. Декларативная конфигурация штатного инструмента, application entrypoint и обычные application tests отдельным custom script не считаются.
| Repo | CLI / standalone tooling files | Loaded custom helpers | Git hooks без расширения | Ключи scripts в основном manifest |
Дополнительные workspace scripts |
|---|---|---|---|---|---|
frontend |
5 | 1 | 2 | 25 | 2 |
backend |
9 | 1 | 0 | 27 | 0 |
specs |
1 | 0 | 1 | 5 | 0 |
docs |
1 | 1 | 0 | 5 | 0 |
| Всего | 16 | 3 | 3 | 62 | 2 |
Таким образом, 19 физических custom tooling files + 3 hook entrypoints и 64 npm script entries, включая workspace builds. Это разные единицы: npm aliases не являются 64 собственными реализациями. Пересчёт возможен по явным спискам следующих таблиц; секции scripts находятся в frontend/package.json:9–35, backend/package.json:11–39, specs/package.json:8–14, docs/package.json:8–14, двух package manifests ниже.
Root отдельно содержит 3 npm entries: release:preview, release:prepare, commitlint (package.json:8–12); custom CLI/helper files в его tracked allowlist не найдены. Root .agents/ — установленный агентский toolbox, не application tooling четырёх targets; стандартные skills и их reference scripts не пересчитывались.
3.2. Complete Custom Script Inventory
В колонке imports указаны прямые зависимости, существенные для исполнения. Частота означает настроенный trigger, не измеренное количество запусков. Общий владелец — repo, содержащий файл; специальный consumer указан отдельно.
| ID | Entrypoint / фактическая команда / тип | Imports и inputs | Outputs / side effects | Consumers / triggers | Failure mode, инвариант и последствие удаления |
|---|---|---|---|---|---|
| F1 | frontend/scripts/check-openapi.mjs:1–45; node scripts/check-openapi.mjs; validation wrapper |
node:child_process, fs/promises, os, path; local snapshot, committed types, installed generator |
Генерирует в private system temp, сравнивает UTF-8 text, удаляет temp; tracked output не пишет | openapi:check → verify; локальный вызов, PR/push/image gates |
Mismatch/generator failure → nonzero; защита freshness. Удаление без переноса команды теряет gate; штатная замена — TOOL-001 |
| F2 | frontend/scripts/check-release.cjs:1–24; node scripts/check-release.cjs; custom guard |
assert, child_process, ../package.json; merged semver Git tags |
Только чтение Git и version | after:git:init → обе release-команды |
Version должна равняться последнему merged vX.Y.Z, иначе отказ. Без guard повторная подготовка версии может пройти при наличии release-коммита |
| F3 | frontend/scripts/test-eslint.mjs:1–395; node --test scripts/test-eslint.mjs; regression executable |
ESLint API, установленные plugin presets, assert, fs.globSync, node:test; synthetic TS/TSX и реальные config scopes |
Assertions; fix:true применяется к lintText в памяти, файлы не переписывает |
test:lint → verify; каждое исполнение canonical gate |
Проверяет scope/config, custom rules, formatter stability и сохранение JSX text. Без него lint остаётся, но исчезает proof правильного подключения/исключений |
| F4 | frontend/scripts/test-pre-commit.mjs:1–79; node --test scripts/test-pre-commit.mjs; isolated hook regression |
assert, child_process, crypto.randomBytes, fs, os, path, node:test; hook, установленный Gitleaks |
Private temp Git repo, staged/unstaged synthetic secret, fake npm/npx, marker; cleanup |
README:24; CI verify.yml:63 с PATH=/tmp/gitleaks-bin:$PATH |
Assertions для index-only scan, redaction, fail closed и запрета downstream после отказа. Удаление теряет проверку hook boundary, не заменяется обычным history scan |
| F5 | frontend/scripts/check-image-publication.cjs:1–88; вручную node --test scripts/check-image-publication.cjs; synthetic workflow regression |
assert, child_process, fs, os, path, node:test; извлечённый shell block image.yml, fake Docker/npm |
Temporary binaries, markers, call log; cleanup; реальный registry не используется | Локальный исполняющий caller не найден; manual entrypoint возможен | Проверяет post-push retry, digest-bound labels/smoke и отсутствие второго build. possible unused; сохранять до определения владельца — TOOL-004 |
| F6 | frontend/eslint-rules.mjs:1–178; loaded ESLint plugin |
ESLint context/AST; filename, source text | Diagnostics; whitespace fixer при --fix |
eslint.config.mjs:23–30 → lint, lint-staged, verify, test:lint |
2 custom rules: readability и JSX sibling spacing. Удаление снимает локальные style/placement требования; не снимает типовые React/security rules |
| B1 | backend/scripts/check-release.cjs:1–11; node scripts/check-release.cjs; custom guard |
assert, child_process, package version, merged tags |
Только чтение | release-it hook:22 → preview/prepare | Та же release-version защита, что F2; нужна локальная реализация без зависимости от соседнего checkout |
| B2 | backend/scripts/generate-openapi.cjs:1–41; node scripts/generate-openapi.cjs; generator glue |
crypto.randomBytes, fs/promises.writeFile, NestFactory, compiled AppModule/openapi; synthetic env |
Перезаписывает openapi.json в cwd; создаёт Nest preview, закрывает app; не слушает порт |
openapi:generate после build; openapi-contract.e2e-spec.ts:139–151 из temp cwd |
Failure → exitCode 1; офлайн публикация contract из DTO/Swagger metadata. Удаление теряет artifact-producing entrypoint; frontend generator его не заменяет |
| B3 | backend/test/sqlite.cjs:1–95; node test/sqlite.cjs [suite… / --all]; custom runner |
child_process.spawn, fs, os, path; suite filenames, Prisma CLI, Jest config |
Для каждой suite private temp SQLite, migration deploy, Jest child process group, cleanup; внешний DATABASE_URL заменяется | test:e2e, test:performance, test:sqlite, test:openapi-contract; README, CI verify/image, B4 |
Unknown suite, migration/test failure, signals → nonzero. Держит DB isolation, общий URL для migration/Jest, kill/cleanup; стандартный Jest этого не обеспечивает |
| B4 | backend/test/sqlite-regression.cjs:1–96; node test/sqlite-regression.cjs; manual runner proof |
assert, child_process.spawn, fs, os, path; B3, sentinel DB, engine/signal overrides |
3 sequential + 2 parallel full suite passes и 3 failure/signal probes; temp logs/sentinel сохраняются как evidence | README:250–254; не включён в npm verify или CI |
Assert distinct DBs, cleanup, external sentinel unchanged, exit codes. Удаление теряет runner regression proof; число повторов не равно измеренным CI затратам |
| B5 | backend/test/e2e-env.cjs:1–17; loaded setup |
os.tmpdir, path; WL_E2E_DIRECTORY, DATABASE_URL |
При несовпадении temp binding бросает ошибку; задаёт synthetic test env | test/jest-e2e.json:5; B10 |
Прямой Jest с посторонней DB отвергается до suite. Удаление открывает путь тестам в пользовательскую базу; KEEP |
| B6 | backend/test/eslint-config.cjs:1–146; node --test test/eslint-config.cjs; config regression |
ESLint API, assert, fs, path, node:test; synthetic snippets/config |
В одном тесте создаёт .eslint-require-* под repo cwd и удаляет в finally; остальные проверки in-memory |
test:lint → verify |
Проверяет typed rules, boundaries и source resolution compiled imports. Это не formatter write; удаление теряет proof wiring линтера |
| B7 | backend/test/runtime-check.cjs:1–8; node test/runtime-check.cjs; built-artifact assertion |
assert, fs; package.json, built entrypoint, compiled Prisma client |
Read-only assertions и module import | Только упоминания в ESLint config/test fixtures; исполняющий caller не найден | Проверяет точную строку start:prod, наличие build и import client. possible unused; без caller сегодня не добавляет automated protection — TOOL-003 |
| B8 | backend/test/container-smoke.cjs:1–77; node test/container-smoke.cjs <image>; image-boundary test |
assert, child_process.execFileSync, crypto.randomUUID; Docker image, CLI |
Создаёт disposable volume/container, мигрирует isolated DB, auth HTTP внутри контейнера, restart и cleanup | test:container; image workflow:55 передаёт $IMAGE@$DIGEST |
Missing config, unhealthy runtime, assets/native modules/auth/persistence defects → nonzero. Удаление теряет проверку реально опубликованного image |
| B9 | backend/test/bank-cards-durability.cjs:1–219; node test/bank-cards-durability.cjs <baseline-dir>; historical durability runner |
assert, child_process, crypto, events, fs, net, os, path, better-sqlite3; отдельный заранее собранный baseline |
Private DB, migrations, real local app HTTP, restart/rollback, backups, retained logs/result.json; child stop в finally | test:durability; README:268–293, testing convention:55; manual при data/schema changes |
Baseline/current history mismatch и assertions → failure. Защита денежных данных/replay/history через реальные restart/restore boundaries; обычный fresh-DB E2E не равносилен |
| B10 | backend/test/fixtures/tbank-sync-crash.cjs:1–86; child fork(..., [checkpoint]); crash fixture |
B5, ConfigService, compiled access/token/sync/repository/Prisma classes; synthetic upstream, temp DB | Real staging/publication в test DB, IPC checkpoint; process намеренно останавливает родитель SIGKILL | test/tbank-operations-sync.e2e-spec.ts:424–488 → B3/test:e2e |
Failure до checkpoint → error; демонстрирует durable boundaries между страницами/до/после publish. Изоляция отдельного процесса принципиальна; mocks не заменяют SIGKILL |
| S1 | specs/scripts/check-release.cjs:1–10; node scripts/check-release.cjs; release guard |
assert, child_process, package version/tags/porcelain status |
Только чтение; rejects untracked/staged/unstaged files и version mismatch | release hook:22 → preview/prepare | Сохраняет clean-tree включая untracked и запрет repeated bump; native release-it имеет более узкую clean-tree проверку |
| D1 | docs/scripts/check-release.cjs:1–10; та же команда |
Те же imports/inputs, но только локальный docs checkout | Только чтение | release hook:22 → preview/prepare | Те же гарантии, что S1. Копия между самостоятельными repos не доказывает ненужную общую abstraction |
| D2 | docs/.markdownlint-rule-relative-links.cjs:1; loaded adapter |
Установленный markdownlint-rule-relative-links, его .default export |
Экспорт rule, без собственного validation algorithm | docs/package.json:9: обе ветви Markdown lint |
Однострочный CommonJS adapter; полезная совместимость. Без него нужно доказать корректную загрузку package export штатным CLI |
Git hooks и прочие config entrypoints
| Entrypoint | Execution graph / inputs | Side effects / failure / invariant |
|---|---|---|
frontend/.husky/pre-commit:1–3 |
gitleaks git --pre-commit --staged --redact=100 --no-banner → npx lint-staged → npm run deps |
Scan index; lint-staged намеренно автоисправляет staged JS/TS; deps собирает packages и проверяет graph. Secret scan failure останавливает downstream. npx install fallback — TOOL-002 |
frontend/.husky/commit-msg:1 |
npx --no-install commitlint --edit "$1" |
Read commit message, reject invalid format; без package download fallback |
specs/.githooks/commit-msg:1–2 |
npx --no-install commitlint --edit "$1" --strict |
Та же responsibility; подключается npm prepare через git config core.hooksPath .githooks |
frontend/dependency-cruiser.cjs:1–88 |
Штатные declarative forbidden rules/options |
Cycles, unresolved dependencies, layers/public APIs, production→tests; собственного graph parser нет |
frontend/.storybook/dependency-cruiser.cjs:1–23 |
Расширяет base config; reachable: true, tsPreCompilationDeps: false |
Дополнительно запрещает transitive reachability stories→application data. Однострочный direct-import lint не равносилен |
frontend/vite.config.ts:15–20 |
PWA configureOptions проверяет наличие Storybook plugin |
Меняет только build plugin options, отключая worker в каталоге; installed tool integration, не отдельный executable framework |
backend/prisma.config.ts:1–13 |
Prisma CLI загружает dotenv/config и native defineConfig |
Удаляет RUST_LOG только из текущего CLI process env. Это compatibility shim с описанным historical failure; актуальная необходимость не воспроизводилась |
4 repo-local commitlint.config.cjs |
@commitlint/config-conventional + declarative type enum |
Нативная конфигурация; не custom parser и не отдельный gate implementation |
3.3. Package script graph — все aliases и реальные префиксы
Frontend — 25 entries
| Script names | Команды / порядок |
|---|---|
dev |
npm run build:packages && vite |
dev:catalog |
npm run build:packages && storybook dev -p 6006 --no-open --disable-telemetry |
build:catalog |
npm run build:packages && storybook build --output-dir storybook-static --disable-telemetry |
preview:catalog |
vite preview --outDir storybook-static |
typecheck |
npm run build:packages && tsc -b --noEmit |
build |
npm run build:packages && tsc -b && vite build |
lint → lint:eslint |
npm run lint:eslint → npm run build:packages && eslint . --max-warnings=0 |
lint:fix |
npm run build:packages && eslint . --fix --max-warnings=0 |
test, test:run, test:coverage |
Каждый сначала npm run build:packages, затем соответственно vitest, vitest run, vitest run --coverage |
test:lint |
node --test scripts/test-eslint.mjs |
openapi:generate |
openapi-typescript src/shared/api/spec/openapi.json -o src/shared/api/generated/schema.d.ts |
openapi:check |
node scripts/check-openapi.mjs |
knip |
npm run build:packages && knip |
deps |
npm run build:packages && depcruise src packages --config dependency-cruiser.cjs --output-type err-long |
deps:storybook |
npm run build:packages && depcruise src packages .storybook/preview.tsx --config .storybook/dependency-cruiser.cjs --output-type err-long |
verify |
build:packages → openapi:check → tsc -b --noEmit → eslint . --max-warnings=0 → test:lint → vitest run --coverage → knip → оба depcruise commands без повторного npm prefix → tsc -b → vite build → storybook build --output-dir storybook-static --disable-telemetry |
prepare |
husky |
preview |
vite preview |
release:preview, release:prepare |
release-it --dry-run --ci, release-it --ci; оба загружают local release hook |
commitlint |
commitlint |
build:packages |
npm run build --workspaces --if-present |
Workspace entries: packages/icons/package.json:19–21 и packages/ui/package.json:23–25 содержат по одному build = vite build && tsc -p tsconfig.json. packages/tokens/package.json:1–12 не содержит scripts; --if-present намеренно его пропускает.
Backend — 27 entries
| Script names | Команды / порядок |
|---|---|
build |
prisma generate && nest build |
openapi:generate |
npm run build && node scripts/generate-openapi.cjs |
format → lint:fix |
npm run lint:fix → eslint . --fix --max-warnings=0 |
start |
nest start |
start:dev |
NODE_ENV=development nest start --watch --path tsconfig.dev.json |
start:debug |
nest start --debug --watch --path tsconfig.dev.json |
start:prod |
node dist/src/main.js |
lint → lint:check |
npm run lint:check → eslint . --max-warnings=0 |
typecheck:app, typecheck:test |
tsc --project tsconfig.typecheck.app.json, tsc --project tsconfig.typecheck.test.json |
test |
node --experimental-vm-modules node_modules/jest/bin/jest.js |
test:watch, test:cov |
npm test -- --watch, npm test -- --coverage |
test:debug |
node --experimental-vm-modules --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand |
test:e2e |
npm run build && node test/sqlite.cjs --all |
test:performance |
npm run build && node test/sqlite.cjs tbank-read-baseline.e2e-spec.ts |
test:sqlite |
node test/sqlite.cjs; default: auth + bank-cards suites |
test:container |
node test/container-smoke.cjs; caller должен передать image |
test:durability |
node test/bank-cards-durability.cjs; caller должен передать baseline |
test:openapi-contract |
npm run build && node test/sqlite.cjs openapi-contract.e2e-spec.ts |
verify |
npm run lint && npm run test:lint && npm run typecheck:app && npm run typecheck:test && npm run test:cov -- --runInBand && npm run build |
release:preview, release:prepare |
release-it --dry-run --ci, release-it --ci; оба загружают local release hook |
commitlint |
commitlint |
test:lint |
node --test test/eslint-config.cjs |
Важно: test:sqlite, test:container, test:durability сами не собирают backend. Наличие уже подготовленного build/image/baseline — явный input, а не скрытый auto-build/install.
Specs и docs — по 5 entries
| Repo / script | Реальная команда |
|---|---|
specs/verify |
git diff --check |
specs/prepare |
git config core.hooksPath .githooks |
specs/release:preview, specs/release:prepare, specs/commitlint |
release-it --dry-run --ci, release-it --ci, commitlint |
docs/lint |
markdownlint --dot --rules .markdownlint-rule-relative-links.cjs --ignore node_modules --ignore CHANGELOG.md -- "**/*.md" && markdownlint --config .markdownlint-changelog.json --rules .markdownlint-rule-relative-links.cjs -- CHANGELOG.md |
docs/verify |
npm run lint && git diff --check |
docs/release:preview, docs/release:prepare, docs/commitlint |
release-it --dry-run --ci, release-it --ci, commitlint |
specs/verify проверяет whitespace diff, не валидность behavioral specifications. Это ограничение команды, а не обнаруженный custom validator или причина вводить новый framework в этом аудите.
3.4. Scripts Dependency DAG
frontend CI verify / image + local engineering gate
-> npm run verify
-> npm run build:packages
-> npm run build --workspaces --if-present
-> icons, ui: vite build -> tsc -p
-> npm run openapi:check -> check-openapi.mjs -> installed openapi-typescript
-> ESLint -> eslint.config.mjs -> eslint-rules.mjs + native plugins
-> npm run test:lint -> node --test test-eslint.mjs -> ESLint API
-> Vitest -> JSDOM project + browser project -> Playwright/Chromium
-> Knip
-> dependency-cruiser [base config]
-> dependency-cruiser [storybook config -> base, reachable rule]
-> tsc -> Vite/PWA -> Storybook
frontend security job
-> standard sha256sum -> downloaded Gitleaks -> history scan
-> PATH=/tmp/gitleaks-bin:$PATH node --test test-pre-commit.mjs
-> synthetic temp Git repo -> real .husky/pre-commit
-> Gitleaks -> fake npx/npm markers
frontend Git pre-commit
-> staged/redacted Gitleaks -> npx lint-staged [ESLint --fix] -> npm run deps
frontend image workflow
-> inline version/lock/SHA assertions -> immutable publish/resume
-> Docker digest -> pull by digest -> label assertions -> nginx smoke
check-image-publication.cjs [manual entrypoint; caller UNVERIFIED]
-> extracts this workflow shell block -> fake Docker/npm -> recovery assertions
backend CI verify / image + local engineering gate
-> Prisma generate [native config -> process-local RUST_LOG shim]
-> npm run verify
-> ESLint -> native config/plugins
-> node --test eslint-config.cjs -> ESLint API
-> both tsc projects -> Jest coverage -> build [Prisma -> Nest]
-> npm run test:e2e -> build -> sqlite.cjs --all
-> per-suite mkdtemp / fixed test DB -> Prisma migrate deploy
-> Jest --config test/jest-e2e.json --runInBand --runTestsByPath
-> e2e-env.cjs [reject non-runner database]
-> openapi-contract suite -> generate-openapi.cjs in temp cwd
-> compiled AppModule + openapi -> Nest preview -> temp openapi.json
-> operations-sync suite -> fork tbank-sync-crash.cjs -> IPC -> SIGKILL
-> process-group stop / directory cleanup
backend manual SQLite regression -> sqlite-regression.cjs -> sqlite.cjs
backend manual durability -> bank-cards-durability.cjs
-> historical/current builds -> isolated migration + real local HTTP
-> restart / application rollback / SQLite backup-restore -> retained evidence
backend image workflow
-> inline version/lock/SHA assertions -> Docker publish -> digest pull
-> npm run test:container -- IMAGE@DIGEST -> container-smoke.cjs
runtime-check.cjs [manual entrypoint; caller UNVERIFIED]
-> package script string + built main presence + compiled Prisma import
frontend/backend/specs/docs release:preview or release:prepare
-> release-it -> native branch/clean/commits checks
-> after:git:init -> local check-release.cjs -> package version vs merged tags
-> specs/docs additionally check porcelain, including untracked files
specs npm install lifecycle -> prepare -> local Git hook config
specs commit-msg -> local commitlint
specs CI verify -> npm run verify -> git diff --check
docs CI verify -> npm run verify -> Markdown lint
-> one-line relative-links adapter -> installed relative-links rule
-> git diff --check
all four security workflows -> sha256sum -> Gitleaks; npm audit separately
all four PR commit workflows -> commitlint title + BASE_SHA..HEAD_SHA
root PR workflow -> npm exec --no -- commitlint; no cross-repo script delegation
DAG показывает ownership и ordering. Количество запусков, required-check настройки и эффект repeated gates относятся к аудитам 11/14; здесь не измерялись.
3.5. SHA/Fingerprint Mechanism Registry
Категории промпта: a business idempotency/replay; b storage integrity; c generated artifact freshness; d CI/cache identity; e test determinism; f ad hoc guard. Runtime resource revision/identity отдельно помечены как расширение категории d: это не CI cache. Crypto authentication и подписанный cursor указаны отдельно, чтобы не назвать их tooling checks.
Для всех project-owned SHA-256 fingerprints ниже код исходит из практической уникальности digest; отдельных collision detectors не найдено. Это не доказательство криптографической модели — её аудит здесь не проводился. Обычный SHA не является подписью, шифрованием или authorization.
| Mechanism / category | Evidence / caller | Binding input / угроза / assumptions | Альтернативная гарантия и решение |
|---|---|---|---|
| Card/operation creation fingerprints — a | backend/src/modules/banking/bank-cards/application/bank-card-input.ts:74–81; backend/src/modules/banking/bank-cards/application/bank-cards.service.ts:74–95; backend/src/modules/banking/bank-cards/application/bank-operations.service.ts:214–239 |
SHA-256 от normalized input; BigInt сериализуется decimal string. UUID и owner проверяются отдельно; одинаковый intent возвращается, конфликт payload отвергается, tombstone не позволяет воссоздать удалённую operation | Unique ID один не обнаружит изменённый payload; current row comparison после редактирования не равно original intent. KEEP, сохранять ownership/transaction/tombstone |
| Refresh-token hash + CAS — authentication / replay, близко a, не tooling | backend/src/modules/auth/application/auth.service.ts:81–113,166–205; test helper backend/src/modules/auth/application/auth.service.spec.ts:24–25 |
SHA-256 всего token; session/sub/expiry проверяются отдельно; updateMany связывается с прежним hash. Test helper вычисляет expected value тем же стандартным primitive | JWT verify один не заменяет stored-token rotation/CAS. KEEP; security оценка — audit 13 |
| Password hash — credential storage, вне tooling categories | backend/src/modules/auth/application/auth.service.ts:19–26,48–53,64–75 |
bcrypt rounds 12, библиотечный salt; password input; dummy hash для отсутствующего user. Не SHA checksum и не storage-file integrity | Без равносильного password KDF замену не предлагать. KEEP; dependency/security rationalization здесь не выполнялась |
| Operations cursor binding — runtime pagination identity, d-runtime | backend/src/modules/investments/operations/infrastructure/brokerage-operations.repository.ts:128–144; backend/src/modules/investments/operations/application/brokerage-operations.service.ts:239,331–339 |
SHA-256 от user, connection revision, membership revision для all, account operations revisions и filter key; rejects cursor после изменения scope/data | HMAC защищает body от подделки, но сам по себе не проверяет актуальность binding. KEEP |
| Operations cursor HMAC — authentication of opaque cursor | backend/src/modules/investments/operations/application/brokerage-operations.service.ts:347–388; read → encode/decode |
HMAC-SHA256 от base64url JSON body под JWT_SECRET; length + timingSafeEqual; repository отдельно проверяет binding | Неподписанный base64 не равносилен. KEEP; key reuse/полнота validation относятся к audit 13 |
| Operations work scope key — durable deduplication, a | backend/src/modules/investments/operations/infrastructure/brokerage-operations.repository.ts:254–269; backend/src/modules/investments/operations/application/brokerage-operations-sync.service.ts:157–167 |
SHA-256 от отсортированных unique interval keys; owner/revision входят в DB identity отдельно. Угроза — дублирующиеся work intents | Raw canonical JSON можно рассматривать только с DB key/migration proof; отдельная новая защита не нужна. KEEP |
| Operations resource key — d-runtime | backend/src/modules/investments/operations/application/brokerage-operations.service.ts:237–253; controller read → response metadata |
SHA-256 filterKey, base64url; связывает metadata identity с фильтром, не с authenticator | Можно передавать raw filterKey только после проверки wire consumers/compatibility. Экономия не измерена. KEEP |
| Aggregated accounts data revision — d-runtime | backend/src/modules/investments/brokerage-accounts/brokerage-accounts.service.ts:16–65 → investmentResourceMeta; frontend/src/shared/api/resource-query.ts:129–148 проецирует meta |
SHA-256 membership revision и списка account IDs/portfolio data revisions. Hash revision graph, не всего response и не schema | Monotonic stored revision требует другого owner/state; простое UUID на каждый GET меняет стабильность. KEEP |
| Candle data revision — d-runtime | backend/src/modules/investments/instruments/infrastructure/candle.repository.ts:30–53; backend/src/modules/investments/instruments/application/candle.service.ts:101–128 |
SHA-256 JSON упорядоченных candle time/close/isComplete; coverage/freshness отражаются отдельно. Same digest не доказывает same coverage | Timestamp/revision может заменить только после определения равносильной change semantics. KEEP |
| Downloaded Gitleaks archive checksum — b, distribution integrity | frontend/.gitea/workflows/verify.yml:52–58; backend/.gitea/workflows/verify.yml:52–58; specs/.gitea/workflows/security.yml:24–30; docs/.gitea/workflows/security.yml:24–30 |
Pinned SHA-256 целого tar.gz до extraction/execution; checksum доверяется из tracked workflow. Угроза — получение иных bytes | HTTPS без pin не доказывает совпадение bytes с ожидаемым artifact. Используется native sha256sum --check, custom checker нет. KEEP |
| OCI image digest + source SHA binding — d, artifact identity | frontend/.gitea/workflows/image.yml:46–62; backend/.gitea/workflows/image.yml:42–56; F5/B8 |
Docker-generated manifest digest; pull/smoke по IMAGE@DIGEST, revision/version OCI labels проверяются отдельно; source SHA задан event/checkout |
Version tag или label отдельно не связывает проверку с тем же artifact. Native Docker handles digest; не собственный hashing framework. KEEP |
| Event HEAD/PR revision SHA — d, source identity | Image workflows:26–27; four commits workflows; verify log SHA | Git HEAD равен event SHA для publication; commitlint диапазон BASE..HEAD; SHA log — traceability. Не equivalent runtime provenance proof | KEEP native Git assertions; source SHA не доказывает schema freshness |
| npm lockfile SRI — b, package artifact integrity | Четыре package-lock.json, например backend/package-lock.json:85; consumers — npm CLI / npm ci |
Library-maintained integrity, обычно SHA-512; input — package tarball. Не custom registry |
KEEP package manager ownership. Lock entries не считались отдельными custom mechanisms |
| Frontend generated-types freshness — c, hashing нет | F1; frontend/package.json:22–26; local generator CLI:125–134,280–292 |
Exact generated UTF-8 text сравнивается с committed text. Проверяет воспроизводимость относительно local snapshot, не backend актуальность | Native generator --check обеспечивает ту же гарантию — SIMPLIFY TOOL-001 |
| Backend offline/runtime OpenAPI equality — c, hashing нет | B2; backend/test/openapi-contract.e2e-spec.ts:126–159 |
Generated JSON из compiled preview сравнивается с configured app document; child network listen/connect запрещены; temp artifact | JSON equality дополняется HTTP behavior tests, не SHA. KEEP; не переносить чтение backend source во frontend gate |
| SQLite integrity/foreign keys — b, hashing нет | B8:63; B9:109–118,202–205; backend/test/tbank-migration.e2e-spec.ts:78–79,259–260 |
Native PRAGMA integrity_check / foreign_key_check после runtime/migration/restore boundaries |
Filesystem byte checksum не доказывает relational integrity. KEEP native DB checks |
| Release version / migration-prefix guards — f, hashing нет | F2/B1/S1/D1; B9:13–23 | Version vs accepted merged semver; historic migration bytes unchanged; synthetic baseline/current directories distinct | Native release-it checks частично покрывают prerequisites, но не всю семантику; KEEP |
| Synthetic determinism — e, собственный hash не найден | F4:22; F5:38–46; B4:14–18; B9:88–106 | Random temp IDs/secret и фиксированный fake digest sha256:exact; deterministic fixtures/assertions. Fake digest не вычисляется и не является security evidence |
KEEP isolation; не добавлять hash registry для тестов |
| PWA generated precache revisions — d, dependency-owned cache identity | frontend/vite.config.ts:12–51; Vite/PWA/workbox build |
Asset content revisions обслуживает установленный генератор; own glob/static-shell policy, API paths excluded from navigation fallback | Это generated output, не custom SHA checker. KEEP library ownership; build artifacts не аудитировались |
Не найдено: project-owned SHA/fingerprint registry для FSD, conventions, specs или generated freshness; custom CI cache hash scripts; snapshot-update scripts в канонических commands. Наличие слова snapshot в financial DTO/tests не классифицировалось как test snapshot tooling.
3.6. Native Tool Replacement Matrix
| Custom mechanism / wrapper | Проверенная native возможность | Реальная эквивалентность / решение |
|---|---|---|
| F1 OpenAPI freshness wrapper | Installed openapi-typescript@7.13.0 --check -o; CLI:125–134 и 280–292 |
Да, для нынешнего single local schema/output. Генерация в памяти, сравнение, exit 0/1 до write. Перенести команду и удалить F1 |
F1 через regenerate + git diff --exit-code |
Git показывает изменение tracked result | Нет для read-only verification: генерация сначала перепишет result; обычный diff не видит untracked. Native generator check проще и точнее |
| Release clean-tree guard S1/D1 | release-it requireCleanWorkingDir: true |
Не полностью: installed docs/node_modules/release-it/lib/plugin/git/Git.js:126–130 использует git diff --quiet HEAD, custom guard использует porcelain status и видит untracked. Не удалять assertion как «дубликат» |
| Version-vs-last-tag guard F2/B1/S1/D1 | release-it requireBranch, requireCommits; npm.ignoreVersion |
Нет: commits-after-tag не проверяет equality package version/accepted tag; ignoreVersion меняет источник версии. Сохранить guard |
| SQLite scheduling B3 | Jest --runTestsByPath, --runInBand, config/setupFiles |
Native Jest уже используется. Нет замены mkdtemp, migration binding, override external URL, process-group cleanup. KEEP thin custom orchestration |
| E2E environment safety B5 | Jest setupFiles | Native hook — caller, не сама гарантия безопасной DB. KEEP 17-строчный guard |
| Crash/durability/image checks | Jest/Vitest mocks, Playwright browser tests, TypeScript compile | Нет: не воспроизводят SIGKILL, historical migrations/restore и actual Docker packaging. KEEP boundary-specific runners |
| ESLint config tests F3/B6 | eslint ., --max-warnings=0, ESLint API / native RuleTester |
Native CLI проверяет current code, но не synthetic counterexamples wiring. Применён native API; новый validator/framework не нужен |
| F6 JSX-spacing | Installed @stylistic/jsx-newline, prevent:false; frontend/node_modules/@stylistic/eslint-plugin/dist/rules/jsx-newline.js:43–84 |
Не drop-in: native rule обрабатывает все JSXExpressionContainer и gaps, custom — только выражения с JSX, не text interpolation; алгоритмы различны. Сначала определить нужную policy, не заменять вслепую |
| F6 readability | Native no-restricted-syntax / no-restricted-imports, TypeScript rules |
Части placement/style policy можно выразить selectors; единой эквивалентной замены всего plugin не установлено. Наличие syntax rule не доказывает нужность самой convention. KEEP до доказанной цены/false positives |
| FSD/story isolation | dependency-cruiser rules с circular, couldNotResolve, reachable, capture groups |
Уже native declarative config, не custom graph analyzer. Direct ESLint import запрет не покрывает transitive story reachability. KEEP |
| D2 Markdown adapter | markdownlint CLI --rules + installed relative-links package |
Однострочный adapter уже минимален; semantic link validation принадлежит dependency. Не добавлять собственный link checker |
| Named npm aliases | npm run, workspaces --if-present |
Stable developer commands полезны. Нельзя считать одно делегирование основанием DELETE |
Pre-commit npx lint-staged |
npm exec --no / npx --no; старое --no-install конвертируется в --no |
Native отказ от установки покрывает конкретный side effect; использовать его без новой dependency — TOOL-002 |
| Biome / Prettier | В manifests не установлены; README frontend:95–99 описывает удаление Biome | Нет основания вводить второй formatter ради сокращения текущего tooling |
Проверенные внешние источники: OpenAPI TypeScript CLI (https://github.com/openapi-ts/openapi-typescript/blob/main/packages/openapi-typescript/bin/cli.js), release-it Git prerequisites (https://github.com/release-it/release-it/blob/main/docs/git.md), npm exec/npx (https://github.com/npm/cli/blob/latest/docs/lib/content/commands/npx.md). Для version-sensitive решений приоритет отдан установленному коду, не только latest документации.
3.7. Проверки и их side effects
| Поток | Фактический side effect | Оценка |
|---|---|---|
Frontend verify, typecheck, lint, deps |
Префикс build:packages создаёт package dist; verify также coverage, TS/build artifacts, app/catalog/PWA output |
Заявленный build-backed gate. Не read-only в строгом файловом смысле, но generated types не переписывает; не подтверждён forbidden tracked rewrite |
Backend verify |
Coverage, Prisma client generation и compiled build | Заявленные outputs. Нельзя запускать в аудите read-only; не повод удалять build |
openapi:generate frontend/backend |
Перезаписывает artifact | Явно generation, не check. Не использовать как read-only proof |
F1 и предложенный native --check |
F1 пишет private temp, native single-schema check не пишет output | Native вариант уменьшает и implementation, и файловые side effects |
F3/B6 test:lint |
F3 fixes in-memory; B6 temporary source в repo с finally cleanup | Не source auto-fix. При строгом read-only режиме всё равно не запускалось |
| Pre-commit | lint-staged auto-fix/stage; packages build; возможный npx install fallback | Auto-fix заявлен README/package config. Установка отсутствующего tool не нужна проверке — TOOL-002 |
Frontend/specs prepare lifecycle |
Husky setup / изменение local Git core.hooksPath |
Installation lifecycle, не validator; npm ci --ignore-scripts обходит lifecycle в commitlint jobs |
| SQLite/E2E/crash runners | Migration/write/delete только runner temp DB; tests могут слушать local HTTP | Поддерживаемая isolation boundary. Не запускать без side-effect review; не заменять на direct Jest с inherited DB |
| Container smoke | Docker volume/container, migration/auth write внутри disposable image environment | Явные isolated тестовые изменения, cleanup предусмотрен |
| Durability/regression | Retained temporary DB, backups, logs/result.json | Заявленные диагностические outputs в README, не скрытый snapshot update |
| Image publication | Docker login/build/push/pull и registry changes | Реальное publication, не безопасная локальная validation команда. Не исполнялось |
False positives / negatives: текущий freshness checker и native replacement требуют exact text equality: различие generator output может блокировать gate даже при эквивалентных TS типах. Это выбранная reproducibility-гарантия; частота такого churn не измерена. Одинаковые snapshot/generated files могут быть совместно устаревшими — это не ложное обещание текущего README, который ограничивает check локальным snapshot. Для F6 синтаксические эвристики не устанавливают semantic ownership: schema branch реагирует на имя метода refine/superRefine, helper branch проверяет определённую форму arrow-component. Production false positives/negatives и реальный churn UNVERIFIED; отдельный finding без примера текущего consumer не сформирован.
4. Findings
TOOL-001 — Самописный OpenAPI checker заменяется уже установленным --check
- Decision: SIMPLIFY.
- Severity: P3.
- Confidence: High.
- Evidence:
frontend/scripts/check-openapi.mjs:1–45;frontend/package.json:22–26;frontend/scripts/test-eslint.mjs:88–90;frontend/.ai/conventions/data.md:32–33. Проверка замены: installedfrontend/node_modules/openapi-typescript/bin/cli.js:125–134,280–292. - Claim: temp-directory/spawn/read/compare/cleanup реализация не добавляет гарантий к нынешнему single-schema native check.
- Current mechanism:
verifyвызываетopenapi:check; helper запускает тот же generator с теми же input/options, но с temporary output, затем сравнивает UTF-8 strings и транслирует exit code. - Impact / actual cost: один дополнительный 45-строчный file, process wrapper и filesystem lifecycle для сопровождения. Impact unmeasured для времени/CI/tokens; генерация всё равно нужна и её стоимость не исчезнет.
- Why now: native option присутствует в закреплённой версии 7.13.0; положительная и отрицательная ветви read-only CLI проверены на текущем checkout.
- Minimum change: сохранить alias и задать
openapi:check = openapi-typescript src/shared/api/spec/openapi.json -o src/shared/api/generated/schema.d.ts --check; удалить толькоscripts/check-openapi.mjs; synthetic ESLint sample filePath:88 заменить на surviving.mjsfile; data convention:33 описать native check вместо temp implementation. - Guarantees at risk: mismatch должен давать nonzero; check не должен чинить generated file, читать соседний backend или обращаться к runtime endpoint. Обновление native version/options должно применяться одинаково к generate/check.
- Counterarguments / trade-offs: теряется собственное сообщение с подсказкой
npm run openapi:generate; native diagnostic короче. Custom wrapper оправдан при реальных дополнительных нескольких schemas/outputs или иной семантике сравнения, которых сейчас нет. - Verification or rollback: сверить success на committed artifact, rejection на отличающемся output, отсутствие изменений после обоих исходов; при реализации повторить существующий
test:lint. Rollback — восстановить helper и прежнюю строку alias, без изменения schema/artifact. - Effort: S.
- Related finding IDs: —.
TOOL-002 — Pre-commit допускает установку отсутствующего lint tool
- Decision: FIX.
- Severity: P3.
- Confidence: High для способности fallback; фактическое использование fallback UNVERIFIED.
- Evidence:
frontend/.husky/pre-commit:1–3;frontend/package.json:36–38,106;frontend/.husky/commit-msg:1;frontend/scripts/test-pre-commit.mjs:38–46,53–74; npm npx/exec semantics в источниках секции 3.6. - Claim: plain
npx lint-stagedне ограничивает hook установленным tool и допускает ненужный install side effect при его отсутствии. - Current mechanism: Git pre-commit сначала проходит Gitleaks, затем npx разрешает binary. После нормального
npm ciлокальныйlint-staged@17.5.1уже существует; при неполной установке npm может запросить/выполнить installation в cache, а не сразу отказать. - Impact / actual cost: возможны registry/cache mutation, ожидание сети/подтверждения и запуск tool вне текущей локальной installation. Impact unmeasured; проблема не воспроизводилась удалением packages и не заявляется как состоявшаяся установка.
- Why now: явный no-install pattern уже используется соседним commit-msg hook; изменение одной строки устраняет ненужную возможность побочного эффекта.
- Minimum change: использовать
npx --no lint-staged; поддерживаемый existing spellingnpx --no-install lint-stagedтакже транслируется npm в отказ от установки. Остальные hook steps сохраняются. - Guarantees at risk: Gitleaks должен остаться первым, redacted и fail closed; lint-staged должен продолжить intended auto-fix/index handling; dependency graph check не пропускать.
- Counterarguments / trade-offs: в штатной installation fallback не нужен и не происходит. Hook станет явно требовать подготовленной development installation; он не должен устанавливать её во время commit. Отказ от установки не является полной проверкой provenance уже закешированных/global executables.
- Verification or rollback: существующий hook regression проверяет order/failure/redaction, но fake npx не доказывает no-install resolution. Самая дешёвая дополнительная проверка — controlled temporary PATH/cache с отсутствующим tool и explicit
--no, подтверждающая отказ без установки; не трогать текущие node_modules. Rollback — прежняя hook строка. - Effort: S.
- Related finding IDs: —.
TOOL-003 — У build runtime assertion не найден исполняющий consumer
- Decision: INVESTIGATE.
- Severity: P3.
- Confidence: Medium.
- Evidence:
backend/test/runtime-check.cjs:1–8;backend/eslint.config.mjs:67–75;backend/test/eslint-config.cjs:14–23;backend/package.json:11–39;backend/Dockerfile:21–41;backend/test/container-smoke.cjs:29–65; caller search по active manifests/workflows/docs/scripts. - Claim: инструмент
possible unused: references в lint scope/synthetic lint cases не являются его выполнением. - Current mechanism: вручную исполнимый script сравнивает строку
start:prod, проверяет наличиеdist/src/main.jsи импортирует compiled Prisma client. Npm script, workflow, Docker RUN/CMD и активный README его не вызывают. - Impact / actual cost: небольшой orphan file и специальные lint/test references; automated runtime protection не подтверждена. Impact unmeasured; потеря времени/CI не заявляется.
- Why now: complete script inventory выявляет неопределённое ownership; это позволяет убрать лишний навигационный путь, если manual/external caller отсутствует.
- Minimum change: сначала спросить release/runtime owner об external pipeline/manual use. При отрицательном ответе удалить файл и исключительно связанные config/test references; не добавлять новый alias только ради оправдания существования файла.
- Guarantees at risk: проверка literal command string исчезнет; actual packaging/client loading частично защищает container smoke, но это другая boundary и другой trigger.
- Counterarguments / trade-offs: файл может быть полезной дешёвой локальной проверкой build без Docker. Отсутствие repo references не исключает ручной запуск или external automation.
- Verification or rollback: подтвердить отсутствие external/manual caller; сравнить защищаемые ошибки с existing image smoke и build. Если нужная local гарантия отсутствует, KEEP и документировать действующий caller. Rollback — восстановить 8-строчный file и его lint entries.
- Effort: S.
- Related finding IDs: TOOL-004 — общий вопрос ownership, не общая реализация.
TOOL-004 — Publication recovery regression не подключён к найденному графу команд
- Decision: INVESTIGATE.
- Severity: P3.
- Confidence: Medium.
- Evidence:
frontend/scripts/check-image-publication.cjs:15–29,31–47,49–87;frontend/.gitea/workflows/image.yml:46–62;frontend/.gitea/workflows/verify.yml:63,88–92;frontend/package.json:21,26;frontend/vitest.config.ts:26–64; caller search по active docs/configs/scripts. - Claim: нет найденного локального исполняющего consumer, хотя test защищает реальную recovery-семантику публикации.
- Current mechanism: Node test извлекает конкретный shell block из YAML по имени/indentation и запускает его с temporary fake Docker/npm. Проверяет failed first pull, успешный retry по тому же digest, label/smoke failure и один build.
- Impact / actual cost: наличие test file само по себе не даёт regression gate. Его связь с workflow также требует поддержки при rename/reindentation шага. Impact unmeasured; actual CI failure/churn не установлен.
- Why now:
test:lintзапускает один другой file; application Vitest projects не включают этот.cjsscript; workflows не вызывают его напрямую. Нужна ясная responsibility перед cleanup. - Minimum change: установить, используется ли test manually/external pipeline. Если recovery-проверка нужна, закрепить существующий entrypoint у image-tooling owner; выбор trigger отдать audit 11. Если этот сценарий намеренно больше не нужен, удалять test только вместе с решением о гарантии.
- Guarantees at risk: без равносильной regression можно потерять safe post-push resume/digest-bound smoke. Реальную immutable publication и label/digest checks не удалять.
- Counterarguments / trade-offs: standalone manual test вполне допустим; широкий
verifyне обязан исполнять все diagnostic tools. String extraction тестирует actual block, но чувствительна к структуре YAML; переход на новый custom YAML framework не оправдан. - Verification or rollback: дешёвая safe проверка — текущий
node --test scripts/check-image-publication.cjsпосле просмотра implementation, в synthetic окружении; в этом аудите не запускалась. Подтвердить manual ownership/trace перед удалением. Rollback — восстановить file/caller; registry не изменять. - Effort: S.
- Related finding IDs: TOOL-003 — общий вопрос ownership.
5. DELETE / SIMPLIFY / KEEP / INVESTIGATE
| Decision | Объект | Почему / сохранённая гарантия |
|---|---|---|
| DELETE | Безусловных кандидатов нет | Ни один orphan не доказан dead с учётом manual/external use |
| SIMPLIFY | F1 check-openapi.mjs implementation, TOOL-001 |
Удалить файл после переноса alias на native --check; freshness и read-only output сохраняются |
| FIX | Plain npx в pre-commit, TOOL-002 | Explicit refusal to install; staged secret scan и auto-fix остаются |
| KEEP | Stable npm delegation aliases / workspace builds | Это interface commands, не 64 отдельных bespoke tools |
| KEEP | F2/B1/S1/D1 release guards | Version equality не заменяется requireCommits; specs/docs porcelain дополнительно видит untracked |
| KEEP | B3/B5 SQLite isolation/guard | Не допускает migrations/tests на inherited пользовательском DATABASE_URL |
| KEEP | B4 runner regression | Manual proof process isolation/cleanup; не включён в обычный CI, стоимость не измерена |
| KEEP | B8/B9/B10 image/durability/crash runners | Native modules/assets, durable publication, exact financial/replay/rollback guarantees |
| KEEP | B2 и backend offline/runtime schema suite | Offline artifact producer + отдельный runtime parity proof |
| KEEP | F3/B6 ESLint config regressions | Synthetic negative cases проверяют реальные scopes и formatter behavior |
| KEEP | F4 Gitleaks staged/redaction regression | History scan не доказывает index-only behavior и downstream stop |
| KEEP | SHA-256 fingerprints, CAS, cursor HMAC, digest/checksum assertions | Business/security/artifact invariants; native hashing уже используется |
| KEEP | D2 one-line rule adapter / native depcruise configs | Уже минимальная delegation/config integration |
| INVESTIGATE | B7 runtime-check, TOOL-003 | Possible unused; first verify external/manual ownership |
| INVESTIGATE | F5 publication regression, TOOL-004 | Сохранить защиту recovery, пока не принято решение о consumer |
| INVESTIGATE | F6 readability/JSX style policy | Нет подтверждённой native semantic equivalence или измеренной цены false positives |
| INVESTIGATE | Prisma process-local RUST_LOG shim | Historical failure описан, current-version reproduction отсутствует; не удалять по факту обновления Prisma |
6. Cost & benefit
| Изменение | Ожидаемый класс экономии | Что действительно измерено | Обязательная граница безопасности |
|---|---|---|---|
| TOOL-001 | Maintenance, cognitive load; меньше custom process/temp orchestration | Read tool показал 45 физических строк helper, включая imports/blanks; native success/failure выполнены. Runtime, CI minutes и agent tokens — not measured | Не заменять check на mutating generate; не обращаться к backend checkout/endpoint |
| TOOL-002 | Предотвращение ненужной network/install работы и неоднозначного error recovery | not measured; подтверждена command capability, не частота fallback | Сохранить порядок scan → intended format → deps и failure propagation |
| TOOL-003 | Potential cleanup одного 8-строчного файла и orphan references | File size из текущего чтения; benefit/use frequency — not measured | Manual/external use должен быть подтверждён до DELETE |
| TOOL-004 | Ясность ownership / сохранение полезного test | not measured; test execution сейчас UNVERIFIED | Не терять immutable post-push recovery regression |
| Protected runners | Избежание повторного создания inferior wrappers/checks | not measured | DB isolation, money/replay invariants, migration history и process shutdown остаются |
Complexity-pass в формате установленного skill:
native: убрать custom temp-generation checker; заменить installed openapi-typescript --check, сохранив npm alias. [frontend/scripts/check-openapi.mjs]- net: -45 lines, -0 deps possible. Это потенциал удаления одного текущего 45-строчного helper, не measured net diff после сопутствующей правки docs/test fixture и не оценка ускорения. Условные orphan deletions в число не включены.
Candidate Removal Plan
| Candidate | Минимальная безопасная последовательность | Proof before removal | Rollback |
|---|---|---|---|
| F1 helper — подтверждённый implementation removal | Перенести local alias на native check; поправить synthetic ESLint path и описание; удалить helper | Success + deliberate mismatch + unchanged output + existing lint config test | Восстановить file и alias; generated artifact не менять |
| B7 runtime-check — условный | Подтвердить manual/external ownership; при отсутствии удалить file и только exclusive references | Existing build/image consumers сохраняются; определить нужность literal start command assertion | Восстановить file/config references |
| F5 publication regression — удаление сейчас не рекомендовано | Сначала решить, является ли recovery scenario сохраняемой гарантией; при необходимости оставить существующий test у owner | Перед потерей гарантии нужен равносильный proof или явное решение о её прекращении | Восстановить test/caller; не перепубликовывать image |
Не предлагать общий release-tooling repo, новый YAML/parser framework, новую dependency для трёхстрочного hook или custom fingerprint framework.
7. Top actions
Quick wins
- TOOL-002: закрыть install fallback pre-commit одной explicit no-install опцией. Low effort; полезно даже без доказанной частоты fallback.
- TOOL-001: перенести
openapi:checkна installed native--check, удалить wrapper implementation; сохранить имя команды и обновить две связанные references.
Решения с ownership / тестовым подтверждением
- TOOL-003: уточнить manual/external consumers runtime-check; DELETE только при подтверждённом отсутствии потребности.
- TOOL-004: уточнить owner/consumer существующей recovery regression; по умолчанию сохранить. Trigger выбирать в CI-аудите, не расширять canonical verify автоматически.
Ни одно подтверждённое quick win не требует ADR. ADR имеет смысл только если будет изменяться публичная release/recovery или DB-safety гарантия, а не из-за удаления wrapper file. Массовое переписывание runners и общие tooling abstractions не рекомендованы.
8. Cross-audit signals
- Audit 11 — CI/CD:
frontend/scripts/check-image-publication.cjs,frontend/.gitea/workflows/image.yml,backend/.gitea/workflows/image.yml:45–55— owner/trigger recovery test и различающаяся политика повторного запуска после post-push failure; здесь registry-поведение не воспроизводилось. - Audit 13 — security/integrity: hash/HMAC/CAS consumers из registry — сохранить guarantees; отдельно оценивать binding/key policy, не трактовать наличие SHA как over-engineering.
- Audit 14 — agent workflow/conventions:
frontend/eslint-rules.mjs:63–98,frontend/eslint.config.mjs:270–282— нужность общего запрета local component handlers/helpers и реальный churn должны оцениваться по policy/consumer, не по числу lint rules. - Граница targets: отдельный
deploy/deploy.shиdeploy/tests/требуют явного дополнительного tooling target; их анализ не входит в инвентарь четырёх targets этого запуска.
9. Open questions / verification plan
| Вопрос, меняющий решение | Текущий статус | Самый дешёвый способ проверить |
|---|---|---|
| Есть ли внешний/manual caller runtime-check? | UNVERIFIED | Ответ runtime owner / поиск в его external pipeline configuration. Без caller и потребности DELETE; иначе KEEP |
| Выполняется ли publication recovery test вручную и нужна ли эта гарантия? | UNVERIFIED | Ответ image owner и один existing synthetic Node test. Затем решение о consumer, не о новом framework |
| Происходил ли npx install fallback во время commit? | UNVERIFIED; capability подтверждена | Не требуется для однострочного FIX. Если нужна оценка частоты — только имеющиеся redacted logs; не удалять пакеты в checkout |
| Можно ли заменить JSX-spacing native rule без text/layout изменений? | UNVERIFIED, code semantics различаются | На существующих representative TSX/examples сравнить diagnostics и in-memory fixes; не делать массовый autofix для исследования |
| Нужен ли RUST_LOG workaround на Prisma 7.10.0? | UNVERIFIED | В отдельной разрешённой тестовой сессии fresh temporary DB migration с warn/error и default env; пользовательскую DB не использовать |
Отчёт не подтверждает доступность real registry/runner, correctness всех financial/hash algorithms, полноту HTTP contract behavior или actual full-suite PASS. Эти ограничения не мешают подтверждённому native-wrapper cleanup.
Машинно-считываемая таблица для консолидации
| ID | Decision | Severity | Confidence | Repo | Files | One-line impact | Effort | Related IDs |
|---|---|---|---|---|---|---|---|---|
| TOOL-001 | SIMPLIFY | P3 | High | frontend | scripts/check-openapi.mjs; package.json; scripts/test-eslint.mjs; .ai/conventions/data.md | Native --check preserves freshness while removing one custom wrapper | S | — |
| TOOL-002 | FIX | P3 | High | frontend | .husky/pre-commit | Plain npx permits unnecessary installation when the local lint tool is absent; occurrence unverified | S | — |
| TOOL-003 | INVESTIGATE | P3 | Medium | backend | test/runtime-check.cjs; eslint.config.mjs; test/eslint-config.cjs | No executing local caller found; manual/external use must be verified before removal | S | TOOL-004 |
| TOOL-004 | INVESTIGATE | P3 | Medium | frontend | scripts/check-image-publication.cjs; .gitea/workflows/image.yml | Useful publication recovery regression has no discovered executing consumer | S | TOOL-003 |