# Аудит 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 и не создавал лишние колонки. ```sh # 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 с тестовым подтверждением 4. **DEAD-001:** удалить manual writer плюс normalization/repo writer closure; оставить status compatibility и live DI/source owners. 5. **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 |