feat(doc): persistent names follow the kernel's exact face history (#136)

Why: every reference a user makes to a face or edge (fillet and chamfer
edges, sketches on faces, shell/draft/offset faces, joints, appearances)
is stored as a name and found again after any upstream edit. Those names
were re-derived by sampling points of each face and voting, and pieces
of a split face were numbered by where their centres lay. After an
upstream edit that splits, merges, mirrors or shrinks a face, a fillet
or sketch could silently re-attach to the wrong face, and nothing told
the user. The kernel now reports exact history for its operations, so
names follow it and fail loudly instead of guessing.

- crates/doc/src/lineage.rs: a feature's kernel histories composed into
  one lineage over nameable operands (bodies before the feature, moved
  copies, shell cavities, tools named by role: sketch curve, cap, box
  side, imported face). Instrumented: extrude/revolve/sweep/loft tools,
  join/cut/intersect, lumps after a cut, fillet/chamfer, shell, draft,
  split face/body, pattern/mirror (bodies and features), combine,
  boundary fill, move/scale, offset/delete face, thread, import.
- crates/doc/src/history_names.rs: names from lineage; split pieces told
  apart by the faces only they touch (F2:top#[F2:side:l4,F4:side:l4]),
  merged faces answer to every name (aliases), lump bodies ordered by
  their faces' names instead of shell order.
- crates/doc/src/name_lookup.rs, piece_names.rs: references resolve by
  exact name, alias or bounding faces, else nearest piece with a
  warning; names worked out from geometry (operations without history)
  are reported when only geometry decided.
- Format 14: names stored by older formats get a legacy mark and are
  found as the build that saved them found them (some geometric names
  name a face history names differently: a tube's outer wall was named
  after its inner circle). New corpus file saved by 9a979cf.
- kernel: Body::lumps carries each piece's history over the whole.
- Adversarial tests: split, merge, mirrored twins, shrink to a sliver,
  moving cut with body pieces, history-less bodies, certified sketch.
- docs/book/src/dev/naming.md describes the real mechanism and why.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01J53sR6gEaVt56soFDpTck8
This commit is contained in:
Iraklis KourtisandClaude Opus 5.5 authored and bherbruck committed 2026-10-12 11:52:53 -04:00
1 parent 2bda050872
commit 08cf526fe2
29 files changed
+2917 -322

No files matched your search

+9 -2
View File
@@ -1005,9 +1005,16 @@ impl Body {
impl Body {
/// The separate pieces of a body: each outer shell with the voids inside it. A body in one
/// piece comes back as itself.
/// piece comes back as itself. Pieces of a body in several carry their history over
/// `[self]` (their faces and edges are its own), so whoever names them can follow it.
pub fn lumps(&self) -> Result<Vec<Body>> {
self.lumps_with_clearance(0.0)
let pieces = self.lumps_with_clearance(0.0)?;
if pieces.len() < 2 {
return Ok(pieces);
}
let counts = [(self.face_count(), self.edge_count())];
let histories = crate::boolean_record::parts_of(&pieces, self);
Ok(pieces.into_iter().zip(histories).map(|(piece, history)| piece.with_checked_history(history, &counts)).collect())
}
/// Whether this body and `other` share material or touch (within a fine mesh tolerance).