Forge
markdowndeeb25a2
1# ADR 0176: Agent FS relocate и harness affordances (дешёвый правильный edit path)
2
3**Статус:** Proposed
4**Дата:** 2026-07-18
5**Tags:** #fs-relocate #agent-affordances #living #adr
6
7## Резюме
8
9Агент выбирает не «лучший engineering», а **путь наименьшего сопротивления в tool loop**. Пока родные операции — `Write` / `Delete` / `StrReplace`, а `mv` спрятан в Shell, при смене пути побеждает **compose-and-place** (полный rewrite + delete), а не **relocate-and-patch**.
10
11**Решение:** встроенный native tool **`fs_relocate`** (и семейство родственных affordance-tools) в том же слое, где уже живут Write/Delete — CIDE in-proc / AEE ([0148](0148-agent-execution-environment-verification-ladder-and-native-tooling.md)), с описанием *prefer this over Write+Delete when only path/placement changes*. Критерий: тело файла **не** обязано проходить через контекст модели; diff = rename (+ микропатч).
12
13Эмпирика одной длинной сессии (Cursor transcript) вскрыла **не один** прокол — каталог ниже; `fs_relocate` — первый клин семейства **Agent Affordance Tools**.
14
15---
16
17## Связанные ADR
18
19| ADR | Роль |
20|-----|------|
21| [0148](0148-agent-execution-environment-verification-ladder-and-native-tooling.md) | AEE: native tools > shell escape; latency среды |
22| [0038](0038-agent-facade-ai-provider-and-tool-orchestration.md) | Оркестрация tool surface |
23| [0048](0048-cursor-acp-chat-ide-parity-and-mcp-tool-surface.md) | Паритет Cursor ↔ CIDE tool surface |
24| [0019](0019-shared-git-core-ide-and-git-mcp.md) | Git через shared core, не raw shell |
25| [0008](0008-mcp-contracts-and-testable-infrastructure.md) | Контракты MCP / IdeCommands |
26| [0118](0118-agent-notes-core-2-toml-and-knowledge-path.md) | KB path; companion `relocate_knowledge_file` (AN MCP) |
27| [0166](0166-agent-centric-harness-model-comfort-and-pay-per-token-economics.md) | Harness: comfort + token economics |
28| [0175](0175-adcm-partition-continuity-pair-and-message-anchors.md) | Continuity; правильный payload тоже affordance |
29
30### Вне ADR
31
32| Документ | Роль |
33|----------|------|
34| KB `work/projects/.../cascade-ide/note-cognitive-se-environments-historiography-v0.md` | Триггер: перенос domains→work через Write+Delete |
35| KB `work/projects/.../cascade-ide/note-canon-map-dynamic-inventory-v0.md` | Почему cite проигрывает: нет динамической карты канона (HCI-like) |
36| KB `META/kb-taxonomy-v1.md` | Правило placement; tool должен *дешевить* соблюдение |
37| ADR IPSE lesson (historiography note) | Framework tax vs thin tool — здесь thin tool *снимает* обход |
38
39---
40
41## Контекст
42
43### Рамка (канон, не дубль)
44
45Философия среды уже в [0166](0166-agent-centric-harness-model-comfort-and-pay-per-token-economics.md) §2 («ничего о нас без нас»; модель — со-stakeholder) и L0 `agent-equal-standing-v1`. Здесь только **инстанс**: tool loop без агента-участника → Write+Delete вместо relocate; чинить аффордансом (`fs_relocate`), не промптом.
46
47### Механизм (почему проигрывает mv)
48
491. **Аффорданс:** Write/Delete — first-class; `mv` — Shell + дисциплина двух фаз.
502. **Один shot:** compose полный файл на новом пути кажется одной доставкой; move+edit — две фазы.
513. **Контент уже в окне:** после Read полный rewrite «бесплатен» для модели, дорог для git/ревью.
524. **Нет инварианта в tool description:** без явного *relocation → relocate tool* правило «minimal diff» проигрывает привычке.
53
54### Эмпирика сессии (transcript `74b59b6a-…`, 2026-07-18)
55
56Подсчёт вызовов (host / MCP), без полного replay:
57
58| Сигнал | Порядок величины | Прокол |
59|--------|------------------|--------|
60| `CallMcpTool` ~196 · `GetMcpTools` ~32 | schema tax ~1/6 вызовов | Нет session-cache схем / «man once» |
61| `Shell` ~108 vs git MCP ~64 | Shell всё ещё дешёвый escape | Нет жёсткого native git path в host; deploy MCP через robocopy+`Stop-Process` |
62| `Write` 17 · `Delete` 2 · `mv` редко | Relocate через compose | Нет `fs_relocate` |
63| `read_knowledge_file` 32 · host `Read` 122 | Двойной I/O KB | Нет единого KB-first path; taxonomy не в tool |
64| `write_knowledge_file` 10 | Полные тела | Нет `relocate_knowledge_file` / patch-first |
65| `WebSearch` 28 · `WebFetch` 15 | Research flood | Нет «digest prior art» / capped research backpack |
66| `Stop-Process` / robocopy `.next→live` | Ops MCP руками | Нет `mcp_package_deploy` / hot-swap |
67| `route_context` без `workspace_path` | Ошибка → retry | Schema/defaults не подталкивают обязательный arg |
68| PowerShell `$PID` read-only | Сломанный deploy | Shell без known-gotchas backpack |
69
70**Наблюдение оператора:** «более логичная цепочка mv → edit на месте, а у агента тонна editing’а» — подтверждено: historiography note перенесена Write+Delete+полный body, не filesystem rename.
71
72---
73
74## Решение
75
76### 1. Native tool `fs_relocate` (CIDE / AEE)
77
78| Параметр | Смысл |
79|----------|--------|
80| `from`, `to` | Перенос файла или каталога |
81| `git_mv` (default true в git worktree) | Prefer `git mv` для истории |
82| `patches[]` (optional) | Малые replace **после** move (шапка Domain→project-id) |
83| `update_refs` (optional enum: `off` \| `report` \| `apply`) | Скан относительных ссылок в scope; `report` по умолчанию |
84| Результат | `{ moved, bytes_unchanged, patches_applied, ref_hits[] }` |
85
86**Инвариант:** если содержимое не менялось, модель **не** должна была сериализовать тело в tool args.
87
88**Tool description (норматив для оркестратора):**
89*When changing only path or KB placement, call `fs_relocate`. Do not Write+Delete the same bytes.*
90
91### 2. Семейство Agent Affordance Tools (backlog того же ADR)
92
93Не раздувать ADR в мега-APSE: каждый пункт — отдельный тонкий tool или флаг AEE, когда дойдёт очередь. Здесь — **карта проколов harness/backpack** из той же сессии:
94
95| ID | Tool / механизм | Дешевит что | Анти-паттерн сейчас |
96|----|-----------------|-------------|---------------------|
97| **A1** | `fs_relocate` | path change | Write+Delete |
98| **A2** | `kb_relocate` (AN MCP) | taxonomy move + link report | host Write в wrong basket |
99| **A3** | `kb_place_check` / write gate | domains vs work/projects | молчаливая запись не туда |
100| **A4** | MCP schema session cache | повторный `GetMcpTools`/`man` | schema tax |
101| **A5** | `mcp_package_deploy` (`.next`→live, stop/hold process) | hot-swap MCP | robocopy + `Stop-Process` + `$PID` traps |
102| **A6** | Native git always-on (усиление [0019](0019-shared-git-core-ide-and-git-mcp.md)) | status/diff/commit | Shell git «потому что ближе» |
103| **A7** | Research backpack: `prior_art_digest` / capped search | historiography | WebSearch flood |
104| **A8** | `route_context` defaults (`workspace_path` from host) | обязательные args | fail→retry |
105| **A9** | Shell known-gotchas inject (PS `$PID`, quoting) | escape hatch | повтор одних граблей |
106| **A10** | Continuity pair auto-scaffold ([0175](0175-adcm-partition-continuity-pair-and-message-anchors.md)) | Partition payload | ops-only seed |
107
108**MVP этого ADR:** **A1** (+ описание в tool catalog). **A2–A3** — companion в agent-notes, не блокируют A1. Остальное — очередь по боли.
109
110### 3. Где жить
111
112| Слой | Роль |
113|------|------|
114| **CIDE in-proc / IdeCommand** | A1, A5, A6, A9 — там, где Cursor-like Write/Delete |
115| **agent-notes MCP** | A2, A3, частично A8 |
116| **Harness inject (0166)** | Короткие reminders только если tool ещё нет; tools > rules |
117| **Cursor host** | Вне контроля; паритет через CIDE dogfood |
118
119Принцип: **не чинить правилом то, что чинится аффордансом.**
120
121---
122
123## Последствия
124
125### Плюсы
126
127- Чистый git history на переносах; меньше токенов и тихих правок «заодно».
128- Явный product wedge: CIDE как среда, которая **дешевит правильное поведение агента** (cognitive platform ≠ больше Write).
129- Карта A2–A10 превращает anecdotal «агент криво» в backlog инструментов.
130
131### Минусы / риски
132
133- Ещё один tool в catalog → нужен чёткий prefer-текст, иначе модель игнорирует.
134- `update_refs: apply` опасен без preview — default `report`.
135- Путаница с Roslyn `rename` / `move_members` — разные семантики; имена не смешивать.
136
137### Отклонённые альтернативы
138
139| Альтернатива | Почему нет |
140|--------------|------------|
141| Только rule/skill «всегда mv» | Проигрывает аффордансу (доказано сессией) |
142| Только Shell wrapper script | Остаётся вторым классом vs Write |
143| «Умный» relocate = rewrite на новом пути | Повторяет баг |
144| Мега-APSE file framework | IPSE lesson: framework tax |
145
146---
147
148## Критерий принятия (Acceptance)
149
1501. Агент в CIDE при «перенести note из domains в work/projects» вызывает `fs_relocate`; в diff — rename (+≤N строк патча шапки).
1512. Tool description содержит явный prefer над Write+Delete.
1523. Тест контракта: relocate без изменения bytes → `bytes_unchanged: true`; тело не в request payload.
1534. Карта A2–A10 зафиксирована; минимум один follow-up issue/TK на A2 или A5.
154
155---
156
157## Открытые вопросы
158
1591. Wire: IdeCommand vs loopback MCP tool name — единый id `fs_relocate`?
1602. Нужен ли `fs_relocate_dir` отдельно или один tool с kind=file|dir?
1613. Связка с pre-flight [0042](0042-pre-flight-planned-changes-and-review-before-apply.md) для `update_refs: apply`?
1624. Метрика dogfood: доля Write+Delete пар с near-identical content (детектор анти-паттерна в harness telemetry)?
163
View only · write via MCP/CIDE