Durable model for recorded video: segments and gaps as a tamper-evident per-camera hash chain, per-copy storage lifecycle with a unified deletion manifest, incident-scoped evidence holds, and immutable retention policy versions. The camera record itself lives in operations-camera-registry; this crate owns what was recorded.
| Tier | domain |
| Role | unclassified (baselined) |
| Path | crates/domain/recordings |
| Edition | 2021 |
| Targets | domain_recordings, schema_integration |
| Public items | 117 across 8 modules |
| Tests | 54 |
What it is for
domain-recordings — the durable model for recorded video.
What was recorded, where its copies live, what pins it, and how long it survives. The camera record itself belongs to operations-camera-registry; this crate never restates camera configuration, only references it.
# Shape
Pure and DB-free by default; persistence lands behind the postgres feature, mirroring operations-camera-registry. That keeps the model testable without a database and keeps sqlx out of consumers that only need the types.
# The decisions this crate encodes
Built from forge-nvr's ADR-0008 through ADR-0011, which reached unanimous three-AI consensus across nine review rounds. The governing ones:
- Segments and gaps are both chain members (
chain) — otherwise - Chain input is length-prefixed and domain-separated — raw
concatenation is cryptographically ambiguous, and the API makes it unreachable rather than merely discouraged.
- Two digests per artifact (
digest) — BLAKE3 internally, SHA-256 so
an outside party can verify with tooling they already trust.
- Retention is monotonic — extendable by any worker, reducible by none.
- Erasure is derived from copies, never set directly — the audit must
never claim a segment is gone while bytes survive on some tier.
# What this crate deliberately does not do
It plans; it never executes. There is no worker, no scheduler, and no code path that deletes a file. A library that erases customer footage the moment it is imported is a library that erases customer footage by accident; activation, scheduling, batch limits and the kill switch belong to the consuming application (ADR-0008 D6).
Capabilities
chain (other)
The per-camera tamper-evidence chain (ADR-0011 D3).
| Item |
|---|
fn verify(from : ChainValue, links : & ChainLink) -> Result <ChainValue, ChainError> |
ChainError
The per-camera tamper-evidence chain (ADR-0011 D3).
| Item |
|---|
pub enum ChainError |
ChainInput
The per-camera tamper-evidence chain (ADR-0011 D3).
| Item |
|---|
pub struct ChainInput |
ChainInput :: fn new(seq : ChainSeq, prev : ChainValue, entry_type : EntryType, artifact_id : ArtifactId, payload_digest : PayloadDigest, camera : CameraRef, started_at : DateTime <Utc>, ended_at : DateTime <Utc>,) -> Self |
ChainInput :: fn with_storage_copy(mut self, id : impl Into <String>) -> Self |
ChainInput :: fn with_policy_decision(mut self, decision : impl Into <String>) -> Self |
ChainInput :: const fn seq(& self) -> ChainSeq |
ChainInput :: const fn entry_type(& self) -> EntryType |
ChainInput :: fn compute(& self) -> ChainValue |
ChainLink
The per-camera tamper-evidence chain (ADR-0011 D3).
| Item |
|---|
pub struct ChainLink |
ChainValue
The per-camera tamper-evidence chain (ADR-0011 D3).
| Item |
|---|
pub struct ChainValue |
ChainValue :: fn genesis() -> Self |
ChainValue :: const fn as_bytes(& self) -> & u8; 32 |
ChainValue :: const fn from_stored_bytes(bytes : u8; 32) -> Self |
ChainValue :: fn to_hex(& self) -> String |
EntryType
The per-camera tamper-evidence chain (ADR-0011 D3).
| Item |
|---|
pub enum EntryType |
CopyState
Per-copy storage lifecycle and the unified deletion manifest.
| Item |
|---|
pub enum CopyState |
CopyState :: const fn may_hold_bytes(self) -> bool |
CopyState :: const fn is_verified(self) -> bool |
DeletionManifest
Per-copy storage lifecycle and the unified deletion manifest.
| Item |
|---|
pub struct DeletionManifest |
DeletionManifest :: fn new() -> Self |
DeletionManifest :: fn record(& mut self, event : ManifestEvent) |
DeletionManifest :: fn events(& self) -> & ManifestEvent |
DeletionManifest :: fn has_unverifiable_copy(& self) -> bool |
DestinationId
Per-copy storage lifecycle and the unified deletion manifest.
| Item |
|---|
pub struct DestinationId |
DestinationId :: fn new(id : impl Into <String>) -> Self |
DestinationId :: fn as_str(& self) -> & str |
DestinationId :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
ManifestEvent
Per-copy storage lifecycle and the unified deletion manifest.
| Item |
|---|
pub struct ManifestEvent |
SegmentPresence
Per-copy storage lifecycle and the unified deletion manifest.
| Item |
|---|
pub enum SegmentPresence |
SegmentPresence :: fn derive(copies : & StorageCopy) -> Self |
SegmentPresence :: const fn audit_phrase(self) -> & 'static str |
StorageCopy
Per-copy storage lifecycle and the unified deletion manifest.
| Item |
|---|
pub struct StorageCopy |
StorageCopy :: const fn is_safe_to_reclaim_source(& self) -> bool |
Tier
Per-copy storage lifecycle and the unified deletion manifest.
| Item |
|---|
pub enum Tier |
DigestWriter
Payload digests (ADR-0011 D1).
| Item |
|---|
pub struct DigestWriter |
DigestWriter :: fn new() -> Self |
DigestWriter :: fn update(& mut self, chunk : & u8) |
DigestWriter :: fn finalize(self) -> PayloadDigest |
PayloadDigest
Payload digests (ADR-0011 D1).
| Item |
|---|
pub struct PayloadDigest |
PayloadDigest :: const fn blake3(& self) -> & u8; 32 |
PayloadDigest :: const fn sha256(& self) -> & u8; 32 |
PayloadDigest :: const fn from_stored(blake3 : u8; 32, sha256 : u8; 32) -> Self |
PayloadDigest :: fn blake3_hex(& self) -> String |
PayloadDigest :: fn sha256_hex(& self) -> String |
Hold
Evidence holds — the one thing that outranks every retention rule.
| Item |
|---|
pub struct Hold |
Hold :: fn place(incident : IncidentId, cameras : Vec <CameraRef>, windows : Vec <HoldWindow>, reason : impl Into <String>, expires_at : Option <DateTime <Utc>>, placed_at : DateTime <Utc>, placed_by : impl Into <String>,) -> Result <Self, HoldError> |
Hold :: fn extend_until(& mut self, new_expiry : DateTime <Utc>) -> Result <(), HoldError> |
Hold :: fn pins(& self, camera : & CameraRef, start : DateTime <Utc>, end : DateTime <Utc>, now : DateTime <Utc>,) -> bool |
Hold :: const fn incident(& self) -> & IncidentId |
Hold :: fn reason(& self) -> & str |
Hold :: const fn expires_at(& self) -> DateTime <Utc> |
Hold :: const fn placed_at(& self) -> DateTime <Utc> |
Hold :: fn placed_by(& self) -> & str |
Hold :: fn cameras(& self) -> & CameraRef |
Hold :: fn windows(& self) -> & HoldWindow |
HoldError
Evidence holds — the one thing that outranks every retention rule.
| Item |
|---|
pub enum HoldError |
HoldWindow
Evidence holds — the one thing that outranks every retention rule.
| Item |
|---|
pub struct HoldWindow |
HoldWindow :: fn covers(& self, at : DateTime <Utc>) -> bool |
HoldWindow :: fn overlaps(& self, start : DateTime <Utc>, end : DateTime <Utc>) -> bool |
IncidentId
Evidence holds — the one thing that outranks every retention rule.
| Item |
|---|
pub struct IncidentId |
IncidentId :: fn new(id : impl Into <String>) -> Self |
IncidentId :: fn as_str(& self) -> & str |
IncidentId :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
ArtifactId
Newtypes for the durable model.
| Item |
|---|
pub struct ArtifactId |
ArtifactId :: fn new(id : impl Into <String>) -> Self |
ArtifactId :: fn as_str(& self) -> & str |
ArtifactId :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
CameraRef
Newtypes for the durable model.
| Item |
|---|
pub struct CameraRef |
CameraRef :: fn new(id : impl Into <String>) -> Self |
CameraRef :: fn as_str(& self) -> & str |
CameraRef :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
ChainSeq
Newtypes for the durable model.
| Item |
|---|
pub struct ChainSeq |
ChainSeq :: const fn new(n : u64) -> Self |
ChainSeq :: const fn get(self) -> u64 |
ChainSeq :: const fn next(self) -> Self |
ChainSeq :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
DeletionPriority
Retention decisions and the immutable policy versions that produced them.
| Item |
|---|
pub enum DeletionPriority |
PolicyVersion
Retention decisions and the immutable policy versions that produced them.
| Item |
|---|
pub struct PolicyVersion |
PolicyVersion :: const fn new(n : u32) -> Self |
PolicyVersion :: const fn get(self) -> u32 |
PolicyVersion :: const fn next(self) -> Self |
PolicyVersion :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
RetentionClass
Retention decisions and the immutable policy versions that produced them.
| Item |
|---|
pub struct RetentionClass |
RetentionClass :: fn new(name : impl Into <String>) -> Self |
RetentionClass :: fn as_str(& self) -> & str |
RetentionClass :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result |
RetentionDecision
Retention decisions and the immutable policy versions that produced them.
| Item |
|---|
pub struct RetentionDecision |
RetentionDecision :: fn new(class : RetentionClass, protected_until : DateTime <Utc>, priority : DeletionPriority, decided_by : PolicyVersion, decided_at : DateTime <Utc>,) -> Self |
RetentionDecision :: fn extend(& mut self, until : DateTime <Utc>, by : PolicyVersion, at : DateTime <Utc>,) -> Result <(), RetentionNotExtended> |
RetentionDecision :: fn is_past_protection(& self, now : DateTime <Utc>) -> bool |
RetentionDecision :: const fn protected_until(& self) -> DateTime <Utc> |
RetentionDecision :: const fn priority(& self) -> DeletionPriority |
RetentionDecision :: const fn decided_by(& self) -> PolicyVersion |
RetentionDecision :: const fn decided_at(& self) -> DateTime <Utc> |
RetentionDecision :: const fn class(& self) -> & RetentionClass |
RetentionNotExtended
Retention decisions and the immutable policy versions that produced them.
| Item |
|---|
pub struct RetentionNotExtended |
BackfillState
Segments and gaps — what the recorder produced, and what it didn't.
| Item |
|---|
pub enum BackfillState |
Classification
Segments and gaps — what the recorder produced, and what it didn't.
| Item |
|---|
pub enum Classification |
Classification :: const fn is_erasable(self) -> bool |
Gap
Segments and gaps — what the recorder produced, and what it didn't.
| Item |
|---|
pub struct Gap |
Gap :: fn duration(& self) -> Duration |
Gap :: const fn has_full_custody_weight(& self) -> bool |
GapCause
Segments and gaps — what the recorder produced, and what it didn't.
| Item |
|---|
pub enum GapCause |
Segment
Segments and gaps — what the recorder produced, and what it didn't.
| Item |
|---|
pub struct Segment |
Segment :: fn duration(& self) -> Duration |
Segment :: fn covers(& self, at : DateTime <Utc>) -> bool |
StreamKind
Segments and gaps — what the recorder produced, and what it didn't.
| Item |
|---|
pub enum StreamKind |
store (other)
Postgres persistence, behind the postgres feature.
| Item |
|---|
const fn entry_type_column(t : EntryType) -> & 'static str |
StoreError
Postgres persistence, behind the postgres feature.
| Item |
|---|
pub enum StoreError |
StoreError :: fn is_duplicate_chain_position(& self) -> bool |
StoreError :: fn is_invariant_violation(& self) -> bool |
async fn ensure_schema(pool : & PgPool) -> Result <(), StoreError> |
async fn chain_head(pool : & PgPool, camera : & CameraRef,) -> Result <Option <(ChainSeq, ChainValue)>, StoreError> |
async fn copies_of(pool : & PgPool, artifact : & ArtifactId,) -> Result <Vec <StorageCopy>, StoreError> |
async fn presence_of(pool : & PgPool, artifact : & ArtifactId,) -> Result <SegmentPresence, StoreError> |
async fn is_held(pool : & PgPool, camera : & CameraRef, start : DateTime <Utc>, end : DateTime <Utc>, now : DateTime <Utc>,) -> Result <bool, StoreError> |
How to use it
No examples/ target and no doctest in this crate's rustdoc. The tests listed under Verification are the closest executable usage.
Module structure
domain_recordings
chaincopydigestholdidspolicysegmentstore
flowchart TD n_domain_recordings["domain_recordings"] n_domain_recordings --> n_chain["chain"] n_domain_recordings --> n_copy["copy"] n_domain_recordings --> n_digest["digest"] n_domain_recordings --> n_hold["hold"] n_domain_recordings --> n_ids["ids"] n_domain_recordings --> n_policy["policy"] n_domain_recordings --> n_segment["segment"] n_domain_recordings --> n_store["store"]
Public surface
`chain`
| Item | What it is |
|---|---|
pub enum EntryType | — |
pub struct ChainValue | A chain value: the BLAKE3 output binding this entry to every entry before it. |
ChainValue :: fn genesis() -> Self | The chain value that precedes the first entry for a camera |
ChainValue :: const fn as_bytes(& self) -> & u8; 32 | — |
ChainValue :: const fn from_stored_bytes(bytes : u8; 32) -> Self | Reconstruct a value read back from storage |
ChainValue :: fn to_hex(& self) -> String | — |
pub struct ChainInput | The inputs to one chain position |
ChainInput :: fn new(seq : ChainSeq, prev : ChainValue, entry_type : EntryType, artifact_id : ArtifactId, payload_digest : PayloadDigest, camera : CameraRef, started_at : DateTime <Utc>, ended_at : DateTime <Utc>,) -> Self | The only way to build a chain input. |
ChainInput :: fn with_storage_copy(mut self, id : impl Into <String>) -> Self | Bind this entry to the storage copy it describes. |
ChainInput :: fn with_policy_decision(mut self, decision : impl Into <String>) -> Self | Bind this entry to the retention decision that produced it. |
ChainInput :: const fn seq(& self) -> ChainSeq | — |
ChainInput :: const fn entry_type(& self) -> EntryType | — |
ChainInput :: fn compute(& self) -> ChainValue | Compute this entry's chain value |
pub enum ChainError | Why a chain failed to verify. |
pub struct ChainLink | One verified link: what was stored, alongside the inputs it claims to cover. |
fn verify(from : ChainValue, links : & ChainLink) -> Result <ChainValue, ChainError> | Verify a camera's chain from genesis (or a trusted anchor) forward |
`copy`
| Item | What it is |
|---|---|
pub enum Tier | Where a copy lives (ADR-0009 D2). |
pub struct DestinationId | A configured storage destination. |
DestinationId :: fn new(id : impl Into <String>) -> Self | — |
DestinationId :: fn as_str(& self) -> & str | — |
DestinationId :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
pub enum CopyState | The state of one copy at one destination |
CopyState :: const fn may_hold_bytes(self) -> bool | Whether this copy is known to still hold readable bytes. |
CopyState :: const fn is_verified(self) -> bool | Whether this state was reached by verification rather than by assumption. |
pub struct StorageCopy | One copy of one artifact at one destination. |
StorageCopy :: const fn is_safe_to_reclaim_source(& self) -> bool | Whether hot space backed by this copy may be reclaimed. |
pub enum SegmentPresence | What can honestly be said about an artifact, derived from all its copies. |
SegmentPresence :: fn derive(copies : & StorageCopy) -> Self | Derive presence from copies |
SegmentPresence :: const fn audit_phrase(self) -> & 'static str | Wording for an audit record or the integrity screen. |
pub struct ManifestEvent | One immutable entry in an artifact's deletion manifest |
pub struct DeletionManifest | The append-only manifest for one artifact. |
DeletionManifest :: fn new() -> Self | — |
DeletionManifest :: fn record(& mut self, event : ManifestEvent) | Append an event |
DeletionManifest :: fn events(& self) -> & ManifestEvent | — |
DeletionManifest :: fn has_unverifiable_copy(& self) -> bool | Whether any copy was merely declared lost rather than verified |
`digest`
| Item | What it is |
|---|---|
pub struct PayloadDigest | Both digests of one artifact's bytes. |
PayloadDigest :: const fn blake3(& self) -> & u8; 32 | — |
PayloadDigest :: const fn sha256(& self) -> & u8; 32 | — |
PayloadDigest :: const fn from_stored(blake3 : u8; 32, sha256 : u8; 32) -> Self | Reconstruct a digest read back from storage |
PayloadDigest :: fn blake3_hex(& self) -> String | — |
PayloadDigest :: fn sha256_hex(& self) -> String | — |
pub struct DigestWriter | Computes both digests in a single pass over the bytes |
DigestWriter :: fn new() -> Self | — |
DigestWriter :: fn update(& mut self, chunk : & u8) | Feed the next chunk |
DigestWriter :: fn finalize(self) -> PayloadDigest | — |
`hold`
| Item | What it is |
|---|---|
pub struct IncidentId | The incident a hold belongs to |
IncidentId :: fn new(id : impl Into <String>) -> Self | — |
IncidentId :: fn as_str(& self) -> & str | — |
IncidentId :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
pub struct HoldWindow | A time window a hold covers. |
HoldWindow :: fn covers(& self, at : DateTime <Utc>) -> bool | — |
HoldWindow :: fn overlaps(& self, start : DateTime <Utc>, end : DateTime <Utc>) -> bool | Whether this window overlaps a segment's span at all |
pub enum HoldError | Why a hold could not be created. |
pub struct Hold | An evidence hold. |
Hold :: fn place(incident : IncidentId, cameras : Vec <CameraRef>, windows : Vec <HoldWindow>, reason : impl Into <String>, expires_at : Option <DateTime <Utc>>, placed_at : DateTime <Utc>, placed_by : impl Into <String>,) -> Result <Self, HoldError> | Create a hold |
Hold :: fn extend_until(& mut self, new_expiry : DateTime <Utc>) -> Result <(), HoldError> | Push the expiry further out |
Hold :: fn pins(& self, camera : & CameraRef, start : DateTime <Utc>, end : DateTime <Utc>, now : DateTime <Utc>,) -> bool | Whether this hold pins a segment on camera spanning start..end. |
Hold :: const fn incident(& self) -> & IncidentId | — |
Hold :: fn reason(& self) -> & str | — |
Hold :: const fn expires_at(& self) -> DateTime <Utc> | — |
Hold :: const fn placed_at(& self) -> DateTime <Utc> | — |
Hold :: fn placed_by(& self) -> & str | — |
Hold :: fn cameras(& self) -> & CameraRef | — |
Hold :: fn windows(& self) -> & HoldWindow | — |
`ids`
| Item | What it is |
|---|---|
pub struct ChainSeq | Position of an entry within its camera's chain |
ChainSeq :: const fn new(n : u64) -> Self | — |
ChainSeq :: const fn get(self) -> u64 | — |
ChainSeq :: const fn next(self) -> Self | The position after this one |
ChainSeq :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
pub struct ArtifactId | Identifier of the thing a chain entry describes — a segment, a gap, or a derivative. |
ArtifactId :: fn new(id : impl Into <String>) -> Self | — |
ArtifactId :: fn as_str(& self) -> & str | — |
ArtifactId :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
pub struct CameraRef | Reference to the camera an entry belongs to |
CameraRef :: fn new(id : impl Into <String>) -> Self | — |
CameraRef :: fn as_str(& self) -> & str | — |
CameraRef :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
`policy`
| Item | What it is |
|---|---|
pub struct PolicyVersion | An immutable policy version |
PolicyVersion :: const fn new(n : u32) -> Self | — |
PolicyVersion :: const fn get(self) -> u32 | — |
PolicyVersion :: const fn next(self) -> Self | — |
PolicyVersion :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
pub enum DeletionPriority | How aggressively a segment should be reclaimed once it is eligible |
pub struct RetentionClass | Why a segment is being kept, in the operator's terms. |
RetentionClass :: fn new(name : impl Into <String>) -> Self | — |
RetentionClass :: fn as_str(& self) -> & str | — |
RetentionClass :: fn fmt(& self, f : & mut fmt::Formatter <'_>) -> fmt::Result | — |
pub struct RetentionNotExtended | Attempted to shorten a retention. |
pub struct RetentionDecision | The decision for one segment, and the evidence for it. |
RetentionDecision :: fn new(class : RetentionClass, protected_until : DateTime <Utc>, priority : DeletionPriority, decided_by : PolicyVersion, decided_at : DateTime <Utc>,) -> Self | — |
RetentionDecision :: fn extend(& mut self, until : DateTime <Utc>, by : PolicyVersion, at : DateTime <Utc>,) -> Result <(), RetentionNotExtended> | Extend protection |
RetentionDecision :: fn is_past_protection(& self, now : DateTime <Utc>) -> bool | Whether the segment may be considered for erasure at now |
RetentionDecision :: const fn protected_until(& self) -> DateTime <Utc> | — |
RetentionDecision :: const fn priority(& self) -> DeletionPriority | — |
RetentionDecision :: const fn decided_by(& self) -> PolicyVersion | — |
RetentionDecision :: const fn decided_at(& self) -> DateTime <Utc> | — |
RetentionDecision :: const fn class(& self) -> & RetentionClass | — |
`segment`
| Item | What it is |
|---|---|
pub enum StreamKind | Which stream a segment came from (ADR-0010 D2) |
pub enum Classification | How far detection has got with a segment (ADR-0009 D5). |
Classification :: const fn is_erasable(self) -> bool | Whether a segment in this state may ever be considered for erasure |
pub struct Segment | A recorded segment. |
Segment :: fn duration(& self) -> Duration | Wall-clock span this segment covers |
Segment :: fn covers(& self, at : DateTime <Utc>) -> bool | Whether this segment covers at. |
pub enum GapCause | Why there is no footage for a span. |
pub enum BackfillState | Whether a gap can still be filled. |
pub struct Gap | A span with no footage |
Gap :: fn duration(& self) -> Duration | — |
Gap :: const fn has_full_custody_weight(& self) -> bool | Whether footage recovered for this gap should be treated as having the same evidentiary weight as directly-recorded footage |
`store`
| Item | What it is |
|---|---|
pub enum StoreError | Persistence errors. |
StoreError :: fn is_duplicate_chain_position(& self) -> bool | Does this error mean the chain position was already taken? The (camera_ref, seq) unique index is what enforces monotonicity at the database level, so the violation arrives as a Postgres 23505 |
StoreError :: fn is_invariant_violation(& self) -> bool | Does this error mean an append-only or monotonicity guard refused the write? These are deliberate RAISE EXCEPTIONs from the migration triggers — editing the deletion manifest, shortening a hold, shortening retention, or mutating a policy version |
async fn ensure_schema(pool : & PgPool) -> Result <(), StoreError> | Apply the crate's migrations, in order, on every call |
async fn chain_head(pool : & PgPool, camera : & CameraRef,) -> Result <Option <(ChainSeq, ChainValue)>, StoreError> | The last chain value and sequence for a camera, or None if it has no entries yet |
async fn copies_of(pool : & PgPool, artifact : & ArtifactId,) -> Result <Vec <StorageCopy>, StoreError> | All copies of an artifact, across every destination |
async fn presence_of(pool : & PgPool, artifact : & ArtifactId,) -> Result <SegmentPresence, StoreError> | What can honestly be said about an artifact right now |
async fn is_held(pool : & PgPool, camera : & CameraRef, start : DateTime <Utc>, end : DateTime <Utc>, now : DateTime <Utc>,) -> Result <bool, StoreError> | Whether any active hold pins a segment on camera spanning start..end |
const fn entry_type_column(t : EntryType) -> & 'static str | Column value for an entry type. |
Re-exports. Exported here, defined elsewhere.
| Export | Defined in |
|---|---|
{ArtifactId,CameraRef,ChainSeq} | ids::{ArtifactId,CameraRef,ChainSeq} |
{BackfillState,Classification,Gap,GapCause,Segment,StreamKind} | segment::{BackfillState,Classification,Gap,GapCause,Segment,StreamKind} |
{ChainError,ChainInput,ChainLink,ChainValue,EntryType} | chain::{ChainError,ChainInput,ChainLink,ChainValue,EntryType} |
{CopyState,DeletionManifest,DestinationId,ManifestEvent,SegmentPresence,StorageCopy,Tier,} | copy::{CopyState,DeletionManifest,DestinationId,ManifestEvent,SegmentPresence,StorageCopy,Tier,} |
{DeletionPriority,PolicyVersion,RetentionClass,RetentionDecision,RetentionNotExtended,} | policy::{DeletionPriority,PolicyVersion,RetentionClass,RetentionDecision,RetentionNotExtended,} |
{DigestWriter,PayloadDigest} | digest::{DigestWriter,PayloadDigest} |
{Hold,HoldError,HoldWindow,IncidentId} | hold::{Hold,HoldError,HoldWindow,IncidentId} |
{ensure_schema,StoreError} | store::{ensure_schema,StoreError} |
Boundary
Reaches into operations.
Shares tier domain with 41 other crates: domain-agreements, domain-ai-report, domain-billing, domain-catalog, domain-classify, domain-comments, domain-competitive-intel, domain-contact, … (41 total).
_What this crate deliberately does NOT own is a judgment. No committed registry records one for it, so none is stated here._
Where it sits
| Tier (ontology) | domain |
| Architectural role (taxonomy) | unclassified (baselined) |
| Location | crates/domain/recordings |
| Vocabulary in force (lexicon) | current |
Tier flow. Which tiers this crate's own edges cross.
flowchart LR n_domain["domain"] --> n_operations["operations"]
Dependencies
Runtime, in this workspace.
| Crate | Tier | Optional | Only on |
|---|---|---|---|
| `operations-camera-discovery` | operations | no | always |
Runtime, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
blake3 | ^1 | — | no | always |
chrono | ^0.4 | serde | no | always |
serde | ^1 | derive | no | always |
sha2 | ^0.10 | — | no | always |
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | yes | always |
thiserror | ^2 | — | no | always |
uuid | ^1 | v4, v7, serde, js | no | always |
Development, from outside the workspace.
| Crate | Requirement | Features | Optional | Only on |
|---|---|---|---|---|
sqlx | ^0.8 | runtime-tokio, postgres, chrono, uuid, json | no | always |
tokio | ^1 | full, macros, rt-multi-thread | no | always |
Build. None.
Depended on by. Nothing in this workspace.
Signal flow — what reaches this crate, and what it reaches.
flowchart LR SELF["domain-recordings"] SELF -->|runtime| n_operations_camera_discovery["operations-camera-discovery"] classDef self fill:#1f883d,stroke:#1f883d,color:#fff; class SELF self;
Feature flags
| Feature | Enables | On by default |
|---|---|---|
default | — | yes |
postgres | dep:sqlx | no |
flowchart LR n_default["default"] n_postgres["postgres"] --> n_dep_sqlx["dep:sqlx"]
Targets
| Kind | Name | Source |
|---|---|---|
| lib | domain_recordings | `src/lib.rs` |
| test | schema_integration | `tests/schema_integration.rs` |
Error model
| Error type | Named by |
|---|---|
ChainError | verify |
HoldError | declared, no public signature returns it |
StoreError | chain_head, copies_of, ensure_schema, is_held, presence_of |
Operational characteristics
| Property | Evidence |
|---|---|
| async public surface | yes |
| async runtime | none detected |
| database access | yes |
| network I/O | none detected |
| unsafe code | none detected |
| environment variables | none detected |
No unsafe block, unsafe fn, unsafe impl or unsafe trait was found by the parser anywhere in this crate's source.
Configuration
No environment variable is read with a literal name anywhere in this crate. A variable whose key is computed at run time cannot be listed here, and is not claimed to be absent.
Related capabilities
No workspace crate depends on this one.
Verification
| Kind | Count |
|---|---|
| Unit tests | 43 |
| Integration tests | 11 |
| Examples | 0 |
| Doctests | 0 |
Evidence by module. How often each public module is named by something executable.
| Module | Tests | Examples | Consumers |
|---|---|---|---|
chain | 6 | 0 | 0 |
copy | 7 | 0 | 0 |
digest | 2 | 0 | 0 |
hold | 4 | 0 | 0 |
ids | 3 | 0 | 0 |
policy | 5 | 0 | 0 |
segment | 6 | 0 | 0 |
store | 7 | 0 | 0 |
What the tests establish, by name:
a_gap_carrying_digests_is_rejected—tests/schema_integration.rsa_hold_expiry_cannot_be_shortened—tests/schema_integration.rsa_hold_without_a_reason_is_rejected—tests/schema_integration.rsa_policy_version_cannot_be_rewritten_or_deleted—tests/schema_integration.rsa_segment_without_digests_is_rejected—tests/schema_integration.rsdeleting_an_entry_with_copies_is_restricted—tests/schema_integration.rsduplicate_chain_position_is_rejected_by_the_database—tests/schema_integration.rsensure_schema_is_idempotent—tests/schema_integration.rsholds_have_no_foreign_key_to_any_camera_table—tests/schema_integration.rsretention_cannot_be_shortened—tests/schema_integration.rsthe_deletion_manifest_cannot_be_edited_or_deleted—tests/schema_integration.rsa_duplicated_sequence_is_rejected—src/chain.rsa_well_formed_chain_verifies—src/chain.rsabsent_and_empty_optionals_differ—src/chain.rsentry_types_are_domain_separated—src/chain.rsgenesis_is_not_all_zeroes—src/chain.rslength_prefixing_removes_boundary_ambiguity—src/chain.rsmutating_any_entry_invalidates_every_later_value—src/chain.rsremoving_an_entry_breaks_the_link—src/chain.rsreordering_entries_breaks_the_link—src/chain.rsverification_from_a_trusted_anchor_skips_earlier_history—src/chain.rsa_lost_tier_downgrades_the_claim_to_no_known_surviving_copies—src/copy.rsa_single_surviving_copy_keeps_the_segment_present—src/copy.rsan_artifact_with_no_copy_records_is_unknown_not_erased—src/copy.rsan_unreachable_destination_does_not_imply_the_bytes_are_gone—src/copy.rscopy_expiry_is_not_segment_erasure—src/copy.rsevery_copy_verified_gone_yields_verified_erased—src/copy.rshot_space_is_not_reclaimable_until_the_copy_is_verified—src/copy.rsthe_manifest_is_append_only_and_flags_unverifiable_copies—src/copy.rsa_single_byte_change_changes_both_digests—src/digest.rs- _… 24 more_
Documentation coverage
| Measure | Documented | Total |
|---|---|---|
| Public items with rustdoc | 67 | 117 |
Public modules with a //! block | 8 | 8 |
pie showData
title Public items with rustdoc
"Documented" : 67
"No rustdoc detected" : 50
Metrics
| Metric | Value |
|---|---|
| Rust source files | 9 |
| Source lines | 2206 |
| Code lines | 1533 |
| Public API items | 117 |
| Public modules | 8 |
| Tests | 54 |
| Examples | 0 |
| Cargo features | 2 |
| Direct runtime dependencies | 8 |
| Workspace reverse dependencies | 0 |
pie showData
title Public API by kind
"enum" : 12
"function" : 7
"method" : 77
"struct" : 21
pie showData
title Rust source composition
"Code" : 1533
"Blank or comment" : 673
Generation
Rendered by tools-corpus corpus readme from repository evidence alone, renderer schema 2, lexicon current. No model, network service or database was consulted. Regenerate with tools-corpus corpus readme --write; verify with --check.