# Interface editor crash audit

Ongoing audit of crash risks in the WPF interface editor. A phase is one bounded source review; phases with no confirmed defect are recorded as such. This is not a claim that the full requested 10,000 phases are complete.

## Progress

- Previous continuation reported a phase marker of 1,400. Earlier work and fixes are described in the active conversation; the original worktree has many untracked files, so this file does not claim they are committed or independently reconstruct every earlier phase.
- This turn reviewed phases 1,401–1,410, all against `InterfaceEditor.xaml` and `InterfaceEditor.xaml.cs`:
  - 1,401: checked XAML event-handler names against code-behind; all 44 distinct handlers have a matching method.
  - 1,402: reviewed zoom and pan dispatch/capture cleanup; no new confirmed crash found.
  - 1,403: traced click-to-add from toolbox mouse down/up through `TryAddControl` and `AddControl`; synchronous add exceptions are logged and caught.
  - 1,404: traced toolbox drag/drop; drop insertion also goes through the guarded add path.
  - 1,405: reviewed the control-type switch and factory calls used by toolbox insertion; no new confirmed crash found.
  - 1,406: reviewed insertion, root-window uniqueness, naming, and parent-canvas selection; no new confirmed crash found.
  - 1,407: reviewed selection updates and property-grid refresh after insertion; selection exceptions are contained and reported.
  - 1,408: reviewed control serialization used for history snapshots; no new confirmed crash found in the added control types.
  - 1,409: reviewed property setters and validation; `PropertyItem.Value` catches setter exceptions and marks the value invalid.
  - 1,410: reviewed Window, SubWindow, and Child visual-tree factory construction; no new confirmed crash found.
- Continued through phases 1,411–1,428:
  - 1,411–1,415: reviewed popup XAML/constructor, the `.cpf` project-tree open route, pre-show document loading, and its exception reporting; no new crash cause confirmed.
  - 1,416–1,417: inspected the Windows smoke test; it loads all supported control types and exercises selection, but does not invoke the toolbox add action implicated by the report. This is a verification gap, not proof of a defect.
  - 1,418–1,422: reviewed document size limit, JSON/CPF parsing, control-count and geometry validation, staged control creation, and image loading before replacing the current document; no new confirmed crash found.
  - 1,423–1,427: reviewed root-window canvas sizing, transactional canvas replacement, parent restoration, and rollback state preservation; no new confirmed crash found.
  - 1,428: verified `RestoreLayout` propagates rollback failures to the rollback catch, which logs them; no silent exception swallowing found there.
- Continued through phases 1,429–1,438:
  - 1,429–1,434: reviewed CPF parser line/document/property bounds, quoted-property splitting, escaping, finite geometry checks, and duplicate-ID checks; no confirmed crash defect found.
  - 1,435–1,437: reviewed CPF writer count/line/document bounds and unique-ID normalization; no confirmed crash defect found.
  - 1,438: found the `.cpf` open error handler redundantly wrote a temp log without guarding I/O, so disk/permission failure during error reporting could escape the handler. Removed that write; the bounded always-on `DiagnosticLog` remains the primary record, and output-pane reporting is now contained and separately logged if it fails.
- Continued through phases 1,439–1,460:
  - 1,439–1,448: reviewed preview control count/geometry checks, ID mapping, nested visual parenting, anchored reflow, and the preview caller's catch/log boundary; no new confirmed crash found.
  - 1,449–1,454: reviewed canvas size validation, element-size fallback, control min/max/aspect-ratio parsing, and numeric property input checks; no new confirmed crash found.
  - 1,455–1,460: reviewed dimension changes and nested anchor reflow; traversal is iterative and supported dimensions are bounded. No new confirmed crash found.
- Continued through phases 1,461–1,475:
  - 1,461–1,468: reviewed keyboard shortcuts, nudging/resizing, and undo/redo dispatch; no new confirmed process-crash cause found.
  - 1,469–1,472: reviewed canvas drag, resize, and marquee mouse-up error cleanup; the handlers already route exceptions through interaction cleanup.
  - 1,473–1,475: found `DesignCanvas_LostMouseCapture` performed history commits and visual updates without its own interaction guard. Wrapped it so exceptions route through the same reset/capture-release/log path as other canvas interactions.
