# Carrier Visual Protocol 1 (CVP1)

Release: **1.0.0**. Normative wire specification: `cvp1/1.0.0/spec.md`. Executable reference: `cvp1/1.0.0/cvp1.js`.

The dictionary describes the purpose of CVP1 and points to this release; its entry text and spoken payload are not an alternative technical specification. Conformance is evaluated against this versioned contract and its fixtures. A disagreement between the reference implementation and this contract is a defect requiring investigation and a new release. Dictionary review, implementation conformance, and independent implementation agreement are distinct.

Status: implementation specification for the standalone visual carrier. This is an outer byte transport. It does not replace, alter, or extend the existing `carrier.js` syllable and typed-phrase codec. An object may contain ordinary bytes, UTF-8 text, a dictionary export, or existing Carrier phrases.

This specification defines exact logical symbols and byte recovery. The supplied browser decoder targets original exports, quarter-turn rotations, whole-image resizes, and the calibrated color changes covered by its tests. It does not promise recovery from arbitrary camera perspective, cropping, blur, JPEG compression, print/scan conditions, or a language model's unaided visual interpretation.

## 1. Vocabulary and acceptance

- **Original object:** the exact input byte sequence before optional compression.
- **Stream:** the original bytes, or their gzip-compressed representation.
- **Frame:** one image carrying a header and one consecutive stream chunk.
- **Module:** one square logical cell in the image layout.
- **Data symbol:** a four-bit value, represented by one of sixteen nominal sRGB colors.
- **Verified recovery:** successful structural, frame, sequence, stream-hash, decompression, length, and original-hash checks. Plausible content alone is not success.

Hashes provide integrity comparisons. They do not establish authorship, authorization, provenance, secrecy, or protection against an adversary who can replace the data and recompute its checksums.

## 2. Transport alphabet

For a nibble `v` from 0 through 15:

```
rLevel = v >> 2
gBit   = (v >> 1) & 1
bBit   = v & 1
RGB    = (rLevel * 85, gBit * 255, bBit * 255)
v      = (rLevel << 2) | (gBit << 1) | bBit
```

| Value | sRGB hex | Value | sRGB hex |
|---:|---|---:|---|
| 0 | #000000 | 8 | #AA0000 |
| 1 | #0000FF | 9 | #AA00FF |
| 2 | #00FF00 | 10 | #AAFF00 |
| 3 | #00FFFF | 11 | #AAFFFF |
| 4 | #550000 | 12 | #FF0000 |
| 5 | #5500FF | 13 | #FF00FF |
| 6 | #55FF00 | 14 | #FFFF00 |
| 7 | #55FFFF | 15 | #FFFFFF |

Each wire byte produces two cells: its high nibble first, then its low nibble. These colors can themselves be named by the existing Carrier color codec, but a CVP1 transport cell is a four-bit symbol. It is not an original twelve-bit Carrier phrase syllable. Converting existing phrases to this outer transport must retain the original phrase bytes exactly.

## 3. Image geometry

The data grid side `M` is one of `64`, `128`, or `256` modules. The complete square image has side `S = M + 24` modules and a white background. Coordinates below are zero-based, with x increasing rightward and y downward in the canonical orientation. Module rectangles include their starting coordinate and exclude their far edge.

The `M` by `M` data grid begins at `(12, 12)`. Its cells are traversed row by row, left to right, beginning at that position.

Four 7 by 7 finders begin at:

| Finder | Top-left coordinate | Center color value |
|---|---|---:|
| Top left | `(2, 2)` | 12 |
| Top right | `(S-9, 2)` | 2 |
| Bottom right | `(S-9, S-9)` | 1 |
| Bottom left | `(2, S-9)` | 14 |

Each finder has a one-module black outer ring, a white inner 5 by 5 square, and a colored central 3 by 3 square. Their asymmetric colors identify orientation. These landmarks are framing, not payload.

