# Carrier Visual Protocol 1 (CVP1)

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

Release 1.1.0 extends supported grid sizes and bounded raster recognition. It preserves wire version 1, every header field, palette, Reed–Solomon convention, byte order, and the exact raster of existing 64/128/256 exports at the same cell size. The immutable 1.0.0 implementation remains valid for those original profiles; it does not recognize the newly supported sizes. New encoders must identify their executable/specification release separately from the wire-version byte.

Release 1.2.0 raises the reference source/stream limit to 128 MiB and the sequence limit to 65,535 frames. It adds an optional prepared-sequence API that produces one frame on demand. These are explicitly versioned implementation/resource-policy changes: wire version 1, grid geometry, capacity, compression flag, checksums, hashes and every header field retain their previous meaning. Older decoders continue to read objects within their limits and reject larger declarations according to their own resource policy.

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 any integer multiple of 8 from `32` through `4096`, inclusive. Named presets are `64`, `128`, `256`, `1024`, `2048`, and `4096`; fitted sizes use the same format. 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 considers supported grids with at least one raster pixel per module, prioritizing exact integer scales from 1 through 24, then the named presets, then remaining supported sizes in ascending order. Each candidate is tried in four quarter-turn orientations. It samples cell interiors, estimates each palette color from four calibration-patch observations across the two strips, and compares samples with that measured palette. At exactly one pixel per module it reads that pixel; otherwise it uses a per-channel median of nine interior samples at offsets -0.16, 0, and 0.16 around the module center. 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.

Before allocating a candidate's complete wire array, the decoder samples the 255 interleaved bytes of header codeword 0, applies Reed–Solomon recovery, and validates the complete header against that candidate grid. Only then does it sample all transmitted payload symbols. It checks the header again during ordinary wire decoding. 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 |
|---:|---:|---:|---:|---:|---:|
| 32 | 56 | 1,024 | 2 | 223 | 4 |
| 64 | 88 | 4,096 | 8 | 1,561 | 16 |
| 128 | 152 | 16,384 | 32 | 6,913 | 64 |
| 256 | 280 | 65,536 | 128 | 28,321 | 256 |
| 1024 | 1048 | 1,048,576 | 2,056 | 458,265 | 16 |
| 2048 | 2072 | 4,194,304 | 8,224 | 1,833,729 | 64 |
| 4096 | 4120 | 16,777,216 | 32,896 | 7,335,585 | 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 128 MiB (134,217,728 bytes), sequences to 65,535 frames, and complete input/output rasters to 4,120 pixels per side (16,974,400 pixels). The image must be square with width at least `M+24` pixels. The supplied renderer accepts integer cell sizes from 1 through 24, additionally bounded by `(M+24)*cellSize <= 4120`. Its default is `min(8, floor(4120/(M+24)))`; all original named profiles retain their old default of 8. The largest frame therefore has a 4096×4096 data grid inside a 4120×4120 raster and uses one pixel per module. Its single RGBA buffer occupies 67,897,600 bytes. Applications must inspect image dimensions before creating a canvas or decoded RGBA buffer and must release obsolete raster/preview objects instead of retaining an entire large sequence in memory.

A single assembly call accepts at most 131,070 decoded-frame objects, including duplicates. Reject out-of-policy declarations before expensive allocation or decoding. The original/stream byte limit and exact chunking equations additionally constrain the valid frame count for any grid. For example, a raw 128 MiB source exceeds 65,535 frames at a 32 or 64 grid and must use a larger grid, compression that reduces it enough, or separate messages. Frame index, count, original length, stream length, chunk length and offset are all unsigned 32-bit fields, not 16-bit fields. Consistent accepted offsets and lengths stay at or below the 128 MiB bound, far below either unsigned 32-bit or JavaScript safe-integer overflow.

The reference encoder interleaves one codeword at a time, and its renderer writes directly into one RGBA buffer without first allocating a module matrix. The decoder validates the header before complete-wire allocation and retains only declared chunk bytes, while still validating every transmitted codeword and all zero padding. A finer grid offers more bytes per image; at a fixed pixel size it also leaves fewer pixels per cell. One-pixel exports require preservation of those exact pixels; successful resampling of larger-cell fixtures is not a promise of recovery after shrinking or filtering a one-pixel frame.

### Fit to content

`encode(bytes, {grid:'auto', ...})` and `prepare(bytes, {grid:'auto', ...})` first perform optional gzip and retain it only when it reduces the stream. Let `L` be the resulting stream byte length. Choose the smallest allowed `M` whose capacity `C(M)` is at least `L`; an empty stream selects 32. Equivalently, round `sqrt((ceil(L/223)+1)*510)` upward to a multiple of 8, with a minimum of 32. If `L > C(4096)`, choose 4096 and apply normal multi-frame chunking. The 128 MiB message limit then needs at most nineteen automatically fitted frames.

