|
| 1 | +# Void Constraints V2 Plan (Planegcs-First, Fallback as Safety Net) |
| 2 | + |
| 3 | +## Goal |
| 4 | + |
| 5 | +Move sketch solving to a clean planegcs-first architecture, remove dual-solver behavioral drift, and improve drag/tangent stability. |
| 6 | + |
| 7 | +## Current Findings |
| 8 | + |
| 9 | +1. Constraint solving is currently dual-mode by default: |
| 10 | + - `enforceWithPlanegcs()` runs, then a fallback settle pass is still applied. |
| 11 | + - This can reintroduce different motion/priority behavior after planegcs already converged. |
| 12 | + |
| 13 | +2. Drag interactions frequently force fallback: |
| 14 | + - During drag, `useFallback: tangentDriven || !pointDrag` is used in pointer drag paths. |
| 15 | + - This bypasses planegcs exactly where stable incremental behavior matters most. |
| 16 | + |
| 17 | +3. Tangent constraints are not mapped into planegcs in the current mapper: |
| 18 | + - `toPlanegcsConstraint()` covers many constraints but not sketch `tangent`. |
| 19 | + - Tangency currently depends on fallback heuristics (`constraints_tangent.js`). |
| 20 | + |
| 21 | +4. The planegcs wrapper already supports temporary constraints: |
| 22 | + - Constraint objects with `temporary: true` are supported by the wrapper path. |
| 23 | + - This enables proper drag-driving constraints with lower priority solving semantics. |
| 24 | + |
| 25 | +5. `angle_via_point` is available in the solver bindings: |
| 26 | + - Suitable for robust endpoint tangency encoding (angle = 0 at shared endpoint). |
| 27 | + - This aligns with FreeCAD guidance for improved stability vs direct tangent formulations in corner cases. |
| 28 | + |
| 29 | +## Root Cause Summary |
| 30 | + |
| 31 | +1. Two solvers are actively shaping geometry during interaction. |
| 32 | +2. Drag logic has explicit fallback preference in key paths. |
| 33 | +3. Tangency is solved outside planegcs, creating inconsistent convergence and corner-case instability. |
| 34 | + |
| 35 | +## Target Architecture |
| 36 | + |
| 37 | +1. Planegcs is the primary and default solver for all live interaction and final settle. |
| 38 | +2. Fallback solver is retained only as failure recovery. |
| 39 | +3. Drag uses temporary constraints in planegcs: |
| 40 | + - Temporary point-to-point/point-to-line style guidance constraints to cursor/ghost references. |
| 41 | + - No permanent topology mutation from drag constraints. |
| 42 | +4. Tangency uses planegcs-native representation: |
| 43 | + - Shared-endpoint tangent: `angle_via_point` with angle = 0. |
| 44 | + - Non-shared cases: use direct tangent primitives where stable (`tangent_la`, `tangent_aa`, etc.), with endpoint-angle fallback where needed. |
| 45 | + |
| 46 | +## Phased Execution |
| 47 | + |
| 48 | +## Phase 1: Instrumentation and Guardrails |
| 49 | + |
| 50 | +1. Add solver telemetry per enforce call: |
| 51 | + - planegcs used, fallback used, solve status, elapsed time. |
| 52 | +2. Add debug toggle to display active temporary constraints during drag. |
| 53 | +3. Add deterministic logs for tangent constraint path selection. |
| 54 | + |
| 55 | +Exit Criteria: |
| 56 | +1. We can observe when and why fallback is invoked. |
| 57 | + |
| 58 | +## Phase 2: Temporary Drag Constraints |
| 59 | + |
| 60 | +1. Add drag-time temporary constraints (`temporary: true`) in planegcs solve graph. |
| 61 | +2. Remove drag-path forced fallback defaults. |
| 62 | +3. Keep fallback only if planegcs solve fails or returns non-converged status. |
| 63 | + |
| 64 | +Exit Criteria: |
| 65 | +1. Drag no longer “snaps back” from dual-pass disagreement. |
| 66 | +2. Solver path during normal drag is planegcs-only. |
| 67 | + |
| 68 | +## Phase 3: Tangent Migration |
| 69 | + |
| 70 | +1. Implement tangent mapping in `toPlanegcsConstraint()`: |
| 71 | + - line-arc, arc-arc, line-circle as available. |
| 72 | +2. For shared-endpoint tangent pairs, map to `angle_via_point` (angle=0). |
| 73 | +3. Keep old tangent fallback path behind a temporary feature flag for rollback. |
| 74 | + |
| 75 | +Exit Criteria: |
| 76 | +1. Tangent drag corner cases no longer require tangent-specific fallback aggressiveness. |
| 77 | +2. Shared-endpoint tangent cases are stable under repeated edits/drag. |
| 78 | + |
| 79 | +## Phase 4: Remove Default Dual Settle |
| 80 | + |
| 81 | +1. Remove unconditional fallback settle after successful planegcs solve. |
| 82 | +2. Fallback runs only on explicit planegcs failure paths. |
| 83 | +3. Keep compatibility switch (`constraints_v2_force_fallback`) for emergency rollback. |
| 84 | + |
| 85 | +Exit Criteria: |
| 86 | +1. Single primary solver behavior in normal operation. |
| 87 | +2. Fewer constraint jitter/regressions from solver disagreement. |
| 88 | + |
| 89 | +## Phase 5: Cleanup |
| 90 | + |
| 91 | +1. Simplify pointer drag enforcement call sites. |
| 92 | +2. Remove tangent-specific fallback tuning knobs that become obsolete. |
| 93 | +3. Document canonical constraint mapping table and temporary-constraint rules. |
| 94 | + |
| 95 | +Exit Criteria: |
| 96 | +1. Constraint code paths are materially simpler and easier to reason about. |
| 97 | + |
| 98 | +## Proposed Code Touchpoints |
| 99 | + |
| 100 | +1. `src/void/sketch/constraints.js` |
| 101 | + - Add temporary constraint plumbing and tangent mapping in `toPlanegcsConstraint()`. |
| 102 | + - Remove unconditional fallback settle on success. |
| 103 | + |
| 104 | +2. `src/void/sketch/pointer.js` |
| 105 | + - Replace drag-time fallback preference with planegcs temporary constraints. |
| 106 | + |
| 107 | +3. `src/void/sketch/constraints_actions.js` |
| 108 | + - Ensure apply/edit flows use planegcs-first, fallback-on-failure behavior. |
| 109 | + |
| 110 | +4. `src/void/sketch/constraints_tangent.js` |
| 111 | + - Transition from primary solver role to compatibility fallback only. |
| 112 | + |
| 113 | +5. `src/void/solver/sketch/gcs_wrapper.js` |
| 114 | + - Confirm temporary constraint lifecycle handling and cleanup. |
| 115 | + |
| 116 | +## Risks and Mitigations |
| 117 | + |
| 118 | +1. Risk: Regression in legacy sketches tuned around fallback behavior. |
| 119 | + - Mitigation: feature flag + staged rollout + telemetry. |
| 120 | + |
| 121 | +2. Risk: Performance regressions during drag with added temporary constraints. |
| 122 | + - Mitigation: limit temporary constraint count to active dragged subset; cap iterations. |
| 123 | + |
| 124 | +3. Risk: Incorrect tangent mapping for mixed entity types. |
| 125 | + - Mitigation: explicit mapping matrix tests per constraint subtype. |
| 126 | + |
| 127 | +## Validation Plan |
| 128 | + |
| 129 | +1. Unit tests: |
| 130 | + - Tangent mapping (shared endpoint and non-shared). |
| 131 | + - Temporary constraint injection/removal lifecycle. |
| 132 | + - Planegcs success path without fallback pass. |
| 133 | + |
| 134 | +2. Interaction tests: |
| 135 | + - Drag with dimensions, coincident, perpendicular, and tangent combos. |
| 136 | + - Repeated drag/release cycles without geometric drift. |
| 137 | + - Circular/grid/polygon pattern interactions under drag. |
| 138 | + |
| 139 | +3. Regression scenarios: |
| 140 | + - Known tangent corner cases. |
| 141 | + - Previously flaky dual-solver “snap back” sketches. |
| 142 | + |
| 143 | +## Recommendation |
| 144 | + |
| 145 | +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. |
0 commit comments