alonso.torres 6cf5f6088e 🐛 Fix the container helpers for copies and components
Fixes in the helpers that walk, instantiate, compare and absorb components
(Phase 3c).

- List each shape once in get-children-in-instance.

  The recursion handed each child the vector built so far, ancestors
  included, and the caller added what came back to its own copy of that
  vector, so every ancestor came back once per child below it (F59). It now
  threads one result through a reduce. Both callers, the repair of
  :shape-ref-cycle and migration legacy-65, make a set of the result, so
  they see the same shapes.

  container-test counts the shapes of an instance.

- Walk every ancestor in has-any-copy-parent?.

  It recursed with the parent's id where it expects a shape, so it only ever
  looked at the direct parent (F63). It now walks up to the root, which is
  its own parent. Users never saw it: every descendant of a copy is a copy,
  so the direct parent gave the right answer.

  container-test checks a shape two levels below the copy.

- Start a new copy without the remote-synced mark of its main.

  Instantiating a component cleared the touched groups of the shapes it
  copies from the main, but not :remote-synced, so a nested copy in the main
  that had been synced from a remote main passed the mark on to every new
  copy of the component, whose shapes refer to their near main (F18).
  make-component-instance now clears it too.

  container-test: a new copy of a component whose nested copy is touched and
  remote-synced has neither mark.

- Compare the stored shapes of components by value.

  mod-component marks a component modified when the change alters any of its
  keys, which ctk/diff-components reports. For :objects, the shapes a
  deleted component stores, it compared the ids found by walking :children,
  a shape format older than the objects map, so it read nil on both sides
  and never saw a change there (F96). It now compares every key, :objects
  included, by value.

  container-test: a change to a stored shape of a deleted component is a
  difference; the same component is none.

- Keep nested copies and annotations of absorbed components.

  When a file absorbs a library's components (the library is deleted, or a
  binfile export merges libraries), each used component gets a main in the
  file, a copy of the library main with the same ids (F89):
  - every shape of that main lost its :shape-ref, so the copies nested in it
    stopped being copies of anything;
  - every head in it was pointed at the local file, even one whose component
    lives in a third library;
  - the component lost its annotation.

  The main now keeps the refs of its nested copies, which with the same ids
  point at the absorbed mains of the components they nest (a file that shows
  a nested copy uses its component, so that one is absorbed too); only heads
  of the absorbed library are pointed at the local file; the annotation is
  copied. A variant still becomes a plain component.

  absorb-assets-test: the nested copy of an absorbed main keeps its ref and
  is a copy of the local component; the annotation stays.

- Say what the component placement rule checks.

  invalid-structure-for-component? said it kept a shape out of its own
  subtree, but its check compares components only: a plain shape moved into
  its own child passes, and the move itself refuses it (F58). The comments
  now say what it checks; the behavior stays, as the layers panel relies on
  it to do nothing for such a drop (decision (s)).

Benchmark (lower quantile, ms; baseline / now / ratio):
  deepest-edit-through-three-levels    35.2 /  17.0 / 0.48
  edit-through-a-chain-of-dependents   68.9 /  33.5 / 0.49
  library-update-into-copies           83.1 /  40.1 / 0.48
  main-edit-among-many-shapes           4.8 /   2.1 / 0.43
  main-edit-into-10-copies              1.8 /   0.8 / 0.47
  main-edit-into-100-copies            15.4 /   8.3 / 0.54
  main-edit-into-1000-copies          153.1 /  82.3 / 0.54
  variant-switch-into-copies           32.1 /  18.6 / 0.58

AI-assisted-by: claude-opus-5-5
2026-10-16 11:05:21 +02:00
..