Files
main/audits/2026-10-11/reports/04-dead-code-and-legacy-report.md
T
codex-bot d07fbfabb1 docs: archive technical audit 2026-10-11 in develop (#36)
Переносит архив `audits/2026-10-11/` (19 файлов) из codex/audit-remediation-2026-10-11 в develop и добавляет точечный allowlist в .gitignore.
2026-10-17 19:38:03 +03:00

83 KiB
Raw Blame History

Аудит 04 — Dead Code & Legacy

1. Audit metadata

  • Audit ID / name: 04 / Dead Code & Legacy.
  • Дата: 2026-10-11.
  • Исполнитель: один независимый исполнитель направления 04; другие субагенты не запускались.
  • Результат: исследование reachability и безопасных границ удаления. Изменён только этот отчёт вне application checkout.
  • Workspace: /Users/ksv741/Project/vibe/WealthLedger.
Checkout Абсолютный путь HEAD, проверенный самостоятельно Начальный status
root /Users/ksv741/Project/vibe/WealthLedger dc030f84c979cedb2628ef4bd97c62d6c63a9256 чистый
frontend /Users/ksv741/Project/vibe/WealthLedger/frontend c8821200ce699dab1ce65360d1968d5877a2e78b чистый
backend /Users/ksv741/Project/vibe/WealthLedger/backend 0ad84ff4f0b4712abc7e69dc299856f14af6eadd чистый
specs /Users/ksv741/Project/vibe/WealthLedger/specs fcdc805f6c1b3be6a20a7e858e3e80cbd83a9121 чистый
docs /Users/ksv741/Project/vibe/WealthLedger/docs e6fd4f64b81dd73b33959b845a1babcfac1891c8 чистый

Метод фиксации: в каждом checkout выполнены git rev-parse HEAD && git status --porcelain=v1; пустой porcelain означает отсутствие staged, unstaged и видимых Git untracked changes, а не отсутствие ignored файлов. Root allowlist исключает audit-results/ (.gitignore:1–7), поэтому отчёт не должен появляться в обычном root status.

Инструкции: прочитаны AGENTS каждого checkout. Для backend и frontend прочитаны их собственные architecture, engineering и активированные conventions: HTTP/data/testing/integrations/security для backend; TypeScript/React/data/UI/testing/Storybook для frontend. Root conventions использованы только для root-границы отчёта. Specs выбраны через AI_INDEX.md и точные тематические targets; три актуальных требования нового потока, которых нет в индексе, прочитаны по известным абсолютным путям. Вложенных AGENTS в source-областях frontend/backend поиск не обнаружил.

Skills: установленный ponytail-audit загружен первым через Skill tool. Применены его delete: / shrink: теги, ранжирование по сокращению ненужной maintenance surface и запрет исправлений. Схема отчёта расширена обязательным протоколом 04. Числовой net не выдуман: deletion diff не создавался. Также загружены graphify и verification-before-completion.

Graphify: существующего graphify-out/graph.json не обнаружено в root и четырёх checkout: проверены списки корневых директорий, дополнительно Glob в frontend/backend. Graph query не выполнялся; graph generation, cache, manifest и другие artifacts не создавались. Отсутствие существующего graph — ограничение; выводы получены статической трассировкой актуальных source.

Что выполнялось: Read/Glob/Grep из соответствующих repo directories, read-only rg -n -c для явно указанных символов и git inspection. technical-audit-2026-10-11.md прочитан только как список гипотез; его выводы и оценка ~550 lines не использованы как доказательство. Другие новые отчёты аудиторов не читались и не изменялись.

Что не выполнялось: Node-команды, install, build, codegen, migrations, full-suite, targeted tests, запуск приложения, запросы к реальным API, изменение config/source/lockfiles, commits, PR и генерация исследовательских инструментов. Это статический аудит, не runtime-воспроизведение. npm run knip, deps, frontend test scripts предварительно вызывают build:packages (frontend/package.json:14–26); их запуск нарушил бы заданную read-only границу. Их результаты из прежнего отчёта не наследуются.

2. Executive verdict

  1. Факт: command-часть TbankSyncService.request → dispatch не имеет production entrypoint. Nest создаёт service для status, но controller предоставляет только GET. Удаление command-closure обосновано — DEAD-001.
  2. Факт: вслед за ней обнаружен менее очевидный dead producer: CatalogDiscoveryService.request/refresh/drain. Реальные HTTP search, detail и ticker читают онлайн либо вызывают persisted reader только с observe=true; старый request-driven импорт каталога запускают прямые тесты и недоступная manual orchestration — DEAD-002.
  3. Факт: frontend observe() используется только двумя прямыми тестовыми вызовами; все восемь production consumers useScreenSync игнорируют его return value, а _scope вообще не читается. Можно удалить эти API-хвосты, сохранив действующий timer — DEAD-004/005.
  4. Факт и граница: статусный GET и backend sync=observe действительно публично достижимы. Отсутствие их использования в текущей SPA не доказывает отсутствия внешних consumers или старых DB rows. Их удаление сейчас не подтверждено — DEAD-006/007, INVESTIGATE.
  5. Риск ошибочной зачистки: planner операций, hourly lifecycle, candle loader, shared source repository и connection/attempt fences остаются живыми. Массовое удаление по словам screen, catalog или sync может остановить данные либо каскадно удалить свечи — DEAD-008–011, KEEP.
  6. Итог: 5 actionable findings: P0 = 0, P1 = 0, P2 = 2, P3 = 3. Отдельно KEEP = 4, INVESTIGATE = 2. Для непроверенной внешней совместимости указан UNVERIFIED; экономия времени/строк не измерена.

3. Inventory & coverage

3.1. Фактическая карта entrypoints

Вход / поток Проверенная цепочка и owner Следствие для reachability
SPA bootstrap frontend/src/main.tsx:1–23 → src/app/ui/App.tsx:23–43 → src/app/routes/AppRoutes/AppRoutes.tsx:9–103,105–257 Lazy imports являются настоящими consumers page exports. CSS, i18n и dayjs locale — side effects, не orphan imports.
SPA routes AppRoutes.tsx:105–257: login/register; cards/card; stocks/stock; bonds/bond; accounts/account/events/income/operations; settings; wildcard Страницы доступны через router, включая динамические chunks; отсутствие статического прямого import не делает их мёртвыми.
Backend HTTP backend/src/main.ts:44–60 → src/app.module.ts:18–36 → controllers Prefix, validation, cookies, error boundary и shutdown hooks задаются src/main.ts:19–42; controller decorators являются registration.
Controller families backend/src/modules/auth/presentation/auth.controller.ts:51; backend/src/modules/banking/bank-cards/presentation/bank-cards.controller.ts:79; backend/src/modules/investments/brokerage-accounts/brokerage-accounts.controller.ts:15; backend/src/modules/investments/portfolio/presentation/portfolio.controller.ts:15; backend/src/modules/investments/operations/presentation/brokerage-operations.controller.ts:18; backend/src/modules/investments/income/income-analytics.controller.ts:20; backend/src/modules/investments/upcoming-events/upcoming-events.controller.ts:18; backend/src/modules/investments/instruments/stocks/presentation/stock.controller.ts:48; backend/src/modules/investments/instruments/bonds/presentation/bond.controller.ts:37; backend/src/modules/investments/tbank-connection/tbank-connection.controller.ts:33; backend/src/modules/investments/tbank-sync/tbank-sync.controller.ts:31 Проверены registrations всех этих семейств поиском @Controller, root module и нужными application chains; это не полный семантический аудит CRUD/auth.
Hourly job backend/src/modules/investments/tbank-sync/tbank-sync.module.ts:24–25 → scheduler onModuleInit:48–50 → tick:56–71 → reserveHourly / walk Один native timer, durable work и source owners; запуск не зависит от frontend.
Source queues Portfolio queueSnapshot, operations sync, metadata, enrichment, candles используют setImmediate; declarations найдены в source, живые примеры traced ниже Удаление manual dispatcher не даёт права удалять все очереди с похожими именами.
Production CLI backend/package.json:15–18; compose.yaml:24–38 Backend запускает dist/src/main.js; отдельная migration service — Prisma CLI. В manifest не найден CLI, вызывающий manual sync или persisted catalog producer.
Test dynamic entrypoint backend/test/fixtures/tbank-sync-crash.cjs:1–17 Динамические require ведут в operations sync/repository, не в TbankSyncService или CatalogDiscoveryService. Fixture не запускался.
OpenAPI tooling backend/scripts/generate-openapi.cjs:19–31 → AppModule preview → src/openapi.ts:6–10 Generator читает зарегистрированный controller contract; не вызывает service methods по именам. Наличие DTO decorator само по себе не публикует DTO.
Storybook / packages frontend/.storybook/main.ts:3–7; packages/ui/package.json:9–22; src/app/ui/App.tsx:3–8 Stories — дополнительные entrypoints; UI CSS явно side-effectful. Feature/query candidates не экспортируются public UI package.
Env / imports backend/src/config/env.validation.ts:9–33,102–113, .env.example:1–10, src/app.module.ts:18–36; frontend/vite.config.ts:54–61, tsconfig.app.json:8–20 Env задаёт транспорт/config, но не включает manual sync module/method или старую catalog producer ветку. Alias @/ ведёт в source.

3.2. Метод отбора и счёта

Исследованы 12 кандидатов C01–C12, отобранных по стоимости сопровождения и риску ошибочного удаления: старая orchestration, связанные producer paths, orphan DTO, frontend API-хвосты, публичная compatibility и защищённые live owners. Число 12 — число строк Reachability Ledger, не результат analyzer. Findings — 11: C01/C02 образуют одну deletion closure DEAD-001.

Порядок: declaration → exports/DI/registration → все найденные callers → реальный runtime entrypoint → external/public accessibility → контрпример. Поиск применялся к source, затем отдельно tests/scripts/artifacts, чтобы не принять direct test invocation за пользовательский путь.

Воспроизводимые search counts: это количество matching lines, а не число AST references; вывод вручную разделён по declarations/imports/calls. Поиск не считается самостоятельным доказательством отсутствия callers.

Поиск и границы Результат и независимая проверка
Q01, backend source/tests/scripts, команда ниже TbankSyncService найден только в своём service, controller и module; sync.request( — 0 строк. Controller calls только status. Для normalizeScreen(: 1 declaration, 1 вызов в dead request, 9 строк вызовов в tbank-screen.spec.ts. DTO Accepted — 1 declaration, 0 consumers.
Backend: owner-aware поиск this.discovery.* в instruments и чтение обоих catalog services 6 live delegation call sites: search/detail/byTicker у stocks и bonds. Ни один не вызывает read/request/refresh напрямую. discovery.refresh найден в manual dispatcher. В discovery owner три вызова this.read находятся после online-return ветки и получают observe=true; this.request — в read(!observe) и refresh.
Q02, frontend source/packages/Storybook/scripts, команда ниже observe() — 2 строки, обе в resource-query.test.tsx:63,167; production вызовов 0. useScreenSync( — 8 production call lines, 2 test call lines, 1 declaration. Все 8 VM прочитаны целиком: return hook не захватывается.
Q03, frontend source/packages/Storybook, команда ниже tbank-sync — 2 строки JSON snapshot и 1 generated route declaration; runtime call site 0. Литерал sync: "observe" — 1 строка в observationKey. Accepted DTO — 0.
Q04, backend OpenAPI artifact, команда ниже 2 matching lines: GET path и operationId; Accepted DTO отсутствует. Artifact не регенерировался, поэтому свежесть runtime parity — UNVERIFIED; controller/source metadata дополнительно проверены.

Команды выполнены с workdir соответствующего checkout, без cd и записи output-файлов. Exact regex приведены вне таблицы, чтобы Markdown не подменял alternation и не создавал лишние колонки.

# Q01 — backend
rg -n -c 'TbankSyncService|sync\.request\(|normalizeScreen\(|TbankSyncAcceptedDto|discovery\.(read|request|refresh)\(' src test scripts --glob '*.{ts,cjs,mjs}'
# Q02 — frontend
rg -n -c '\.observe\(|\["observe"\]|\[.observe.\]|\buseScreenSync\(' src packages .storybook scripts --glob '*.{ts,tsx,cjs,mjs}' --glob '!**/generated/**' --glob '!**/dist/**'
# Q03 — frontend
rg -n -c 'tbank-sync|TbankSyncAcceptedDto|sync: "observe"' src packages .storybook --glob '!**/dist/**'
# Q04 — backend
rg -n -c 'TbankSyncAcceptedDto|TbankSyncController_status|/api/v1/tbank-sync' openapi.json

Dynamic checks: source search по ModuleRef, reflection/getMetadata, computed request/observe, import()/require, factory/alias DI и cron/timers не выявил alternate entrypoint кандидатов на DELETE. Проверены явные @Injectable, @Module, @Controller, @Get, ApiExtraModels, useExisting и module exports. В backend useFactory используется для logging/auth, TBANK_ACCESS alias — для instruments (instruments.module.ts:24); кандидатов он не dispatch-ит. В frontend dynamic imports представлены явными router chunks; Storybook собирает stories по glob. No-match ограничен этими checkout: неизвестный deployed consumer не исключён.

3.3. Coverage и ограничения выборки

  • Сфокусированы investments synchronization/catalog и frontend consumers, где после перехода архитектуры есть сильные гипотезы с большими closures.
  • Банковские/auth routes проверены на существование root registration; correctness их бизнес-логики здесь не исследовалась.
  • Tests прочитаны как callers и deletion dependencies. Тестовое покрытие проекта, mutation score и качество всех assertions не оценивались.
  • Specs/docs рассматриваются как intended behavior и compatibility context, а не доказательство текущего исполнения. Архивы не являются candidates.
  • Generated/dist, coverage, реальные .env, DB, deployment logs и секреты не служили source call graph; lockfiles/dependency removal вне scope 04.
  • Runtime trace, bundle size, CI minutes, tokens и размер потенциального diff не измерены. Статическая карта не доказывает отсутствие внешних клиентов.

4. Findings

Severity actionable findings отражает текущую engineering cost, а не обещанную экономию. В KEEP/INVESTIGATE Severity обозначает риск ошибочного удаления; эти строки не являются подтверждёнными дефектами и не включены в actionable severity totals. Ни один finding не предлагает исправление в этом аудите.

DEAD-001 — Удалить недоступную manual screen orchestration вместе с closure

  • Decision: DELETE.
  • Severity: P2.
  • Confidence: High.
  • Evidence: backend/src/modules/investments/tbank-sync/tbank-sync.service.ts:41–51,54–311; tbank-sync.controller.ts:31–41; tbank-sync.module.ts:23–25; tbank-sync.repository.ts:62–109,135–169; tbank-screen.ts:8–122; tbank-screen.spec.ts:1–75. Последние пять путей относительны той же backend/src/modules/investments/tbank-sync/.
  • Claim: у request → normalizeScreen → reserve → setImmediate(dispatch) нет production entrypoint; соответственно manual child planner и writer progress поддерживаются без пользовательского сценария.
  • Current mechanism / runtime consumer: service зарегистрирован Nest, но его единственный production consumer — constructor controller, вызывающий status. request не имеет route/scheduler decorator, service не экспортирован TbankSyncModule, reflection dispatcher не найден. normalizeScreen фактически вызывают direct unit tests и недоступный request.
  • Impact / actual cost: лишняя orchestration source owners, ручные reservations, field normalization и отдельный тестовый сценарий; Impact unmeasured. Runtime RPC savings не заявляются: путь уже недоступен.
  • Why now: текущие source entrypoints и specs/openspec/specs/tbank-data-sync/spec.md:9–25 передали обновление hourly owner и запрещают manual commands. Это не предположение только по ADR.
  • Minimum change: удалить request/dispatch, reservations, exclusive DI/imports/constants, repository reserve/progress, normalization и её tests. Сохранить весь status reader и его compatibility types, пока DEAD-006 не решён; сохранить shared source owners и operations planner.
  • Guarantees at risk: access/revision checks внутри живого status, source CAS, hourly lifecycle, shared metadata/portfolio/candle owners. Не удалять эти owners вместе с исключёнными constructor injections.
  • Counterarguments / trade-offs: создание service Nest не равно вызову всех его методов. Возвращение manual sync было бы новым продуктовым решением; restore из Git возможно. Старые screen work могут ещё читаться status: поэтому reader не входит в DELETE.
  • Verification or rollback: после отдельного cleanup — type/DI proof, отсутствие POST command в configured OpenAPI, HTTP status compatibility, существующие local-read/hourly scenarios. Rollback — вернуть code-only closure одним revert; DB/schema не менять.
  • Effort: M.
  • Related finding IDs: DEAD-002, DEAD-006, DEAD-008, DEAD-009, DEAD-011.

DEAD-002 — Удалить недоступный persisted catalog discovery producer

  • Decision: DELETE.
  • Severity: P2.
  • Confidence: High.
  • Evidence: backend/src/modules/investments/instruments/application/catalog-discovery.service.ts:39–64,66–86,143–149,220–227,340–496; instruments/stocks/application/stock-catalog.service.ts:21–31,59–83; instruments/bonds/application/bond-catalog.service.ts:24–34,58–82; instruments/infrastructure/catalog-discovery.repository.ts:341–464; backend/test/tbank-catalog-discovery.e2e-spec.ts:85–118,179–196,231–244,270–299. Три укороченных instruments/ пути относительны backend/src/modules/investments/.
  • Claim: producer request/refresh/drain production-недостижим в текущем graph. После DEAD-001 исчезает даже его единственный caller из недоступной ветки. HTTP sync=observe сохраняет reader, но не включает этот writer.
  • Current mechanism / runtime consumer: ordinary search вызывает onlineSearch; ordinary detail/byTicker выходят через online ветки. Только observe-ветки доходят до read, всегда с true, и потому пропускают if (!observe) request. Единственный caller refresh в production source — недоступный manual dispatcher. Прямые тесты service.read(..., false/default) и service.request(...) реально запускают queue, но не являются HTTP consumers.
  • Impact / actual cost: producer map/queue, forced joins, completions, logger dependency и отдельная persisted discovery publication поддерживают прежнее поколение поведения. Impact unmeasured; это сокращение maintenance, не устранение измеренного fan-out живого online search.
  • Why now: онлайн-входы уже существуют; persisted discovery writer не обслуживает ни их, ни hourly events. Online-only requirement независимо прочитан: specs/openspec/specs/online-instrument-information/spec.md:8–17.
  • Minimum change: после DEAD-001 удалить Producer/state/request/refresh/drain, dead read(!observe) branch и только exclusive repository publish. Сохранить reader read/work, enrichment, normalization/selection и online error projection. Не удалять repository reserve, finish, readSources, publishSource: их использует live CatalogEnrichmentService.
  • Guarantees at risk: shared source writes, CAS/invalid-token isolation, legacy observe read, UID/FIGI identity и candle FK. Schema и данные не входят в эту code-only deletion.
  • Counterarguments / trade-offs: public instruments.api.ts:2 экспортирует provider внутри приложения, а не published npm method contract; backend/package.json:6,11–38 — private application без CLI producer. HTTP compatibility может оправдать persisted reader (DEAD-007), но не writer, которого эти routes не вызывают. Прямые tests доказывают механизм, не пользовательскую reachability.
  • Verification or rollback: переназначить/удалить direct producer-only cases в test/tbank-catalog-discovery.e2e-spec.ts; сохранить проверку живого online selection/whitelist и legacy reader через существующие HTTP suites. Проверить unchanged publishSource/candles на isolated SQLite в cleanup PR. Rollback — code-only revert без DB migration.
  • Effort: M.
  • Related finding IDs: DEAD-001, DEAD-007, DEAD-010, DEAD-011.

DEAD-003 — Удалить orphan TbankSyncAcceptedDto

  • Decision: DELETE.
  • Severity: P3.
  • Confidence: High.
  • Evidence: backend/src/modules/investments/tbank-sync/tbank-sync.dto.ts:212–218; tbank-sync.controller.ts:13–27,34–40; backend/test/openapi-contract.e2e-spec.ts:27–55; frontend/src/shared/api/spec/openapi.json:5102–5123. Controller путь относителен той же backend sync directory.
  • Claim: DTO command acceptance объявлен, но не используется controller, service, ApiExtraModels, scripts или публикуемым snapshot.
  • Current mechanism / runtime consumer: module DTO загружается живым GET, и decorators этой orphan class регистрируют её собственные metadata. Но нет consumer, который включал бы её в response schema или исполнял её validation. Status class — отдельный live consumer investmentScreenSchema.
  • Impact / actual cost: небольшой устаревший export рядом с действующими response DTO; Impact unmeasured. Его наличие может создавать ложное впечатление сохранённой POST capability.
  • Why now: POST отсутствует в actual controller и snapshot; existing contract test явно ожидает отсутствие /api/v1/tbank-sync command route.
  • Minimum change: удалить только class TbankSyncAcceptedDto. InvestmentScreenDto, screen schema, derived DTO и TbankSyncStatusDto остаются нужны public status response.
  • Guarantees at risk: accidental изменение GET schema при избыточном удалении shared schema; сама Accepted class не является опубликованным DTO.
  • Counterarguments / trade-offs: export class и decorators не равны published contract; generator следует зарегистрированным routes. Artifact parity со свежей сборкой здесь не запускалась — UNVERIFIED.
  • Verification or rollback: targeted OpenAPI schema comparison при cleanup; Accepted absent, Status и его discriminator unchanged. Rollback — вернуть class.
  • Effort: S.
  • Related finding IDs: DEAD-001, DEAD-006.

DEAD-004 — Удалить only-test frontend observe API

  • Decision: DELETE.
  • Severity: P3.
  • Confidence: High.
  • Evidence: frontend/src/shared/api/resource-query.ts:69–82,104–127,144; src/shared/api/resource-query.test.tsx:40–71,139–173; src/shared/api/index.ts:12–15; frontend/package.json:2–5; src/features/tbank-connection/model/screen-sync.ts:28–50. Укороченные src/ пути относительны frontend.
  • Claim: observationKey и возвращаемый observe не используются production callers; они поддерживают отдельный transport режим только для direct tests. Удаление frontend callback не означает удаления backend query.
  • Current mechanism / runtime consumer: live useResourceQuery вызывается entity hooks, но observe() — только tests :63,167. Callback вручную переписывает queryKey для transport, cancel/query/select policy; production screen timer вызывает обычный refetch.
  • Impact / actual cost: дополнительный путь cancel/cache replacement и его own tests без UI consumer; Impact unmeasured. Bundle/runtime эффект не измерен, tree-shaking не проверялся.
  • Why now: текущий runtime использует resource GET и refetch; источник attempt state — metadata, а не orchestration notification.
  • Minimum change: убрать observationKey, observe, его return member и exclusive imports (QueryFunctionContext, локальный import session snapshot). Удалить первый observe-only test; race-сценарий :139–173 перенести на живой cancellation/refetch boundary, если он нужен для общей гарантии.
  • Guarantees at risk: не менять useAuthenticatedQuery, invalidateResourceAccess, projected data/meta, canonical query identity, session switching и обычный refetch envelope.
  • Counterarguments / trade-offs: .ai/conventions/data.md:61–63 всё ещё описывает наблюдение, но правило не создаёт отсутствующий production caller. SPA private, feature не public package; dynamic/router/story consumers проверены. Backend sync=observe остаётся доступен внешнему HTTP клиенту; наличие реального такого клиента здесь не подтверждено.
  • Verification or rollback: существующие resource tests :72–138,174–210 и auth/connection boundary tests при cleanup; synthetic MSW, без реальной сети. Rollback — вернуть callback/tests, никакой data migration.
  • Effort: S.
  • Related finding IDs: DEAD-005, DEAD-007, DEAD-011.

DEAD-005 — Сократить unused facade useScreenSync, сохранив live timer

  • Decision: SIMPLIFY.
  • Severity: P3.
  • Confidence: High.
  • Evidence: frontend/src/features/tbank-connection/model/screen-sync.ts:1–18,22–61; screen-sync.test.tsx:21–80 в той же directory; src/pages/accounts/ui/AccountsPage/AccountsPage.vm.ts:21–24; src/pages/account/ui/AccountPage/AccountPage.vm.ts:78–84; src/pages/account-operations/ui/AccountOperationsPage/AccountOperationsPage.vm.ts:96–99; src/pages/account-events/ui/AccountEventsPage/AccountEventsPage.vm.ts:67–75; src/pages/account-income/ui/AccountIncomePage/AccountIncomePage.vm.ts:66–69; src/pages/bonds/ui/BondsPage/BondsPage.vm.ts:12–13; stock/bond VM :45–55. Все src/ пути относительны frontend; полные stock/bond пути перечислены в Ledger C06.
  • Claim: _scope, returned manual refresh/retry/status facade и требуемые только этой facade resource fields не имеют production consumers. Timer :28–35 имеет восемь route-reachable callers и не является dead code.
  • Current mechanism / runtime consumer: все 8 VM вызывают hook как отдельное expression statement. Возвращённые refresh/refreshing/retry/sourceError/ transportError не попадают в VM/view. Scope не читается даже самим hook. Единственные вызовы returned commands — прямые tests :50,78.
  • Impact / actual cost: caller собирает screen descriptor, hook создаёт неиспользуемые commands/status, тип навязывает queryKey/meta/isError/isFetching. Impact unmeasured; allocations/время render не измерены.
  • Why now: hook уже стал периодическим GET reader, но сохранил facade прежней screen orchestration.
  • Minimum change: убрать scope аргумент и все восемь descriptor objects; убрать only-test returned commands/status и exclusive fields/imports. Оставить resourcesRef, актуализацию resources, native interval и cleanup. Перепривязку timer к Query options этот finding не требует.
  • Guarantees at risk: нельзя удалить сам hook вызов: он обеспечивает reread открытого экрана. Нельзя убрать cleanup или обновление resourcesRef: смена route/filter должна читать актуальные queries.
  • Counterarguments / trade-offs: тесты refresh/retry действительно исполняют callbacks, но не делают их доступными пользователю. UX потребность в retry может потребовать нового подключения к view; сейчас такого consumer нет. Таймерная политика живого пути — отдельный audit 02/07 вопрос.
  • Verification or rollback: удалить direct facade-only cases, проверить существующий hook с fake time: reread актуального resource и прекращение после unmount. Page behavior и GET-only boundary сохранить. Rollback — вернуть facade/caller descriptors без изменений данных.
  • Effort: S.
  • Related finding IDs: DEAD-004, DEAD-009.

DEAD-006 — Статусный GET и старые screen: rows требуют compatibility proof

  • Decision: INVESTIGATE.
  • Severity: P2.
  • Confidence: High.
  • Evidence: backend/src/modules/investments/tbank-sync/tbank-sync.controller.ts:21–41; tbank-sync.service.ts:313–391; tbank-sync.repository.ts:111–133; frontend/src/shared/api/spec/openapi.json:5102–5185; backend/test/openapi-contract.e2e-spec.ts:30–55; docs/architecture/http-api.md:46–52. Укороченные sync пути относительны backend sync directory.
  • Claim: GET /api/v1/tbank-sync/{id} локально не вызывается SPA, но зарегистрирован, авторизован и опубликован. Нельзя назвать его confirmed dead или удалить screen reader вместе с недоступным writer. Наличие реальных внешних consumers — UNVERIFIED; High относится к reachability.
  • Current mechanism / runtime consumer: любой авторизованный HTTP consumer может вызвать controller → status. Reader обслуживает screen: intent и source works; access/revision проверяется до и после observation. Старые screen work могли сохраниться от предыдущей версии приложения.
  • Impact / actual cost: retained compatibility несёт reader/types/schema complexity; Impact unmeasured. Ошибочное удаление — breaking response/route.
  • Why now: writer можно удалить отдельно, оставив минимальную проверенную границу совместимости. Deadline поддержки в прочитанных источниках не найден.
  • Minimum change: сейчас не удалять endpoint/reader/derived DTO. Получить список поддерживаемых consumers и решить срок поддержки; затем отдельно согласовать withdrawal route либо поддержку только source status.
  • Guarantees at risk: user/connection ownership, old work observation, stable scope/date discriminator и публичная wire compatibility.
  • Counterarguments / trade-offs: docs говорит, что command/status не текущая AS-IS модель; это подтверждает legacy intent, но не отсутствие live HTTP route и external clients. Отсутствие frontend calls — слабое отрицательное evidence.
  • Verification or rollback: самый дешёвый proof — ответ owner API о consumers плюс существующая обезличенная access-log выборка и aggregate count screen: work из disposable DB copy. Ничего из этого здесь не получено. Rollback будущего изменения — возврат endpoint/schema до destructive migration.
  • Effort: M.
  • Related finding IDs: DEAD-001, DEAD-003, DEAD-007.

DEAD-007 — Backend observe/persisted reference compatibility внешне достижима

  • Decision: INVESTIGATE.
  • Severity: P2.
  • Confidence: High.
  • Evidence: backend/src/modules/investments/instruments/stocks/presentation/stock.controller.ts:58–82,112–144; instruments/bonds/presentation/bond.controller.ts:55–89,102–114; instruments/application/catalog-discovery.service.ts:84–141,168–217,251–293; backend/src/modules/investments/investment-resource.dto.ts:15–24; docs/architecture/http-api.md:50–52; docs/adr/019-hourly-reads-and-online-instrument-reference.md:22–26. Укороченные instruments пути относительны backend/src/modules/investments/.
  • Claim: persisted catalog/detail/ticker read branches являются legacy public contract, а не confirmed dead. Из DELETE old producer не следует DELETE observe readers или shared instrument storage. Нужность долгой поддержки — UNVERIFIED; High относится к подтверждённому механизму.
  • Current mechanism / runtime consumer: query DTO допускает sync=observe; controllers переводят его в boolean, передают catalog services, которые достигают reader branches. Это реальный внешний вход даже без SPA callback.
  • Impact / actual cost: две модели справочного чтения рядом — online и persisted compatibility; Impact unmeasured. API withdrawal требует consumer transition, а blanket data purge рискует candle coverage.
  • Why now: online-only intended behavior уже принят, но compatibility сохранена source/HTTP metadata. Нужно ограничить именно поддержку старого reader, а не удалять shared business/persistence primitives по названию.
  • Minimum change: сохранить текущий wire parameter/reader; отдельно решить endpoint-specific retirement. При подтверждённой ненужности можно перестать направлять reference reads в old branches, затем удалить их closure. Не удалять общую InvestmentReadQueryDto для всех ресурсов автоматически.
  • Guarantees at risk: passive observation, distinction unknown/empty/ ambiguous lookup, account access, precision, persisted calendars и candles.
  • Counterarguments / trade-offs: requirement запрещает долговременную самостоятельную reference copy, но не доказывает безопасность удаления TbankInstrument identity: у неё cascade FK на candles/source rows (backend/prisma/schema.prisma:148–229). Внешние consumers не проверены.
  • Verification or rollback: consumer list + metadata/access logs без реальных API calls; agreed contract transition и isolated DB/FK proof перед любым data removal. Rollback code routing возможен, восстановление данных потребует backup; поэтому data purge сейчас не предложен.
  • Effort: M.
  • Related finding IDs: DEAD-002, DEAD-004, DEAD-006, DEAD-010, DEAD-011.

DEAD-008 — Planner и interval helpers живы через Account Ledger

  • Decision: KEEP.
  • Severity: P2.
  • Confidence: High.
  • Evidence: backend/src/modules/investments/investment-sync-plan.ts:67–140,271–328; operations/application/brokerage-operations.service.ts:16–19,69–85,120–150,203–209; operations/application/brokerage-operations-sync.service.ts:9,106–112; investment-sync-plan.spec.ts:100–134. Укороченные пути относительны backend/src/modules/investments/.
  • Claim: нельзя удалить planInvestmentScreen, accountHistory, ledgerRange или их файл вслед за manual sync: они обслуживают живой Ledger.
  • Current mechanism / runtime consumer: operations controller → read → planner для screen='operations', membership gating и selected interval → sync.readPlan. History/read metadata также вызывает accountHistory; interval helpers используются независимо от dead request.
  • Impact / actual cost: broad screen vocabulary содержит прежние ветки, но ядро живо; Impact unmeasured. Whole-file deletion ломает получение первого отсутствующего интервала, границы времени и history state.
  • Why now: это конкретный counterexample прежней гипотезе «screen planner принадлежит только manual orchestration».
  • Minimum change: сохранить live planner/helpers. После DEAD-001 допустим отдельный узкий reachability pass по вариантам screen, если это стоит усилий; автоматическое удаление всех planner tests недопустимо.
  • Guarantees at risk: account scope, membershipKnown gating, inclusive/ exclusive end, historical boundaries, нерасширение произвольного интервала.
  • Counterarguments / trade-offs: немало branches после removal manual writer станет only-test reachable. Это повод сузить конкретные варианты с equivalence proof, а не удалить финансовые interval rules. В 04 это не generic refactor.
  • Verification or rollback: current ledger HTTP/local-read/interval tests при любом будущем narrowing; сравнить selected intervals, unknown membership, all/account и date-only/instant boundaries. Сейчас deletion отсутствует.
  • Effort: S. Здесь и в других KEEP effort относится к сохранению deletion boundary; narrowing/migration оцениваются отдельно.
  • Related finding IDs: DEAD-001, DEAD-009.

DEAD-009 — Hourly scheduler является runtime owner, а не legacy provider

  • Decision: KEEP.
  • Severity: P2.
  • Confidence: High.
  • Evidence: backend/src/app.module.ts:14,35; src/modules/investments/tbank-sync/tbank-sync.module.ts:24–25; tbank-hourly.scheduler.ts:28–87,119–175; tbank-sync.repository.ts:174–243,245–286; compose.yaml:32–35; specs/openspec/specs/hourly-investment-sync/spec.md:8–40. Укороченные sync пути относительны backend sync directory.
  • Claim: отсутствие HTTP callers tick или прямых тестов не делает scheduler dead; Nest lifecycle запускает его native timer.
  • Current mechanism / runtime consumer: onModuleInit → setInterval(tick) читает connections, резервирует work и через setImmediate запускает owners membership/portfolio/operations/events; onModuleDestroy очищает timer. Метаданные ресурсов читают repository hourly result.
  • Impact / actual cost: runtime coordination необходима для обновления данных при закрытой SPA; Impact unmeasured. Удаление отключило бы normal personal refresh. Корректность lifecycle отдельно не сертифицируется.
  • Why now: whole-folder cleanup tbank-sync/ выглядел бы коротким, но смешивает dead manual writer с current root entrypoint.
  • Minimum change: сохранить scheduler, registration, repository hourly методы и DTO; убирать только manual command closure DEAD-001.
  • Guarantees at risk: запуск без экрана, single-attempt fence, generation, остановка timer, section result visibility и отсутствие catch-up очереди.
  • Counterarguments / trade-offs: наличие lifecycle hook не доказывает правильность всех failure branches. Подозрения на их correctness направлены владельцу audit 13/08, а не использованы для рекомендации DELETE.
  • Verification or rollback: перед cleanup DI/module proof и существующий source-owner behavior; scheduler error/time scenarios — отдельные проверки при изменении его поведения. Сейчас механизм сохраняется.
  • Effort: S.
  • Related finding IDs: DEAD-001, DEAD-005, DEAD-008, DEAD-011.

DEAD-010 — Candle loader и staging не удаляются вместе с manual force caller

  • Decision: KEEP.
  • Severity: P2.
  • Confidence: High.
  • Evidence: backend/src/modules/investments/instruments/application/candle.service.ts:101–124,206–261,264–326; instruments/stocks/application/stock-market.service.ts:54–64; instruments/bonds/application/bond-market.service.ts:58–68; instruments/infrastructure/candle.repository.ts:137–228,257–284; backend/test/tbank-candles-persistence.e2e-spec.ts:117–200,486–501; specs/openspec/specs/tbank-data-sync/spec.md:16–22. Укороченные instruments пути относительны backend/src/modules/investments/.
  • Claim: CandleService.request, queue/stage/publication и coverage runtime-required: read запускает первое получение отсутствующего диапазона.
  • Current mechanism / runtime consumer: GET stock/bond candles → market service → history.read → при отсутствии coverage request → drain/load. Отдельно enrichment.ensureDetail использует shared sources. Manual force — не единственный caller source owner.
  • Impact / actual cost: механизм обеспечивает запрошенный диапазон, точные decimal strings, empty coverage и transactional publication; Impact unmeasured. Удаление owner сделает cold candles недоступными.
  • Why now: соседство с manual request повышает риск удалить весь loader, его source repository или associated tests без проверки hidden read caller.
  • Minimum change: сохранять ordinary request/staging/coverage. Нужность отдельно forced/priority вариантов после DEAD-001 UNVERIFIED: нужен variant-level pass, в этом отчёте whole-loader deletion отвергнута.
  • Guarantees at risk: точность, rollback неполного reconciliation, absence ≠ empty, unchanged coverage вне окна и connection fencing.
  • Counterarguments / trade-offs: часть direct force tests относится к old command variants; это не делает всю suite или transactional primitive legacy. Default method caller в read:121–123 — положительное доказательство жизни.
  • Verification or rollback: при любой variant deletion оставить ordinary period, reopen, exact decimals, closed empty и failed publication cases; isolated SQLite proof, не mock транзакции. Сейчас deletion не требуется.
  • Effort: S.
  • Related finding IDs: DEAD-001, DEAD-002, DEAD-007, DEAD-011.

DEAD-011 — Shared source CAS, identity и FK защищают живые use cases

  • Decision: KEEP.
  • Severity: P1.
  • Confidence: High.
  • Evidence: backend/src/modules/investments/instruments/application/catalog-enrichment.service.ts:64–87,164–225,545–579; instruments/infrastructure/catalog-discovery.repository.ts:154–179,184–249,280–339,466–487; backend/src/modules/investments/upcoming-events/upcoming-events.service.ts:182–239; backend/src/modules/investments/portfolio/application/portfolio.service.ts:264–283; backend/prisma/schema.prisma:148–229,232–262. Укороченные instruments пути относительны backend/src/modules/investments/.
  • Claim: общая CatalogDiscoveryRepository не является legacy repository целиком. reserve/finish/publishSource, attempt/initiator fences и instrument identities остаются runtime-required после removal discovery producer.
  • Current mechanism / runtime consumer: hourly events.refresh → readSources запускает enrichment source work; candles.ensureDetail делает то же для dependency. Enrichment.reserve/drain обращается в shared repository, где transaction проверяет origin и observer attempt до публикации public payload. Live portfolio owner также вызывает metadata.request для своих positions.
  • Impact / actual cost: защита от late/superseded/invalid-token publication и сохранение data relationships; Impact unmeasured. Удаление ради меньшего числа проверок может изменить чужую source revision/timestamp; удаление instrument identity каскадирует source/candle/coverage rows.
  • Why now: это важная граница closure DEAD-002: method publish exclusive старому discovery producer, method publishSource — живому enrichment.
  • Minimum change: сохранять shared owner, registration, transaction/CAS, identity и schema. Code-only deletion может затронуть только exclusive discovery writer publish, а не весь repository или таблицы.
  • Guarantees at risk: connection isolation, conditional publication, invalid-token boundary, identity reuse, candle data и PII-safe projection.
  • Counterarguments / trade-offs: online-only reference requirement не делает DB identity disposable. Название repository и один прежний caller не определяют его реальную область ответственности. Data migration, если потребуется, должна быть совместимой и отдельно доказанной.
  • Verification or rollback: targeted source/candle persistence и late connection-switch proof при cleanup; перед destructive migration — disposable backup/restore и FK проверка. В этом аудите DB не открывалась.
  • Effort: S.
  • Related finding IDs: DEAD-001, DEAD-002, DEAD-004, DEAD-007, DEAD-009, DEAD-010.

5. DELETE / SIMPLIFY / KEEP / INVESTIGATE

Decision IDs Подтверждённая граница
DELETE DEAD-001 Только manual writer/reservation/progress/normalization closure; status и live owners сохраняются.
DELETE DEAD-002 Только persisted discovery producer и exclusive repository publish; shared source repository и observe reader сохраняются.
DELETE DEAD-003 Только Accepted DTO; status screen schema сохраняется.
DELETE DEAD-004 Только frontend observe callback/transport key rewrite; auth/access/refetch и backend API сохраняются.
SIMPLIFY DEAD-005 Scope/returned command facade убрать; timer/current resources/cleanup сохранить.
KEEP DEAD-008 Live Ledger planner, history и interval boundaries.
KEEP DEAD-009 Registered hourly scheduler, durable work и lifecycle.
KEEP DEAD-010 Candle first-range load, staging, rollback и coverage.
KEEP DEAD-011 Shared enrichment repository, CAS, identity/FK и metadata source owner.
INVESTIGATE DEAD-006 Public status GET/old screen rows: consumers/retirement неизвестны.
INVESTIGATE DEAD-007 Public backend observe/persisted reference readers: transition и безопасная data граница неизвестны.

FIX не назначен: correctness живых путей не превращалась в параллельный аудит.

5.1. Special result — Reachability Ledger

confirmed dead означает отсутствие функционального production consumer в проверенном source graph; import metadata registration при этом может исполняться. only-test reachable означает реальный тестовый вызов при отсутствии production entrypoint. External-use неизвестность всегда указана отдельно.

Candidate Reachability evidence: declaration → exports/registration → callers → runtime entrypoints → external accessibility Dynamic/external risks Affected tests/docs/config Minimum safe deletion Rollback Confidence
C01 — TbankSyncService.request/dispatch; confirmed dead; DEAD-001 Declaration backend/src/modules/investments/tbank-sync/tbank-sync.service.ts:54–78; DI tbank-sync.module.ts:24, только class construction → controller calls status:40, command callers 0 → no method decorator/timer → no command route, только GET. Все короткие пути в backend sync directory. DI не auto-dispatch-ит methods; module exports только scheduler. Alternate computed/reflection/script invocation не найден. Normalize tests C02; controller/status DTO остаются; intended boundary specs/openspec/specs/tbank-data-sync/spec.md:9–25. Writer closure, не service целиком. Code-only revert. High
C02 — normalizeScreen, repo screen writers; only-test reachable; DEAD-001 backend/src/modules/investments/tbank-sync/tbank-screen.ts:9–11 export → import в dead service :28,55 → 9 test call lines → no runtime entrypoint → не public HTTP validator текущего GET. Repo reserve:62–109/progress:135–169 callers только request/dispatch. InvestmentScreenDto жив через Swagger/status; нельзя удалить его по association. Helpers не имеют top-level work/timer. tbank-screen.spec.ts:1–75 только manual descriptor behavior; status schema tests сохранить. Helper/test file и exclusive repo methods удалить после C01. Вернуть closure. High
C03 — CatalogDiscoveryService.request/refresh/drain; only-test reachable + dead-parent reachable; DEAD-002 backend/src/modules/investments/instruments/application/catalog-discovery.service.ts:340–496 → provider/API registration instrument-sources.module.ts:18–21, instruments.api.ts:2 → public methods search/detail/byTicker, но online return или observe=true reader → HTTP не попадает в producer; dead manual refresh tbank-sync.service.ts:197. Живые exported provider/HTTP reader не равны live producer. No lifecycle writer hook; setImmediate только внутри недоступного request. Direct service cases backend/test/tbank-catalog-discovery.e2e-spec.ts:85–322; update factory/selection checks, reader compatibility. Producer state/methods + exclusive repo publish, оставить shared reserve/finish/publishSource. Code-only revert, rows/schema untouched. High
C04 — TbankSyncAcceptedDto; confirmed dead export; DEAD-003 backend/src/modules/investments/tbank-sync/tbank-sync.dto.ts:212–218 → export with decorators → 0 consumers/ApiExtraModels → no POST response metadata → отсутствует в обоих известных OpenAPI artifacts. Class decorators исполняются на import, но не создают route. Shared investmentScreenSchema используется Status. Fresh parity не запускалась. backend/test/openapi-contract.e2e-spec.ts:30–55; no Accepted-only test/config consumer. Только orphan class. Вернуть class. High
C05 — frontend observe/observationKey; only-test reachable; DEAD-004 frontend/src/shared/api/resource-query.ts:71,104,144 → hook public index src/shared/api/index.ts:12–15 → tests resource-query.test.tsx:63,167 → production pages используют refetch → private SPA, не public package export. Dynamic router imports и stories не используют callback; backend wire mode остаётся reachable C09. Два observe scenarios; сохранить successful-null/refetch/access tests. Convention data :61–63 — intended old flow, не runtime. Callback/helper/exclusive imports; safe race proof перевести на живой caller при необходимости. Вернуть code/tests. High
C06 — _scope и returned screen facade; live timer / only-test commands; DEAD-005 frontend/src/features/tbank-connection/model/screen-sync.ts:15–22,37–61 → feature index.ts:1 → 8 VM call sites → все calls expression statements в lazy routed pages → callback exposure вне SPA не найден. Удаление всего hook опасно: :28–35 timer жив. Typed resource fields не означают usage после facade removal. screen-sync.test.tsx:22–80 direct commands; all page callers. Только scope/unused commands/status/fields; live effect сохранить. Вернуть facade/call signatures. High
C07 — planInvestmentScreen/accountHistory/ledgerRange; runtime required; DEAD-008 backend/src/modules/investments/investment-sync-plan.ts:67,287,301 exports → operations source imports → brokerage-operations.service.ts:80,120,203, sync service :106 → Account Ledger HTTP → real public read capability. Частично legacy vocabulary не делает файл orphan. No DI требуется чистым exported functions. investment-sync-plan.spec.ts:100–134, interval/ledger cases; historical screen cases отдельно проверить после C01. Whole-file deletion запрещён; variant narrowing требует proof. Not applicable: KEEP. High
C08 — status GET и screen reader; externally reachable/unknown + legacy documented contract; DEAD-006 backend/src/modules/investments/tbank-sync/tbank-sync.service.ts:313–391 → @Get(':id') → controller :40 → guarded HTTP + snapshot frontend/src/shared/api/spec/openapi.json:5102–5185 → любой authorized consumer с work ID. Local SPA calls 0; external consumers/old rows UNVERIFIED. Reflection не нужна: route явный. Status DTO, screen discriminator, repository read/progress types, contract tests, old DB work. Пока deletion запрещён; отдельное compatibility решение. Вернуть route/schema; data не удалять. High reachability
C09 — catalog observe reader branches; externally reachable + legacy documented contract; DEAD-007 backend/src/modules/investments/instruments/application/catalog-discovery.service.ts:84–141,168–217,251–293 → stock/bond catalog services → controller query.sync → runtime HTTP ?sync=observe → snapshot query enum и docs compatibility. External use/retirement UNVERIFIED. Pub DTO decorators и router сохраняют вход без frontend observe. Legacy reference schemas/read tests, shared DTO, persisted data; online requirement online-instrument-information/spec.md:8–17. Сначала consumer transition; не удалить общую storage identity/все query modes. Code routing revert; data restore потребует backup. High reachability
C10 — hourly scheduler; runtime required; DEAD-009 backend/src/modules/investments/tbank-sync/tbank-hourly.scheduler.ts:33–56 → providers/root import → Nest onModuleInit → interval.tick + setImmediate.walk → personal source owners, а не внешняя command API. Lifecycle/reflection registration — positive entrypoint. Env feature switch не найден; single-process deployment compose.yaml:34. Hourly resource DTO/repo + mapper/source tests, hourly spec; scheduler stubs не доказательство смерти. KEEP provider/root import/durable hourly rows. Not applicable: KEEP. High
C11 — candle request/staging; runtime required; DEAD-010 backend/src/modules/investments/instruments/application/candle.service.ts:101–123,206–261 → source module exports → stock/bond market.history.read → controller candle GET → first missing range source work. Dead manual force caller не отменяет ordinary read caller. Variant-level force нужность UNVERIFIED. backend/test/tbank-candles-persistence.e2e-spec.ts:117–200,486–501; candle coverage/decimal tests; shared source/FK. KEEP loader/repository; force variants не удалять без отдельного trace. Not applicable: KEEP. High
C12 — shared source repository/CAS/identity; runtime required; DEAD-011 backend/src/modules/investments/instruments/infrastructure/catalog-discovery.repository.ts:154–179,280–339,466–487 → DI instrument-sources.module.ts:19 → enrichment request/publishSource/finish → hourly events and candle ensureDetail → resource HTTP consumes snapshots. Имя CatalogDiscovery вводит в заблуждение; FK Cascade на instrument → candles/coverage backend/prisma/schema.prisma:199,213,227. Source origin/observer fence — live invariant. Source/candle persistence, calendar consumers, Prisma schema; data purge не выполнялся. KEEP shared repo/CAS/identity; exclusive discovery publish отделим C03. Code rollback; destructive data rollback только backup. High

Полные production call sites C06:

Page Exact path:line-range
Accounts frontend/src/pages/accounts/ui/AccountsPage/AccountsPage.vm.ts:21–24
Account frontend/src/pages/account/ui/AccountPage/AccountPage.vm.ts:78–84
Operations frontend/src/pages/account-operations/ui/AccountOperationsPage/AccountOperationsPage.vm.ts:96–99
Events frontend/src/pages/account-events/ui/AccountEventsPage/AccountEventsPage.vm.ts:67–75
Income frontend/src/pages/account-income/ui/AccountIncomePage/AccountIncomePage.vm.ts:66–69
Bonds frontend/src/pages/bonds/ui/BondsPage/BondsPage.vm.ts:12–13
Stock frontend/src/pages/stock/ui/StockPage/StockPage.vm.ts:45–55
Bond frontend/src/pages/bond/ui/BondPage/BondPage.vm.ts:45–55

5.2. Special result — Deletion Closure Plan

План предназначен для последующей отдельной реализации. В рамках аудита ни один пункт не применён. Это method-level closure, а не whole-folder purge.

Candidate Reachability evidence Dynamic/external risks Affected tests/docs/config Minimum safe deletion Rollback Confidence
C01/C02 / DEAD-001 No request root; normalize/repo writers only under dead writer, Ledger planner live Status route и old screen rows отдельно C08; service/controller DI сохраняются tbank-screen.ts, tbank-screen.spec.ts; service imports/injections/fields; repo reserve/progress; tbank-sync.module.ts reviewed, сохраняет hourly. Existing docs hourly model уже не требует command; archived ADR/spec не менять. Удалить request/dispatch и reservation field; helper/test files; repo screen reserve/progress; exclusive instrument/candle/metadata/portfolio/membership DI service dependencies. Оставить repository/access/operations, runId/startedAt/status и screen intent/progress types reader. Revert только code/test deletion. High
C03 / DEAD-002 HTTP ordinary online; observe reader read(true); refresh only dead C01 Source repository жив и backend observe externally reachable Service imports randomUUID, logger, attempt type, missing-revision constant/state; constructor factory backend/test/tbank-catalog-discovery.e2e-spec.ts:28–35; producer-only cases; source module remains. Online selection/whitelist cases сохранить/перепривязать. Docs online intended model не требует producer; archives retain. Удалить Producer/state/request/refresh/drain и request branch read; удалить только repository publish:341–464. Убрать exclusive logger constructor/import. Не удалять CatalogDiscoveryService provider целиком, shared repository registration, reserve/finish/publishSource/readSources/workMany, catalog selection, online client или schema. Code/test revert; сохранённые reference rows остаются readable. High
C04 / DEAD-003 Declaration only, not in response/ApiExtraModels/artifacts Status shared screen schema остаётся published DTO class only; contract test existing. No script/config exclusive to Accepted найден. Удалить TbankSyncAcceptedDto:212–218; сохранить соседние live classes/imports, которыми они пользуются. Вернуть class. High
C05 / DEAD-004 2 direct tests, no production observe symbol consumer Auth/access effects и server query mode сохраняются Helper/callback/imports/return member; tests :40–71,139–173; frontend data convention old observe paragraph requires owner follow-up, not archive deletion. Feature index useResourceQuery остаётся. Удалить only-test observe path; не удалять resource hook или session snapshot implementation, используемую authenticated-query. Guard/cancellation race проверять через оставшийся live boundary. Вернуть path/tests. High
C06 / DEAD-005 8 callers ignore return, scope unused Live timer — dangerous to remove automatically 8 VM descriptor arguments; screen hook resource type; direct refresh/retry tests; mocked facade frontend/src/pages/account-events/ui/AccountEventsPage/AccountEventsPage.test.tsx:15 пересмотреть по новым exports. Feature barrel остаётся. Убрать scope/facade, narrowing inputs до использованных timer полей; оставить useEffect/ref/interval cleanup. Rename/move/new helper не требуются. Вернуть signature/facade/caller descriptors. High
C08/C09 / DEAD-006/007 Explicit HTTP GET/query registration ОПАСНА автоматическая зачистка: external compatibility и existing rows UNVERIFIED Contract/source DTO/read tests и published frontend artifact; old rows и FK; potential API retirement notice Не удалять до согласованного support/consumer решения. Получить evidence, затем отдельная route/reader closure. Destructive schema/data removal — отдельный совместимый шаг. Restore routing/schema, не полагаться на revert для удалённых данных. High reachability; deletion unverified
C07/C10/C11/C12 / DEAD-008–011 Positive Ledger/lifecycle/candle/enrichment call traces ОПАСНА автоматическая зачистка: live behavior, generation/CAS, rollback и cascade data loss Planner/interval, hourly, source/candle/metadata tests; schema; module registration KEEP; никакой whole-file/whole-folder/schema deletion по совпадению legacy vocabulary. Не требуется без изменения; data migration отдельно. High

Важная closure-граница: убрать injection из TbankSyncService не означает убрать соответствующий provider из TbankModule/PortfolioModule/InstrumentSourcesModule. Наличие status branch и shared repository читается независимо от отсутствия writer. Документальные references закрываются корректировкой текущего описания только при реальном изменении поведения; история ADR/OpenSpec не стирается.

6. Cost & benefit

IDs Ожидаемый класс экономии Фактическое измерение Обязательные регрессии / безопасная граница
DEAD-001/002 Maintenance, cognitive load, navigation/agent context; меньше old producer tests not measured; нет готового diff, baseline CI timings или token профиля Не менять public status/observe, source owners, CAS, hourly/candle/ledger; DI compilation + applicable isolated tests при cleanup. Runtime запросы уже недоступных paths не объявлены экономией.
DEAD-003 Малое сокращение obsolete API surface not measured Status OpenAPI schema unchanged; no whole DTO/schema purge.
DEAD-004/005 Maintenance, test surface, caller descriptors и unused facade not measured Session/access invalidation/refetch/cached envelope; periodic current-resource read и cleanup. Bundle/render выгода не заявлена.
DEAD-006/007 Возможная будущая экономия compatibility maintenance UNVERIFIED / not measured Нужны consumer/retirement proof; shared identity/FK сохраняются.
DEAD-008–011 Предотвращение ошибочного cleanup и регрессий not measured Сохранить финансовые interval/decimal/transaction/generation/lifecycle invariants.

Ponytail-audit shortlist, от крупной closure к малой:

  • delete: manual screen writer/reservation/normalization. Замена: ничего; hourly source owners уже обслуживают текущий сценарий. [backend/src/modules/investments/tbank-sync/tbank-sync.service.ts:54–311]
  • delete: persisted discovery producer и exclusive publish. Замена: существующие online paths; compatibility reader сохранить. [backend/src/modules/investments/instruments/application/catalog-discovery.service.ts:340–496]
  • delete: frontend only-test observe callback/key rewrite. Замена: существующий ordinary refetch. [frontend/src/shared/api/resource-query.ts:69–127]
  • shrink: screen scope/returned facade. Замена: оставить только используемый periodic GET effect. [frontend/src/features/tbank-connection/model/screen-sync.ts:15–61]
  • delete: orphan Accepted DTO. Замена: ничего. [backend/src/modules/investments/tbank-sync/tbank-sync.dto.ts:212–218]

net: сокращение строк not measured, dependencies not assessed (направление 12). Оценка прежнего аудита ~550 не повторяется; ни процент, ни скорость, ни CI minutes из inspection не выводятся.

7. Top actions

Максимум подтверждённых code cleanup actions — пять, а не искусственно десять. Последовательность учитывает dependency closures и цену ошибки.

Quick wins

  1. DEAD-003: удалить одну orphan class; проверить Status schema.
  2. DEAD-004: убрать only-test frontend observe path с сохранением живых resource/auth guarantees и meaningful race boundary.
  3. DEAD-005: удалить unused scope и facade, не удаляя periodic effect; обновить 8 callers и проверить timer current-resource/unmount.

Более крупные closures с тестовым подтверждением

  1. DEAD-001: удалить manual writer плюс normalization/repo writer closure; оставить status compatibility и live DI/source owners.
  2. DEAD-002: после DEAD-001 удалить discovery producer и только exclusive repository publish; перепривязать нужные online/shared-source assertions.

Решения, требующие compatibility/ADR или test proof: DEAD-006/007 не являются подтверждёнными шагами DELETE. API owner должен решить external support до withdrawal route/query semantics. Отдельное ADR оправдано, только если меняется сохранённый public contract/support policy; внутренние dead methods нового ADR сами по себе не требуют. Любая data migration отдельно доказывает FK/restore.

8. Cross-audit signals

Тема Evidence Рекомендуемый audit ID
Timer/refetch policy и disabled queries — живой путь, не DELETE frontend/src/features/tbank-connection/model/screen-sync.ts:28–31; src/pages/bonds/ui/BondsPage/BondsPage.vm.ts:10–13 02 / 07
Old observe convention при новых consumers и documented legacy support frontend/.ai/conventions/data.md:61–63; docs/architecture/http-api.md:50–52 15
Income read сохранил request-driven membership branch; это достижимое поведение backend/src/modules/investments/operations/application/brokerage-operations.service.ts:408–435 07 / 13
Проверка scheduler failure/time lifecycle нужна независимо от cleanup backend/src/modules/investments/tbank-sync/tbank-hourly.scheduler.ts:93–110,178–218 08 / 13
Producer-only tests должны быть пересмотрены по текущему entrypoint backend/test/tbank-catalog-discovery.e2e-spec.ts:85–118,179–196; frontend/src/shared/api/resource-query.test.tsx:139–173 08

Это сигналы владельцам, не отдельные findings этих направлений. Дублирование живых mappers, dependencies, generic VM complexity и архивные docs не аудировались.

9. Open questions / verification plan

Вопрос, меняющий решение Текущее состояние Самый дешёвый proof
Есть ли поддерживаемый consumer GET /tbank-sync/{id}? Local SPA consumers 0; actual external use UNVERIFIED. Owner API/deployment отвечает о clients; существующая обезличенная access-log выборка по route, без запросов к real API.
Нужны ли старые screen: work после перехода? Writer недостижим, reader публичен; сохранённые DB rows не проверялись. Aggregate count/age/scope на disposable копии SQLite + agreed support horizon. Не печатать intent/token/account payloads.
Кто пользуется sync=observe именно у справочных routes? Source/DTO публикуют режим; потребитель может быть вне SPA. Endpoint-specific consumer list/log sample и контрактное решение; не выводить removal всех modes из удаления frontend callback.
Можно ли удалить persisted reference storage целиком? Нет: есть positive live source/metadata reads и cascade candle FK. Отдельная source/FK карта нужных identities и backup/restore proof; сначала code-only producer cleanup.
Какие variants planner/candle force останутся после manual deletion? Owners живы; unused variant removal отдельно UNVERIFIED. После узкого diff пересчитать callers конкретных variants; current Ledger/candle behavior comparison, не whole-file purge.
Пройдут ли cleanup DI/schema/regressions? Изменений приложения нет, tests/build не запускались. В отдельной implementation task сначала targeted owner/HTTP/isolated persistence checks, затем локальные обязательные gates по affected repos.

9.1. Проверка полноты и сохранности результата

  • Проверены 9 общих разделов, полная finding schema для всех 11 IDs, 12 candidate chains, explicit DI/dynamic/public/external checks, Reachability Ledger и Deletion Closure Plan.
  • Финальная consolidation table содержит по одной строке на finding; C01/C02 не удваивают actionable count. KEEP/INVESTIGATE не смешаны с DELETE.
  • Source pointers просмотрены по локальным файлам и строкам; отрицательный поиск дополнен положительными traces/counterexamples, ограничения сохранены.
  • После записи отчёта повторно проверены SHA/status всех пяти checkout и git diff --check; source/config четырёх репозиториев и root tracking чисты. Отчёт проверен отдельно, потому что root .gitignore его игнорирует.
  • Semantic/Boy Scout review ограничен самим report: не добавлены новые helpers, scripts, обязательные workflows или неподтверждённые измерения; source edits отсутствуют. Existing dated audits, archives и references не менялись.

Final machine-readable consolidation table

ID Decision Severity Confidence Repo Files One-line impact Effort Related IDs
DEAD-001 DELETE P2 High backend src/modules/investments/tbank-sync/tbank-sync.service.ts; src/modules/investments/tbank-sync/tbank-screen.ts; src/modules/investments/tbank-sync/tbank-screen.spec.ts; src/modules/investments/tbank-sync/tbank-sync.repository.ts Недоступная manual orchestration и exclusive writer/test closure M DEAD-002,DEAD-006,DEAD-008,DEAD-009,DEAD-011
DEAD-002 DELETE P2 High backend src/modules/investments/instruments/application/catalog-discovery.service.ts; src/modules/investments/instruments/infrastructure/catalog-discovery.repository.ts; test/tbank-catalog-discovery.e2e-spec.ts Producer старого persisted discovery недоступен production; shared readers/writers живы M DEAD-001,DEAD-007,DEAD-010,DEAD-011
DEAD-003 DELETE P3 High backend src/modules/investments/tbank-sync/tbank-sync.dto.ts Orphan Accepted DTO без wire consumer S DEAD-001,DEAD-006
DEAD-004 DELETE P3 High frontend src/shared/api/resource-query.ts; src/shared/api/resource-query.test.tsx Observe callback и key rewrite используются только direct tests S DEAD-005,DEAD-007,DEAD-011
DEAD-005 SIMPLIFY P3 High frontend src/features/tbank-connection/model/screen-sync.ts; src/features/tbank-connection/model/screen-sync.test.tsx; src/pages/accounts/ui/AccountsPage/AccountsPage.vm.ts; src/pages/account/ui/AccountPage/AccountPage.vm.ts; src/pages/account-operations/ui/AccountOperationsPage/AccountOperationsPage.vm.ts; src/pages/account-events/ui/AccountEventsPage/AccountEventsPage.vm.ts; src/pages/account-income/ui/AccountIncomePage/AccountIncomePage.vm.ts; src/pages/bonds/ui/BondsPage/BondsPage.vm.ts; src/pages/stock/ui/StockPage/StockPage.vm.ts; src/pages/bond/ui/BondPage/BondPage.vm.ts Scope/returned facade unused; live periodic GET effect сохранить S DEAD-004,DEAD-009
DEAD-006 INVESTIGATE P2 High backend src/modules/investments/tbank-sync/tbank-sync.controller.ts; src/modules/investments/tbank-sync/tbank-sync.service.ts; src/modules/investments/tbank-sync/tbank-sync.dto.ts Public status GET и old screen rows требуют external compatibility proof M DEAD-001,DEAD-003,DEAD-007
DEAD-007 INVESTIGATE P2 High backend src/modules/investments/instruments/application/catalog-discovery.service.ts; src/modules/investments/investment-resource.dto.ts; src/modules/investments/instruments/stocks/presentation/stock.controller.ts; src/modules/investments/instruments/bonds/presentation/bond.controller.ts Backend observe readers externally reachable; retirement UNVERIFIED M DEAD-002,DEAD-004,DEAD-006,DEAD-010,DEAD-011
DEAD-008 KEEP P2 High backend src/modules/investments/investment-sync-plan.ts; src/modules/investments/operations/application/brokerage-operations.service.ts; src/modules/investments/operations/application/brokerage-operations-sync.service.ts Ledger использует planner/history/interval helpers S DEAD-001,DEAD-009
DEAD-009 KEEP P2 High backend src/modules/investments/tbank-sync/tbank-hourly.scheduler.ts; src/modules/investments/tbank-sync/tbank-sync.module.ts; src/modules/investments/tbank-sync/tbank-sync.repository.ts Nest lifecycle запускает живой hourly owner без frontend S DEAD-001,DEAD-005,DEAD-008,DEAD-011
DEAD-010 KEEP P2 High backend src/modules/investments/instruments/application/candle.service.ts; src/modules/investments/instruments/infrastructure/candle.repository.ts Ordinary candle read требует first-range loader/staging/coverage S DEAD-001,DEAD-002,DEAD-007,DEAD-011
DEAD-011 KEEP P1 High backend src/modules/investments/instruments/infrastructure/catalog-discovery.repository.ts; src/modules/investments/instruments/application/catalog-enrichment.service.ts; prisma/schema.prisma Shared source CAS/identity live; blanket deletion рискует isolation и candle data S DEAD-001,DEAD-002,DEAD-004,DEAD-007,DEAD-009,DEAD-010