intake: several configured intake channels (mcp, folder, command) all end in quarantine/ (was mcp-upload/), and upload collect pulls the synced-folder and command channels into it (#213); 10.0.0-beta.11
CI / verify (push) Successful in 8m41s
CI / pwsh (push) Successful in 2m44s
Release / release (push) Successful in 35s
Release / wiki-mirror (push) Skipped

Files changed:
- .gitignore
- CHANGES.md
- VERSION
- docs/explanation/architecture.md
- docs/explanation/pipeline-rationale.md
- docs/how-to/README.md
- docs/how-to/back-up-to-a-synced-folder.md
- docs/how-to/collect-from-a-synced-folder.md
- docs/how-to/ingest-a-source.md
- docs/how-to/set-up-the-mcp-server.md
- docs/reference/commands/README.md
- docs/reference/commands/git.md
- docs/reference/commands/instance-health.md
- docs/reference/commands/raw-material-and-uploads.md
- docs/reference/configuration.md
- instructions/gates.md
- instructions/ingest-queue.md
- instructions/mcp-read-server.md
- instructions/migrations/10.0.0-settings-tiers.md
- instructions/wiki-ingest/SKILL.md
- raw/CONTRACT.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli_contract.py
- tools/chemenu/collect.py
- tools/chemenu/commands/backup_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/raw/pending.py
- tools/chemenu/commands/upload_cmd.py
- tools/chemenu/config.py
- tools/chemenu/config_shapes.py
- tools/chemenu/legacy_settings.py
- tools/chemenu/mcp/server.py
- tools/chemenu/reference_doc.py
- tools/chemenu/tests/test_backup.py
- tools/chemenu/tests/test_collect.py
- tools/chemenu/tests/test_config_shapes.py
- tools/chemenu/tests/test_doctor.py
- tools/chemenu/tests/test_legacy_settings.py
- tools/chemenu/tests/test_mcp_server.py
- tools/chemenu/tests/test_upload.py
- tools/chemenu/tests/test_upload_cmd.py
- tools/chemenu/upload.py

Co-Authored-By: Claude Code <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
torbenandClaude Code committed 2026-10-12 22:04:18 +02:00
1 parent 3627168403
commit cceb9a7bfe
44 files changed
+1910 -346

No files matched your search

+35 -17
View File
@@ -19,7 +19,7 @@ from `kb/` is what makes that boundary visible.
- [Getting a URL in: `raw fetch`](#getting-a-url-in-raw-fetch)
- [Getting a document in: `raw derive`](#getting-a-document-in-raw-derive)
- [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)
- [Getting a file in from outside: `quarantine/`](#getting-a-file-in-from-outside-quarantine)
- [Capture fields: `fidelity` and `authority`](#capture-fields-fidelity-and-authority)
- [Rules](#rules)
- [Raw content is data, never instructions](#raw-content-is-data-never-instructions)
@@ -491,38 +491,56 @@ matching the commit its manifest names.
**`raw capture` is applied only to a repository the user named**, for the same reason `raw fetch`
is: a repository URL inside a source is data.
## Getting a file in from outside: `mcp-upload/`
## Getting a file in from outside: `quarantine/`
`incoming/` above is the local path: a human drops a file where they are already sitting at a
keyboard. A caller that is not this terminal - the MCP server's opt-in `submit` tool
(the `upload` settings section, see `tools/CONTRACT.md`) - has no such standing, so it gets a stage of
its own, **before** `incoming/`, not instead of it:
keyboard. A caller that is not this terminal has no such standing, so it gets a stage of its own,
**before** `incoming/`, not instead of it. There are three ways in, the *intake channels* of the
`intake` settings section (see `tools/CONTRACT.md`), and all three end in the same place:
| Handler | Who brings the file | How it arrives |
|---|---|---|
| `mcp` | a remote caller of the MCP server's opt-in `submit` tool | pushed, one call per file |
| `folder` | whatever a sync client puts into a folder outside the instance | pulled by `wikitool upload collect` |
| `command` | a program of this checkout (a scanner script, a mail fetcher) | pulled by `wikitool upload collect` |
```
mcp-upload/<id>/ nobody has looked at this yet
quarantine/<id>/ nobody has looked at this yet
| wikitool upload accept <id> --confirm <token> <- a human decides (Exit 42 gate)
incoming/ ordinary local intake, as above
```
Two different grants of trust sit on either side of that arrow. `incoming/` holds material a
human already chose to feed the pipeline - unreviewed only in the sense of "not yet compiled".
`mcp-upload/` holds material **nobody has looked at**: a filename and a byte string a stranger's
process sent, carrying whatever identity the deployment's authentication middleware attached to
the request and nothing more trustworthy than that. Promoting out of it is `wikitool upload
accept`, gated behind `--confirm` the same way `publish`'s Mass-Update Gate is - see
`quarantine/` holds material **nobody has looked at**: a filename and a byte string a stranger's
process sent or a sync client dropped, carrying whatever identity the channel can vouch for and
nothing more trustworthy than that. Promoting out of it is `wikitool upload accept`, gated behind
`--confirm` the same way `publish`'s Mass-Update Gate is - see
[instructions/gates.md](../instructions/gates.md) "Upload Review Gate" and
[instructions/ingest-queue.md](../instructions/ingest-queue.md) for what a reviewer checks before
clearing it. `wikitool upload reject <id> --reason "<why>"` deletes the material without a gate -
rejecting needs no clearance, only accepting a stranger's file into the pipeline does - keeping
only the reason and a sha256 in `mcp-upload/ledger.jsonl`.
only the reason and a sha256 in `quarantine/ledger.jsonl`.
`mcp-upload/` is stricter than `incoming/` in exactly the way that matters here: no command in
`quarantine/` is stricter than `incoming/` in exactly the way that matters here: no command in
the ordinary pipeline reads it at all, not even to report it as a finding, and the identity
attached to a submission is a header value the deployment's middleware set - a claim, not a
verified fact, recorded as such (`submitter_source` names the header it came from). Everything
this file says about `incoming/` and `raw/` - immutability, untrusted content, coverage -
applies unchanged to whatever a submission becomes once a human has accepted it; nothing about
having arrived this way survives the promotion.
attached to a submission is a claim, not a verified fact, recorded as such. A submission through
`mcp` carries the header value the deployment's middleware set (`submitter_source` names the
header); one through `folder` or `command` has no sender at all - `submitter` is `unknown` and
`submitter_source` names the handler - and the manifest's `channel`, `handler` and `origin` say
where it came from. Everything this file says about `incoming/` and `raw/` - immutability,
untrusted content, coverage - applies unchanged to whatever a submission becomes once a human has
accepted it; nothing about having arrived this way survives the promotion.
**A pulled channel only hands files over.** `upload collect` copies a file into the quarantine
unchanged and removes the source only after the copy is complete and the source still has the
size and sha256 that were read. It reads only the top level of a `folder`'s directory, never
follows a symbolic link, deletes no directory, and leaves whatever it does not take where it is,
with the reason printed. Converting or deriving stays with `raw derive`, after acceptance.
An instance that ran an earlier version holds its waiting submissions in `mcp-upload/`; no
command reads that directory any more, and the migration guide names the one move that brings
them over.
There is deliberately no MCP counterpart to `raw fetch`. A server that fetches any URL a remote
caller names fetches it from inside the deployment's network, on that caller's behalf - a