fix(toolintent): manifest gate defers to task affected_paths; scaffold-glob guidance

Two failed web-ui freestyle runs dead-ended on the write manifest. The
scaffold_frontend stage declared writes=[frontend/package.json,
frontend/vite.config.ts], so every other file the scaffold produced
(tsconfig, src/main.tsx, index.html, App.tsx) was BLOCKED as
PATH_OUTSIDE_MANIFEST with no agent-facing escape hatch — unlike WRITE_SCOPE,
which advertises task_update. Retry exhausted -> WorkflowFailed.

- ManifestContainmentRule: a write already inside the active task's
  affected_paths is allowed even when the stage manifest is narrower. The
  task scope is the agent-widenable, recorded authority (see WriteScopeRule);
  the stage manifest is a planner hint that defers to it. Block message now
  names the remedy (widen affected_paths via task_update).
- architect_freestyle prompt: a scaffold/generator stage must declare its
  `writes` as a covering directory glob (frontend/**), not enumerate files,
  and use ** not * — frontend/* does not cover frontend/src/main.tsx.

core:toolintent green (78 tests), detekt clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 17:32:48 +04:00
parent 68c56b6af6
commit 0a001c42c7
3 changed files with 73 additions and 17 deletions
@@ -103,7 +103,12 @@ Emit a JSON object that validates against the `execution_plan` schema:
always pass the template/preset arg the generator requires (`-- --template react-ts`) since
there's no prompt to fall back on. `file_write` is the fallback when no generator fits the
stack. Only bare remote runners (`npx`, `bunx`, `pnpx`) stay blocked — they execute arbitrary
remote code; reach them via `npm create` instead.
remote code; reach them via `npm create` instead. A scaffold/generator stage emits an
open-ended file set (a whole `frontend/src/**` tree, not two named files), so declare its
`writes` as the covering directory glob — `["frontend/**"]`, **not** an enumerated
`["frontend/package.json", "frontend/vite.config.ts"]`. A too-narrow `writes` becomes the
stage's write manifest and blocks every file the generator legitimately produces. Use `**`
(recursive), not `*` (one level) — `frontend/*` does not cover `frontend/src/main.tsx`.
- **Every stage prompt must describe its exact JSON output structure when using a
structured kind.** The model that runs the stage never sees the raw JSON schema — it only sees
the kind's name (e.g. `analysis`, `research_report`, `review_report`) and the prompt you write