The top calibration strip begins at `((S-32)/2, 3)`. It contains values 0 through 15 in order from left to right, each occupying a 2 by 2 module patch. A second strip repeats that order at `y = S-5`. The two strips expose the palette near opposite image edges.

Alternating black/white timing lines occupy `x = 10`, `y = 10`, `x = S-11`, and `y = S-11`, spanning coordinates 12 through `12+M-1` on the varying axis. A varying-axis coordinate is white when odd and black when even. They are available to support grid recognition and sampling; payload recovery must not interpret them as data. The reference decoder does not inspect the timing lines.

The reference decoder treats the complete square raster as the frame bounds. It tries the three grid profiles and four quarter-turn orientations, samples cell interiors, estimates each palette color from four calibration-patch observations across the two strips, and compares samples with that measured palette. It requires every pair of measured palette colors to have RGB Euclidean distance at least 40 and accepts a candidate orientation only when at most 12% of the 196 sampled finder cells disagree with their expected symbols. Any sampled pixel with alpha below 250 rejects that candidate. These are implementation thresholds, not general recovery guarantees. It does not locate a frame inside a larger photograph or estimate perspective. Header and payload checks must still succeed before any candidate is accepted.

## 4. Reed-Solomon profile and interleaving

ECC profile 1 is full-length, systematic RS(255,223): 223 data bytes followed by 32 parity bytes. The field is GF(256), primitive polynomial `0x11d`, primitive element `alpha = 2`. The generator roots are `alpha^0` through `alpha^31`; bytes are coefficients in descending polynomial degree. All 255 bytes are transmitted. Zero padding is encoded as data; this is not a shortened-code variant.

The v1 decoder repairs unknown byte errors; it has no erasure-position input. Up to 16 erroneous bytes in each codeword are within its correction guarantee. Beyond this bound, decoding can reject or miscorrect, so the following integrity checks remain mandatory. The general error-and-erasure bound must not be presented as an implemented erasure feature.

Let `K = floor(M*M/510)`. A frame has `K` codewords. Codeword 0 carries the 223-byte header. The other `K-1` codewords carry consecutive chunks of 223 payload bytes, with zero padding at the end. Codewords are interleaved column by column:

```
wire[i*K + k] = codeword[k][i]
for i = 0..254 and k = 0..K-1
```

Convert each wire byte to two palette values, then place them in data-grid traversal order. A canonical encoder sets any remaining data-grid cells to palette value zero. They are outside the transmitted wire bytes and all hashes; the reference decoder does not sample or validate them. Altering these unused cells therefore does not, by itself, invalidate a recovered object. This spreads neighboring wire-byte errors across different codewords; it does not establish a universal tolerance expressed as a percentage of damaged pixels.

## 5. Header

All multi-byte integers are unsigned and little-endian. All hash fields contain raw digest bytes, not hexadecimal text. A header occupies exactly 223 bytes.

| Offset | Bytes | Meaning |
|---:|---:|---|
| 0 | 4 | ASCII magic `UCV1` |
| 4 | 1 | Version: 1 |
| 5 | 1 | Flags: bit 0 means gzip; all other bits zero |
| 6 | 1 | Palette profile: 1 |
| 7 | 1 | ECC profile: 1 |
| 8 | 2 | Header length: 223 |
| 10 | 2 | Data grid side `M` |
| 12 | 4 | Zero-based frame index |
| 16 | 4 | Total frame count |
| 20 | 4 | Original byte length |
| 24 | 4 | Stream byte length |
| 28 | 4 | Bytes of stream in this frame |
| 32 | 4 | Byte offset of this chunk in the stream |
| 36 | 32 | SHA-256 of this chunk's exact bytes |
| 68 | 32 | SHA-256 of the complete stream |
| 100 | 32 | SHA-256 of the original object |
| 132 | 16 | Message ID: first 16 bytes of the original-object SHA-256 |
| 148 | 2 | Metadata length in UTF-8 bytes, at most 69 |
| 150 | 69 | Metadata bytes followed by zeros |
| 219 | 4 | CRC-32 of header bytes 0 through 218 |

CRC-32 uses the reflected IEEE profile, polynomial `0xedb88320`, initial value `0xffffffff`, and final XOR `0xffffffff`. The check value for ASCII `123456789` is `0xcbf43926`. Store that integer little-endian. The CRC is a header corruption check, not a cryptographic authenticator.

Metadata is a valid UTF-8 JSON object whose parsed key set is exactly `n` and `t`, both strings, for filename and media type. Its exact serialized byte length must fit the 69-byte field. The canonical encoder serializes `n` before `t` without extra whitespace. It replaces filename control characters and path punctuation with underscores, initially keeps at most 80 Unicode code points, and then shortens the name by code points until the serialized object fits. It defaults the media type to `application/octet-stream` and also uses that fallback when serializing `{n:'',t}` with the requested media type would exceed 65 UTF-8 bytes. It uses `data` if truncation leaves an empty filename. Do not slice raw UTF-8 bytes or serialized JSON to make them fit.

The reference decoder validates UTF-8, JSON parsing, the exact parsed key set and string types, and zero metadata padding; it does not require canonical key order or whitespace. Metadata is descriptive, untrusted content; it must not be executed or inserted as raw HTML. Sequence comparison uses the exact metadata bytes, not merely equivalent parsed JSON.

The magic uses `UCV1`, while the format's display name is CVP1. Implementations must compare the literal wire magic specified here.

## 6. Capacity and chunking

The payload capacity `C` of a frame is `(K-1)*223` bytes. The header consumes one complete codeword.

| M | Complete side S | Grid cells | K | Payload bytes per frame C | Unused data cells |
|---:|---:|---:|---:|---:|---:|
| 64 | 88 | 4,096 | 8 | 1,561 | 16 |
| 128 | 152 | 16,384 | 32 | 6,913 | 64 |
| 256 | 280 | 65,536 | 128 | 28,321 | 256 |

For stream length `L`:

```
frameCount = max(1, ceil(L/C))
chunkOffset(i) = i*C
chunkBytes(i) = min(C, L-i*C)
```

The uncompressed empty object is represented by one frame, with a zero-length chunk and the SHA-256 digest of empty bytes. Each nonfinal chunk is full. Only the final chunk may be short. Payload slots beyond `chunkBytes` are zero. Padding does not belong to any object or chunk hash.

Wire length fields are u32, but this does not promise that the browser can process objects approaching 4 GiB. The reference browser limits both original and stream size to 8 MiB (8,388,608 bytes), sequences to 1,024 frames, and input rasters to 16 million pixels. The image must be square with width at least `2*(M+24)` pixels. A single assembly call accepts at most 2,048 decoded-frame objects, including duplicates. Reject out-of-policy declarations before expensive allocation or decoding. A finer grid offers more bytes per image; at a fixed pixel size it also leaves fewer pixels per cell.

## 7. Compression and exact reproducibility

Flag 0 transports original bytes directly; stream and original hashes and lengths must then agree. Flag 1 means the stream is gzip and must decompress to exactly `originalBytes` bytes with the declared original SHA-256. The reference encoder keeps compression only if it reduces stream size.

The object hash is computed before compression. The stream hash identifies one particular encoded stream. Different conforming gzip implementations can produce different valid streams for the same object; original-object recovery remains byte-exact. Reproducible image fixtures therefore freeze the input stream bytes, flags, metadata bytes, grid choice, encoder version, and rendering parameters. Do not claim identical PNG files from different browser or gzip implementations merely because they decode to the same object.

During decompression, stop if output exceeds the declared original length or the implementation's resource limit. Never rely on a size check performed only after allocating an unbounded decompressed object. Unsupported compression is a failure, not permission to treat compressed bytes as a verified original file.

## 8. Decoder acceptance sequence

1. Apply raster and supported-layout limits. Establish a candidate canonical orientation and sampling geometry, then read palette values and reconstruct exactly the wire bytes. Unused grid cells and timing lines are not part of reference-decoder acceptance.
2. Deinterleave and RS-decode codeword 0 first, including syndrome verification. Parse its 223 data bytes before allocating or decoding the payload codewords.
3. Verify header CRC, magic, version, flags, profiles, header length, grid size, field bounds, metadata validity, zero metadata padding, and agreement of the message ID with the first 16 bytes of the original hash.
4. Require `frameCount`, index, offset, and chunk length to obey the fixed-capacity chunking rules; uncompressed original and stream lengths must agree. RS-decode the remaining codewords, verify their repaired syndromes, retain repair counts, and require zero payload padding.
5. Extract the exact chunk length and verify its full SHA-256. A frame is not accepted merely because RS decoding returned bytes.
6. Group frames using the full stream SHA-256. Within a sequence require identical flags, grid size, frame count, original and stream lengths, both full hashes, message ID, and exact metadata bytes. The shortened message ID is a display convenience, never sufficient as the sole grouping key.
7. At assembly, reparse each retained header and compare its fields with the supplied decoded-frame fields. Recheck every chunk hash. Require every declared index exactly once after deduplicating frames with identical sequence metadata and chunk bytes. Conflicting duplicates, missing chunks, gaps, overlaps, or contradictory metadata are explicit failures. Arrival order is irrelevant; output order follows validated indices and offsets.
8. Assemble the exact stream and verify its declared length and SHA-256. Decompress only when flagged, within the declared and configured bounds.
9. Verify the final original length and SHA-256. Only now expose an object as verified recovered bytes. A verified object may still contain untrusted content.

Errors beyond the correction budget can occasionally become another valid RS codeword. The header CRC and independent chunk, stream, and original checks are therefore required parts of acceptance. Hash verification confirms equality to the claims in the frame; it does not authenticate who supplied those claims.

## 9. Dictionary packages and multi-image use

The visual layer carries a generic file. A dictionary-package JSON structure, checked/working raw JSONL strings, source heads, and their digests live inside that file and are outside this transport header. The package parser must validate its own format after byte recovery.

Preserve downloaded JSONL byte strings before hashing. Parsing and reserializing JSON can change spaces, key order, line endings, Unicode escapes, or final newlines even if the parsed values are equivalent. Original-byte claims must refer to the exact bytes actually carried.

There is no unlimited per-image dictionary capacity. A large package consumes the calculated number of frames, subject to the implementation limits. Export a sequence manifest alongside images, but keep each image self-identifying through its verified header. A missing image remains a missing chunk; within-frame RS does not reconstruct an absent frame.

### Application profile: pinned meaning references

Applications that use recovered bytes as references to Carrier meaning must identify each reference with the tuple **registry + tier + id + head**: the registry's stable identifier, the exact `working` or `checked` tier, the stable entry ID, and the complete head of the intended dictionary snapshot. An RGB anchor alone is not a unique record identifier; multiple entries may share one, and the same anchor can have different interpretations across registries or snapshots. A display name is not an identity substitute.

Resolve the entry only against that pinned snapshot and apply the registry's own head-verification rules. A snapshot head and a digest of exported JSONL bytes are different claims; do not substitute one for the other. Preserve or obtain the required historical snapshot. If it is unavailable or fails verification, report an unresolved reference instead of silently substituting today's entry. Byte recovery does not promote a working entry to checked status or establish the truth of its definition.

Graph applications must declare their schema and version, encode relation types explicitly, and identify source and target records by the same complete reference tuple. An untyped link remains an untyped link; it does not imply `enables`, `depends-on`, or another specific relation. Do not infer semantic relations from picture position, color similarity, or proximity unless a separately declared, versioned spatial grammar defines those rules. CVP1's row-major transport positions only determine byte order.

