CBDF Specification: Text Section

Version 1.1 (Phase II)

Document: 04-Text-Section • Date: 2026-07-13

1. Overview

The Text section holds readable content: UTF-8 interspersed with control codes for styles, structure, and embeds. One grammar only — not a second GS/RS/US layer/container/component tree. Layers come from composite layer_id; containers from layout panes + STYLE_CONTAINER.

[Length: 4 bytes LE] [STX] [optional SOH subject] [body] [ETX]

Length prefix is authoritative. ETX is a validation sentinel (SHOULD land where length indicates).

2. CRLF Normalization (normative)

Encoders MUST normalize Windows CRLF and bare CR to LF (0x0A) before writing Text. In Phase II Text, 0x0D is always HORIZ_RULE followed by one border-style index byte — never a soft carriage return.

3. Plain-Text Extraction

  1. Decompress if needed.
  2. Scan STX…ETX.
  3. Keep bytes ≥ 0x20, plus TAB and LF.
  4. Skip other controls and their payloads (see table below).
  5. Optionally map HORIZ_RULE → ---.
CodePayload to skip
0x0D HORIZ_RULE1 (style index)
0x0E LINK_START1 + 1 + N (type, len, target)
0x10 DATA_ESCAPE2 + N (len LE + data)
0x11 / 0x12 / 0x131 (style index)
0x15 ELEMENT_ID1, or 3 if first byte is 0xFF
0x16 IMAGE1
0x19 ITEM_BLOCK2
0x1A AI_PROMPT1 + 2 + N
0x1B ESCAPEPhase III; fail closed if unknown

Degradation SHOULDs: PARA_BREAK → blank line; item US → newline + bullet; table RS → newline; table US → TAB (TSV).

The payload-skip table is versioned with the control registry: every future command MUST be self-delimiting and listed here in the same change.

4. Style Stack (strict)

  • Push: STYLE_TEXT, STYLE_CONTAINER, STYLE_TABLE
  • Pop style only: STYLE_END
  • Close block + pop: BLOCK_END
  • Pop on empty stack or unclosed block at ETX → invalid document
  • STYLE_TEXT always pushes (no replace-in-place)
  • Max depth 32
  • Style index ≥ document sub-table count with explicit styles (key 32 = 0) → invalid (not clamp to 0)
  • With named set (key 32 ≥ 1), index beyond client's set copy → fall back to set style 0 + warn (registry skew)

5. Control Usage Patterns

5A. Text styles

[STYLE_TEXT index] ...text... [STYLE_END]

5B. Containers

[STYLE_CONTAINER composite_index] ... [BLOCK_END]

Encoders SHOULD open top-level containers in the layout's pane index order (Header → Left → Main row-major → Right → Footer).

5C. Tables

[STYLE_TABLE index]
  cells separated by UNIT_SEP (0x1F)
  rows separated by RECORD_SEP (0x1E)
[BLOCK_END]

5D. Lists and nav

[ITEM_BLOCK type style_index] item [US] item ... [BLOCK_END]

Types: 0 unordered, 1 ordered, 2 nav, 3 definition list.

5E. Links

[LINK_START type len target...] visible text [LINK_END]

Types: 0 URL, 1 QWeb page ID, 2 mailbox (7 B), 3 Logic action (Phase III).

5F. Images

[IMAGE image_def_index]

Index into Image Definitions sub-table → Resource ID → binary data. Width/height in the definition support placeholders when Resources are skipped.

5G. AI prompts

[AI_PROMPT type len_lo len_hi utf8...]

Types: 0 style, 1 image, 2 layout. Advisory only; document MUST remain legible if ignored.

5H. Element IDs

[ELEMENT_ID id] [next element]
[ELEMENT_ID 0xFF][id_lo][id_hi]  ; extended

Stable aliases for Phase III Logic; optional for static render.

5I. Breaks

LINE_BREAK, PARA_BREAK, PAGE_BREAK, HORIZ_RULE [border style index].

6. Hierarchical Addressing

Implicit path: section / layer / container / element from pane index table + stream order — nothing written on the wire. ELEMENT_ID is the stable mutation alias.

7. Separator Roles in Text

ByteRole
GS 0x1DNot used in free Text (Styles sub-tables only)
RS 0x1ETable rows inside STYLE_TABLE only
US 0x1FTable cells / list / nav items inside established blocks