`store.removeVariable` walks `doc.children` via `replaceVariableRefsInTree` and rewrites every node that references the deleted variable. That's the right behavior for explicit user removal but the wrong behavior for the orchestrator's seed/rollback dance — those are meant to swap "ambient" palette tokens between briefs WITHOUT touching node structure. If the rollback fired with the user's doc already containing nodes that referenced one of the 7 plan-derived names (carryover from a prior brief, manual ref, etc), the rollback would silently null those refs and break the user's existing colors. Fix: - New `patchDocVariables` applies a name → def|undefined patch via direct setState — bypasses the variable actions and their tree walk. - `seedDocVariablesFromStyleGuide` and the new `rollbackPlanDerivedVariables` helper both use it, so both paths are node-safe. - The 3 inline rollback blocks (catch + Phase 4 throw + Phase 4 abort) now share the helper. Trade-off: seed and rollback no longer push a per-key history entry. They still mark `isDirty: true`, and when the orchestrator runs in animated mode the whole brief is wrapped in a startBatch/endBatch so the variable swap rolls into one undo step regardless. In the non-animated path the swap is a single transaction (one setState) instead of 7 — cleaner. |
||
|---|---|---|
| .. | ||
| public | ||
| server | ||
| src | ||
| CLAUDE.md | ||
| components.json | ||
| dev.ts | ||
| package.json | ||
| tsconfig.json | ||
| vite.config.ts | ||