stack: MCP submit-Tool mit Upload Review Gate und Quarantäne-Schreibpfad (schliesst #32)
CI / verify (push) Successful in 53s
Release / release (push) Successful in 36s

Files changed:
- .gitignore
- AGENTS.md
- CHANGES.md
- INSTALL-MCP.md
- README.md
- VERSION
- docs/why-gates-are-code.md
- instructions/gates.md
- instructions/ingest-queue.md
- instructions/mcp-read-server.md
- instructions/wiki-ingest/SKILL.md
- raw/CONTRACT.md
- tools/CONTRACT.md
- tools/chemenu/cli.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/upload_cmd.py
- tools/chemenu/config.py
- tools/chemenu/mcp/server.py
- tools/chemenu/tests/test_doctor.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
This commit is contained in:
2026-09-11 09:51:37 +02:00
parent 4781140375
commit 828521861d
24 changed files with 1866 additions and 56 deletions
+25 -4
View File
@@ -24,6 +24,7 @@ Read the exit code first - it says which of these applies:
- [Exit 42: user clearance required](#exit-42-user-clearance-required)
- [Publish-Remote Gate](#publish-remote-gate)
- [Upload Review Gate](#upload-review-gate)
- [Mass-Update Gate blind spot: `upstream merge`](#mass-update-gate-blind-spot-upstream-merge)
- [Iteration Budget Gate and loop-breaker](#iteration-budget-gate-and-loop-breaker)
- [Taking a new session id](#taking-a-new-session-id)
@@ -33,10 +34,11 @@ Read the exit code first - it says which of these applies:
## Exit 42: user clearance required
A `wikitool` command that exits **42** is not reporting an error. It is refusing to act until a
human has *read its output*. Three gates use it today - the Mass-Update Gate (`publish`, on a
human has *read its output*. Four gates use it today - the Mass-Update Gate (`publish`, on a
change touching 10 or more counted files), the rebase-review gate (`sync` and `publish`, on
a rebase whose incoming commits touch a file this session is also changing), and the
Publish-Remote Gate (`publish`, on a push to a target this checkout has not declared) - but the
a rebase whose incoming commits touch a file this session is also changing), the
Publish-Remote Gate (`publish`, on a push to a target this checkout has not declared), and the
Upload Review Gate (`upload accept`, on a submission nobody has cleared yet) - but the
rule is about the exit code, not the command:
> **Copy the command's output into your reply - the substance of it, not a description of it -
@@ -103,7 +105,7 @@ checkout is in, WARNing only when there is more than one remote and no allowlist
file is an error rather than "no restriction": a corrupted safeguard must not read as a disabled
one.
**This gate has no `--confirm` token, on purpose.** The other two clear with a token because the
**This gate has no `--confirm` token, on purpose.** The other three clear with a token because the
question they ask ("is this change right?") is one the agent can put to the user and the user can
answer for that one changeset. This one asks "does this content belong to that repository?", which
is a standing property of the checkout, not a per-push judgment. The way past it is for the user
@@ -114,6 +116,25 @@ The setup this gate exists for - a private instance that takes stack updates fro
upstream - is [private-instance.md](private-instance.md). Step 4 there arms it, deliberately
*before* the first `publish`: added afterwards it leaves open exactly the window it closes.
### Upload Review Gate
The MCP server's opt-in `submit` tool (`.wikitool-upload.json`) writes into a
quarantine, `mcp-upload/`, that no other command reads. This gate is the only door out of it:
`wikitool upload accept <id>` refuses without a matching `--confirm <token>`, printing the
submission's manifest in full - filename, size, sha256, submitter, and `submitter_source` (the
*header* the submitter's name came from, not a verified fact) - plus the exact re-run line.
Same shape as the Mass-Update Gate, scoped to one submission instead of a changeset: the token
digests id/filename/size/sha256/submitter, so an edited or superseded manifest invalidates it the
same way a rewritten file invalidates a stale `--confirm`. What a reviewer actually checks before
clearing it - secrets, license, an injection attempt, whether the material is worth a source page
at all - is [instructions/ingest-queue.md](ingest-queue.md), not this file: the same split as the
Mass-Update Gate's review report versus this file's exit-42 procedure.
`wikitool upload reject <id> --reason "<why>"` is the other way out, and it has **no gate at
all** - rejecting needs no clearance, only accepting a stranger's file into the pipeline does. It
deletes the material and keeps only the reason and a sha256 in `mcp-upload/ledger.jsonl`.
### Mass-Update Gate blind spot: `upstream merge`
`upstream merge` (a private instance taking a stack update - see