# LAVS-001 implementer FAQ

| | |
|---|---|
| **Status** | Adopted |
| **Version** | 1.0 |
| **Date** | 2026-05-27 |
| **Applies to** | All LAVS-001.X versions |
| **License** | CC BY 4.0 |
| **Companion docs** | [`LAVS-001.md`](./LAVS-001.md), [`VERSIONING.md`](./VERSIONING.md), [`CRC-SCOPE.md`](./CRC-SCOPE.md), [`PROPERTY-NAMESPACES.md`](./PROPERTY-NAMESPACES.md), [`EDITIONS.md`](./EDITIONS.md), [`KEYS.md`](./KEYS.md) |

This document answers questions an external implementer (third-party decoder, marketplace tool, gallery operator, signer/verifier) is likely to ask while reading the spec. The questions are grouped by topic. Each answer cites the relevant spec section and supporting docs so implementers can read deeper.

The FAQ is intended for the audience that has read the spec and the implementer tutorial at [`tutorial.md`](https://lavos-pubkey.projectlavos.com/tutorial.md) but still has operational questions that the spec text alone does not resolve. If your question is not answered here, file an issue at [github.com/guitargnarr/lavs-format/issues](https://github.com/guitargnarr/lavs-format/issues).

---

## 1. Versioning

### 1.1 How do I handle a v1.2 Environment object in a v1.1-only decoder?

You skip it. The Environment object (Type 19) is unknown to your v1.1 decoder. Per `VERSIONING.md` §3 (reader contract), a v1.X reader **MUST** treat unknown Core types as skippable via the property dictionary's wire-type tag table.

Concretely:

1. Read the type ID (LEB128) → 19. Unknown to v1.1.
2. Loop reading property pairs until you hit the sentinel `0x00`:
   - Read the property ID (LEB128).
   - Look up the wire type from the file's property dictionary (NOT your built-in property table — the file declares its own wire types).
   - Read the value with the right byte width based on wire type.
   - Discard the value (your v1.1 decoder has no use for it).
3. Continue to the next scene object.

The scene renders without IBL contribution — geometry, materials, direct lights all render correctly. Transmissive glass materials will read flat because there's no environment to reflect, but that's a visual degradation, not a parser failure.

If your v1.1 decoder is strict about Profile features (`features = "pbr-color,environment"` would include `environment` as a flag), you have a choice:

- Strict-conformant: refuse the file because you don't implement the `environment` feature flag.
- Lenient-conformant: warn that `environment` is unsupported and render without IBL.

Both are valid per LAVS-001 §13.

### 1.2 What if my decoder encounters spec major 2 someday?

Refuse. Per `VERSIONING.md` §3, a v1.X reader **MUST** refuse files where `specMajor != 1`. Don't try to be helpful and parse a future major — major bumps may have moved bytes in the header.

Project Lavos LLC commits to no v2.0 publication before 2027 and a 6-month transition window. So you have time.

### 1.3 How do I declare what spec minor I implement?

Two ways:

- **Documentation**: state your supported minor in your README, e.g., "implements LAVS-001.2."
- **Programmatic API**: expose a constant or method, e.g., `supportedSpecMinor: 2`.

There is no in-protocol negotiation. Decoder/encoder pairs that need to coordinate (e.g., a buyer using a v1.1 viewer on a v1.2 file) do so out of band.

---

## 2. Integrity & verification

### 2.1 What happens if CRC verifies but signature doesn't?

The file's edition metadata is intact (CRC passed) but the full-file integrity has been compromised (signature failed). See [`CRC-SCOPE.md`](./CRC-SCOPE.md) for the scope split.

Concretely:

- The file's edition badge (title, author, edition number, license) is likely correct. The metadata bytes were not tampered.
- The scene stream may have been tampered with. Vertices may be off, materials may be substituted, the rendered image may not be what the signer signed.
- A LAVS-001-conformant **Strict** consumer **MUST** refuse to render such a file (per §13.1 of the main spec, signature verification failure is a refusal condition).
- A LAVS-001-conformant **Lenient** consumer **MAY** render the file with a prominent warning that signature verification failed.

The recommendation for marketplace and gallery tools: treat signature failure as a refusal. Don't render. The risk of displaying a tampered scene under the original signer's identity is reputational — the original signer is implicated in what's displayed.

### 2.2 Why is the CRC scope only the edition block?

Performance and use case. The CRC is designed to support **fast-path verification of edition metadata** — gallery viewers reading directory listings of hundreds of files, marketplace tools generating badges. Restricting CRC scope to the edition block (typically a few hundred bytes) makes that fast-path viable.

For full-file integrity, use the signature blob (§8.2 of the main spec). The signature covers everything except the signature blob itself and the CRC footer. Implementers should:

- Always verify the CRC (mandatory per §8.3).
- Always verify the signature when present (mandatory for Strict consumers per §13.1).
- Use the manifest's SHA-256 hash (when published, e.g., at `https://lavos-pubkey.projectlavos.com/manifest.json`) for cross-implementation distribution integrity.

See [`CRC-SCOPE.md`](./CRC-SCOPE.md) for the full reasoning.

### 2.3 Can I rely on the CRC alone for "is this file safe to render?"

No. CRC alone is insufficient for trust. CRC catches accidental corruption (disk errors, network truncation, stale cache) on the edition metadata. It does NOT catch deliberate tampering of the scene stream.

For "is this file safe to render," you need (in increasing order of strictness):

1. CRC valid → metadata is probably intact.
2. Signature valid → file is bit-identical to what the signer authored.
3. Signature valid AND key not in revocation list → the signing identity is still trusted.
4. All of the above AND the key matches your known set of trusted signers → safe to render with full provenance.

A marketplace operator typically operates at level 4. A casual viewer may operate at level 2. The conformance test suite at [`https://lavos-pubkey.projectlavos.com/conformance.md`](https://lavos-pubkey.projectlavos.com/conformance.md) verifies CRC structurally but does not verify signatures (the suite is a structural conformance gate, not a trust gate).

---

## 3. Extensibility

### 3.1 Can I emit my own property IDs?

Yes, in the 1000+ range. Per [`PROPERTY-NAMESPACES.md`](./PROPERTY-NAMESPACES.md) §3, property IDs ≥ 1000 are reserved for implementer-defined extensions. You declare them in the file's property dictionary like any standard property; other readers will skip them via the wire-type tag table without breaking.

Rules:

- Use 1000+ only. Do NOT use property IDs in the 100–999 range — those are claimed by current or future spec.
- Pick a contiguous range you control (e.g., 1000–1099 for your project) and document it in your README to reduce collision risk with other implementers' private IDs.
- Don't assume any other reader will recognize your private IDs.

If your extension becomes broadly useful, propose promotion to the standard ranges via a v1.X spec minor bump.

### 3.2 How do I extend the spec without breaking interop?

Three rules:

1. **Additions only.** New Core types in the reserved 20–99 range, new property IDs in unused namespace blocks, new feature flags. Never remove, never repurpose, never change wire types of existing properties.
2. **Spec minor bump.** Every extension that touches the standard ranges (100–999) must bump the spec minor and be declared in the encoder's spec minor header field.
3. **Backward-compatible reader behavior.** A v1.0 reader must still parse a v1.X file with your extension, skipping the unknown bits cleanly.

See [`VERSIONING.md`](./VERSIONING.md) §1 for the full set of bump rules. The shorthand: anything that breaks the rules in `VERSIONING.md` §1 is a v2.0 change, not a v1.X minor.

### 3.3 Can I add a new wire type?

No, without breaking the spec. The wire-type tag table uses 2 bits per property, supporting exactly 4 types (varint, string, float, color). All four are allocated. Adding a fifth wire type requires a wider tag table, which is a v2.0 change.

If you need to encode data that doesn't fit the four existing types, use:
- `string` for raw binary payloads (this is the pattern used for vertex positions/normals/indices — see `property-table.toml` for the list of properties that carry raw bytes).
- `varint` for any unsigned integer up to 2^49.
- Multiple `float` properties for vectors (skyAccentDir is encoded as 3 separate floats).

---

## 4. Edition lifecycle

### 4.1 What is the difference between a Release Candidate and a signed Edition I?

A Release Candidate (RC) is an unsigned `.lavs` file with no `signatureAlgorithm` in the Edition block. It is revisable — the producer may change the scene, re-encode, and republish. RCs are not numbered editions in the buyer-facing sense.

A signed Edition I is a `.lavs` file with `signatureAlgorithm = "ed25519"`, a verifying signature blob, and an `editionNumber` ≥ 1. It is **frozen at signing**: the bytes are bit-identical to what the signer authored, the signature ties those bytes to the signer's identity, and the edition number is committed permanently.

See [`EDITIONS.md`](./EDITIONS.md) §6 for the policy. The shorthand: an RC is studio output; a signed Edition I is a release.

The TEST marker convention introduces a third category for substrate validation: `editionNumber=0` + `license` matching `^TEST` is a recognized TEST/REFERENCE marker, not a release candidate (won't ever be signed) and not an edition (no buyer-facing number). See [`EDITIONS.md`](./EDITIONS.md) §6 and the conformance suite check 12 for details.

### 4.2 Why does editionTotal == 0 mean "open edition"?

Because the spec defines it that way. Per `LAVS-001.md` §8.1, `editionTotal == 0` is the convention for an open edition — the producer has not committed to a fixed total. Open editions can grow over time; closed editions (where `editionTotal == N > 0`) cannot.

The convention is symmetric with `editionNumber == 0` (TEST marker) but semantically distinct: `editionNumber` of 0 means "this is not a numbered edition" (TEST); `editionTotal` of 0 means "the total is unbounded" (open edition).

### 4.3 How do I number Edition II of a slug?

You ship 33 copies of one configuration sealed at editionNumber 1, 2, 3, ..., 33 with `editionTotal=33`. Each copy carries a different `editionNumber` but identical scene bytes; each is separately signed so each copy is cryptographically unique despite identical scene content.

This is the limited-numbered-copies pattern from `EDITIONS.md` §2. The slug is the lineage key; the edition number is the copy number.

If you want to ship a different *configuration* (different palette, different parameters, different aesthetic), use a sub-slug (e.g., `mobius-violet` instead of `mobius`) per `EDITIONS.md` §3.2 — NOT a higher edition number on the same slug.

---

## 5. Signing

### 5.1 How do I provision my own signing identity?

Follow [`KEYS.md`](./KEYS.md) §6. Briefly:

1. Acquire a hardware token (YubiKey 5-series with ed25519 support, or equivalent).
2. Generate an ed25519 keypair on-device. The private key never leaves the token.
3. Provision a second token as backup. Cross-sign the two public keys.
4. Publish the active public key at a stable HTTPS URL with a valid certificate.
5. Publish an empty revocation list (`revoked.txt`) at the same domain.
6. Publish your rotation policy documenting compromise procedures.
7. Test signing end-to-end with a throwaway file before signing a real edition.

The Project Lavos LLC signing identity is at [`https://lavos-pubkey.projectlavos.com`](https://lavos-pubkey.projectlavos.com) — that infrastructure is the operational model for "signing identity as a public surface."

You do NOT need to use a YubiKey. Any system that keeps the private key offline (HSM, hardware token, encrypted USB stored physically off-laptop) is acceptable. The YubiKey is what Project Lavos LLC chose; it is not a spec requirement.

### 5.2 What signature algorithm should I use?

Ed25519. It is what the reference implementation supports and what `LAVS-001.md` §8.2 documents.

In principle the `signatureAlgorithm` field is a string, so a producer could declare a different algorithm (e.g., `rsa-sha256` or `ecdsa-p256`). But:

- Verifiers built against the reference implementation only handle ed25519 today.
- Adding a new algorithm requires updating the verification path in every conformant reader.
- Ed25519 is fast, compact (64-byte signatures), widely supported, and the cryptographic community considers it a safe default for new designs.

Stick with ed25519 unless you have a specific reason not to.

### 5.3 What if my YubiKey breaks?

Use the backup token (you provisioned two per `KEYS.md` §1). Sign new editions with the backup; provision a new backup within 30 days per `KEYS.md` §2 to restore the two-key posture.

Editions previously signed under the broken token remain valid — the signature was computed at signing time; the token's subsequent failure doesn't invalidate past signatures. The token holds the key; the key produced the signature; the signature lives in the file forever.

If the token is suspected compromised (not just broken), follow the compromise rotation procedure in `KEYS.md` §2: add the key to the revocation list, sign new editions under the backup, publish a signed rotation notice. Editions signed before the revocation date are "provable as signed at the time of signing" but flagged as "signed under a revoked key" by conformant verifiers.

---

## 6. Building your own implementation

### 6.1 How do I verify my decoder is spec-conformant?

Run your output through the conformance test suite at [`https://lavos-pubkey.projectlavos.com/conformance.md`](https://lavos-pubkey.projectlavos.com/conformance.md). The 18 checks across structural, edition, LAVS-001.2 Environment, and forward-compatibility categories are the operational compliance gate.

The TypeScript suite is at [`scripts/conformance.ts`](../scripts/conformance.ts) in the reference repo. The Python suite is at [`lavs/conformance.py`](https://github.com/guitargnarr/lavs-format-py) (publication pending). Both produce identical JSON output structures so cross-language parity is verifiable.

If your decoder agrees with both reference suites on every check for every canonical edition, you are spec-conformant.

### 6.2 What if my decoder disagrees with the reference on a check?

That's a divergence. It means either:

1. Your decoder has a bug.
2. The reference has a bug.
3. The spec is ambiguous and your decoder reasonably interpreted it differently.

Open an issue at [github.com/guitargnarr/lavs-format/issues](https://github.com/guitargnarr/lavs-format/issues) with:

- The file in question (the canonical edition or your test case).
- The check ID that diverges.
- Your decoder's output for that check.
- The reference's output for that check (run via `npx tsx scripts/conformance.ts --json <file.lavs>`).

Divergences are spec ambiguities until proven otherwise. They are the most valuable feedback for the spec — they identify gaps the spec text alone cannot close.

### 6.3 Should my decoder support encoding too?

That's a separate question. The reference implementation supports both encode and decode. Many third-party implementers will only need decoding (for marketplace tools, viewers, badge generators). Some will need both (for design tools).

If you implement encoding:

- Match the reference encoder's output byte-for-byte for the same scene description. The conformance suite verifies decoder behavior; encoder conformance is implicit (a conformant decoder of a conformant encoder's output should reach the same conclusions as the reference).
- Test with the canonical reference editions: decode them with your decoder, re-encode with your encoder, decode again, assert structural equality with the original.
- Round-trip test the worked example in `LAVS-001.md` §10 (cube) and §6.5 (Environment) — your encoder should produce the documented byte sequences.

---

## 7. Where do I go next?

- The main spec: [`LAVS-001.md`](./LAVS-001.md)
- The implementer tutorial (byte-by-byte cube.lavs walkthrough): [`https://lavos-pubkey.projectlavos.com/tutorial.md`](https://lavos-pubkey.projectlavos.com/tutorial.md)
- The conformance suite docs: [`https://lavos-pubkey.projectlavos.com/conformance.md`](https://lavos-pubkey.projectlavos.com/conformance.md)
- The signing policy: [`KEYS.md`](./KEYS.md) and the published version at [`https://lavos-pubkey.projectlavos.com/keys-policy.md`](https://lavos-pubkey.projectlavos.com/keys-policy.md)
- The editions policy: [`EDITIONS.md`](./EDITIONS.md) and the published version at [`https://lavos-pubkey.projectlavos.com/editions-policy.md`](https://lavos-pubkey.projectlavos.com/editions-policy.md)
- Versioning policy: [`VERSIONING.md`](./VERSIONING.md)
- CRC scope clarification: [`CRC-SCOPE.md`](./CRC-SCOPE.md)
- Property namespaces: [`PROPERTY-NAMESPACES.md`](./PROPERTY-NAMESPACES.md)
- Issue tracker: [github.com/guitargnarr/lavs-format/issues](https://github.com/guitargnarr/lavs-format/issues)

---

*This FAQ is a living document. Questions added here when they recur or when an implementer surfaces a real gap in the spec docs. Cross-referenced from `LAVS-001.md` §1.*
