From 357e25f5480a6e52482906d9383a02a4f2d9c302 Mon Sep 17 00:00:00 2001 From: Stewart Allen Date: Mon, 2 Mar 2026 21:44:30 -0500 Subject: [PATCH] add constraints plan --- docs/void/plan-constraints-v2.md | 145 +++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 docs/void/plan-constraints-v2.md diff --git a/docs/void/plan-constraints-v2.md b/docs/void/plan-constraints-v2.md new file mode 100644 index 00000000..b0d03f19 --- /dev/null +++ b/docs/void/plan-constraints-v2.md @@ -0,0 +1,145 @@ +# Void Constraints V2 Plan (Planegcs-First, Fallback as Safety Net) + +## Goal + +Move sketch solving to a clean planegcs-first architecture, remove dual-solver behavioral drift, and improve drag/tangent stability. + +## Current Findings + +1. Constraint solving is currently dual-mode by default: + - `enforceWithPlanegcs()` runs, then a fallback settle pass is still applied. + - This can reintroduce different motion/priority behavior after planegcs already converged. + +2. Drag interactions frequently force fallback: + - During drag, `useFallback: tangentDriven || !pointDrag` is used in pointer drag paths. + - This bypasses planegcs exactly where stable incremental behavior matters most. + +3. Tangent constraints are not mapped into planegcs in the current mapper: + - `toPlanegcsConstraint()` covers many constraints but not sketch `tangent`. + - Tangency currently depends on fallback heuristics (`constraints_tangent.js`). + +4. The planegcs wrapper already supports temporary constraints: + - Constraint objects with `temporary: true` are supported by the wrapper path. + - This enables proper drag-driving constraints with lower priority solving semantics. + +5. `angle_via_point` is available in the solver bindings: + - Suitable for robust endpoint tangency encoding (angle = 0 at shared endpoint). + - This aligns with FreeCAD guidance for improved stability vs direct tangent formulations in corner cases. + +## Root Cause Summary + +1. Two solvers are actively shaping geometry during interaction. +2. Drag logic has explicit fallback preference in key paths. +3. Tangency is solved outside planegcs, creating inconsistent convergence and corner-case instability. + +## Target Architecture + +1. Planegcs is the primary and default solver for all live interaction and final settle. +2. Fallback solver is retained only as failure recovery. +3. Drag uses temporary constraints in planegcs: + - Temporary point-to-point/point-to-line style guidance constraints to cursor/ghost references. + - No permanent topology mutation from drag constraints. +4. Tangency uses planegcs-native representation: + - Shared-endpoint tangent: `angle_via_point` with angle = 0. + - Non-shared cases: use direct tangent primitives where stable (`tangent_la`, `tangent_aa`, etc.), with endpoint-angle fallback where needed. + +## Phased Execution + +## Phase 1: Instrumentation and Guardrails + +1. Add solver telemetry per enforce call: + - planegcs used, fallback used, solve status, elapsed time. +2. Add debug toggle to display active temporary constraints during drag. +3. Add deterministic logs for tangent constraint path selection. + +Exit Criteria: +1. We can observe when and why fallback is invoked. + +## Phase 2: Temporary Drag Constraints + +1. Add drag-time temporary constraints (`temporary: true`) in planegcs solve graph. +2. Remove drag-path forced fallback defaults. +3. Keep fallback only if planegcs solve fails or returns non-converged status. + +Exit Criteria: +1. Drag no longer “snaps back” from dual-pass disagreement. +2. Solver path during normal drag is planegcs-only. + +## Phase 3: Tangent Migration + +1. Implement tangent mapping in `toPlanegcsConstraint()`: + - line-arc, arc-arc, line-circle as available. +2. For shared-endpoint tangent pairs, map to `angle_via_point` (angle=0). +3. Keep old tangent fallback path behind a temporary feature flag for rollback. + +Exit Criteria: +1. Tangent drag corner cases no longer require tangent-specific fallback aggressiveness. +2. Shared-endpoint tangent cases are stable under repeated edits/drag. + +## Phase 4: Remove Default Dual Settle + +1. Remove unconditional fallback settle after successful planegcs solve. +2. Fallback runs only on explicit planegcs failure paths. +3. Keep compatibility switch (`constraints_v2_force_fallback`) for emergency rollback. + +Exit Criteria: +1. Single primary solver behavior in normal operation. +2. Fewer constraint jitter/regressions from solver disagreement. + +## Phase 5: Cleanup + +1. Simplify pointer drag enforcement call sites. +2. Remove tangent-specific fallback tuning knobs that become obsolete. +3. Document canonical constraint mapping table and temporary-constraint rules. + +Exit Criteria: +1. Constraint code paths are materially simpler and easier to reason about. + +## Proposed Code Touchpoints + +1. `src/void/sketch/constraints.js` + - Add temporary constraint plumbing and tangent mapping in `toPlanegcsConstraint()`. + - Remove unconditional fallback settle on success. + +2. `src/void/sketch/pointer.js` + - Replace drag-time fallback preference with planegcs temporary constraints. + +3. `src/void/sketch/constraints_actions.js` + - Ensure apply/edit flows use planegcs-first, fallback-on-failure behavior. + +4. `src/void/sketch/constraints_tangent.js` + - Transition from primary solver role to compatibility fallback only. + +5. `src/void/solver/sketch/gcs_wrapper.js` + - Confirm temporary constraint lifecycle handling and cleanup. + +## Risks and Mitigations + +1. Risk: Regression in legacy sketches tuned around fallback behavior. + - Mitigation: feature flag + staged rollout + telemetry. + +2. Risk: Performance regressions during drag with added temporary constraints. + - Mitigation: limit temporary constraint count to active dragged subset; cap iterations. + +3. Risk: Incorrect tangent mapping for mixed entity types. + - Mitigation: explicit mapping matrix tests per constraint subtype. + +## Validation Plan + +1. Unit tests: + - Tangent mapping (shared endpoint and non-shared). + - Temporary constraint injection/removal lifecycle. + - Planegcs success path without fallback pass. + +2. Interaction tests: + - Drag with dimensions, coincident, perpendicular, and tangent combos. + - Repeated drag/release cycles without geometric drift. + - Circular/grid/polygon pattern interactions under drag. + +3. Regression scenarios: + - Known tangent corner cases. + - Previously flaky dual-solver “snap back” sketches. + +## Recommendation + +Start with Phase 2 (temporary drag constraints + fallback-on-failure only for drag) before full tangent migration. This yields immediate UX improvement and reduces dual-solver interference while keeping rollback safety.