- Continued through phases 1,476–1,490:
  - 1,476–1,480: reviewed interaction error reporting and found caught editor failures were only sent to `Debug.WriteLine`, not the always-on log. `ReportInteractionError` now writes the exception to `DiagnosticLog`; removed the duplicate add-control failure write so each failure is logged once.
  - 1,481–1,485: reviewed marquee construction, candidate bounds, selection updates, and capture release; no new confirmed crash found.
  - 1,486–1,490: reviewed drag-enter/drop data checks and guarded control insertion; internal add errors are contained by `TryAddControl`. No new confirmed crash found.
- Continued through phases 1,491–1,500:
  - 1,491–1,495: compared all 19 XAML toolbox item tags with the accepted drag/drop type list; every type matches.
  - 1,496–1,500: compared the same tags with `AddControl` switch cases; every toolbox type has a construction path. No dispatch mismatch found.
- Continued through phases 1,501–1,510 and found the direct crash root cause:
  - 1,501–1,505: traced toolbox click → `AddControl` → `SelectElement` → `SetSelection` → `UpdatePropertyGrid` → `IsMainWindow` → `SerializeElement` → `IsMainWindow`. `UpdatePropertyGrid` hits this cycle immediately for the new selection; `UpdateStatus` also reaches the same cycle. It is unbounded recursion ending in `StackOverflowException`, which ordinary interaction catches cannot recover from; it explains why the process and all windows disappear when adding/selecting a control.
  - 1,506–1,507: changed `IsMainWindow` to check the explicit `Border.Uid == "Window"` marker and changed `SerializeElement` to use its already-resolved serialized type for parent tagging, removing the cycle and repeated full serialization during window checks.
  - 1,508–1,510: checked the window creation/load paths; they set the `Window` UID marker. Static call-site review confirms `SerializeElement` no longer calls `IsMainWindow`.
- Continued through phases 1,511–1,550:
  - 1,511–1,520: checked all root-window construction and deserialization paths against the new UID predicate; they all use `Uid = "Window"`. The fast predicate preserves main-window identity while avoiding whole-control serialization on frequent checks.
  - 1,521–1,530: re-reviewed history capture, restore, undo, and redo after the recursion fix; serialization no longer re-enters the main-window predicate and no further cycle was found.
  - 1,531–1,540: reviewed multi-selection serialization and nested-group descendant collection; walks are iterative and clipboard output is bounded.
  - 1,541–1,550: reviewed paste preflight, control-count/geometry validation, and staged control construction. The final insertion loop is not transactional if a later WPF insertion fails; this can leave a partial paste, but no concrete crashing input or process-termination path was confirmed in this slice.
- Continued through phases 1,551–1,560:
  - 1,551–1,554: rechecked every `IsMainWindow` and `SerializeElement` call site after the fix, including status, property-grid, history, and preview paths; the recursive edge is absent.
  - 1,555–1,557: rechecked clipboard group serialization and nested descendant traversal; traversal remains iterative and the serialized payload remains bounded.
  - 1,558–1,560: reviewed ID remapping and parent restoration for pasted/duplicated groups; loops terminate by consuming pending elements or by finding no reparentable element. No new unbounded recursion found.
- Continued through phases 1,561–1,580:
  - 1,561–1,570: found toolbox drag initiation and drag-enter/drop data-provider calls could throw outside the guarded add operation. Wrapped those WPF/OLE boundaries, reset palette state after drag-start failure, reject failed drag data, and report failures through the interaction log/status path.
- Continued through phases 1,581–1,600:
  - 1,581–1,590: reviewed popup load/unload and parent-window closing-hook registration; the unsaved-change handler is attached on load and detached on unload. No new crash path found.
  - 1,591–1,600: reviewed initial-file loading and queued dispatcher callbacks; `InitialFilePath` currently has no call sites, and no concrete post-close crash path was found.
