apply_repair's preflight raises PreflightError when the graph it is about
to write would fail at Graph.init. Every handler caught it as a plain
ValueError, so the five apply sites could not tell it apart from a
graph_ops rejection:
- plan approval (Build, Edit) called ANY ValueError "The workflow can't
start", including "node not found: x", sending the user hunting for a
broken node that does not exist;
- the repair-apply gates (Build/Edit await_repair, Fix apply) called a
preflight rejection "The proposed fix no longer applies to the current
draft" -- the fix applied fine; it would leave an unstartable draft.
Add core DraftWouldNotStartError(ValueError) and make PreflightError
subclass it (services imports core; core still imports no services).
Each site now catches it before the ValueError branch, with the same
control flow and the true reason: plan approval keeps "The workflow
can't start" for it and says "Couldn't apply the workflow" otherwise;
the repair gates say "The workflow can't start" for it and keep
"Couldn't apply the fix" otherwise. The shared card/turn construction is
factored (_graph_not_applied, _change_not_applied, and
drop_unapplied_repair in handlers_fix) and the new literals are
catalogued in strings.py.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>