Skip to content

refactor(intents): выпилить поле title из сущности Intent#242

Merged
gently-whitesnow merged 2 commits into
masterfrom
refactor/drop-intent-title
Jul 10, 2026
Merged

refactor(intents): выпилить поле title из сущности Intent#242
gently-whitesnow merged 2 commits into
masterfrom
refactor/drop-intent-title

Conversation

@gently-whitesnow

@gently-whitesnow gently-whitesnow commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Цель

Удалить мёртвую опциональную фичу title у Intent из всех слоёв: OpenAPI (source of truth), домен, application, API, EF/Infra, фронт и CLI-skill. Инвариант «card-linked intent обязан иметь title» уже снят (ADR-0052); поле ни на что существенное не завязано.

Существенные изменения

  • OpenAPI specs/contracts/intents/openapi.yaml: удалён endpoint PUT /api/v1/intents/{id}/title (+ его 422), поле title из CreateIntentRequest/IntentDetailDto/IntentListItemDto, схема SetIntentTitleRequest. Контракты C#/TS перегенерированы (nswag + openapi-typescript) — генерируемые файлы руками не правились.
  • Domain: убраны Intent.SetTitle/NormalizeTitle, параметр title у Create/Restore, поле IntentState.Title.
  • Application: удалены SetIntentTitleHandler, SetIntentTitleOutcome, IIntentRepository.SetTitleAsync, DI-регистрация; Title убран из CreateIntentCommand; удалено событие IntentTitleChanged (нигде не проецировалось в realtime).
  • API: удалены SetIntentTitleEndpoint и его wiring; Title убран из IntentDtoMapper и CreateIntentEndpoint.
  • Infra/EF: убран IntentRow.Title + маппинг/конфиг/мьютатор.
  • Terminals: убран проброс intent.State.Title в workspace-map промпт спавна (WorkspaceMapPrompt/RunPreflightSpawn/RunPreflightPromptDelivery/RunPreflightOrchestrator) — строка «Заголовок интента:» из карты workspace убрана.
  • Frontend: удалена фича features/set-intent-title; шапка IntentDetailHeader показывает сниппет текста; поправлены use-board-rows и AddLinkForm.
  • Skill skills/intent/bin/throne-intent: убраны подкоманда set-title и флаг --title у create; обновлён SKILL.md.

БД / поиск (решение уточнено в ходе ревью)

Изначально договаривались оставить orphan-колонку без миграции. По требованию «код приложения не должен знать про title никакими косвенными способами» решение пересмотрено: пока колонка оставалась в FTS, поиск позиционно завязан на неё (snippet индекс 2, bm25-вес title-слота).

  • Новая миграция DropIntentTitle: дропает FTS-триггеры и intents_fts, ALTER TABLE intents DROP COLUMN title, пересоздаёт intents_fts как (intent_id UNINDEXED, text) с триггерами без title, репопулирует из intents.text. Триггеры дропаются до колонки (иначе SQLite блокирует DROP COLUMN). Down полностью обратим.
  • EfIntentSearchReader: snippet(intents_fts, 1, …), bm25(intents_fts) без весов — text теперь единственная индексируемая колонка. Упоминаний title в коде поиска не осталось.

Отброшено

  • «Только код, без миграции» (ограничить MATCH колонкой text + обнулить bm25-вес): убирает поведение, но snippet-индекс и слот веса структурно всё равно кодируют фантомную колонку — не полная чистка.
  • Правка EfIntentContextReader.o.Title — это board title (счётчики досок), к intent.title отношения не имеет.

Ограничения

  • Миграция необратимо стирает legacy-значения intents.title из БД (заголовки больше не хранятся нигде).
  • Проза ADR-0050/0052 про title не правилась.

Проверка

  • Backend apps/api: dotnet build 0/0; dotnet test1225 passed, 0 failed. Миграция применяется на живой SQLite через MigrateAsync (в т.ч. EfSqliteRuntimeRegressionTests, EfIntentSearchTests) без ошибок.
  • Frontend apps/web: pnpm codegen + pnpm typecheck чисто; pnpm test259 passed. В generated intents/{types,endpoints}.ts нет title/setIntentTitle.

Удаляет мёртвую опциональную фичу title у Intent из всех слоёв: OpenAPI
(source of truth), домен, application, API, EF/Infra, фронт и CLI-skill.
Инвариант «card-linked intent обязан иметь title» уже снят (ADR-0052);
поле ни на что существенное не завязано.

Решения:
- БД без новой миграции: колонки intents.title и intents_fts.title
  остаются orphan (приложение перестаёт их писать/читать). Миграции
  AddIntentTitle/IntentSearchIndex не тронуты; ThroneDbContextModelSnapshot
  приведён к модели (убран Title у IntentRow) — HasPendingModelChanges даёт
  false, старт/ef не падает.
- Контракты C#/TS перегенерированы nswag + openapi-typescript из
  правленого openapi.yaml; генерируемые файлы руками не редактировались.
- Убрано и то, чего не было в исходном плане, но что тянуло title:
  событие IntentTitleChanged (нигде не проецировалось в realtime) и
  проброс intent.State.Title через workspace-map промпт спавна терминала
  (WorkspaceMapPrompt/RunPreflightSpawn/PromptDelivery/Orchestrator) —
  строка «Заголовок интента:» в карте workspace убрана.

Отброшено:
- Полная чистка FTS5-схемы (drop колонки title в intents_fts): потребовала
  бы миграции, которая по решению не делается. bm25-веса в
  EfIntentSearchReader оставлены как есть — поиск по телу не ломается.
- Правка EfIntentContextReader: тамошний o.Title — это board title
  (счётчики досок), к intent.title отношения не имеет; не трогалось.
- Data-миграция для очистки существующих значений: не нужна.

Ограничения:
- Колонки title в intents и intents_fts остаются в БД навсегда пустыми.
- ADR-0050/0052 упоминают title в прозе — текст ADR не правился (схему БД
  менять нельзя, правка прозы опциональна).
Ревизия прежнего решения «orphan-колонку не трогаем»: по требованию код
приложения не должен знать про title никакими косвенными способами.
Пока колонка оставалась в FTS, поиск позиционно завязан на неё
(snippet индекс 2, bm25-вес title-слота) — это и убираем.

Решения:
- Новая EF-миграция DropIntentTitle: дропает FTS-триггеры и intents_fts,
  выполняет ALTER TABLE intents DROP COLUMN title, пересоздаёт intents_fts
  как (intent_id UNINDEXED, text) с триггерами без title и репопулирует из
  intents.text. Триггеры дропаются до колонки, иначе SQLite не даёт
  DROP COLUMN. Down полностью обратим (возвращает колонку и старый FTS).
- EfIntentSearchReader: snippet(intents_fts, 1, …), bm25(intents_fts) без
  весов — text теперь единственная индексируемая колонка (позиция 1).
  Никаких упоминаний title в коде поиска не осталось.
- ModelSnapshot/Designer сгенерированы EF; IntentRow без Title.

Отброшено:
- Вариант «только код, без миграции» (ограничить MATCH колонкой text,
  обнулить bm25-вес): убирает поведение, но snippet-индекс и слот веса
  структурно всё равно кодируют фантомную колонку — не полная чистка.

Ограничения:
- Миграция необратимо стирает legacy-значения title из БД (данные о
  заголовках больше не хранятся нигде).
@gently-whitesnow
gently-whitesnow merged commit 48d7fc6 into master Jul 10, 2026
1 check passed
@gently-whitesnow
gently-whitesnow deleted the refactor/drop-intent-title branch July 10, 2026 09:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant