Files
main/audits/2026-10-11/reports/10-custom-scripts-and-tooling.md
T
ksv741 2b63bde934
Conventional commits / commits (pull_request) Successful in 13s
docs: archive technical audit 2026-10-11 in develop (#36)
2026-10-17 19:30:38 +03:00

79 KiB
Raw Blame History

Аудит 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 сам по себе не подтверждает наличие или качество нового отчёта. Файл проверяется отдельно.

Что запускалось

  1. git rev-parse HEAD, git status --short, git ls-files в указанных checkout.

  2. Статические чтения manifests, hooks, workflows, конфигураций и всех найденных custom tooling files; rg --files --hidden --no-ignore и адресные content searches.

  3. Context7 для актуальной семантики openapi-typescript --check, release-it Git checks и npm/npx fallback; установленные реализации генератора и release-it проверены отдельно.

  4. Две небольшие 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

  1. Факт: основной tooling уже делегирует штатным ESLint, TypeScript, Vitest/Jest, dependency-cruiser, npm, Prisma и release-it. Biome сейчас отсутствует; возвращать его ради сокращения scripts не обосновано.
  2. Подтверждённое упрощение: frontend check-openapi.mjs повторяет имеющийся openapi-typescript --check. Можно убрать один 45-строчный файл, сохранив npm run openapi:check и ту же гарантию сравнения generated types с локальным snapshot — TOOL-001.
  3. Подтверждённая возможность нежелательного side effect: pre-commit использует npx lint-staged без отказа от установки отсутствующего пакета. При корректном npm ci используется локальный пакет; при неполной установке команда допускает registry/cache fallback. Фактическая установка во время commit UNVERIFIED — TOOL-002.
  4. Непроверенная эксплуатационная гипотеза: у backend/test/runtime-check.cjs и frontend/scripts/check-image-publication.cjs не найдены локальные исполняющие callers. Это possible unused, не доказанный dead code. У второго есть полезный recovery-инвариант, поэтому автоматическое удаление особенно неуместно — TOOL-003/004.
  5. KEEP: SQLite isolation/cleanup, crash-process fixture, durability checks, offline backend schema generator и release version guards имеют самостоятельную ответственность. Ни обычный Jest, ни git diff --exit-code, ни базовые release-it checks полностью её не заменяют.
  6. Граница доказательства: локальная 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. Проверка замены: installed frontend/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 .mjs file; 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 spelling npx --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 не включают этот .cjs script; 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

  1. TOOL-002: закрыть install fallback pre-commit одной explicit no-install опцией. Low effort; полезно даже без доказанной частоты fallback.
  2. TOOL-001: перенести openapi:check на installed native --check, удалить wrapper implementation; сохранить имя команды и обновить две связанные references.

Решения с ownership / тестовым подтверждением

  1. TOOL-003: уточнить manual/external consumers runtime-check; DELETE только при подтверждённом отсутствии потребности.
  2. 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