DreamDB Specification — 0009: Conformance
Status: Draft. Builds on
0000–0008(the entire v0 spec). This document defines what "DreamDB-conformant" means for each component (Backend, Storage Connector, Protocol Component / SDK), enumerates the test-vector battery that any conformant implementation MUST pass, and resolves the meta-OQs about concrete tag values: OQ-11 (CBOR tag numbers), OQ-12 (multihash algorithm tags), OQ-17 (time-anchor CBOR tag).
1. Purpose
The DreamDB v0 spec defines a protocol composed of byte formats, address grammars, HTTP semantics, algorithms, and operational disciplines. An implementation is DreamDB-conformant if it correctly realizes the relevant subset for its role. This document:
- Defines the three conformance roles (Backend, Storage Connector, Protocol Component) and what each must implement.
- Resolves the spec's meta-OQs — concrete CBOR tag values, multihash algorithm tags, and other registry-style commitments deferred from earlier docs.
- Enumerates the test-vector categories that a conformant implementation MUST pass, organized by source spec doc.
- Specifies the test-vector exchange format — a structured JSON form that is portable across implementation languages.
- Defines the conformance reporting that an implementation publishes to advertise its level.
What this document does not do:
- Enumerate every individual vector in full. The reference corpus lives in
dreamdb-conformance/vectors/in this repository; §10 describes its exchange organization. Category rows define requirements or named performance profiles, not proof that every row has an implemented test or has run on every platform. - Replace earlier specs' normative requirements. Conformance is judged against the entire spec; this document is a roadmap, not a substitute.
2. Conformance Roles
DreamDB's three-layer architecture (0000 §3) admits three conformance roles, each independently testable:
| Role | What it implements | Tested by |
|---|---|---|
| Backend | HTTP semantics (0005) | HTTP-level test suite hitting a deployed backend |
| Storage Connector | HTTP-to-DreamDB transport shim (0005 §8) | Unit + integration tests against a reference backend |
| Protocol Component (SDK) | DreamDB Protocol verbs (0001–0008) | End-to-end tests + algorithmic/byte-format vectors |
A complete implementation is two of these (Connector + Protocol; the Backend is supplied by an existing object store) plus a binding to a chosen Backend that has independently been verified Backend-conformant.
2.1 Backend conformance
A Backend is ContentStore-Conformant if it correctly implements:
- HTTP verbs PUT, GET (with
Range), HEAD, LIST (with prefix and pagination), DELETE per0005§3. - Strong read-after-write consistency for content-addressed paths (
0005§5.1). - Lexicographic byte-order LIST results (
0005§3.5.1). - The §3–§5 HTTP semantics over HTTP/1.1 or later (
0005§6). HTTP/2 / HTTP/3 is a performance upgrade (a profile attribute,0023), not a conformance requirement — the byte contract is identical across versions.
A Backend is RefStore-Conformant if, additionally, it correctly implements:
If-None-Match: *andIf-Match: <etag>conditional writes per0005§4.- Linearizable CAS semantics (
0005§5.2).
Each tier is independently certifiable; a Backend MAY be ContentStore-Conformant only.
2.2 Storage Connector conformance
A Storage Connector is conformant if it:
- Translates DreamDB protocol-layer requests into HTTP per
0005. - Iterates LIST pagination to exhaustion (
0005§3.5.2). - Round-trips ETags opaquely for
If-Matchand canonicalizes for cross-request comparison (0005§8.5). - Reuses connections per
(backend host, auth identity)pair rather than one-per-request (0005§8.1); when it negotiates HTTP/2 / HTTP/3 those requests share the connection's multiplexed streams. The multiplexing is a performance-profile attribute (0023), not a conformance gate; the connector is conformant over HTTP/1.1. - Translates
bytes:<a>-<b>(DreamDB half-open) →Range: bytes=<a>-<b−1>(HTTP inclusive) (0005§3.3). - Exposes no DreamDB-semantic logic — bytes pass through opaquely (
0005§8.4).
2.3 Protocol Component (SDK) conformance
A Protocol Component is conformant if it correctly implements:
- The eight verbs of
0006§2 (Open,Resolve,Query,Stream,Get,Append,Layer,Publish). - The per-session cache discipline of
0006§3 (cache by content hash; never by path). - Manifest Supremacy — never use list-prefix during steady-state reads (
0005§5.3.1). - The integer-only time arithmetic discipline of
0003§4.1. - The f32-determinism discipline for spatial-key derivation (
0004§5.4). - The deterministic CBOR encoding of all hashable Objects (
0002§3). - The base2 spatial-key encoding, base32 hash encoding, 16-char hex time encoding of
0002§6 / §8 and0003§6. - The byte-format layouts of
0007for every Object kind it produces or reads. - The DAG semantics of
0008— multi-parent Manifests, MUST-refuse-on-SpatialIndex-conflict merges, lex-greatest tiebreak for Constants. - The operational disciplines of
0006§4.1.1, §4.4.1, §7.3 (Ref freshness, Stream prefetch, GC).
3. Resolved Meta-OQs
This section resolves the placeholder values used in earlier docs.
3.1 Multihash algorithm tag for BLAKE3 (resolves OQ-12)
DreamDB uses the BLAKE3 algorithm code 0x1e, but its fixed 33-byte wire value
below is DreamDB's encoding, not a complete standard multihash serialization:
there is no digest-length varint. Matching an algorithm code does not make the
encodings interchangeable. A future algorithm requires an explicit protocol
revision; readers must not enable it merely because an external registry lists it.
A multihash for BLAKE3-256 on the wire is therefore:
Encoded for use in addresses as base32-lowercase-no-padding (per 0002 §8.1): 53 characters (33 bytes × 8 bits / 5 bits per char = ceil(52.8) = 53).
3.2 DreamDB CBOR tag value (resolves OQ-11, OQ-17)
DreamDB specifies one locally chosen CBOR tag for foreign-CBOR-embedding scenarios:
This is not an IANA private-use allocation. The IANA CBOR Tags registry places 32768 and above under First Come First Served registration, not a private-use policy. This document does not establish a DreamDB registration or global collision freedom. Foreign-CBOR integrations must agree on the local meaning; any registration or renumbering needs a separate compatibility decision. This correction does not change the value or introduce tags into DreamDB Object schemas (§3.2.1).
3.2.1 Tag scope: foreign-CBOR contexts only
The tag is a deployment-local foreign-CBOR convention. An integration MUST agree both its use of 65521 and the wrapped semantic type out of band. Seeing 65521 in an arbitrary document is not sufficient evidence of DreamDB content; without that agreement a consumer preserves it as an uninterpreted tag or refuses the unsupported application format, rather than interpreting it as a DreamDB value. The wrapped CBOR major type alone is insufficient (modality tags and spatial keys are both strings).
Inside the schema-typed fields of DreamDB Objects, this tag is NOT used. Those fields use plain CBOR types directly:
- Time anchors → plain CBOR uint (per
0003§5). - Hashes → plain CBOR byte string (per
0002§3). - Modality tags → plain CBOR text string.
- Spatial keys → plain CBOR text string (base2 chars).
The schema's field name (or array position) is the type indicator. Adding a tag inside DreamDB schemas would be redundant and adds 2–3 bytes per occurrence — at billion-scale, that is GB-class waste.
Ordinary DreamDB Object readers do not acquire tagged alternatives to their
fields. The reference core exports DREAMDB_TAG and its generic CBOR codec can
round-trip a tagged value, but this does not perform automatic DreamDB semantic
interpretation or establish an interoperable foreign-document format.
3.2.2 Maps vs. positional arrays in DreamDB schemas
0002 §3.1 specifies two encoding choices for schema-typed DreamDB Objects:
- Maps with string keys: low-volume schemas (Manifest top-level, Genesis, SpatialIndex Object, Track Object metadata). Self-describing; debugger-friendly.
- Positional CBOR arrays: high-volume schemas (Index Page leaf entries and internal entries per
0007§7.3 / §7.5). Field order pinned in spec text; saves ~40 bytes per entry and ~40 GB on a 1B-entry Track.
Conformance test vectors (§5.1) MUST cover both encodings — including a positional-array round-trip that confirms the field order matches the spec.
4. Test-Vector Format
Conformance test vectors are exchanged as JSON documents with the following schema:
4.1 Test ID convention
Example IDs:
0002.cbor.deterministic.0001— first deterministic-CBOR test in0002.0004.lsh-cosine.f32-rounding.0003— third f32-rounding-edge-case test fordreamdb.lsh-cosine.0005.http.range-translation.0001— first byte-range translation test.0008.dag.refuse-spatial-index-incompat.0001— first MUST-refuse merge test.
This makes failures locatable and grep-friendly.
4.2 Categories
Each category specifies its own input/expected schema. The full schema definitions live in the conformance suite repo (§10); summary follows in §5–§8.
4.3 Pass / fail criteria
Vectors specify their own pass criteria. Common kinds:
- Byte-identical: produced output bytes equal expected bytes exactly.
- Functional equivalence: produced output is semantically equivalent (e.g. an array order-independent set comparison).
- Behavioral assertion: under specified conditions, the implementation makes (or does not make) certain HTTP requests; takes (or does not take) certain actions.
- Tolerance bound: produced metric (e.g. recall, latency) is within a stated bound of the expected value.
4.4 Conformance vs. performance (normative)
The four kinds in §4.3 fall into two classes with different normative force, and an implementation MUST be evaluated against them separately:
- Conformance criteria — the
byte-identical,functional-equivalence, andbehavioral-assertionkinds. These are deterministic and environment-independent: given the same inputs, a correct implementation passes on any hardware, network, or workload. An implementation is DreamDB-conformant for a category if and only if it passes every conformance criterion in that category. A failure here is non-conformance. - Performance-profile targets — the
tolerance-boundkind (recall, latency, throughput, bytes-fetched, wall-clock). These depend on the workload (corpus size, dimensionality, distribution) and the environment (storage round-trip, bandwidth, CPU/GPU). They are advisory: missing a target means the implementation does not claim that performance profile — it does not make the implementation non-conformant. Performance profiles are defined separately in0023-performance-profiles.mdand version on their own cadence.
The boundary must be read carefully: a quantity fixed by the protocol for the declared fixture is a behavioral assertion, not a timing target. For example, Manifest Supremacy requires zero query LISTs. An exact Bucket GET count additionally depends on the fixture's split count, cache state, coalescing and retry conditions; it cannot be inferred from the number of tables alone. “Completes in <100 ms p95” is a performance-profile target.
Performance narrative elsewhere in the spec (e.g. 0004 §7.3/§8 latency budgets) is informative. The normative requirements such narrative rests on — chiefly Manifest Supremacy (0005 §5.3.1: no list-prefix on the steady-state read path) and the cold-start round-trip bound — are stated as conformance criteria in their own right (§6, §7), never inferred from a budget.
5. Test Categories — Byte Formats and Algorithms
5.1 0002: Content addressing
| Category | Pass criterion | Coverage |
|---|---|---|
cbor.deterministic.* | Byte-identical canonical encoding | All hashable Object types |
multihash.encoding.* | Byte-identical multihash + base32 round-trip | BLAKE3 hashes (0x1e) |
address.grammar.* | Path parse and re-emit produces same bytes | All address forms; URI scheme |
modality.tag.parsing.* | Tag → (class, encoding, params) parse correctness | Built-in classes; reverse-DNS |
spatial-key.base2.* | base2 encoding round-trips arbitrary-N bit strings | Bit lengths 1-256, prefix-preservation |
paged-index.btree.* | B-tree page traversal returns expected leaf entries | Inline + paged forms; mixed |
bao.range-integrity.* | Standard outboard bytes are byte-identical; arbitrary unaligned ranges verify and trim exactly; changed data or proof is refused | 1 KiB boundaries; tail chunk; malformed/truncated/corrupt proof and subject |
multihash.encoding.* covers whole-Object hashing. bao.range-integrity.*
separately pins the derived proof bytes and the verified-range algorithm from
0002 §6.5.4; passing one category does not imply passing the other.
5.2 0003: Time encoding
| Category | Pass criterion | Coverage |
|---|---|---|
time-anchor.hex.* | u64 ↔ 16-char hex round-trip; lex order = numeric order | Min (0), max (2⁶⁴ − 1), mid, near-boundary values |
time-bucket.placement.* | floor(t_start / D) produces correct bucket for boundary cases | t_start = 59.9 s, 60.0 s, 60.1 s, 59.999999999 s with D=60s |
time-bucket.overflow.* | Overflow stress — t at 2⁶⁴ − 1, t + duration overflow detection, bucket-duration near 2⁶³ − 1, bucket-duration = 1 ns (degenerate floor(t/1)=t), bucket-duration = 2⁶³ − 1 (degenerate floor(t/huge)=0) | Edge u64 values; catastrophic-overflow guards |
genesis.cbor.* | Genesis Object round-trips deterministically | Anchored/abstract; with/without horizon |
duration-parsing.overflow.* | Duration suffix parsing rejects values whose ns count would exceed 2⁶³ − 1 | 1_000_000_000h, 2⁶³ s, etc. |
integer-only.violation.* | Implementation rejects f64 in time arithmetic at compile/lint time, OR fuzz tests confirm no f64 path exists | Static analysis hooks |
5.3 0004: Spatial indexing
0004.lsh_l2.001–002 pin the optional dreamdb.lsh-l2 profile (§5.8 of
0004): canonical SpatialIndex hash, seeded signed-bin/probe order, raw
negative squared L2 score, and decoder rejection of canonical CBOR containing
a zero bucket width. Category lsh-l2-determinism expresses the seed and
binary64 width as little-endian hex bytes; query/candidate JSON numbers become
binary32 inputs. This is deterministic wire/arithmetic evidence, not a
measurement of global ANN recall or independent-implementation agreement.
| Category | Pass criterion | Coverage |
|---|---|---|
lsh-cosine.hyperplanes.* | ChaCha20 seed → hyperplane table is bit-identical across implementations | Multiple seeds; D ∈ {64, 128, 768} |
lsh-cosine.bit-derivation.* | (vector, hyperplanes) → spatial-key bits are bit-identical | Edge cases including <v, h_i> = 0 ties |
lsh-cosine.f32-rounding.* | f32 left-fold dot product produces bit-identical results on every required hardware path | See §5.3.1 — multi-architecture coverage |
recall.locality.* | Reports empirical bit-collision rates for the exact §5.3 normalized-cube generator; no spherical 1 − θ/π acceptance threshold applies | Fixed synthetic corpus and seeds, with the measured profile versioned alongside results |
multi-table.union.* | Query combines the expected per-table candidates under the format's duplicate rules | Fixed candidate sets; empirical recall belongs to 0023 |
lineage.spatial-index-hash.* | Bucket header spatial_index_hash mismatch triggers abort, NOT silent decode | Deliberate mismatches |
5.3.1 Multi-architecture f32-determinism conformance (mandatory)
Floating-point determinism across heterogeneous hardware is the single most fragile conformance surface. SIMD optimizers (AVX-512 fused-multiply-add, ARM NEON's vector-friendly rounding modes, GPU paths) are at liberty to reorder f32 operations; the resulting drift is invisible until two SDKs disagree on a single bit and silently route data to different Spatial Buckets.
The discipline:
Pure-scalar reference is the canonical implementation. The dreamdb.lsh-cosine algorithm spec (0004 §5) is interpreted to mean the bytes the scalar reference path produces, with all SIMD optimizations disabled. Any SIMD path is conformant if and only if it produces bit-identical output to scalar.
Required hardware coverage: a conformant implementation MUST be tested on the following paths, all producing bit-identical results to the scalar reference:
| Hardware path | Notes |
|---|---|
| x86-64, AVX-512 | FMA, vectorized accumulator |
| x86-64, AVX2 | older Intel/AMD; subset of AVX-512 |
| x86-64, scalar (no SIMD) | reference path; canonical |
| ARM64, NEON | Apple Silicon, AWS Graviton, server ARM |
| ARM64, scalar (no SIMD) | reference path; canonical |
Test-vector design: vectors crafted to expose rounding-order sensitivity:
- Pairs with dot products at exactly
0.5 ulp(the rounding boundary). - Vectors where left-fold and right-fold accumulation order produce different f32 results — and where the spec mandates left-fold (
0004§5.4). - Adversarial inputs: extreme magnitude ranges, near-zero dot products, denormalized floats.
- Pairs at exactly the
<v, h_i> = 0tie boundary (0004§5.1 specifies tie → 1).
Non-conformance: an implementation that produces different bits under SIMD vs. scalar on any required hardware path is non-conformant for that path. The implementation MUST disable SIMD optimization on that platform until parity is achieved. Compromised SIMD paths shipping silently is the failure mode this discipline exists to prevent.
This is the same model used by cryptographic library testing (BoringSSL, RustCrypto, libsodium): bit-identical scalar reference, hardware paths verified against it, no SIMD path ships without bit parity.
5.4 0007: Object byte formats
| Category | Pass criterion | Coverage |
|---|---|---|
bucket.inline.layout.* | Record i starts at header_size + i × record_size; its vector/code begins after the record's anchor fields | Legacy 160-byte, compressed 200-byte and declared extension layouts |
bucket.reference.layout.* | Reference resolves to correct Vector-Storage byte range | Multi-table cases |
fragment.cmaf.* | CMAF Fragment can be played by reference decoder | H.264 / H.265 / AV1 / Opus / FLAC |
time-batch.in-object-index.* | (time_anchor, byte_offset, byte_size) index round-trips | Variable-payload events |
index-page.delta-encoding.* | Delta-encoded leaves round-trip through encode/decode | Page-boundary cases |
dynamic-height.* | Adding items past height-N capacity produces height-(N+1) tree with old root preserved | Heights 1→2→3→...→8 |
multi-bucket-merge.* | Query against spatial-key with 3 bucket splits returns merged result in t_start order | Time-overlapping splits |
6. Test Categories — HTTP Contract (0005)
6.1 ContentStore HTTP semantics
| Category | Pass criterion | Coverage |
|---|---|---|
http.put.idempotent.* | PUT same bytes twice → second is no-op (200/201/412) | With/without If-None-Match: * |
http.range.translation.* | DreamDB bytes:<a>-<b> → HTTP Range: bytes=<a>-<b−1> | Boundaries 0, 1, 1MB, large |
http.list.exhaust.* | Pagination iterates correctly across K×1000 boundary | K ∈ {0, 1, 2}; k×1000+1 cases |
http.list.sort-order.* | Backend returns lex-byte-order across pages | Adversarial keys, ASCII paths |
http.consistency.read-after-write.* | PUT → GET returns the bytes immediately | Multiple regions if applicable |
6.2 RefStore HTTP semantics
| Category | Pass criterion | Coverage |
|---|---|---|
http.refs.create.* | If-None-Match: * → 412 on existing (treat as success) | Initial create + idempotent re-create |
http.refs.cas.* | If-Match: <etag> → 412 on mismatch (treat as conflict) | Concurrent advance |
http.refs.linearizable.* | Two concurrent CAS attempts: exactly one succeeds | Stress test |
http.etag.flavor.* | Round-trip ETag with quotes, with W/, multipart-style | Backend-specific flavors |
6.3 Connector behaviors
| Category | Pass criterion | Coverage |
|---|---|---|
connector.connection-reuse.* | Multiple parallel requests reuse one connection per (host, auth) — HTTP/1.1 keep-alive suffices (0005 §8.1) | 16-parallel-GET hot path |
connector.retry.exponential.* | 5xx / 429 → exponential backoff up to budget | 5xx, 429, network errors |
connector.412.tier-aware.* | 412 on ContentStore PUT = success; 412 on RefStore PUT = conflict | Both tiers |
Profile-only (not a conformance gate):
connector.h2.shared-connection.*— multiple parallel requests share one HTTP/2 (or HTTP/3) multiplexed connection. This is a0023performance-profile attribute (0023§"environment_class"), exercised only when the profile asserts an HTTP/2+ environment; it is not required for connector conformance (§2.2,0005§6). An HTTP/1.1 connector that reuses connections via keep-alive (connector.connection-reuse.*above) is fully conformant.
7. Test Categories — Verbs and SDK behavior (0006)
| Category | Pass criterion | Coverage |
|---|---|---|
verb.append-publish.roundtrip.* | Standard transaction succeeds; new Manifest is reachable | Single-modality + multi-modality |
verb.append.retry.* | Mid-Append failure + retry produces idempotent result | Failure injected at every step |
verb.publish.concurrent.* | Two concurrent Publishes → one wins, loser rebuilds | Rebase + merge paths |
verb.query.cold-vs-hot.* | Cold and cached reads return the same result; cached metadata is reused | Pin cache state and index shape; no universal one-round-trip bound |
verb.query.no-list-prefix.* | Hot-path query issues ZERO LIST HTTP requests (Manifest Supremacy) | Steady-state queries |
verb.gc.algorithm.* | Synthetic orphans + reachable mix → orphans deleted, reachable preserved | Threshold honored |
verb.stream.prefetch.* | Prefetch preserves stream order and honors cancellation and configured lookahead | Stall/latency targets require a 0023 workload, not a universal lookahead of two |
verb.refs.freshness.* | HEAD-detected ETag mismatch triggers Resolve flow | Long-lived session |
cache.content-hash-keyed.* | Different Tracks Object for same (timeline, modality) produce two cache entries | Cross-Manifest |
8. Test Categories — DAG and Versioning (0008)
| Category | Pass criterion | Coverage |
|---|---|---|
dag.parents-array.* | Manifests with parents: [], [1], and [2+] round-trip | All cardinalities |
dag.fast-forward.* | Detect when one parent is ancestor of the other | Linear, branching, multi-level |
dag.spatial-index-incompat.* | MUST refuse merge with named conflicting hashes; auto-merging implementation is non-conformant | Edge cases |
dag.merge-equivalence.* | Merged read result is strategy-independent (0008 §5.3): layered, fused, and fused-then-compacted yield identical query results — the §6 union of both parents | Disjoint + overlapping branches; pre/post compaction |
dag.constant-tiebreak.* | Lexicographically-greatest layer-Track address wins | Multi-layer Constants |
dag.cas-rebase-loop.* | Bounded retries terminate; surface PublishConflict | Retry budget exhaustion |
dag.feature-branch-load.* | Report throughput for a pinned branch-per-writer versus shared-Ref workload | Performance profile (0023), not a conformance gate |
dag.monotonic-ts.* | Writer fix-up of ts < max(parents.ts) produces monotonic chain; reader-side Timeline-Jump flag surfaces | Clock-skew injection |
dag.history-walk.* | DAG traversal terminates; visits each Manifest at most once | Cyclic-input rejection (impossible by construction, but verify) |
8.5 Test Categories — Phase-3 ObjectKinds and Verbs
Phase-3 specs (0010, 0012, 0013, 0014) introduce new ObjectKinds and
query/write extensions. The conformance battery for them is OPTIONAL for
pre-Phase-3 v0 SDKs and REQUIRED for SDKs claiming Phase-3 conformance.
8.5.1 0010 — Vector compression
v0.1 normative for the framework + raw-f32 / rabitq-cosine / pq-cosine. The Object byte format and RaBitQ encode-determinism are vector-gated (dreamdb-conformance/vectors/0010/); the rerank-recall target is a 0023 performance profile, not a conformance gate.
| Category | Pass criterion | Coverage |
|---|---|---|
vc.roundtrip.* | VectorCompressor Object → canonical CBOR encode/decode/re-encode byte-identical (raw-f32 / rabitq-cosine / pq-cosine) | Vector-gated |
vc.rabitq.encode-determinism.* | encode(v) reproduces the scalar-canonical code for a fixed rotation seed; decode reproducible (0004 §5.4 gate) | Vector-gated |
vc.raw-f32.identity-code.* | raw-f32 encode is the identity f32-LE byte layout | Vector-gated |
vc.bucket-header.200-byte.* | Buckets with a vector_compressor_hash use the 200-byte v2 header, with the hash at 86..119, zero-filled reservation at 119..200, and records at 200 + i×record_size | Vector-gated |
vc.reference-inline-code.* | A compressed reference Bucket uses record_size = 49 + code_bytes; query scoring reads the inline code, exact reranking retains the raw VS reference, and legacy 160/49 Buckets remain byte-compatible | Behavioral (dreamdb-protocol + dreamdb-dataset tests) |
vc.lineage-mismatch-abort.* | Decoding a Bucket against the wrong VC Object causes a critical-error abort | Behavioral (dreamdb-dataset tests) |
vc.rerank-storage.* | Re-rank fetch path closes the recall gap to exact f32 | Performance profile (0023), not a gate |
vc.qinco.* | Learned-codebook roundtrip + MLP determinism | Deferred (OQ-46) |
8.5.2 0012 — Federation
| Category | Pass criterion | Coverage |
|---|---|---|
fed.manifest.canonical.* | FederationManifest decode/re-encode bytes and content hash are identical | Vector-gated |
fed.hash-verify-abort.* | A coordinator or shard backend serving wrong bytes for a known hash MUST abort | Negative backend-corruption check |
fed.scatter-gather.partial.* | A quorum-satisfied response with a missing logical shard is flagged partial:true | One shard offline |
fed.shard-key.range-prune.* | Hybrid-range shards outside the query's anchor range are skipped | Multi-shard time queries |
fed.schema-mismatch-abort.* | Shards whose canonical Schema hash differs are never score-merged | Negative multi-shard query |
fed.router.fanout-reduction.* | Router-graph dispatches reduce contacted shards from N to K_router | Deferred (0012 §8) |
8.5.3 0013 — Graph indexing
| Category | Pass criterion | Coverage |
|---|---|---|
graph.vamana.build.deterministic.* | A build from the pinned (vectors, seed, alpha, L_build, passes) reproduces the complete canonical adjacency and entry point | Small inline case + raw f32le/u32le reference graph (dim=64, 10K nodes, R=8) |
graph.vamana.search.deterministic.* | Final ids, f32 score bits and every expanded trajectory pair are identical across implementations | Three queries over the 10K-node reference graph |
graph.page.header.lineage.* | A batch GraphPage header's graph_index_hash matches the current batch GraphIndex | Cache-mis-keying |
fresh-vamana.page-lineage.* | Reused and rewritten pages bind one validated batch root; foreign-root, missing-root, mutable-family and malformed page-range cases refuse | Root + two Fresh snapshots |
graph.compose-with-compressor.* | Measure recall for a declared supported graph/compressor combination | Performance profile (0023); reserved QINCo is not required |
graph.entry-point.medoid.* | Approximate-medoid entry point selection is deterministic across implementations | Sample-size cap |
8.5.4 0014 — Streaming extensions
| Category | Pass criterion | Coverage |
|---|---|---|
chunk.itemmanifest.roundtrip.* | Existing map wire form decodes/re-encodes byte-identically; empty Item uses one zero-sized chunk, never an empty list | Single-chunk + multi-chunk + empty Item |
chunk.fragmententry.4-tuple.* | Direct entries (absent Schema chunking policy, no packing) retain v0 4-tuples | Backwards-compat |
chunk.fragmententry.5-tuple.* | Schema chunking emits 5-tuples with is_manifest=true, without requiring a modality parameter | Manifest-bearing case |
chunk.stitching.range-fetch.* | Byte-range [A,B) fetches only the chunks overlapping range | Partial reads at every chunk boundary |
chunk.total-size-verify.* | Manifest-declared total mismatches actual concatenated size → critical error | Negative test |
chunk.gc.transitive.* | GC walks ItemManifest → chunk hashes transitively; no dangling refs | Mixed reachable/orphan |
playlist.renditions.roundtrip.* | CLOSED RenditionPlaylist CBOR and registry binding roundtrip deterministically | VideoItem snapshots |
playlist.cross-rendition.anchor.* | Publication refuses unequal Item extents or Fragment boundaries before any playlist write | Public publisher boundary |
playlist.snapshot.gc.* | A playlist-pinned VideoItem remains readable after current field replacement and GC | Transitive closure |
playlist.hls.emission.* | HLS .m3u8 emission is byte-identical for the same playlist and shim base URI | Translation determinism |
8.5.5 New ObjectKind path-grammar coverage
| Category | Pass criterion | Coverage |
|---|---|---|
path.parser.items.* | <timeline>/<modality>/items/<hash> parses to ItemManifest ObjectKind | All 6 new slots |
path.parser.playlist.* | <timeline>/<modality>/playlist/<hash> parses to RenditionPlaylist | |
path.parser.graph-index.* | graph-index/<hash> parses to GraphIndex | |
path.parser.graph-page.* | <timeline>/<modality>/graph-page/<hash> parses to GraphPage | |
path.parser.vector-compressor.* | vector-compressor/<hash> parses to VectorCompressor | |
path.parser.federation-manifests.* | federation-manifests/<hash> parses to FederationManifest |
8.6 Test Categories — Phase-4 ObjectKinds and Verbs
Phase-4 specifications (0015, 0016, 0017, 0018, 0019) introduce hybrid retrieval, streaming freshness, schema evolution, multi-tenancy, and encryption. Conformance for them is OPTIONAL for pre-Phase-4 SDKs and REQUIRED for SDKs claiming the corresponding Phase-4 capability. Categories without shipped vectors remain known targets; 0019 now has mandatory format vectors in §8.6.5.
8.6.1 0015 — Hybrid retrieval
| Category | Pass criterion | Coverage |
|---|---|---|
hybrid.rrf.scale-invariance.* | Same RRF score regardless of sub-query score scales | BM25+cosine; cosine+bm25-plus |
hybrid.planner.deterministic.* | Same Manifest + stats + query → same plan | Multi-implementation |
hybrid.prefilter.threshold.* | Selectivity <1% → pre-filter chosen; >1% → post-filter | Adversarial stats |
hybrid.required.elimination.* | required:true sub-query eliminates non-matching candidates | Boolean-AND semantics |
hybrid.bm25.fp32-determinism.* | BM25 scores bit-identical across implementations | Scalar reference vectors |
hybrid.colbert.maxsim.* | MaxSim aggregation matches reference (within fp32 left-fold discipline) | dim=128 reference corpus |
hybrid.colbert.composite-anchor.* | Canonical modality and checked document/token anchor arithmetic agree | Round-trip, final complete window, invalid tail and ordinal |
hybrid.colbert.reopen-exact.* | Write, reopen and query ranks by sidecar f32 even when decoded-code order differs | Public Dataset path; lossy compressor |
hybrid.splade.encoder-validation.* | TextIndex with SPLADE algorithm validates encoder_hash against registry | Encoder mismatch → critical error |
8.6.2 0016 — Streaming freshness
| Category | Pass criterion | Coverage |
|---|---|---|
hotshard.append.flush-threshold.* | Buffered items exceeding threshold trigger Track rewrite | Boundary cases |
hotshard.append.ttl.* | TTL expiry forces flush even below threshold | Clock-skew injection |
hotshard.read.merge.* | Query merges Track + HotShard candidates correctly | Time / vector / scalar predicates |
hotshard.staleness.consumer-tolerance.* | max_staleness_seconds honored; refresh triggered on miss | All staleness levels |
fresh-vamana.append-search.* | After N appends, recall@10 stays within 5% of full-rebuild baseline | N ∈ {10K, 100K, 1M} |
fresh-vamana.consolidation.recall.* | Post-consolidation recall returns to full-rebuild baseline | After 10× threshold of appends |
fresh-vamana.tombstone.delete.* | Tombstoned items absent from query results; remain in graph until consolidation | Mixed insert/delete |
index-health.drift-metric.* | Drift metric monotonically tracks distribution shift | Synthetic drift injection |
index-health.recommended-action.* | Threshold transitions produce correct recommended_action transitions | All policy levels |
8.6.3 0017 — Schema evolution
| Category | Pass criterion | Coverage |
|---|---|---|
evolve.multi-version-registry.* | Registry with v1 + v2 both query correctly | Both versions, independent queries |
evolve.reencode.resumable.* | Crash mid-Reencode + resume produces same final state as uninterrupted run | Failure injected per-batch |
evolve.reencode.checkpoint-monotonic.* | last_anchor strictly increases across batches | Adversarial batch orderings |
evolve.planner.all-versions-fallback.* | version_preference: "all" fills v2 coverage gap with v1 scores | Partial coverage scenarios |
evolve.gc.decommission-v1.* | After v1 removed from registry, its Objects become eligible after safety threshold | Standard GC test |
evolve.compatible-with.semantics.* | coverage: "complete" means every v1 Item present in v2; verifier asserts | Mixed coverage states |
8.6.4 0018 — Multi-tenant
| Category | Pass criterion | Coverage |
|---|---|---|
tenant.quota.storage-507.* | Storage cap exceeded → HTTP 507 + correct DreamDB-Quota header | Multiple storage types |
tenant.quota.rate-429.* | Rate limit exceeded → HTTP 429 + Retry-After header | Per-resource rate |
tenant.token.tenant-id-mismatch.* | Token tenant_id ≠ Space tenant_id → HTTP 403 | All scope levels |
tenant.token.cross-tenant-isolation.* | Token from tenant A can never access tenant B's paths | Negative test |
tenant.usage-batch.publish-cadence.* | Batches emitted on schedule; chain of previous_batch links unbroken | Multi-window scenario |
tenant.usage-batch.violations-recorded.* | 429/507 events surfaced in subsequent batch's violations array | Adversarial load |
tenant.fair-share.anti-monopoly.* | One tenant cannot capture >50% capacity when other tenants are active | Multi-tenant load test |
tenant.federation.cross-issuer.* | Federation hop preserves tenant_id; no escalation | Cross-issuer scenarios |
tenant.offboarding.gc.* | After quota=0 + retention window, all tenant Objects reclaimed | Standard GC + retention |
8.6.5 0019 — Data-plane encryption
0019 is a normative wire format, but the reference Dataset/SDK does not yet implement it. The vectors in dreamdb-conformance/vectors/0019/ are mandatory for any implementation claiming Lineage-v3 encryption capability. Passing them establishes the deterministic format and cryptographic decisions below; it does not certify a cloud KMS adapter, key-destruction procedure or plaintext-handling environment.
| Category | Pass criterion | Coverage |
|---|---|---|
encryption-envelope | Canonical header/envelope bytes, address and decrypt result match; malformed, unauthenticated or address-substituted input produces the named refusal | Convergent, randomized, empty and multi-chunk Objects |
enc.convergent.dedup.* | Same plaintext and DWK produce identical bytes/address; another DWK differs; sealed hash+DEK is recoverable without prior plaintext | Domain-scoped equality |
enc.randomized.uniqueness.* | Supplied distinct fixture DEKs produce distinct envelopes and both decrypt | Two logical writes |
enc.aead.tamper-detect.* | Modified authenticated header or sealed chunk is refused before plaintext is returned | Header + ciphertext bit flips |
enc.range.chunk.* | Prefix/header and requested chunk ranges are Bao-bound to the expected envelope address before AES-SIV decryption; an Object substituted from the same domain is refused; empty plaintext has one 16-byte sealed chunk | First/middle/final/empty/substitution |
enc.key-bundle.* | AES-KW integrity and convergent P/DEK re-derivation are enforced | Corrupt wrap + mismatched bundle |
enc.lineage-v3-policy.* | CLOSED policy/slot shapes, canonical slot order and mode/suite/domain agreement are enforced | Positive + malformed declarations |
The vector runner supplies a raw DWK as the result of a successful fixture KMS slot. That is an input to the protocol algorithm, not a substitute test for KMS authentication. KMS call rate, key-cache hit ratio and throughput belong to implementation operations/performance evidence, not conformance.
8.6.6 Phase-4 path-grammar coverage
| Category | Pass criterion | Coverage |
|---|---|---|
path.parser.text-index.* | <timeline>/<modality>/text-index/<hash> parses to TextIndex | All grammar cases |
path.parser.text-index.posting.* | <timeline>/<modality>/text-index/posting/<hash> parses to TextIndex page | Two-segment disambiguation |
path.parser.hot-shard.* | <timeline>/<modality>/hot-shard/<hash> parses to HotShard | All grammar cases |
path.parser.tenant-usage.* | tenant-usage/<hash> parses to TenantUsageBatch | Top-level namespace |
path.parser.tenant-usage-refs.* | tenant-usage-refs/<tenant_id> parses to TenantUsageRef | Top-level refs namespace |
8.7 0021 — Compaction
Categories for the bucket/tombstone compaction pass (0021). Several overlap the §8 merge categories — compaction must preserve query results exactly (0008 §5.3 read-equivalence).
| Category | Pass criterion | Coverage |
|---|---|---|
compact.multi-bucket-read.* | Append N batches into k cells, query → top-K matches brute force | LSM multi-fragment-per-cell |
compact.idempotence.* | Compacting an already-consolidated dataset is a no-op | Re-compact stability, including a dataset consolidated to K > 1 by the payload cap |
compact.capacity.* | A cell's merged output is cut into K = ceil(N / C) Buckets, each within bucket_max_bytes of record payload, with the exact sidecar cut at the same boundaries | Over-cap merge split; oversized singleton repaired below threshold; bucket_max_bytes range and threshold=0 refused before any write |
compact.correctness.* | Queries return the same anchors pre- and post-compaction | Pairs with §8 dag.merge-equivalence |
compact.lineage-refusal.* | Compaction across a SpatialIndex-hash change fails with the documented error | Negative test |
compact.anchor-conflict-refusal.* | Two fragments with the same time_anchor but different vectors → fail loudly | Negative test |
compact.read-online.* | A query started against the OLD Manifest while compaction runs completes correctly | Concurrency |
8.8 0022 — Fragment packs
Categories for many-Items-per-Object packing (0022); the byte-range reader obligation is 0002 §6.5.4.
| Category | Pass criterion | Coverage |
|---|---|---|
pack.roundtrip.* | Write N items with pack_items=k → ⌈N/k⌉ packs → read back byte-equal | Whole-pack round-trip |
pack.mixed-batches.* | Batches with different N each → separate packs; item count matches | Per-batch packing |
pack.per-field-independence.* | Packed + unpacked Fields in one Schema → independent pack_items | Schema-level isolation |
pack.reject-pack-plus-chunk.* | pack_items > 1 AND chunk_size on one Field → writer MUST refuse OR degrade to chunking | Negative test |
pack.byte-range-fetch.* | Single-item GET with pack_offset returns exactly [pack_offset, pack_offset + byte_size) | Pairs with §5.4 track-object 6-tuple |
8.9 0020 — Tombstones (read-side deletion)
Categories for the legacy TombstoneListObject, the persistent paged
TombstoneIndexObject, and the read-side suppression filter (0020). The
byte-format categories are vector-gated
(dreamdb-conformance/vectors/0020/); the suppression/time-travel behavior is
a behavioral assertion. Physical reclamation is delegated to 0021 (see
§8.7) per 0020 §6.
| Category | Pass criterion | Coverage |
|---|---|---|
tombstone.list.roundtrip.* | TombstoneListObject → canonical CBOR encode/decode/re-encode byte-identical, decoded == original | Anchors+parents; parent-only "caught-up" marker |
tombstone.list.sort-invariant.* | Anchors stored strictly ascending; decoders REJECT unsorted / duplicate anchor bytes | Sort normalization + rejection |
tombstone.index.roundtrip.* | Tombstone index head plus leaf/internal pages encode/decode/re-encode byte-identically; malformed bounds or summaries are rejected | Timeline-scoped head, parent link, canonical pages, range summaries |
tombstone.read.suppression.* | A query at the deleting Manifest does NOT return tombstoned anchors across any modality | Behavioral (Item-scoped suppression) |
tombstone.read.time-travel.* | A query at a pre-deletion Manifest STILL returns the anchors (suppression resolves at the read Manifest's registry) | Behavioral (0020 §5) |
tombstone.dag.parent-walk.* | Effective tombstone set = breadth-first union over the parent DAG | Incremental deletion |
8.10 0011 — Scalar indexing
Categories for native scalar filtering (0011). v0.2 retains dreamdb.bitmap-categorical for categorical / bool equality and adds byte-pinned value-keyed B-trees for integer/timestamp, finite-float and UTF-8 lexical ordering.
| Category | Pass criterion | Coverage |
|---|---|---|
scalar-index.roundtrip.* | ScalarIndex Object (bitmap or built-in B-tree params) → pinned canonical CBOR bytes and byte-identical round-trip | Vector-gated (vectors/0011/) |
scalar-btree-page.roundtrip.* | Leaf/internal page → pinned canonical CBOR bytes, hash, ordering and byte-identical round-trip | Vector-gated (vectors/0011/) |
scalar.bucket.roaring-roundtrip.* | Per-value RoaringTreemap anchor set encodes/decodes order-independent + deterministic | dreamdb-dataset util.rs tests |
scalar.query.categorical-eq.* | Pure Filter::Where (no Vector/TimeRange) returns exactly the anchors whose categorical value matches | Behavioral (in suite) |
scalar.query.intersect-with-vector.* | Where intersected with a Vector clause narrows the top-K to matching scalars | Behavioral (vector path) |
scalar.query.undeclared-field-error.* | Where on an undeclared / non-Scalar field is a clear schema error | Negative test |
scalar.btree.range.* | Narrow ordered predicate returns exact anchors while fetching fewer than all published scalar index pages | Behavioral (Dataset public entry) |
8.11 0024 — Embedding spec identity
| Category | Pass criterion | Coverage |
|---|---|---|
embedding.spec-id.* | Canonical identity_basis CBOR hashes to the full 53-character lowercase base32 multihash carried by exactly one spec= parameter | Valid identity; truncated, malformed, repeated, and mismatching IDs |
embedding.membership.* | An implementation record joins a spec_id only by clearing 0024 §4 against that basis's own realization_commitment, recomputed from the realization_manifest the embed_spec carries | Same basis with differing implementations; anchor change from failed parity; sub-threshold parity; probe set under 1,000; commitment not matching its manifest |
embedding.modality-grammar.* | The canonical model hint and full spec_id produce a modality accepted by 0002 §5.1 | Underscore model spelling; superseded hyphen spelling rejected |
Vectors in the embedding-spec-identity category spell realization_commitment, parity.against and artifact digests in the canonical base32 string form of 0002 §8.1, and parity.mean_f64le / parity.min_f64le as 16 lowercase hex characters — the 8 bytes of the IEEE-754 binary64 value, little-endian. A runner decodes both vector spellings locally, because the shared JSON-to-CBOR vector helper has no byte-string convention and teaching it one would change how every other category decodes. The hash-bearing digest fields are promoted to byte strings before canonical encoding; the statistics are decoded straight to binary64 for the threshold comparison and are never rebuilt as CBOR here. No CBOR float appears anywhere in the category, in keeping with 0002 §3.1.5.
Every vector nests the CLOSED embed_spec of 0024 §3 — identity_basis, realization_manifest, implementation_records — under an embed_spec key, with fixture metadata (test_id, category, modality, the expectations) outside it. The nesting is what makes the CLOSED check meaningful: at the document root an unknown fourth wire key cannot be told apart from a new metadata key, so a runner reading the three fields from the root would declare the container closed while accepting anything.
implementation_records is always an array, never a singleton shorthand, never empty, and sorted ascending by each record's canonical CBOR bytes with byte-identical entries refused. Computing that order is the one place in the corpus where a record is encoded as the Manifest would carry it — base32 digests and the two hex statistics resolved to their byte strings first.
A runner recomputes the threshold verdict from the stated mean_f64le, min_f64le and count rather than trusting a verdict stated in the record, and checks the structural rules of 0024 §3.2 — including that the vector's realization_manifest hashes to the realization_commitment its identity_basis declares. It does not execute an encoder and therefore does not compute parity itself; the measurement of 0024 §4 is out of scope for the vector corpus.
8.12 0025 — Typed Array Items
| Category | Pass criterion | Coverage |
|---|---|---|
typed-array.declaration.* | CLOSED dense-array declaration encodes canonically and hashes to the complete item= multihash | Full identity; unknown fields and overflow refused |
typed-array.modality.* | Tag projections, parameter order, and legal kind/storage pairs agree with the declaration | Missing parameters, projection mismatch, illegal pair, truncated identity |
typed-array.payload.* | raw has exactly product(shape) × sizeof(dtype) bytes; NPY redundantly agrees on dtype, byte order, shape, and layout | Raw length plus NPY accept/mismatch vectors |
typed-array.sdk.* | Dataset and public SDKs write and read typed arrays without MIME inference | Vector-gated dtype/shape/endianness/layout decode in Python + WASM/TS; public Event and Constant round-trips; WASM-written storage independently read by Rust |
post-v1-array.ragged.* | CLOSED ragged-array v1 declaration hashes to a complete identity and its offsets-values payload obeys the declared row/cell boundary | Positive identity/payload; malformed offsets and value length |
post-v1-array.csr.* | CLOSED sparse-csr v1 declaration hashes to a complete identity and its CSR payload has a canonical row/column representation | Positive identity/payload; malformed row offsets, duplicate and out-of-range columns |
The post-v1 vectors are executable format references, not evidence that a Dataset or SDK writer exists. Dense-v1 vectors and bytes are unchanged.
8.13 0027 — Progressive geometry
geometry-item vectors supply canonical descriptor bytes as cbor_hex and
require either byte-identical decode/re-encode with expected_family, or the
specific expected_error. They invoke the actual CLOSED protocol decoder;
they do not establish Dataset publication, range authentication or GC behavior.
Those claims are exercised separately at the public Dataset and SDK boundary.
9. Test Categories — End-to-End Worked Example
A full end-to-end test that exercises the entire spec in one scenario:
10. Conformance Suite Repository
The actual reference corpus and runner live in this repository:
Vectors use the JSON conventions in §4 and category-specific sections, with binary companion files where needed. The Rust runner is one implementation; sharing it across language bindings does not constitute an independent port.
A v0 implementation publishes a conformance report (a structured JSON document listing which test categories passed/failed) and a chosen Tier ("ContentStore-Conformant Backend," "Full Protocol Component," etc.) when claiming DreamDB compatibility.
11. Self-Certification
Until a formal conformance authority exists, implementations self-certify:
- Run the conformance suite against your implementation.
- Publish the resulting report (machine-readable JSON + human-readable summary).
- State your claimed Tier in the README.
- Cite the spec version (e.g. "DreamDB v0.1.0").
Conformance and performance are reported separately. The Tier in step 3 is a pass/fail conformance claim (it covers only the conformance criteria of §4.4). An implementation MAY additionally publish the performance profiles (0023-performance-profiles.md) it meets, each with the workload and environment it was measured under. A profile that is unclaimed or unmet never affects the conformance Tier — an implementation can be fully conformant while meeting zero performance profiles.
The community SHOULD maintain a public list of self-certified implementations and their reports. Discrepancies between claimed and actual conformance can be challenged via the public report; this is the same model used by Web Platform Tests, IETF interop reports, and similar.
A formal certification authority MAY emerge in v0.1+; v0 leans on community-maintained transparency.
12. Compatibility Across Spec Revisions
DreamDB spec versions follow semantic versioning:
- Patch (v0.1.x → v0.1.y): clarifications, OQ resolutions, conformance test additions. Existing implementations remain conformant.
- Minor (v0.1 → v0.2): feature additions (new modalities, new algorithms, new optional verbs). Existing implementations remain conformant for the subset they support; new features are opt-in.
- Major (v0 → v1): breaking changes. Implementations MAY support multiple major versions in parallel via a version-prefixed namespace (TBD in v1).
Within v0:
- v0 freezes the data model, address grammar, time encoding, hash function, and HTTP contract.
- v0.1+ MAY add: new spatial-indexing algorithms (
dreamdb.pq-ivf,dreamdb.lsh-l2,dreamdb.learned-mlp-v1), additional modalities (AV1, HEVC, FLAC, sensor types), federation primitives, named tags, push-style notifications.
13. Open Questions Resolved by This Document
This document explicitly resolves:
- OQ-11 (concrete CBOR tag numbers): § 3.2.
- OQ-12 (multihash algorithm tags — IPFS-aligned): § 3.1.
- OQ-17 (concrete value for the time-anchor CBOR tag): § 3.2 — folded into local
dreamdb.tag = 65521, by application agreement on number and inner type; not used inside DreamDB schemas or claimed globally registered.
The category taxonomy answers the original requests to specify what conformance
must cover. It does not prove corpus completeness, an executed result or
independent-implementation agreement. Capability-specific unfinished vector
questions remain in their owning specs and in INDEX.md.
14. Open Questions Not Resolved
Two operational decisions deferred to community / operator coordination:
- OQ-42 (→ community / future spec): Public registry of conformance reports. v0 is self-certification only; a formal authority may emerge.
- OQ-43 (→ community / future spec): Publication cadence for the conformance suite repository. v0 is unscheduled — releases tied to spec revisions.
End of v0 specification. Implementations interested in v0 conformance should start with 0000-overview.md, build forward through 0001–0008, and verify against the test categories in this document.