Skip to main content

Module assets

Module assets 

Source
Expand description

assets — the db.md asset layer.

Raw assets (PDFs, recordings, large exports — typically binaries too heavy for Git) belong to a store but live outside the content plane. A content file (the wrapper) declares one via an asset: / assets: frontmatter key; this module records each in the root-level assets.jsonl manifest: store-relative path, SHA-256, size, media type, the declaring wrapper(s), and whether it is required for byte-completeness.

Any in-store file may be declared — including a markdown content file, whose bytes are then integrity-tracked here while the content layer keeps parsing, indexing, and validating it as usual. paths still omits markdown, so an ignore mechanism fed from it can never hide a content file from the VCS.

The manifest is a pure projection of (wrappers + asset files on disk): every field is derivable, so a scan where the bytes are present reproduces it byte-for-byte, exactly like index.jsonl. db.md never transports the bytes and never names a storage provider; that is the hosting/transport layer’s job, keyed off the SHA-256. This module never shells out to git and never touches the network.

Six operations — three writes, three reads:

  • scan (write) discover declared assets, hash present files, rewrite the manifest
  • refresh (write) re-hash one declared asset and update its manifest row
  • refresh_wrapper (write) reconcile every declaration in one wrapper and update the manifest once
  • verify (read) prove the local store is byte-complete for required assets
  • status (read) report present / missing without failing
  • paths (read) the store-relative path list (for an ignore mechanism)

Path safety: every declared path is validated store-relative (no .., no absolute, no escape) via crate::store::ensure_path_within_store wherever a path is read or resolved, so a poisoned manifest can never make scan hash, or a restore write, outside the store.

Structs§

AssetRecord
One asset record — one line of assets.jsonl.
AssetState
One asset’s local state, used by status and verify.
AssetSupersession
A value-free, append-only asset replacement declaration.
Declaration
A single asset: / assets: declaration read from a wrapper’s frontmatter.
RefreshReport
Result of refresh. A refresh is the bounded write-through counterpart to the full-store scan: it re-hashes one declared asset without touching unrelated bytes.
RefreshWrapperReport
Result of refresh_wrapper. This is the bounded batch counterpart to refresh: every asset declared by one wrapper is reconciled, while unrelated wrappers and bytes are untouched.
ScanReport
Result of scan.
StatusReport
Result of status.
VerifyReport
Result of verify.

Constants§

MANIFEST_FILE
The manifest file name at the store root.
SUPERSEDES_ASSET_KEY
Frontmatter key used by an append-only wrapper to state that its single declared asset is the portable replacement for an older asset coordinate.

Functions§

asset_supersession
Parse the optional append-only asset supersession contract from typed frontmatter. The wrapper must declare exactly one required replacement asset; the older coordinate stays in the manifest as optional evidence.
asset_supersession_from_yaml_map
Raw-map equivalent of asset_supersession for the validation sweep.
declarations_from_yaml_map
Read declarations from an already-parsed YAML mapping. Used by crate::validate, which holds the parsed mapping and need not re-read the file. Equivalent to declared_assets but keyed off a raw map.
declared_assets
Read all asset: / assets: declarations from a parsed frontmatter.
normalize_asset_path
Normalize a declared asset path to a CANONICAL store-relative forward-slash string, rejecting absolute paths and any .. / root component. This is the lexical guard; crate::store::ensure_path_within_store is the resolved-path guard applied before any disk read.
paths
The cataloged asset paths, sorted ascending. The VCS-neutral list a harness feeds into a .gitignore managed block or a sync-service exclude. db.md itself never writes any ignore file.
read_manifest
Read assets.jsonl into records, deduped by path (last line wins) and sorted by path ascending. A missing manifest is an empty store, not an error. A malformed line is an InvalidData error (the CLI surfaces it; crate::validate flags it leniently as ASSET_MANIFEST_MALFORMED).
refresh
Re-hash one asset and write just its canonical manifest record.
refresh_wrapper
Reconcile every asset declaration in one wrapper and write the canonical manifest once. This is for bounded generators that own one wrapper with a changing set of assets: it avoids a full-store scan and avoids N manifest rewrites through repeated refresh calls.
scan
Walk every content file, read its asset/assets declarations, hash the present files, and (re)write the manifest. The manifest is a projection: a path no longer declared by any wrapper drops out. Bytes absent locally but previously cataloged are preserved (the eviction / disk-relief case) since they cannot be re-hashed. dry_run computes without writing; untracked additionally reports non-markdown files under sources/ that no wrapper declares. Never writes when nothing changed (keeps the Git diff and the --dry-run-then-scan idempotent).
status
Report which cataloged assets are present locally and how many bytes remain to restore. Never fails on a missing asset (that is verify’s job); it does fail on a malformed manifest.
verify
Check that every required asset (plus optional, under include_optional) is present locally and matches the manifest. quick = presence + size only (fast); otherwise a full SHA-256 re-hash. This is a SWEEP (O(asset bytes) in deep mode), never a loop op. complete is true iff nothing is missing or corrupt in the considered set.
verify_projection
Verify the byte completeness of an intentionally partial projection. Exact listed paths may be absent and are reported as projected_missing; if a listed path is present it is still hashed and any corruption blocks. Unlisted missing assets and every corrupt asset remain blocking.
write_manifest
Write the manifest atomically (temp + fsync + rename through the store’s held root capability), records sorted by path ascending. An empty record set removes the file.