Skip to main content

What is refused, and before what

A path is checked before the file is read and before a brain is opened for a write. Four refusals, exit 2: max_bytes is unset by default, which is right for a person registering their own files and wrong for anything accepting evidence from elsewhere. It is declared per brain and enforced in the runtime, so bytes assembled in memory cannot exceed what bytes read from a file may not.
These are the same four a declared source has applied since it existed. What changed is that a path a person types goes through them too, which is the one that has a symlink in it.

Where it came from is never guessed

--origin is recorded in provenance and is the key a later pull uses to answer “already have this?”. Omitted, it is the path you named — which is meaningful because you named it. Nothing else invents one: the runtime is handed bytes, a media type and an origin, and if a caller has no origin to give it says so rather than having this machine’s directory layout written into a permanent record. See ADR-0021.

The media type is load-bearing

It is recorded in the block, it travels with the artifact, and it is what both normalization dispatch and projection read. A Markdown file filed as application/octet-stream is a file no text pipeline will offer to normalise and no analyzer will read as prose. mimetypes does not know .md, so vitruvio carries a small table of extensions a knowledge brain meets constantly (.md, .rst, .tex, .jsonl, .yaml, .toml, .webp, .avif). Declaring --media-type is still better: an extension is a claim, not evidence.

Normalized views

A normalized view is a deterministic, content-addressed rendering of a source, produced by a named and versioned pipeline, and recorded in provenance. It exists to be read — by a proposer, by an analyzer, by a person, and by search: a canonical block holds no prose of its own, so the view is the only text the indices and the exhaustive scan can observe. One policy decides which pipeline runs, and source register, source replace and ingest run all follow it. Nothing said means the pipeline that suits the media type, from the table below, and no view when none suits — a raster image. --normalize-with NAME overrides it. --normalize-with none produces no view at all. A declared source is the exception: it applies exactly what its declaration says, and nothing more.
Because a view is evidence, one requirement dominates every implementation choice: the same input and the same pipeline version must produce identical bytes on every machine. Which is why:
  • The HTML extractor is html.parser from the standard library, not BeautifulSoup or lxml. Both are better parsers and both change their whitespace and entity handling between releases, which would move a view’s digest on a dependency bump.
  • Nothing reflows prose, fixes spelling or normalises quotes. Those are interpretations, and an interpretation belongs in semantic memory as a cited proposal.
  • Raster images have no pipeline at all. A “normalized PNG” is a re-encode, and re-encoding is not reproducible across libpng versions. Vision embeddings read the original blob instead — the bytes that were observed are the evidence. SVG is the exception only because it is text.

Re-registering is free

Content is addressed by its hash, so registering the same bytes twice produces one block and reports duplicate: true. This is what makes an ingestion pipeline safe to re-run. The view is part of that identity. The same bytes registered under a different pipeline — or under none — are a second block, not a duplicate, because a block that names a view and one that does not are different statements about the evidence. A block registered before views were the default keeps its identity, and stays searchable by media type only, until it is registered or replaced again.

No in-place edit

There is none, anywhere. A newer edition of a source is a new block plus a supersession edge, which is what source replace does. Immutability is what lets a root mean something.