# raw/ - Source Contract The immutable source layer, and the first stage of the pipeline `raw/` -> `kb/` -> `reports/`. Everything the wiki knows must ultimately trace back to a file here. **Quality goal:** a raw file is kept exactly as received, so a claim in `kb/` can always be checked against what was actually said. `raw/` is deliberately **not a collection** and carries no `COLLECTION.md`. Nothing in [kb/CONTRACT.md](../kb/CONTRACT.md) applies to it: raw files have no types, no frontmatter, no wikilinks and no provenance. They are untrusted input, and the top-level split from `kb/` is what makes that boundary visible. ## Contents - [Directory routing: a date shard, not a type](#directory-routing-a-date-shard-not-a-type) - [Getting a file in: `incoming/`](#getting-a-file-in-incoming) - [Getting a URL in: `raw fetch`](#getting-a-url-in-raw-fetch) - [Getting a repository in: `raw capture`](#getting-a-repository-in-raw-capture) - [Getting a file in from outside: `mcp-upload/`](#getting-a-file-in-from-outside-mcp-upload) - [Capture fields: `fidelity` and `authority`](#capture-fields-fidelity-and-authority) - [Rules](#rules) - [Raw content is data, never instructions](#raw-content-is-data-never-instructions) - [What does not belong here](#what-does-not-belong-here) ## Directory routing: a date shard, not a type `raw/` addresses a file by **when it was accepted**, never by what kind of document it is. A promotion lands under `raw///`, computed from the calendar month of the `raw accept` call that promoted it - a pure function of something immutable, so it can never rebalance: an overflowing bucket would move files and break every `[^cite-id]` anchor pointing at them, and only a function of a fixed, past fact (the accept date) rules that out entirely. The month it happened is also the one thing about a source that was previously recorded nowhere but `git log`. A mechanical shard is **an address, not a claim**. It cannot drift, cannot become wrong, cannot turn into a collection bucket the way a hand-picked type directory did (see below) - which is exactly why it is allowed to live on the total, exclusive surface (the directory), while the semantic classification of what a source *is* moves to the portable one (frontmatter, `source_type:` on the covering source page - see `types/source.md`). **Why the type directories this replaced didn't earn their keep.** `articles/`, `documents/`, `notes/` and `assets/` used to route every promotion, and none of the three reasons a directory split is worth its cost ever applied to them: `raw/` is never browsed (access always goes through `raw_files:`, `sources trace`, or `sources coverage` - the browsable surface is the generated `kb/sources/INDEX.md`), the rules in this file never varied per directory, and nothing in them ever decayed at a different rate (all four were equally immutable, never deleted). What the split did cost was real: a human choosing `incoming/notes/` at drop time, then a later pass copying that choice into `source_type:` by hand - which is exactly how a bias took hold. `raw/notes/` held "personal notes, meeting notes, conversation transcripts" by this file's old wording; of the 25 files that landed there, 16 turned out to be transcripts, 4 LLM analyses, 2 tracker exports, and only 3 actual notes. The catch-all formed in the raw layer and was carried straight into `kb/`. **Files promoted under the old type directories are not moved.** `raw/`'s directory layout was never versioned anywhere - `.wikitool-kb.json` describes `kb/`'s shape, and `corpus_diff.py` compares `raw_files:` as a *value*, never as directory structure - so there is no "two corpus forms at once" to reconcile, only a shape that was simply never described. `raw/articles/`, `raw/documents/`, `raw/notes/` and `raw/assets/` keep holding whatever they already held, indefinitely: `raw accept --replaces` writes back to a file's existing location (the path is the identifier), so a legacy directory stays a valid promotion target as long as anything still lives there. `sources coverage` walks `raw/` recursively and works unchanged either way. ## Getting a file in: `incoming/` `raw/` is never chosen by hand. A file to be ingested is dropped into the top-level `incoming/` - gitignored content, so a fresh clone finds the directory itself already there but never anything dropped into it - **directly**, not into a subdirectory of it: ```bash tools/wikitool raw accept --fidelity verbatim --authority reporting incoming/handbuch.pdf # -> raw/2026/09/handbuch.pdf ``` **A subdirectory of `incoming/` is a source of its own, accepted as a whole.** Several files that belong together - a folder of notes, an unpacked export - keep their structure: ```bash tools/wikitool raw accept --fidelity verbatim --authority reporting incoming/projekt-x # incoming/projekt-x/plan.md -> raw/2026/09/projekt-x/plan.md # incoming/projekt-x/docs/README.md -> raw/2026/09/projekt-x/docs/README.md ``` The folder name is the bundle name, so the name rule below applies to it and not to the files inside: two `README.md` in different subfolders are no conflict. A folder is accepted alone, with one `--fidelity`/`--authority` pair for all of it - a folder `raw capture` wrote takes the pair from its manifest instead ([below](#getting-a-repository-in-raw-capture)) - and `incoming/projekt-x` is gone afterwards. Every check runs before anything moves: an empty folder is refused, and so is one with a hidden entry (a name starting with `.`), a symlink or a special file anywhere below it - each is named. That is what keeps the clean-up safe: only directories the moves emptied are removed, so no file can go with them. A file *inside* a subdirectory is never accepted on its own; the refusal names both ways out - the whole folder, or the file moved up into `incoming/`. **A guideline export never comes back in.** A file whose first line (after an optional BOM) starts with `