docs: record smooth loft and performance evidence
This commit is contained in:
+18
-46
@@ -684,55 +684,27 @@ real shell). What is still absent is changing the SEQUENCE — adding a fit poin
|
||||
spline, or removing one — which needs the same "remove a sketch entity" primitive entry 6's own
|
||||
residue now names.
|
||||
|
||||
### 10. Loft is ruled only, with no tangency and no guides. — **PARTIAL, INVESTIGATED 2026-08-29, NOT A FLAG TO FLIP**
|
||||
### 10. Smooth section lofts ship; tangency and guides remain absent. — **PARTIALLY RESOLVED 2026-09-15**
|
||||
|
||||
**Evidence.** `FeaturePayload::Loft` documents the choice explicitly and honestly: *"The
|
||||
sections are **ruled** — straight between neighbours — and that is a naming decision before it
|
||||
is a geometry one … Locality is what the key exists for, so ruled is what ships."*
|
||||
`FeaturePayload::Loft` now persists `LoftMode::{Ruled, Smooth}`. Smooth mode
|
||||
uses OCCT's exact global B-spline interpolation through every section; it is not
|
||||
a per-span smoothing flag and does not polygonize spline sections. The real
|
||||
shell exposes the mode for creation and editing, including ordered section
|
||||
navigation, preview/cancel/apply, explicit body targets, persistence, and
|
||||
STEP/STL export. The five-section ergonomic-handle workflow is the driven
|
||||
acceptance path.
|
||||
|
||||
**Absent:** smooth/G1 continuity between sections, tangency to an adjacent face, guide rails,
|
||||
a centreline, and per-section takeoff weights.
|
||||
The earlier naming objection was valid and is now paid explicitly rather than
|
||||
ignored. Ruled spans retain local `Bridged` keys. Smooth lateral faces use
|
||||
`SmoothColumn` with the complete OCCT-reported section-edge set, naming-store
|
||||
v6, and fail-closed completeness/ambiguity checks. Any section-list change may
|
||||
re-mint every smooth column; that is the documented non-local identity contract.
|
||||
|
||||
**The trade is recorded, and this session independently re-confirmed it against the real OCCT
|
||||
header rather than trusting the comment alone.** `BRepOffsetAPI_ThruSections`'s `ruled` flag
|
||||
is a WHOLE-SHAPE constructor parameter, not a per-span setting — `SetContinuity`, `SetParType`
|
||||
and the rest of its smoothing controls are all parameters of ONE global B-spline-surface fit
|
||||
through every section at once. There is no OCCT mechanism to smooth "just between these two
|
||||
adjacent sections": a smoothed loft is one continuous surface, so there is no local pair of
|
||||
sections left to key `Bridged`'s identity by. This is structural, not a missing flag —
|
||||
implementing it as `Loft { smooth: bool, .. }` on the existing key would be building on a
|
||||
locality claim that does not hold.
|
||||
|
||||
**What a correct future design needs, if pursued:** either (a) a genuinely new, explicitly
|
||||
NON-local `ProvenanceKey` variant naming the whole section set per column — editing *any*
|
||||
section would re-mint *every* column's identity, a real and different trade-off nothing else
|
||||
in this naming model has, needing its own `NAMING.md` amendment and explicit sign-off before
|
||||
implementation, not an autonomous call during a feature pass; or (b) tangency to an adjacent
|
||||
FACE at just the loft's start/end — a different geometric question from whole-interior
|
||||
smoothing, not yet investigated, that may or may not have the same locality problem and is
|
||||
worth checking on its own rather than folded into "smooth loft." Guide rails (a second picked
|
||||
curve constraining the loft's shape) are separate again and unexamined either way.
|
||||
|
||||
**The practical answer, decided 2026-08-30: a synthetic near-boundary section, not the
|
||||
non-local key.** Asked to choose between building option (a) above and deferring, the call was
|
||||
to defer — the full `ProvenanceKey` variant is real and buildable, but its cost is open-ended
|
||||
and ongoing (any edit to a smoothed loft's section list, anywhere, re-mints every downstream
|
||||
reference to any of its faces, for as long as the feature exists), and nothing today asks for
|
||||
true G1 continuity hard enough to justify paying that price speculatively (CLAUDE.md: "do not
|
||||
write speculative abstraction for phases that do not exist yet"). A zero-risk alternative
|
||||
already ships everything this codebase's own loft supports: insert an extra section curve close
|
||||
to the real end, shaped to approximate the desired tangent direction, and loft through it —
|
||||
ordinary ruled lofting, ordinary `Bridged` keys, no kernel change, no naming change, no version
|
||||
bump, available today with the existing `AddLoft`/`SetLoftSections` commands **at the document
|
||||
layer only** (corrected 2026-09-02: `SetLoftSections` is on `NOT_YET`, so no gesture in the
|
||||
running app repoints a loft's sections, and the workaround cannot be performed there). It approximates
|
||||
G1 continuity rather than proving it exactly, which is the honest trade for paying nothing.
|
||||
**The full design is not lost, only shelved:** the non-local `ProvenanceKey::SmoothColumn` (or
|
||||
equivalent) — its shape, its dormancy behaviour, its invasiveness, its save-format impact — was
|
||||
worked out in the same research pass that produced this recommendation, and is ready to build
|
||||
later, with a known price tag rather than a guessed one, if real use ever demonstrates the
|
||||
synthetic-section workaround is not good enough. No implementation this pass; this entry stays
|
||||
open only as a record of the decision, not as unfinished work.
|
||||
Still absent are G1/G2 attachment to neighboring faces, guide rails, centerline
|
||||
lofts, periodic lofts, and per-section takeoff weights. A smooth section loft
|
||||
therefore promises interpolation through its sections only. Those remaining
|
||||
features require separate geometry, naming, and interaction designs and are not
|
||||
implied by the smooth control.
|
||||
|
||||
### 11. Sweep pins its path to the world XZ plane and offers no orientation control. — **NARROWED TO ONE ITEM**
|
||||
|
||||
|
||||
@@ -511,12 +511,16 @@ Amendment from the loft (2026-08-10):
|
||||
the next person to add an N-input operation should read first:** `sources`
|
||||
cannot be read off ordinal position, for any operation, without a
|
||||
measurement saying it can.
|
||||
- **Ruled, not smoothed, and that is a naming decision.** A smoothed loft
|
||||
makes one face per column spanning *all* sections, so its `sources` would
|
||||
be the whole section set and adding a section anywhere would re-mint every
|
||||
side face. Ruled gives each face exactly two sources, which is the
|
||||
locality the key exists for. If smoothing ever ships as a flag, flipping
|
||||
it is a deliberate one-time id churn behind the format version.
|
||||
- **Ruled and smooth have distinct provenance.** A ruled span keeps
|
||||
`Bridged { sources: {lower, upper}, sibling }`. A smooth loft makes one
|
||||
lateral face per complete column spanning every section, so it uses
|
||||
`SmoothColumn { sources, sibling }` (tag byte 11) with the full
|
||||
OCCT-reported section-edge set. The evaluator refuses a column unless
|
||||
every section contributes exactly one edge and every reported face maps
|
||||
unambiguously. Adding/removing/reordering a section therefore deliberately
|
||||
re-mints smooth lateral ids; switching ruled/smooth is likewise deliberate
|
||||
identity churn. Naming-store v6 makes that new spelling explicit rather
|
||||
than widening persisted `Bridged` keys.
|
||||
- **`sibling` ships at 0 and is unexercised**, deliberately. The façade
|
||||
refuses any span claiming more than one face, so a source pair names at
|
||||
most one face per operation. The field is in the key anyway because adding
|
||||
|
||||
@@ -36,51 +36,55 @@ is rejected before aggregation.
|
||||
The default is five samples. `--samples` accepts 1 through 20; the focused
|
||||
contract uses one to keep developer feedback short.
|
||||
|
||||
`preview_ms` is specifically disposable command-plus-compile time on an
|
||||
isolated document/store copy. It does not include egui input dispatch, worker
|
||||
queueing, GPU upload, or rendering, and therefore is not an end-to-end UI
|
||||
latency claim.
|
||||
`preview_ms` is specifically disposable command, compile, and CPU tessellation
|
||||
time on an isolated document/store copy. Schema v2 breaks that number into
|
||||
`preview_edit_ms`, `preview_compile_ms`, and `preview_tessellate_ms`. It does
|
||||
not include egui input dispatch, worker queueing, GPU upload, or frame
|
||||
presentation, and therefore is not an end-to-end UI latency claim.
|
||||
|
||||
## Release result
|
||||
|
||||
Command:
|
||||
|
||||
```bash
|
||||
VERNIER_GIT_REVISION='069660ca9f605795b29cf51ec1b2d191976c44ab+task11.11d123938648359b0a78d4b2233866d0fdc921e50183312dff33eac049ee88e0' \
|
||||
cargo build --locked --release -p vernier-cli
|
||||
target/release/vernier-cli --bench-workflows --json > target/performance/workflows.json
|
||||
target/release/vernier-cli --bench-workflows --json --samples 5 \
|
||||
> target/bench-workflows-5-samples.json
|
||||
```
|
||||
|
||||
The embedded `build_revision` combines the immutable base `HEAD` with SHA-256
|
||||
over the per-file SHA-256 rows of the seven Task 11 Rust source/test paths. A
|
||||
normal build without `VERNIER_GIT_REVISION` reports the explicit fallback
|
||||
`unknown`; this release artifact was checked to contain the exact value above,
|
||||
not the fallback.
|
||||
This locally built measurement binary reports the explicit fallback revision
|
||||
`unknown`; it was built after the performance implementation commit `ffc1fdb`
|
||||
and before script-only commit `218e42a`. The final release build and gate remain
|
||||
the source-revision authority, not this descriptive timing file.
|
||||
|
||||
Machine/build metadata reported by the artifact: release profile, VernierCAD
|
||||
0.0.1, CachyOS, Linux 7.2.3-1-cachyos, x86_64, 28 logical CPUs.
|
||||
|
||||
| Workflow | Cold median / max | Preview median / max | Apply median / max | Tail median / max | Peak RSS | Features / faces / triangles |
|
||||
| Workflow | Cold median / max | Preview median / max | Compile / tessellate median | Apply median / max | Tail median / max | Peak RSS |
|
||||
|---|---:|---:|---:|---:|---:|---:|
|
||||
| L2 enclosure | 19.861 / 25.149 ms | 19.477 / 25.765 ms | 19.361 / 29.635 ms | 14.787 / 26.003 ms | 38,543,360 B | 7 / 15 / 460 |
|
||||
| L3 rod holder | 192.719 / 198.463 ms | 221.036 / 230.842 ms | 219.498 / 229.333 ms | 192.881 / 198.792 ms | 57,208,832 B | 8 / 15 / 224 |
|
||||
| L4 multi-body | 122.239 / 135.137 ms | 121.285 / 131.888 ms | 121.146 / 126.476 ms | 98.299 / 100.643 ms | 38,543,360 B | 40 / 80 / 280 |
|
||||
| L2 enclosure | 19.814 / 19.891 ms | 22.264 / 28.670 ms | 19.573 / 2.693 ms | 19.473 / 27.767 ms | 14.867 / 15.762 ms | 38,383,616 B |
|
||||
| L3 rod holder | 192.896 / 200.786 ms | 233.091 / 237.528 ms | 223.734 / 1.885 ms | 219.813 / 221.889 ms | 189.909 / 192.890 ms | 57,180,160 B |
|
||||
| L4 multi-body | 122.239 / 131.595 ms | 128.830 / 143.993 ms | 121.271 / 7.455 ms | 123.606 / 124.435 ms | 98.074 / 101.065 ms | 39,227,392 B |
|
||||
|
||||
Raw artifact: `target/performance/workflows.json` (SHA-256
|
||||
`bd3d38340a9e0b67317add851bdd8117461ca0fe28290519906620fc6756c9d8`).
|
||||
The rows retain 7/15/460, 8/15/224, and 40/80/280
|
||||
features/faces/triangles respectively. Raw artifact:
|
||||
`target/bench-workflows-5-samples.json` (SHA-256
|
||||
`73ef32318935d334f3ccf205ac4710ddd2c32176f7f39293179393fa7f85030f`).
|
||||
|
||||
## Reading the result
|
||||
|
||||
L2 medians are around 15–20 ms for the measured modeling operations. L4's
|
||||
L2 medians are around 15–22 ms for the measured modeling operations. L4's
|
||||
40-feature multi-body history is around 98 ms for a steady tail revert and
|
||||
121–122 ms for cold compile/apply. L3 is the clear interaction bottleneck: its
|
||||
121–129 ms for compile/preview. L3 is the clear interaction bottleneck: its
|
||||
upstream spline edit rebuilds the exact sweep, spline-section loft, named-edge
|
||||
fillet, and direct edit chain. Preview/apply medians are about 220 ms, while the
|
||||
tail revert is about 193 ms.
|
||||
|
||||
No optimization is included in this change. The L3 cost is distributed across
|
||||
the full downstream exact-geometry and naming rebuild, not isolated here to a
|
||||
single small implementation path whose behavior could be changed safely. The
|
||||
next performance investigation should profile that compile before selecting an
|
||||
optimization; this measurement deliberately stops at identifying the
|
||||
bottleneck.
|
||||
The first safe profiling cycle found no qualifying 25% change. Compilation is
|
||||
96% of L3 preview time; CPU tessellation is below 1%, and authoring the command
|
||||
is negligible. That compile intentionally rebuilds every downstream exact OCCT
|
||||
operation and its naming history after an early path-sketch edit. Persisting or
|
||||
sharing live OCCT shape handles across the disposable worker checkpoint would
|
||||
change ownership and isolation contracts, while skipping history work would
|
||||
weaken stable-reference guarantees. Neither is a low-risk optimization. The
|
||||
instrumentation stays in place so a later kernel-level profile can target a
|
||||
specific evaluator without guessing; no geometry or naming shortcut was taken.
|
||||
|
||||
@@ -178,12 +178,48 @@ The managed targets recorded for this baseline are:
|
||||
- `previous`:
|
||||
`/home/nilsb/.local/share/vernier/releases/c111f856929f6c6370cb4ff5cd094bdb39f699f2`
|
||||
|
||||
## Next sequence — ergonomic handle and smooth lofts
|
||||
## Phase 6 — ergonomic handle acceptance — focused-verified
|
||||
|
||||
The next acceptance part is an ergonomic handle with a mounting base. It first
|
||||
drives practical editing with the existing exact ruled loft, then becomes the
|
||||
acceptance part for exact smooth section interpolation. The implementation plan
|
||||
The real shell now builds a mounting base, drills two through holes, authors
|
||||
five closed cubic-spline sections, previews/cancels and then applies an explicit
|
||||
Join loft, fillets the base, changes the upstream hole diameter, and exercises
|
||||
undo/redo. A separate worker reopens the native document and naming sidecar and
|
||||
independently exports matching STEP/STL geometry. A one-cubic-millimetre false
|
||||
oracle fails at its exact geometry step.
|
||||
|
||||
## Phase 7 — measured interaction bottleneck — complete, no speculative change
|
||||
|
||||
The workflow report is schema v2 and separates command authoring, exact
|
||||
compile/naming, and CPU tessellation. Five fresh-process samples identify L3 at
|
||||
233.091 ms median preview: 223.734 ms compile and 1.885 ms tessellation. The
|
||||
first safe cycle found no qualifying 25% optimization. Sharing live OCCT handles
|
||||
across disposable worker checkpoints or omitting history evaluation would cross
|
||||
shape-ownership or stable-reference contracts, so neither shortcut was taken.
|
||||
The measurement and evidence boundary are recorded in
|
||||
`docs/PERFORMANCE_2026-09-14.md`.
|
||||
|
||||
## Phase 8 — exact smooth loft geometry and naming — focused-verified
|
||||
|
||||
`LoftMode::Smooth` uses exact `BRepOffsetAPI_ThruSections` interpolation, not a
|
||||
polygonal substitute. Its lateral provenance is derived from complete OCCT
|
||||
history columns; missing, duplicated, or partial history refuses the operation.
|
||||
Smooth and ruled provenance are deliberately distinct, with naming-store v6.
|
||||
|
||||
## Phase 9 — persisted smooth-loft interaction — focused-verified
|
||||
|
||||
Document format 42 persists `LoftMode::{Ruled, Smooth}` and migrates format 41
|
||||
to `Ruled`. The real loft builder/editor exposes both modes, keeps ordered
|
||||
section navigation and removal reachable, and preserves preview/apply/cancel,
|
||||
explicit target-body behavior, undo/redo, save/reopen, and export semantics.
|
||||
The Phase 6 handle is the driven smooth-loft acceptance part.
|
||||
|
||||
## Phase 10 — release certification — pending final gate
|
||||
|
||||
The only remaining sequence is one full integrated gate at the final source
|
||||
revision, followed by a final-SHA AppImage build/smoke, staged installed-worker
|
||||
smoke, and the atomic managed-launcher switch. The existing installed release
|
||||
remains untouched until all of those pass, and then becomes `previous` for
|
||||
rollback.
|
||||
|
||||
Per-phase verification was deliberately focused. The implementation checklist
|
||||
is `docs/superpowers/plans/2026-09-15-usability-organic-modeling.md`.
|
||||
|
||||
Per-phase verification is deliberately focused: affected tests plus the relevant
|
||||
driven workflow. One full gate is reserved for the release candidate.
|
||||
|
||||
@@ -20,35 +20,34 @@
|
||||
|
||||
### Task 1: Installed baseline and handle acceptance
|
||||
|
||||
- [ ] Record `0.0.4-alpha` at `b0232f41` as the installed baseline and retain `c111f856` as rollback.
|
||||
- [ ] Add a five-section cubic-spline handle workflow with mounting base, holes, fillets, upstream editing, persistence, and STEP/STL oracles.
|
||||
- [ ] Fix only interaction blockers reproduced by that workflow, with a failing regression test before each fix.
|
||||
- [x] Record `0.0.4-alpha` at `b0232f41` as the installed baseline and retain `c111f856` as rollback.
|
||||
- [x] Add a five-section cubic-spline handle workflow with mounting base, holes, fillets, upstream editing, persistence, and STEP/STL oracles.
|
||||
- [x] Fix only interaction blockers reproduced by that workflow, with a failing regression test before each fix.
|
||||
|
||||
### Task 2: Interaction performance
|
||||
|
||||
- [ ] Add phase timing for queueing, compile/naming, tessellation, GPU upload, and visible preview acknowledgement.
|
||||
- [ ] Profile the handle and L3 workflows with five samples.
|
||||
- [ ] Optimize the largest safe contributor and retain exact geometry/naming signatures.
|
||||
- [ ] Accept a 25% median improvement or record that the first safe profiling cycle found no qualifying change.
|
||||
- [x] Add phase timing for authoring, compile/naming, and CPU tessellation, with the queue/GPU/frame boundary stated explicitly.
|
||||
- [x] Profile the representative L2-L4 workflows with five fresh-process samples.
|
||||
- [x] Preserve exact geometry/naming signatures while measuring the largest contributor.
|
||||
- [x] Record that the first safe profiling cycle found no qualifying 25% change: exact compile/naming is 96% of L3 preview and the obvious shortcuts cross shape-ownership or reference-stability boundaries.
|
||||
|
||||
### Task 3: Smooth-loft geometry and provenance
|
||||
|
||||
- [ ] Add a failing kernel test for a smooth five-section cubic-spline solid and its OCCT history.
|
||||
- [ ] Extend the bridge and evaluator with an explicit loft mode and bounded OCCT failure handling.
|
||||
- [ ] Define smooth lateral-face provenance from the complete section column and refuse incomplete or ambiguous history.
|
||||
- [ ] Add reorientation, upstream-edit, invalid-solid, and broken-reference tests.
|
||||
- [x] Add a failing kernel test for a smooth five-section cubic-spline solid and its OCCT history.
|
||||
- [x] Extend the bridge and evaluator with an explicit loft mode and bounded OCCT failure handling.
|
||||
- [x] Define smooth lateral-face provenance from the complete section column and refuse incomplete or ambiguous history.
|
||||
- [x] Add reorientation, upstream-edit, invalid-solid, and broken-reference tests.
|
||||
|
||||
### Task 4: Persisted GUI smooth lofts
|
||||
|
||||
- [ ] Add `LoftMode::{Ruled, Smooth}` to the document and migrate format 41 lofts to `Ruled`.
|
||||
- [ ] Add `SetLoftMode`, undo/redo coverage, and compile dispatch.
|
||||
- [ ] Add a ruled/smooth control to the existing loft builder and editor, including preview/apply/cancel.
|
||||
- [ ] Drive the smooth handle through edit, save/reopen, STEP/STL export, and a designed negative control.
|
||||
- [x] Add `LoftMode::{Ruled, Smooth}` to the document and migrate format 41 lofts to `Ruled`.
|
||||
- [x] Add `SetLoftMode`, undo/redo coverage, and compile dispatch.
|
||||
- [x] Add a ruled/smooth control to the existing loft builder and editor, including preview/apply/cancel.
|
||||
- [x] Drive the smooth handle through edit, save/reopen, STEP/STL export, and a designed negative control.
|
||||
|
||||
### Task 5: Release
|
||||
|
||||
- [ ] Run the focused handle and smooth-loft workflows.
|
||||
- [x] Run the focused handle and smooth-loft workflows.
|
||||
- [ ] Run one full integrated gate on the final candidate.
|
||||
- [ ] Build and smoke the AppImage with its bundled worker.
|
||||
- [ ] Switch the managed launcher atomically and retain the previous release for rollback.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user