Fit minimizes the data square's unused capacity; it does not stretch text pixels or change the coding system. The framed header, full-length RS blocks, final zero padding, and framing are always present. The exact grid is stored in the existing unsigned 16-bit header field at offset 10, so the receiver does not need the sender's UI choice. Compression can make a long text fit into a very small square.

### Prepared sequences and application memory

`await prepare(bytes, options)` takes a byte snapshot of the source, hashes it, performs optional beneficial gzip and chooses the grid/chunks exactly as `encode` does. It returns a frozen object with these serializable fields:

```text
grid, capacity, flags, originalBytes, streamBytes,
originalHash, streamHash, messageId, name, frameCount
```

`name` preserves the earlier API's serialized metadata JSON containing `n` and `t`; it is not a bare filename. Two methods are also present: `await getFrame(index)` generates the usual frame object for the requested zero-based safe-integer index, and `dispose()` releases the retained stream. A prepared sequence does not contain a `frames` array. Repeated requests for the same index produce identical wire bytes. Changing the caller's original input array after preparation does not alter the prepared source. Disposal is idempotent; later frame requests reject, while already returned frames remain usable. An in-flight request that captured its chunk before disposal can finish; applications must use their own generation/cancellation identifier to ignore obsolete results.

The existing `encode(bytes, options)` API remains compatible and collects all prepared frames into the original result shape. Applications processing large objects should use `prepare` and request frames sequentially in a worker, releasing old wire and raster objects. The plan retains one stream; compression can release the uncompressed snapshot after hashing, but source arrays, browser stream internals, hashing, compression output and assembled decoded bytes still require memory. This API bounds eager wire/raster accumulation, not total memory to one image. Canceling a worker is an application-level way to discard an entire obsolete preparation. A prepared sequence is a transient in-memory object; it is not a serialized wire format.

### RGB24 namespace atlas is a separate image

A 4096×4096 atlas can show every RGB24 color exactly once because it has 16,777,216 pixels. It is a view of the addressing space, including unallocated colors; it is not a CVP1 frame. CVP1 uses sixteen calibrated transport colors and four bits per data cell, with explicit framing, integrity checks, and error correction. Its 4096 grid therefore carries at most 7,335,585 stream bytes rather than 16,777,216 RGB24 semantic references. A namespace atlas must be labeled and exported separately and must not be presented to the CVP1 decoder as a verified message.

## 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 1.2.0 reference stops collecting compression output as soon as its length reaches or exceeds the original byte length, cancels that stream, and keeps the original bytes. Beneficial gzip output remains byte-identical to the same runtime's earlier encoder on the compared fixtures. The maximum source limit applies before compression: compressibility does not authorize a source larger than 128 MiB. The maximum stream and expanded output remain independently bounded.

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 sufficient historical record identifier: current global allocation prevents new overlaps within its scope, while legacy snapshots and other registries can have different interpretations or duplicate anchors. 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.

Release 1.1.0's `codec.test.cjs` adds 14 test groups for bounds and exact capacities; every allowed grid's fit boundary; differential wire and RGBA equality with the 1.0.0 implementation at 64, 128, and 256; fit after beneficial gzip; real 1024, 2048, and 4096 raster round trips; a rotated 1024 frame with 16 byte errors in each of three codewords; a full-capacity 4096 raster carrying 7,335,585 seeded high-entropy bytes; a fitted 40 grid after a specified rotation, nearest-neighbor resize and calibrated RGB changes; independent hash refusal after replacement with a valid RS codeword; resource/geometry rejection; 8 MiB two-frame assembly and missing-frame rejection; and browser-global loading. See the release test report for the executed environment and precise limits of these claims. These tests do not establish recovery after JPEG, camera capture, perspective distortion, print/scan, or shrinking a one-pixel export.

Release 1.2.0 adds 11 test groups covering the increased bounds and unchanged capacities; differential eager/lazy wire, metadata and RGBA agreement with 1.1.0 including compression; more than 8 MiB of repeated book-like text through gzip, fit and a real raster; high-entropy uncompressed input above 9 MiB; full assembly of 1,025 frames; requesting and verifying the last frame of a 65,535-frame plan; source snapshots, deterministic regeneration and disposal; discarded gzip expansion; invalid source/stream/count/header declarations; bounded decompression; and a real 128 MiB source prepared as nineteen frames with its final frame verified. The last test does not claim that all nineteen maximum-source frames were rendered or assembled. The separate test report states exact fixture sizes and execution evidence.

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. Expanding the accepted grid set is explicitly versioned as executable/specification release 1.1.0; increasing reference object/sequence bounds and adding prepared sequences are release 1.2.0 changes. The existing wire-version 1 header retains its exact interpretation.
