# Lace-010 · Records
Tags: record, stored-format

## Purpose

Distributed data needs identity that follows the bytes, plus enough structure to
make those bytes indexable, versioned, and attributable after they arrive from
another source. Lace records provide that unit: canonical bytes with stable
hashes, optional coordinates and headers, and optional verifier signatures.
Stored records have three content forms: Blob record for bytes, Plex record for
coordinate-bearing record versions, and Seal record for a verifier signature over a
Plex record.

This document is for record implementors and higher-layer implementors that
consume record facts. After reading it, an implementor should be able to parse,
validate, store, hash, sign, and index the current H3 record forms.

## Defines

Blob records, Plex records, Seal records, header rules, TAI, coordinate header
validation, thin format, trailer-hash transport form, and examples.

## Every stored record starts with a markline

```text
🖧: <hash-text>
```

`<hash-text>` is `T.<b64a>.H3`, where `T` is `B`, `P`, or `S`. The B64A payload
is the BLAKE3-256 digest of the canonical payload after the markline LF.

Implementations MUST verify that the markline type matches the record type and
that the digest matches the canonical payload.

## Shared header rules keep bytes canonical

Header syntax is `<Name>: <value>`.

Implementations MUST enforce these rules:

- header names are non-empty;
- header names MUST NOT contain `:`, space, or tab;
- exactly one space follows `:`;
- header values are non-empty;
- header names and values are UTF-8 NFC;
- header lines end with LF only;
- CR and CRLF are invalid;
- control bytes `0x00..0x1F` and `0x7F` are forbidden in headers;
- one header line is at most 1024 bytes, excluding LF;
- whitespace is data and is never trimmed.

## Blob records carry raw bytes

```text
🖧: B.<digest>.H3
Data-Length: <len>

<data>
```

The Blob record canonical payload is `Data-Length`, a blank line, and exactly
`<len>` data bytes.

Blob record rules:

- `Data-Length` MUST be base-10 with no leading zero except `0`;
- readers MUST consume exactly `<len>` bytes;
- Blob data MUST NOT exceed 32 MiB.

Blob data is opaque and may contain any bytes.

## Plex records attach coordinates and headers to a Blob record

```text
🖧: P.<digest>.H3
Group: <group>
App: <app>
Name: <name>
TAI: <tai>
[Extra headers]*
🖧: B.<digest>.H3
Data-Length: <len>

<data>
```

The Plex record canonical payload is all Plex headers followed by the full
embedded Blob record.

Plex record rules:

- `Group`, `App`, `Name`, and `TAI` MUST each appear exactly once;
- required headers MUST appear in that order;
- extra headers MUST follow `TAI`;
- extra headers are hash-significant.

A Plex record is a coordinate-bearing record version. It can produce claims only
when a policy or profile explicitly allows unsigned Plex-record claims.

## Seal records sign a Plex record

```text
🖧: S.<digest>.H3
Signed-By: <verifier>
Signature: <signature>
🖧: P.<digest>.H3
Group: <group>
App: <app>
Name: <name>
TAI: <tai>
[Extra headers]*
🖧: B.<digest>.H3
Data-Length: <len>

<data>
```

The Seal record canonical payload is `Signed-By`, `Signature`, and the full
embedded Plex record.

Seal record rules:

- `Signed-By` MUST be `V.<b64a>.H3`;
- `Signature` MUST be a signature over the embedded Plex-record digest;
- readers MUST verify both Seal-record hash and signature.

A Seal record proves that its verifier signed one record version. It does not by
itself prove that the record is authorized or selected by any policy.

## TAI gives record versions a sortable time

`TAI` format is `seconds:subseconds`: 10 decimal seconds digits, `:`, then 9
decimal nanosecond digits.

The seconds field counts SI seconds on the TAI time scale from epoch
`1970-01-01T00:00:00 TAI`. Implementations MUST NOT reinterpret `TAI` as local
time or UTC text. `TAI` is version-ordering data; it is not proof that a signer
observed that time.

Implementations MUST reject any other `TAI` shape.

## Coordinate headers define an indexed record coordinate

`Group`, `App`, and `Name` are coordinate fields used for indexing and selection;
they are not record identity. Many records may share the same coordinate. The
record hash is the durable identity.

`Group` is a root-to-leaf path.

`Group` rules:

- value MUST contain one or more non-empty `/`-separated segments;
- value MUST NOT start or end with `/`;
- each segment MUST be at most 128 bytes;
- total value MUST be at most 675 bytes;
- segments MUST NOT contain `{`, `}`, `|`, or `#`;
- segments MUST NOT equal `.` or `..`.

`App` rules:

