v0.28.0
Greenfield builds work end-to-end, unattended.
Two fixes that together let the planner build a fresh app from create_file directives without a human rescuing it — the last two blockers a clean-machine UAT hit.
The dependency-add escape hatch is no longer fatal to execute
The planner is grounded on package.json and its own prompt tells it: if it needs an undeclared package, emit an explicit dependency-add step (an npm install run_command, or a package.json edit) in the same plan. The quality gate honours that. And then exec rolled the plan back for it.
Both of exec's scope guards — the final one and the per-step one inside runApplyTool — built their expected-file set from step.target || step.path, and a run_command step has NEITHER. So the package.json and package-lock.json an install writes landed in unexpectedFiles → scope violation / exec.diverged → the whole plan rolled back. A planner that obeyed its instructions was punished for it, and a greenfield build burned two identical retries on turn one.
There is now ONE exported exemption rule, consumed by BOTH guards (three copies of the set-difference existed and two disagreed — the per-step guard silently never exempted what the final guard did). It exempts the manifest/lockfile writes ONLY when the plan genuinely declares a dependency-add step — keyed on the plan step, never the filename, so a plan cannot smuggle a package.json rewrite past the guard by touching the file.
The mirror-image bug is fixed too: a plan that "installs" a package package.json ALREADY declares is now flagged (redundant_dependency_add) rather than left to rewrite the manifest and trip the guard.
And the advice stopped lying. On an import-not-declared failure the gate returned a hardcoded [decompose, use_search_replace] — neither of which can declare a dependency — while the check had already computed the right remedy (ground_imports) and thrown it away. Suggestions are now derived from the failing check and travel through to the Build Governor, which reads them.
The React SPA template no longer ships a landmine
The app.web.react.spa scaffold shipped no App.test.tsx, so the planner wrote the route test freehand: screen.getByText(/about/i). That throws "Found multiple elements" the instant a nav <Link to="/about">About</Link> coexists with the page <h1>About</h1> — which the About page's own copy tells you to create. The first story built on the stack that added a page hit it.
The scaffold now ships a correct, nav-collision-safe App.test.tsx that scopes route-name assertions to a unique element (getByRole("heading", { name })) and carries the rule as guidance — so it is both the fix and the exemplar the planner had nothing to copy from. And @testing-library/user-event is now in the scaffold's devDependencies (the standard companion to @testing-library/react, which every interaction test needs).