Byte builders and their cost
A BytesBuilder is an ordered tree of empty, chunk, and append nodes.
(bytes-builder-empty) is the identity; (bytes-builder-chunk bytes) retains
one byte sequence; (bytes-builder-append left right) places all left bytes
before all right bytes. (bytes-builder-build builder) explicitly produces
Bytes. None of these operations decodes text or inserts separators.
Cost model
Let V be the number of builder nodes and B the total output byte count, counting a repeated chunk once per occurrence in the output. Constructing an append node requires constant builder bookkeeping and does not copy payload bytes. Finalization visits O(V) nodes and copies O(B) payload bytes. These bounds exclude computing the expressions or thunks that supply nodes and chunks; arbitrary source checking is not constant-time merely because an append form appears.
The bootstrap strong and weak-head normalizers collect chunks through an explicit pending stack and a reversed chunk list. This avoids copying a growing left prefix at every append. The weak-head stack retains each node's environment and preserves left-to-right forcing, including errors after a neutral node. Unknown builders remain neutral; they are never silently treated as empty.
The default native evaluator uses a measure pass and a copy pass over explicit builder stacks. Its two passes are independent of tree association. The final byte buffer is sized from the measured payload. Native stack/arena exhaustion remains a hard runtime failure; this contract is not an unbounded-memory promise.
Verification and limits
BuilderLaws.alpha compares left- and right-associated builders with an
independent append-based model and literal expected bytes, including empty
chunks. Core tests cover 256 distinct ordered bytes in left, right, balanced,
and interleaved-empty trees, neutral terms, and captured environments.
debug/builder-cost-check.py --output /mounted/evidence compiles the actual
normalizer owners at GHC -O2 and samples allocation for 256,512,1024,2048 chunks.
Its 2.6x doubling limit allows fixed GHC accounting overhead while rejecting the
previous roughly4x growth. Output equality is required at every sample. Timing
is recorded but is not the pass criterion. This is allocated heap bytes, not
unique-node allocation or a whole-compiler resource bound.
debug/builder-native-growth-check.py takes --alpha, --diagnostic-alpha, and
--output. Runtime input determines128,256,512,1024 chunks; an Alpha process
compares builder and model outputs, and a changed-byte control must fail.
Telemetry records VM dispatch steps and byte-arena bytes without compaction.
Both measured dimensions grow linearly. The telemetry does not count every
native payload-copy loop iteration, so full TXT-006 work-counter qualification
remains open. The append-based model is an independent semantic reference;
these counters do not establish that its native execution is quadratic.
No syntax, core constructor, serialized representation, or edition rule changes in this repair. Form contracts remain alpha-2026; alpha-2027 uses the same builder operations. Direct native lowering outside the default evaluator lane has not been requalified by this growth fixture.