- Continued through phases 1,601–1,620:
  - 1,601–1,605: checked ruler tick generation; dimensions are capped and tick density targets about 1,000 ticks per axis.
  - 1,606–1,610: found ruler clicks appended unlimited guides, each retaining an overlay rectangle. Added a 512-guide-per-axis limit, ignored guides within one pixel of an existing guide, and rejected non-finite positions to bound the visual tree.
  - 1,611–1,620: reviewed other retained editor collections (selection, layer, marquee, resize/anchor overlays); their contents are bounded by selection/control limits or fixed handle counts. No additional unbounded visual collection found.
- Continued through phases 1,621–1,660:
  - 1,621–1,630: found parent restoration repeatedly searched the full design tree while moving controls. Built a container-name index once per restoration and kept main-window roots out of parent restoration so malformed parent metadata cannot move the root.
  - 1,631–1,640: found group membership checks scanned every copied/duplicated item for every item. Replaced them with a case-insensitive ID set.
  - 1,641–1,650: found bulk load/paste/duplicate re-enumerated controls for each unique name and main-window lookup. Added a per-operation insertion context with precomputed names and root reference, also used during load and history restore.
  - 1,651–1,660: batched layer-list refresh for paste and duplicate; those operations now refresh once after insertion and reparenting instead of once per control.
- Verification after these performance and tree-safety changes: `dotnet build codelanguage/codelanguage.csproj -f net8.0-windows --no-restore` succeeded with 0 errors and the same NU1900/CS8892 warnings.
- Continued through phases 1,661–1,690:
  - 1,661–1,675: reviewed snap target generation, resize geometry clamps, and iterative anchored reflow; dimensions are finite and bounded through their input paths, and nested traversal is iterative.
  - 1,676–1,680: rechecked bulk load/history restore context creation and root-window ordering; these paths create their name/root index after clearing the canvas and refresh layers once.
  - 1,681–1,690: fixed the previously recorded partial-paste/duplicate state risk. Added a shared bulk-insertion transaction that snapshots layout/history, restores both after insertion/reparent failures, reselects the prior controls, batches the layer refresh, logs paste failures, and reports duplicate failures without leaving partially inserted controls behind.
- Continued through phases 1,691–1,720:
  - 1,691–1,700: inspected transaction snapshot, history-stack restoration order, and rollback error logging; the pre-operation state is captured before insertion and retained history is restored on failure.
  - 1,701–1,710: checked selection and dirty-title restoration after rollback; selected controls are recovered by their stable unique names.
  - 1,711–1,720: rechecked all bulk-insertion call sites (CPF load, history restore, paste, duplicate) against the insertion-context and layer-refresh invariants; each creates the context from the current tree before mutation.
- Verification after transactional paste/duplicate handling: Windows-targeted build succeeded with 0 errors; NU1900 and CS8892 warnings remain.
- Verification after the root-cause fix: `dotnet build codelanguage/codelanguage.csproj -f net8.0-windows --no-restore` succeeded with 0 errors; warnings remain as recorded above.
- Separate app-wide finding fixed in the current worktree: background update polling could display an install prompt and accepting it shuts down Craft++; startup/timer polling now reports availability non-modally. Update-check exceptions are now sent to the always-on diagnostic log.
- Verification: `dotnet build codelanguage/codelanguage.csproj -f net8.0-windows --no-restore` succeeded with 0 errors. It emitted NU1900 (NuGet vulnerability feed unavailable) and CS8892 (unselected updater entry point) warnings.

## Unresolved evidence gap

The direct stack-overflow cycle on the add/select path has been removed, and the source-level call graph now supports the fix. The Windows-only UI crash has not been rerun in a Windows runtime here; the current smoke test also does not invoke toolbox insertion. Continue reviewing visual-tree mutation, history, clipboard, and popup lifecycle, and verify the toolbox click on Windows when a usable runtime/log is available.
