feat!: installation only from a release, into an empty folder; upstream merge/verify and private-instance.md removed, dist adopt, shell-neutral instructions (#153)
CI / verify (push) Successful in 5m19s
CI / pwsh (push) Successful in 1m55s
Release / release (push) Successful in 36s

Files changed:
- .gitea/workflows/ci.yml
- .gitea/workflows/release.yml
- AGENTS.md
- CHANGES.md
- DEVELOPMENT.md
- EVALS.md
- INSTALL.md
- README.md
- VERSION
- docs/ownership-and-templates.md
- instructions/CONTRACT.md
- instructions/bootstrap.md
- instructions/dev/dev-setup.md
- instructions/dev/stack-dev/SKILL.md
- instructions/gates.md
- instructions/ingest-large-tree.md
- instructions/kb-profiles.md
- instructions/mcp-read-server.md
- instructions/migrations/3.0.0-authoring-conventions.md
- instructions/preflight.md
- instructions/private-instance.md
- instructions/session-setup.md
- instructions/setup-instance.md
- instructions/upgrade-instance.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli.py
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/dist_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/git_publish.py
- tools/chemenu/commands/upstream_cmd.py
- tools/chemenu/commands/work_cmd.py
- tools/chemenu/config.py
- tools/chemenu/ownership.py
- tools/chemenu/tests/test_cli.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_instructions_shell.py
- tools/chemenu/tests/test_preflight.py
- tools/chemenu/tests/test_preflight_pwsh.py
- tools/chemenu/tests/test_run_budget.py
- tools/chemenu/tests/test_upstream_cmd.py
- tools/chemenu/toc.py
- tools/preflight.ps1
- tools/preflight.sh
This commit is contained in:
torben committed 2026-10-01 22:12:09 +02:00
1 parent d0f08d1fba
commit a6d07f97c4
46 files changed
+1314 -1936

No files matched your search

+7 -29
View File
@@ -25,7 +25,6 @@ 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)
- [Scope](#scope)
@@ -81,8 +80,8 @@ Background: the [[Mass-Update Gate]] concept page in `kb/`.
The Mass-Update Gate asks whether a change is too large to publish. This one asks the question
underneath it: **whether this is the right repository to publish to at all.**
A checkout that holds private content usually has two remotes - its own, and the public upstream
it takes stack updates from. Git does not distinguish them at push time, so one wrong `--remote`
A checkout that holds private content can have two remotes - its own, and a public one it also
works against. Git does not distinguish them at push time, so one wrong `--remote`
puts a private corpus on a public repository. That is not cheaply reversible: a force-push moves
the branch, but the objects stay fetchable by SHA until someone expires the server's reflogs and
runs `git gc --prune=now` on the bare repo.
@@ -98,8 +97,8 @@ It pins **URLs, not remote names** - a name-based list would wave through a `pub
`pushurl` when one is set, because that is where `git push` actually writes.
The file is per-checkout and gitignored, for the same reason `ENVIRONMENT.md` is: two clones push
to two different places, so a committed copy would tell a private clone that the public upstream
is a legitimate target for its own content. **Absent means unrestricted** - a single-remote
to two different places, so a committed copy would tell a private clone that a public remote is a
legitimate target for its own content. **Absent means unrestricted** - a single-remote
checkout with nothing private in it has nothing to protect, and `doctor` reports which state a
checkout is in, WARNing only when there is more than one remote and no allowlist. A malformed
file is an error rather than "no restriction": a corrupted safeguard must not read as a disabled
@@ -112,9 +111,8 @@ is a standing property of the checkout, not a per-push judgment. The way past it
to add the URL to the file. **An agent must never edit `.wikitool-remotes.json` to get past a
refusal** - that is opening a gate on your own initiative, which AGENTS.md invariant 6 forbids.
The setup this gate exists for - a private instance that takes stack updates from a public
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.
Arm it *before* a second remote is added and before the first `publish` to it: added afterwards
it leaves open exactly the window it closes.
### Upload Review Gate
@@ -135,26 +133,6 @@ Mass-Update Gate's review report versus this file's exit-42 procedure.
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
[private-instance.md](private-instance.md)) can update or delete dozens of stack-owned paths in
one commit, and the Mass-Update Gate does not see any of it. The gate counts the *uncommitted*
changes `publish` is about to stage; by the time `upstream merge` commits, the change is
already history, and the commit it made is not what a later `publish` would be staging - that
publish sees only whatever this session adds on top. A merge touching 200 files therefore goes
out ungated the moment it is pushed.
This is not a hole to patch by making `upstream merge` route through the gate: the gate's
question ("is this too much to publish?") does not apply to a change that only ever touches
stack-owned paths that are, by definition, not this instance's own content. The check that
actually matters here is `upstream merge`'s own postcheck - it re-verifies the merge commit
against `upstream verify`'s logic immediately after committing, and exits 1 with the offending
paths if anything landed outside a stack-owned one. **The merge commit is deliberately left in
place** rather than reverted: it exists, a human has to look at it, and a command that quietly
repaired its own mistake would hide the one event worth seeing. That postcheck is the safeguard
for this command, not the Mass-Update Gate.
## Iteration Budget Gate and loop-breaker
Every `wikitool` call is counted per session. Calls are refused past **60 in a session**, or
@@ -193,7 +171,7 @@ command you actually need to run, and only with the user's approval.
A dozen commands are exempt from this budget entirely - `search` and `doctor` because retrieval
and diagnosis are reading, not iterating, plus the read-only forms of `links`, `cite`, `budget`,
`eval`, `version`, `migrate` and `upstream verify`. The exemption is that allowlist in
`eval`, `version` and `migrate`. The exemption is that allowlist in
[tools/CONTRACT.md](../tools/CONTRACT.md), not a "does not change the wiki" rule of thumb: `lint`
only writes to gitignored `reports/` and still counts, because it is not on the list.