- value MUST contain one or more non-empty `/`-separated segments;
- value MUST NOT start or end with `/`;
- each segment MUST be at most 128 bytes;
- total value MUST be at most 128 bytes;
- segments MUST NOT contain `{`, `}`, or `|`;
- segments MUST NOT equal `.` or `..`.

`Name` rules:

- value MUST contain one or more non-empty `/`-separated segments;
- value MUST NOT start or end with `/`;
- each segment MUST be at most 128 bytes;
- total value MUST be at most 675 bytes;
- segments MUST NOT contain `{`, `}`, or `|`;
- segments MUST NOT equal `.` or `..`.

## Extra headers are sorted after required headers

Extra headers MUST be sorted by header name using bytewise ascending order.
Same-name extra headers MUST be consecutive and MUST preserve user-defined
order.

A Plex record MUST contain at most 512 extra headers.

Reserved extra header names are: `Data-Length`, `Group`, `App`, `Name`, `TAI`,
`Signed-By`, `Signature`, `🖧`, and `⋯🖧`.

## Record-link headers describe hash references

A Plex record extra header whose name is `+Link` or ends with `+Link` is a
record-link header. Record-link headers are ordinary extra headers: they are sorted,
hash-significant, and subject to all extra header rules.

A well-formed record-link header value is:

```text
<link-data> <target-hash>
```

Rules:

- `<link-data>` MUST be non-empty;
- the separator MUST be exactly one ASCII space;
- `<target-hash>` MUST be typed record hash text beginning with `B.`, `P.`, or
  `S.`;
- record-link parsing MUST NOT require the target hash suffix to be `H3`;
- the record definition named by the target hash suffix defines the target hash
  payload syntax and validation rules;
- `<link-data>` is application-defined text and MAY contain spaces except for
  the final separator space before `<target-hash>`.

Malformed record-link headers do not invalidate a record unless they violate
ordinary header rules. They remain ordinary extra headers. Layers that index
record-link headers MUST ignore malformed values. A target hash whose record
format is unsupported by the local store MAY be indexed as a link target, but it
MUST NOT become `Have` unless received bytes validate under a supported record
definition.

Examples:

```text
+Link: evidence S.EXAMPLE_SEAL_HASH.H3
Chunk+Link: 0..33554432 B.EXAMPLE_BLOB_HASH.H3
```

## Thin format stores references to known inner records

Thin Plex records store the Plex markline, Plex record headers, and embedded
Blob markline. Thin Seal records store the Seal markline, `Signed-By`,
`Signature`, and embedded Plex markline.

Thin records are storage and transfer shortcuts. Implementations MUST
reconstruct full record bytes before hash verification.

## Trailer-hash format supports streaming output

Trailer-hash format is a transport form for bytes whose final hash is known only
after payload has been written.

Open marker:

```text
⋯🖧: <type>[ <coordinate>]
```

Close marker:

```text
⋯🖧: <hash>
```

Rules:

- `<type>` MUST be `B`, `P`, or `S`;
- exactly one opening marker is allowed per record;
- nested or repeated open markers are invalid;
- data escapes a line that would begin with `⋯🖧:` by writing `⋯⋯🖧:` instead;
- data ends at the first LF followed immediately by `⋯🖧:`;
- the terminating LF is a separator and is not part of restored data;
- conversion to stored form MUST unescape escaped marker lines, restore ordinary
  marklines, and validate hashes and signatures.

## Examples

Hash strings are symbolic; real records use BLAKE3 digests of the canonical
payload bytes.

Blob record:

```text
🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 11

hello room7
```

Plex record:

```text
🖧: P.EXAMPLE_PLEX_HASH.H3
Group: eu/lab
App: chat
Name: room-7/123
TAI: 1640995200:000000000
Content-Type: text/plain
🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 11

hello room7
```

Seal record:

```text
🖧: S.EXAMPLE_SEAL_HASH.H3
Signed-By: V.EXAMPLE_VERIFIER.H3
Signature: EXAMPLE_SIGNATURE
🖧: P.EXAMPLE_PLEX_HASH.H3
Group: eu/lab
App: chat
Name: room-7/123
TAI: 1640995200:000000000
Content-Type: text/plain
🖧: B.EXAMPLE_BLOB_HASH.H3
Data-Length: 11

hello room7
```

## Common rejection examples

Implementations reject records with CRLF line endings, non-NFC header text,
`Data-Length: 01`, missing required Plex record headers, invalid Group paths
such as `/eu`, `eu/`, `eu//lab`, `eu/./lab`, or `eu/lab#x`, extra headers out of
order, mismatched markline digest, invalid Seal-record signature, or thin record
whose inner hash cannot be reconstructed.