The sixteen-color palette carries four bits per data cell. A sequence of recovered bytes can encode references into a much larger shared snapshot, but those definitions reside in that snapshot or in an explicitly carried package. Sixteen colors do not directly encode millions of concepts, and references do not create additional physical capacity. This is an application contract above CVP1; the transport decoder does not itself resolve semantic references or execute a graph grammar.

These requirements develop the shared semantic-state and explicit-grammar ideas in [Unified State Language: An AI Perspective on Its Current State and Future](https://www.unifiedstate.us/unified-state-language-an-ai-perspective-on-its-current-state-and-future/) and [The Pixel Is Not the Meaning](https://www.unifiedstate.us/the-pixel-is-not-the-meaning-semantic-images-and-the-visual-future-of-unified-state-language/), while keeping their proposed semantic uses separate from the implemented byte transport.

## 10. Datasets, evaluation, and claims

A useful dataset keeps exact source bytes and their SHA-256, stream bytes or their reproducible construction, protocol and encoder versions, metadata bytes, frame index and count, grid and raster settings, and all applied transformations. Synthetic transformations should include recorded parameters and random seeds.

Split by source object before generating rotated, recolored, resized, or damaged variants. Keep all frames and related variants of an object in the same split. Label verified recovery, explicit rejection, and unverified output separately. Include incomplete sequences, conflicting duplicates, corrupt headers, difficult colors, and damage beyond the code's budget.

Report byte-exact object recovery and false-acceptance/rejection results for each tested condition. State the input resolution and profile; raw visual accuracy or a few successful examples do not establish reliable decoding. A model can help explain, inspect, or propose readings, but the deterministic decoder and full integrity checks remain the acceptance authority for this implementation. The format has not by itself established future model decoding capability.

## 11. Conformance evidence and fixture requirements

The following fixture list is a conformance target, not a claim that every case has been published or tested. Publish fixed vectors alongside the implementation: all sixteen palette values; byte-to-two-cell order; the CRC check string; an exact 223-byte RS data block with its parity; a fixed complete header; an uncompressed empty object; a short UTF-8 object; a multi-frame binary object; and one frozen gzip stream. Include corruptions at 1, 16, and more than 16 byte positions per codeword, rotations/resizes actually supported by the browser, missing/conflicting frames, and header/resource-limit rejection cases.

The included `codec-ecc.test.cjs` defines 13 ECC tests: an independent bitwise finite-field/parity oracle, fixed parity vectors, 512 seeded blocks with 0/1/8/16 errors, every byte position, all nonzero magnitudes at the data/parity boundary, contiguous 16-byte bursts, an initial-zero-syndrome case, over-capacity behavior, input validation, and browser-global loading. Successful execution of these checks establishes only their stated ECC coverage; they do not by themselves test raster recognition, complete headers, compression, sequence assembly, or image transformations. Any separate visual test report must name its actual fixtures, transform parameters, and results without extending those results to untested camera or transmission conditions.

The RS implementation supplies these parity vectors, verified against the independent field-arithmetic oracle. Hex bytes are written in transmitted order:

```
data:   00 01 02 ... dc dd de    (223 ascending bytes)
parity: 41841183b11fdb537421939696cda70e1db5c86684af222564b89cc6069f172e

data:   222 zero bytes, followed by 01
parity: 744034ae367e10c2a221219db0c5e10c3b37fde4942fb3b9188afd148e37ac58
```

The codec tests also include a received block that is 17 errors from one codeword but only 16 errors from a different codeword. Correcting it to the latter is within the decoder's mathematics and demonstrates why the independent object-integrity checks cannot be omitted.

The reference implementation and fixtures resolve rendering details that do not affect the logical bytes. Any change to wire semantics, palette values, field layout, code conventions, or traversal order requires a new declared profile or version rather than silent reinterpretation.
