incoming/.gitkeep als Datei- statt Verzeichnismuster trackbar (schliesst #88)
CI / verify (push) Successful in 53s
Release / release (push) Successful in 35s

Files changed:
- .gitignore
- CHANGES.md
- README.md
- VERSION
- incoming/.gitkeep
- instructions/bootstrap.md
- raw/CONTRACT.md
- tools/CONTRACT.md
- tools/chemenu/commands/docs_verify.py
This commit is contained in:
2026-09-11 13:11:31 +02:00
parent 95ab40827a
commit 36da0855cf
9 changed files with 77 additions and 32 deletions
+19 -8
View File
@@ -155,19 +155,30 @@ npm-debug.log*
# one is merely tolerated and ignored; `wikitool raw accept` promotes it into # one is merely tolerated and ignored; `wikitool raw accept` promotes it into
# `raw/`, computing the date-sharded directory and any bundle from what was # `raw/`, computing the date-sharded directory and any bundle from what was
# passed in one call. Unlike raw/ itself this must NEVER be committed - the # passed in one call. Unlike raw/ itself this must NEVER be committed - the
# promotion is what makes a file immutable, not the drop - so this is the one # promotion is what makes a file immutable, not the drop.
# directory pattern in this file that is deliberately not anchored back open #
# by the content backstop below. # File pattern, not directory pattern (Gitea #88): `/incoming/` used to
/incoming/ # exclude the directory itself, and rule 2 above means the negation block at
# the bottom could never re-include a file whose parent was already gone -
# so a fresh clone never had the directory at all, only
# `instructions/bootstrap.md` recreating it by hand. `/incoming/*` excludes
# everything inside instead, so `!/incoming/.gitkeep` right below actually
# applies: that one anchor file is trackable and ships with every clone.
# Nothing else dropped here is rescued by the same rule.
/incoming/*
!/incoming/.gitkeep
# MCP `submit` tool quarantine (see raw/CONTRACT.md "Getting a file in from # MCP `submit` tool quarantine (see raw/CONTRACT.md "Getting a file in from
# outside" and tools/chemenu/upload.py). Material pushed by a caller that is # outside" and tools/chemenu/upload.py). Material pushed by a caller that is
# not this terminal, before a human has reviewed any of it - stronger than # not this terminal, before a human has reviewed any of it - stronger than
# `incoming/` above: not merely uncommitted, but read by no command in the # `incoming/` above: not merely uncommitted, but read by no command in the
# ordinary pipeline. No `.gitkeep`: the directory is created on demand by # ordinary pipeline. Unlike `incoming/` above (Gitea #88), this one keeps the
# the one function that is allowed to write into it, and a checkout that # directory form and gets no `.gitkeep`: the directory is created on demand
# never arms the `submit` tool never gets one. Never anchored back open by # by the one function that is allowed to write into it, and a checkout that
# the content backstop below, same as `incoming/`. # never arms the `submit` tool never gets one - there is no fresh-clone case
# to cover here, since nothing reads this path before that function creates
# it. Never anchored back open by the content backstop below, same as
# `incoming/`.
/mcp-upload/ /mcp-upload/
# Content backstop - keep this block last. Nothing under raw/, kb/ or work/ may # Content backstop - keep this block last. Nothing under raw/, kb/ or work/ may
+37 -1
View File
@@ -35,7 +35,7 @@ dev-checkout concern - readable here, never shipped as something to parse.
--- ---
## 5.0.0-beta.14 - 2026-09-11 - tools/CONTRACT.md als Nachschlage-Dokument strukturiert: ###-Gruppen in beiden Tabellen, spiegelnde Reihenfolge, Lead-in-Regel ## 5.0.0-beta.15 - 2026-09-11 - incoming/.gitkeep als Datei- statt Verzeichnismuster trackbar (schliesst #88)
**Author:** Torben Nehmer **Author:** Torben Nehmer
@@ -67,6 +67,7 @@ dev-checkout concern - readable here, never shipped as something to parse.
- AGENTS.md-Changelog-Absatz korrigiert: Contract-Prosa ist Sitzungsarbeit, doc-pull-through-Instruction ergaenzt - AGENTS.md-Changelog-Absatz korrigiert: Contract-Prosa ist Sitzungsarbeit, doc-pull-through-Instruction ergaenzt
- docs verify prueft die Kommando- und Fehlerkontrakttabelle in tools/CONTRACT.md getrennt, 10 fehlende Fehlerkontrakt-Zeilen nachgetragen (schliesst #91) - docs verify prueft die Kommando- und Fehlerkontrakttabelle in tools/CONTRACT.md getrennt, 10 fehlende Fehlerkontrakt-Zeilen nachgetragen (schliesst #91)
- tools/CONTRACT.md als Nachschlage-Dokument strukturiert: ###-Gruppen in beiden Tabellen, spiegelnde Reihenfolge, Lead-in-Regel - tools/CONTRACT.md als Nachschlage-Dokument strukturiert: ###-Gruppen in beiden Tabellen, spiegelnde Reihenfolge, Lead-in-Regel
- incoming/.gitkeep als Datei- statt Verzeichnismuster trackbar (schliesst #88)
<!-- /wikitool:bumps --> <!-- /wikitool:bumps -->
@@ -1308,6 +1309,41 @@ Verifiziert: `tools/wikitool docs verify`, `tools/wikitool instructions verify`,
`pytest`-Suite (1195 passed). Typischer Zugriff: Median 229 statt 17.500 Tokens. `pytest`-Suite (1195 passed). Typischer Zugriff: Median 229 statt 17.500 Tokens.
Schließt #92. Schließt #92.
**`incoming/.gitkeep` ist jetzt trackbar - Datei- statt Verzeichnismuster in `.gitignore` (#88).**
`/incoming/` schloss bisher das Verzeichnis selbst aus, und Regel 2 im `.gitignore`-Kopf sagt
genau, warum das eine Falle ist: git kann keine Datei wieder einschließen, deren Elternverzeichnis
ausgeschlossen ist, also blieb ein `!incoming/.gitkeep` wirkungslos. Ein frischer Klon hatte den
Eingang deshalb nie - `instructions/bootstrap.md` Schritt 2 (`mkdir -p incoming`) fing das für
einen Menschen ab, der die Instruction liest, aber nicht für einen Checkout, den eine Maschine
anlegt: der Korpus-Checkout des MCP-Read-Servers entsteht aus Klon plus `fetch && reset --hard`
und läuft durch keinen Bootstrap, also fehlte der Eingang dort still, bis das erste Kommando ihn
brauchte.
Umgestellt auf `/incoming/*` plus `!/incoming/.gitkeep` - jetzt ignoriert das Muster den Inhalt,
nicht das Verzeichnis, und die Negation greift tatsächlich. Gegengeprüft in beide Richtungen:
`git check-ignore --no-index incoming/.gitkeep` meldet die Datei als nicht ignoriert,
`incoming/probe.pdf` weiterhin als ignoriert - die Kanarie aus
`docs_verify.REQUIRED_IGNORE_CANARIES` hält also unverändert. `incoming/.gitkeep` steht jetzt
zusätzlich in `REQUIRED_TRACKED_PATHS`, damit eine künftige Rückkehr zur Verzeichnisform
`docs verify` laut fehlschlagen lässt statt still zu wirken. Ein voller `dist export` +
`git init` + `git add -A`-Replay bestätigt, dass `incoming/.gitkeep` im allerersten Commit einer
frischen Instanz landet, während `incoming/probe.pdf` dort weiterhin ignoriert bleibt.
`instructions/bootstrap.md` Schritt 2 entfällt ersatzlos - ein frischer Klon braucht ihn nicht
mehr -, die übrigen Schritte rücken nach. `mcp-upload/` bleibt bewusst bei der Verzeichnisform
ohne `.gitkeep`: die Schreibprimitive des `submit`-Tools legt das Verzeichnis selbst an, sobald
sie gebraucht wird, und ein Checkout, der das Tool nie aktiviert, braucht das Verzeichnis auch
nie - anders als bei `incoming/` gibt es dort keinen Frisch-Klon-Fall abzudecken. Der
`.gitignore`-Kommentar zu `mcp-upload/` benennt diesen Kontrast jetzt ausdrücklich, statt sich
nur noch mit dem alten (identischen) Verhalten von `incoming/` zu vergleichen.
Geändert: `.gitignore` (beide Kommentarblöcke, neues Muster), `incoming/.gitkeep` (neu),
`tools/chemenu/commands/docs_verify.py` (`REQUIRED_TRACKED_PATHS`), `instructions/bootstrap.md`
(Schritt 2 entfernt, Rest umnummeriert), `raw/CONTRACT.md`, `tools/CONTRACT.md` (`dist export`-
Zeile), `README.md` (Architekturdiagramm-Kommentar). Verifiziert: `tools/wikitool docs verify`,
`tools/wikitool instructions verify`, volle `pytest`-Suite (1195 passed), manueller
`dist export`-Replay. Schließt #88.
--- ---
## 4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet ## 4.7.4 - 2026-09-04 - bootstrap.md nennt den session-id-WARN nach frischem Bootstrap explizit als erwartet
+1 -1
View File
@@ -79,7 +79,7 @@ chemenu/
├── mcp-upload/ # QUARANTINE (optional): the MCP `submit` tool's write path, gitignored - ├── mcp-upload/ # QUARANTINE (optional): the MCP `submit` tool's write path, gitignored -
│ # read by no command in the ordinary pipeline; a human reviews it with │ # read by no command in the ordinary pipeline; a human reviews it with
│ # `wikitool upload list/show/accept/reject` │ # `wikitool upload list/show/accept/reject`
├── incoming/ # INBOX: gitignored and flat - drop a file here, `raw accept` promotes it ├── incoming/ # INBOX: flat, content gitignored - drop a file here, `raw accept` promotes it
├── raw/ # INPUT: immutable, untrusted source material ├── raw/ # INPUT: immutable, untrusted source material
│ ├── CONTRACT.md # Date shard, capture fields, immutability, untrusted content │ ├── CONTRACT.md # Date shard, capture fields, immutability, untrusted content
│ ├── 2026/09/ # Where `raw accept` puts a file: the month it was accepted │ ├── 2026/09/ # Where `raw accept` puts a file: the month it was accepted
+1 -1
View File
@@ -1 +1 @@
5.0.0-beta.14 5.0.0-beta.15
View File
+7 -18
View File
@@ -28,24 +28,13 @@ they are published: the agent harness will not offer `wiki-ingest`, `wiki-query`
cd .. cd ..
``` ```
2. **Create the ingest inbox.** `incoming/` (raw/CONTRACT.md "Getting a file in") is gitignored, 2. **Publish the skills:**
so a fresh clone does not have it at all - unlike `raw/` itself, which is committed and
present immediately. It is flat - there is no type subdirectory to create:
```bash
mkdir -p incoming
```
`tools/wikitool doctor` only reports a missing one; it never creates it, so this is a one-off
catch-up here the same way step 5 below is for personalization.
3. **Publish the skills:**
```bash ```bash
tools/wikitool instructions sync tools/wikitool instructions sync
``` ```
4. **Verify:** 3. **Verify:**
```bash ```bash
tools/wikitool instructions verify tools/wikitool instructions verify
@@ -54,14 +43,14 @@ they are published: the agent harness will not offer `wiki-ingest`, `wiki-query`
Expected: `OK`. If it reports drift, re-run `sync` - the source under `instructions/` always Expected: `OK`. If it reports drift, re-run `sync` - the source under `instructions/` always
wins, and a copy is never edited directly. wins, and a copy is never edited directly.
5. **Check for personalization.** A clone predating the personalization files has no 4. **Check for personalization.** A clone predating the personalization files has no
`USER.md`/`SOUL.md`, and `tools/wikitool doctor` reports `personalization: FAIL` for it. `USER.md`/`SOUL.md`, and `tools/wikitool doctor` reports `personalization: FAIL` for it.
That is a one-off catch-up, not a bootstrap step that repeats: run **only** the That is a one-off catch-up, not a bootstrap step that repeats: run **only** the
Personalization step (6) of [setup-instance.md](setup-instance.md), not the whole Personalization step (6) of [setup-instance.md](setup-instance.md), not the whole
procedure - this clone already has its git repo, author identity and content. A clone that procedure - this clone already has its git repo, author identity and content. A clone that
already carries both files needs nothing here. already carries both files needs nothing here.
6. **Offer to record the environment.** `ENVIRONMENT.md` is gitignored, so a fresh clone never 5. **Offer to record the environment.** `ENVIRONMENT.md` is gitignored, so a fresh clone never
has one, and every session in it re-asks which harness is in use, which MCP servers are has one, and every session in it re-asks which harness is in use, which MCP servers are
reachable, and which remote `publish` talks to. Copy `ENVIRONMENT.md.template` to reachable, and which remote `publish` talks to. Copy `ENVIRONMENT.md.template` to
`ENVIRONMENT.md`, fill in what is already known from this clone (`git remote -v`, the `ENVIRONMENT.md`, fill in what is already known from this clone (`git remote -v`, the
@@ -73,15 +62,15 @@ they are published: the agent harness will not offer `wiki-ingest`, `wiki-query`
session pays for it again. Never guess an entry: a wrong remote or an MCP server that is not session pays for it again. Never guess an entry: a wrong remote or an MCP server that is not
there is worse than the empty section it replaced, because it gets believed. there is worse than the empty section it replaced, because it gets believed.
7. **Restart the agent session** if it was already running. Harnesses read the skill 6. **Restart the agent session** if it was already running. Harnesses read the skill
directories at startup, so skills published mid-session are not picked up. directories at startup, so skills published mid-session are not picked up.
8. **Expect a lingering `session-id` WARN.** A `tools/wikitool doctor` run at this point reports 7. **Expect a lingering `session-id` WARN.** A `tools/wikitool doctor` run at this point reports
`OK` throughout except `session-id: WARN` - that check is scoped to the working session, not `OK` throughout except `session-id: WARN` - that check is scoped to the working session, not
the clone, so a freshly bootstrapped checkout with no `WIKITOOL_SESSION_ID` exported yet the clone, so a freshly bootstrapped checkout with no `WIKITOOL_SESSION_ID` exported yet
always shows it. This is expected, not a Bootstrap gap: exporting it here would only be true always shows it. This is expected, not a Bootstrap gap: exporting it here would only be true
for this one-off setup run, not for whichever session picks up the actual work next, in a new for this one-off setup run, not for whichever session picks up the actual work next, in a new
shell after step 7's restart. Run [session-setup.md](session-setup.md) at the start of that shell after step 6's restart. Run [session-setup.md](session-setup.md) at the start of that
session instead. session instead.
## Scope ## Scope
+3 -2
View File
@@ -63,8 +63,9 @@ walks `raw/` recursively and works unchanged either way.
## Getting a file in: `incoming/` ## Getting a file in: `incoming/`
`raw/` is never chosen by hand. A file to be ingested is dropped into the gitignored top-level `raw/` is never chosen by hand. A file to be ingested is dropped into the top-level `incoming/`
`incoming/` - flat: no subdirectory carries any classification any more. A - gitignored content, so a fresh clone finds the directory itself already there but never
anything dropped into it - flat: no subdirectory carries any classification any more. A
subdirectory is still tolerated if one is used out of habit or by an older script (so an upgrade subdirectory is still tolerated if one is used out of habit or by an older script (so an upgrade
never has to touch a caller), but it is **ignored**, never inspected: never has to touch a caller), but it is **ignored**, never inspected:
+1 -1
View File
@@ -184,7 +184,7 @@ tools/wikitool <command> --help
| Command | Purpose | | Command | Purpose |
|---------|---------| |---------|---------|
| `dist export <target> [--dry-run] [--source-repo U] [--source-commit SHA] [--release-url U] [--update-url U]` | Write a contentless, distributable copy of this repo's machinery into an empty `<target>` directory: `AGENTS.md`/`README.md`/`EVALS.md` with any `<!-- dist:strip-start -->...<!-- dist:strip-end -->` region removed, `instructions/` (minus `instructions/dev/`), `types/` (the `root: kb` page type-specs and their schemas re-keyed as `.template`, the stack's own verbatim), `docs/` verbatim, `tools/` (no venv/caches), the `.github/hooks/`+`.vibe/` session-tracing config plus `.claude/settings.json`, `kb/CONTRACT.md` (no pages, no areas), empty `raw/{articles,documents,notes,assets}/` and the matching `incoming/{articles,documents,notes,assets}/` (gitignored again the moment the export becomes a git repository, so `instructions/bootstrap.md` re-creates it for a plain clone that never ran this step), `VERSION`, `USER.md.template`/`SOUL.md.template` plus `kb/CONVENTIONS.md.template` and each collection's contract re-keyed as `kb/<name>/COLLECTION.md.template` (the templates ship; the filled `USER.md`/`SOUL.md`/`kb/CONVENTIONS.md`/`kb/<name>/COLLECTION.md`/`types/<page-type>.md` never do - all of them bind their instance and none are the stack's to decide, and `find_leaks` refuses a plan carrying one), and a generated `.wikitool-release.json` stamp (version, export date, origin, and a sha256 per exported file - the base a later upgrade would compare against). The four origin options only fill stamp fields: `export` never calls git and cannot discover them. Refuses a non-empty target, and a tree with no `VERSION`. See `instructions/setup-instance.md`. One-way: there is no command that reconstructs a distributed instance into a dev instance - work on the stack in the origin repo (or a new dev instance exported from it) instead | | `dist export <target> [--dry-run] [--source-repo U] [--source-commit SHA] [--release-url U] [--update-url U]` | Write a contentless, distributable copy of this repo's machinery into an empty `<target>` directory: `AGENTS.md`/`README.md`/`EVALS.md` with any `<!-- dist:strip-start -->...<!-- dist:strip-end -->` region removed, `instructions/` (minus `instructions/dev/`), `types/` (the `root: kb` page type-specs and their schemas re-keyed as `.template`, the stack's own verbatim), `docs/` verbatim, `tools/` (no venv/caches), the `.github/hooks/`+`.vibe/` session-tracing config plus `.claude/settings.json`, `kb/CONTRACT.md` (no pages, no areas), empty `raw/{articles,documents,notes,assets}/` and the matching `incoming/{articles,documents,notes,assets}/` (`incoming/.gitkeep` is trackable and survives becoming a git repository, so a plain clone gets the directory without any bootstrap step re-creating it), `VERSION`, `USER.md.template`/`SOUL.md.template` plus `kb/CONVENTIONS.md.template` and each collection's contract re-keyed as `kb/<name>/COLLECTION.md.template` (the templates ship; the filled `USER.md`/`SOUL.md`/`kb/CONVENTIONS.md`/`kb/<name>/COLLECTION.md`/`types/<page-type>.md` never do - all of them bind their instance and none are the stack's to decide, and `find_leaks` refuses a plan carrying one), and a generated `.wikitool-release.json` stamp (version, export date, origin, and a sha256 per exported file - the base a later upgrade would compare against). The four origin options only fill stamp fields: `export` never calls git and cannot discover them. Refuses a non-empty target, and a tree with no `VERSION`. See `instructions/setup-instance.md`. One-way: there is no command that reconstructs a distributed instance into a dev instance - work on the stack in the origin repo (or a new dev instance exported from it) instead |
| `dist upgrade <source> [--dry-run] [--keep-local] [--prune] [--pre]` | Apply a stack update `dist export` produced - the write half of `version check`. Never downloads anything: `<source>` is an already-fetched export directory or `.tar.gz` release archive (verified against a sibling `.sha256` if one is present; WARNs, does not block, if it is absent), which must unpack to exactly one top-level directory - the shape `.gitea/workflows/release.yml` packs. The write set is exactly the *new* `.wikitool-release.json`'s `files` block, minus what an export re-seeds from a blank template every time (`kb/log.md`, `raw/*/.gitkeep` - `chemenu.ownership.is_export_stub`) or seeds once and the instance owns from then on (`.wikitool-kb.json`, `CHANGES.md` - `chemenu.ownership.is_upgrade_preserved`), plus the stamp itself, always rewritten. Every candidate path is classified against the *local* `.wikitool-release.json`'s recorded digest for it: unchanged is overwritten silently, absent from the old stamp is created, and locally modified or locally deleted is **never** silently overwritten - the run aborts with the full list unless `--keep-local` says to proceed and leave every one of them untouched. After a `--keep-local` run the new stamp is still written whole, so it records the release's digest for files that were deliberately *not* written: the stamp is the baseline for the next comparison, not a literal inventory of what is on disk. That is what keeps a skipped file diverging - and therefore reported - on every later run, rather than quietly reading as current once it has been skipped once. A path in the old stamp but not the new one is reported as no longer part of the release and left alone unless `--prune` is passed, which removes it only if it is still unchanged since installation. Reports the migration chain the new machinery would owe (`chemenu.kb_state.chain` over the *new* tree's `instructions/migrations/`, read via a `directory` argument to `load_migrations`) but never runs any of it - there is no `migrate run`. Refuses before touching the source at all when: `VERSION` or `.wikitool-release.json` (with a `files` block) is missing locally, `.wikitool-kb.json` is missing, a migration is already outstanding against the *installed* machinery, or the working tree is dirty (not being a git repository at all is a WARN, not a refusal). Refuses after reading the source when: it carries no `VERSION`/`.wikitool-release.json`/`files` block, its version is older than or equal to the installed one (equal is a no-op success), or it is a pre-release (`-beta.N`) without `--pre`. Reports, but does not block on, a crossed compatibility boundary. Never touches git - no commit, no push (invariant 5). See `INSTALL.md` § "Eine Instanz aktualisieren" | | `dist upgrade <source> [--dry-run] [--keep-local] [--prune] [--pre]` | Apply a stack update `dist export` produced - the write half of `version check`. Never downloads anything: `<source>` is an already-fetched export directory or `.tar.gz` release archive (verified against a sibling `.sha256` if one is present; WARNs, does not block, if it is absent), which must unpack to exactly one top-level directory - the shape `.gitea/workflows/release.yml` packs. The write set is exactly the *new* `.wikitool-release.json`'s `files` block, minus what an export re-seeds from a blank template every time (`kb/log.md`, `raw/*/.gitkeep` - `chemenu.ownership.is_export_stub`) or seeds once and the instance owns from then on (`.wikitool-kb.json`, `CHANGES.md` - `chemenu.ownership.is_upgrade_preserved`), plus the stamp itself, always rewritten. Every candidate path is classified against the *local* `.wikitool-release.json`'s recorded digest for it: unchanged is overwritten silently, absent from the old stamp is created, and locally modified or locally deleted is **never** silently overwritten - the run aborts with the full list unless `--keep-local` says to proceed and leave every one of them untouched. After a `--keep-local` run the new stamp is still written whole, so it records the release's digest for files that were deliberately *not* written: the stamp is the baseline for the next comparison, not a literal inventory of what is on disk. That is what keeps a skipped file diverging - and therefore reported - on every later run, rather than quietly reading as current once it has been skipped once. A path in the old stamp but not the new one is reported as no longer part of the release and left alone unless `--prune` is passed, which removes it only if it is still unchanged since installation. Reports the migration chain the new machinery would owe (`chemenu.kb_state.chain` over the *new* tree's `instructions/migrations/`, read via a `directory` argument to `load_migrations`) but never runs any of it - there is no `migrate run`. Refuses before touching the source at all when: `VERSION` or `.wikitool-release.json` (with a `files` block) is missing locally, `.wikitool-kb.json` is missing, a migration is already outstanding against the *installed* machinery, or the working tree is dirty (not being a git repository at all is a WARN, not a refusal). Refuses after reading the source when: it carries no `VERSION`/`.wikitool-release.json`/`files` block, its version is older than or equal to the installed one (equal is a no-op success), or it is a pre-release (`-beta.N`) without `--pre`. Reports, but does not block on, a crossed compatibility boundary. Never touches git - no commit, no push (invariant 5). See `INSTALL.md` § "Eine Instanz aktualisieren" |
| `version show [--json]` | Print this instance's stack version and where it came from (development tree, or a distribution with its export date and origin). Bare `wikitool version` is an alias for this. Read-only, offline, and **exempt from the Iteration Budget Gate** | | `version show [--json]` | Print this instance's stack version and where it came from (development tree, or a distribution with its export date and origin). Bare `wikitool version` is an alias for this. Read-only, offline, and **exempt from the Iteration Budget Gate** |
| `version check [--url U] [--timeout S] [--json]` | Ask the origin's release feed whether a newer stack exists, and whether the step crosses a compatibility boundary (`state: current\|update\|migration\|ahead`). **The only command in `wikitool` that makes a network call** - never reached implicitly from another command, needs no key, times out, and reports an unreachable feed as an error rather than as "up to date". The feed is `$WIKITOOL_UPDATE_URL`, else the release stamp's, else the built-in origin; `$WIKITOOL_UPDATE_TOKEN` is only needed if that feed is not readable anonymously. Read-only and exempt from the budget gate | | `version check [--url U] [--timeout S] [--json]` | Ask the origin's release feed whether a newer stack exists, and whether the step crosses a compatibility boundary (`state: current\|update\|migration\|ahead`). **The only command in `wikitool` that makes a network call** - never reached implicitly from another command, needs no key, times out, and reports an unreachable feed as an error rather than as "up to date". The feed is `$WIKITOOL_UPDATE_URL`, else the release stamp's, else the built-in origin; `$WIKITOOL_UPDATE_TOKEN` is only needed if that feed is not readable anonymously. Read-only and exempt from the budget gate |
+8
View File
@@ -143,6 +143,14 @@ REQUIRED_TRACKED_PATHS = (
# has nothing to fill in - and `find_leaks` refuses to substitute the filled # has nothing to fill in - and `find_leaks` refuses to substitute the filled
# file, correctly, so the export would simply be missing it. # file, correctly, so the export would simply be missing it.
"kb/CONVENTIONS.md.template", "kb/CONVENTIONS.md.template",
# The ingest inbox's one anchor file (Gitea #88). `/incoming/*` ignores
# everything else dropped there, same as the old `/incoming/` did - but
# unlike that form, a directory pattern, this one lets a negation actually
# re-include a single file, so a fresh clone gets the directory without
# `instructions/bootstrap.md` recreating it by hand. A future return to
# the directory form would silently drop this file again; this canary is
# what makes that regression fail loudly instead.
"incoming/.gitkeep",
) )
CLI_README = config.ROOT / "tools" / "CONTRACT.md" CLI_README = config.ROOT / "tools" / "CONTRACT.md"