# Content-Addressed CFC Labels A labeled document's stored CFC envelope names each label it carries by content hash instead of copying the label inline: every `labelMap` entry keeps its `path`, `origin`, and `observes` inline and holds its `label` either as the label itself or as a reference to an immutable `cid:` label document that any number of entries, maps, and tables share. ## Status Design and implementation, behind the `cfcContentAddressedLabels` runtime flag (off by default). Readers interpret both envelope versions; the flag decides only which spelling the persist path writes. ## Last Updated 2026-09-15 ## Motivation Every labeled entity document stores its whole CFC envelope `{ version, schemaHash, labelMap }` at its reserved `cfc` member, and every revision row copies it again. In one real store the envelopes of chat-row entities dominate the bytes: | Measured on 196k labeled entities (latest 200k head rows) | | |---|---| | value bytes per entity | ~465 | | envelope bytes per entity | ~5.2 KB (p50 4.9 KB, max 5.8 KB) | | envelope share of live JSON | ~93% | | `labelMap.entries` per map | 1–9 (5, 8, or 9 for message-row tables) | | bytes per entry | ~790, of which `path`+`origin`+`observes` ~25 and `label` ~620 | | distinct envelopes / labels / clauses across the sample | 11 / 6 / 7 | Each `label` is `{ confidentiality: [3–4 clauses], integrity: undefined }` and each clause is 58–317 bytes. The same six label values recur across 196k documents. The schema half of the envelope is already content addressed (`schemaHash` names a `cid:` schema document, [content-addressed-schemas.md](content-addressed-schemas.md)); the label half is what remains inline. ## Granularity Four candidate granularities, measured on a fixture built to the shape above: 8 entries, 6 distinct labels drawn from 7 distinct clauses (117–258 bytes each), labels of 562–729 bytes, one 414-byte value. A `cid:` reference is 63 bytes (`{"$ref":"cid:fid1:<43 chars>"}`), and each stored `cid:` document is charged ~120 bytes of row overhead beside its content. Store-wide totals extrapolate to 196k entities sharing 11 maps and 6 labels, as measured. | Option | Envelope bytes per entity | Shared documents, once per space | Store total | |---|---|---|---| | inline (today) | 5588 | 0 | 1095 MB | | (a) whole map by reference | 152 | 11 maps, 62 KB | 30 MB | | (b) inline map, labels by reference | 1132 | 6 labels, 4.2 KB | 222 MB | | (c) inline map, clauses by reference | 2765 | 7 clauses, 2.0 KB | 542 MB | | (m) map by reference, map references labels | 152 | 11 maps + 6 labels, 17 KB | 30 MB | What the numbers say: - **Clause-level references lose.** A clause is 60–260 bytes, so replacing one with a 63-byte reference saves little, and a label of four references costs 274 bytes of references plus its own object framing. Option (c) keeps 2.5× the bytes of (b) while adding a resolution hop per clause. A Merkle variant in which label documents reference clause documents saves 2 KB of shared bytes per space and nothing per entity; it is not worth a third document class. - **Label-level references remove 80% of envelope bytes** and are the unit that reuse actually happens at: 6 label values serve 196k documents across several tables, and a map that introduces one new label writes one new ~600-byte document while every other entry keeps its existing reference. Paths and origins stay readable without resolving anything, and the applies-to-path probe that runs on every write reads only them (`readStoredCfcLabelPaths`), so the hot path pays no label-document read; consumers that need the labels themselves resolve them once per distinct document. - **Map-level references are 7× smaller again at rest**, because the measured store repeats 11 maps across 196k entities. They cost a second reference level on every seam (commit validation, traversal, client sync, and every metadata read), a two-hop cold sync (the map document must arrive before its label references are known), and their saving depends on whole-map repetition, which per-document flow labels erode while label-level sharing survives it. The choice is **(b)**: the map stays inline and labels are referenced. Option (m) is a pure addition on top of it — a later envelope version whose `labelMap` is a reference to a document holding exactly the (b) map — and is the follow-on to measure once (b) has landed and the residual is known; nothing in (b) is wasted by it. ### The inline threshold Not every label earns a reference. A label whose canonical JSON is short — `{ "confidentiality": ["secret"] }` is 30 bytes — costs more as a reference (63 bytes plus a document) than inline. A label is stored by reference when its canonical serialization exceeds `CFC_LABEL_INLINE_LIMIT` (128 bytes: two references' worth, above which the saving is at least half the label) and inline otherwise. Inline and referenced labels coexist in one map, which is exactly the "new small label beside existing referenced ones" case. The rule is canonical by construction: it is a pure function of the label's canonical content and the format version, so the same label takes the same form wherever it is written and hashes to the same document. Correctness does not depend on that — a reader accepts either form for any label, and the idempotence check compares resolved labels — but deduplication does: two spellings of one label would be two forms in the store rather than one document. The limit is therefore part of the versioned envelope contract, not a tuning knob. ## Design ### Envelope version 2 ```jsonc { "version": 2, "schemaHash": "fid1:…", "labelMap": { "version": 1, "entries": [ { "path": ["messages", "*", "text"], "origin": "declared", "label": { "$ref": "cid:fid1:…" }, }, { "path": ["title"], "origin": "derived", "label": { "confidentiality": ["room-title"] }, }, ], }, } ``` Version 1 is the fully inline form. Version 2 differs in one respect: an entry's `label` is either an inline label or a single-member `{ "$ref": "cid:" }` reference. A reference has no sibling keys and an inline label never carries `$ref`, so the two are told apart by the key alone. `version` is the gate: a build that predates version 2 fails closed on it through `UnknownCfcMetadataVersionError`, which is the behavior the version field exists for, and why the writer is flagged rather than flipped. ### Label documents A label document is a `cid:` document whose value is one canonical label: - **Id**: `cid:`, the general content hash the commit boundary verifies every `cid:` set against. Nothing but the label enters the hash. - **Content**: `{ "value":