Engine 1.9.352 -> 1.9.353 and the binding wire-up in one train:
- libleptris 1.9.353 (#1689/#1690): leptris_element_attributes_
snapshot — ALL attribute names/values in ONE crossing, two-phase
capacity/retry (sizing pass returns the exact blob capacity;
SIZE_MAX on a too-small provided buffer), optional ns lanes with
SIZE_MAX markers for no-namespace attributes. The count half was
already attached.
- Element#attributes_snapshot mirrors PlanValue#attributes_snapshot
(#447): { name => value }, UTF-8 encoded like the per-name
reader, prefixed attributes carried by their spelled names (ns
lanes stay NULL on this surface), ensure_alive! at entry. Unlike
the memoized attributes/attribute_pairs faces this is a fresh
read every call — change-sensitive by contract.
Honest perf note: on cold first touch the snapshot runs at parity
with the memoized bulk_attr_faces path (both one crossing per
element); the win is the uniform two-phase contract across both
faces, non-memoizing semantics, and the ns lanes available at the
C level for a future surface.
Spec: 8 examples (order, frozen-empty, per-name parity, entities,
UTF-8, prefixed spellings, 4KB values, repeat stability). Suite:
1011 examples, 0 failures.