feat: INSTALL.md is the English installation tutorial; new tutorial docs/tutorials/first-source-to-first-answer.md with a shipped sample source; README.md links it as its first-ingestion step (#191)
CI / verify (push) Successful in 6m14s
CI / pwsh (push) Successful in 2m2s
Release / release (push) Successful in 34s

Files changed:
- CHANGES.md
- INSTALL.md
- README.md
- VERSION
- docs/reference/commands/types-instructions-and-docs.md
- docs/tutorials/README.md
- docs/tutorials/first-source-to-first-answer.md
- docs/tutorials/sample-source.md
- instructions/dev/doc-pull-through.md
- tools/CONTRACT.md
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/install_doc.py
- tools/chemenu/tests/test_install_doc.py

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
torbenandClaude Opus 5.5 committed 2026-10-07 06:38:40 +02:00
1 parent f9056c04f7
commit fe1de63e0f
13 files changed
+403 -190

No files matched your search

+1 -1
View File
@@ -2651,7 +2651,7 @@ Regenerate `INSTALL.md`'s prerequisites lists from `tools/prerequisites.txt`.
**NOTES**
- Rewrites each `<!-- wikitool:prerequisites -->` region in `INSTALL.md` (tools every platform needs) and `<!-- wikitool:prerequisites-<platform> -->` region (tools only that platform needs) from the manifest: one list item per tool, its label and minimum version. The manifest's reason field stays out - it is English prose, and the region sits in a document that need not be.
- Rewrites each `<!-- wikitool:prerequisites -->` region in `INSTALL.md` (tools every platform needs) and `<!-- wikitool:prerequisites-<platform> -->` region (tools only that platform needs) from the manifest: one list item per tool, its label and minimum version. The manifest's reason field stays out - it explains a tool to whoever reads the preflight's own output, while the region only says what to install.
- Never places a region: where a list belongs in the human guide is that guide's own decision. A region the manifest calls for but the file lacks is an error naming the marker pair to add.
- Dry-run by default (says whether the file would change); `--apply` writes.
- `docs verify` checks the result stays current.
+2 -2
View File
@@ -1555,8 +1555,8 @@ def toc_command(
"Rewrites each `<!-- wikitool:prerequisites -->` region in `INSTALL.md` (tools every "
"platform needs) and `<!-- wikitool:prerequisites-<platform> -->` region (tools only that "
"platform needs) from the manifest: one list item per tool, its label and minimum "
"version. The manifest's reason field stays out - it is English prose, and the region "
"sits in a document that need not be.",
"version. The manifest's reason field stays out - it explains a tool to whoever reads "
"the preflight's own output, while the region only says what to install.",
"Never places a region: where a list belongs in the human guide is that guide's own "
"decision. A region the manifest calls for but the file lacks is an error naming the "
"marker pair to add.",
+26 -19
View File
@@ -1,28 +1,31 @@
"""The two places `INSTALL.md` overlaps the installation instructions, held to them.
`INSTALL.md` is written for a human and in the instance's KB language;
`instructions/setup-instance.md` is written for an agent and in English. A
single file serving both was rejected: an agent reads every sentence as an
instruction, and the human needs preparation and decisions where the agent
needs steps and exit codes. So the human document does not retell the
procedure, and what it still shares with the instructions is two enumerable
lists - both checked here, so neither can drift silently:
`INSTALL.md` is written for a human, `instructions/setup-instance.md` for an
agent; both in English (`AGENTS.md` § File naming). A single file serving
both was rejected: an agent reads every sentence as an instruction, and the
human needs preparation and decisions where the agent needs steps and exit
codes. So the human document does not retell the procedure, and what it still
shares with the instructions is two enumerable lists - both checked here, so
neither can drift silently:
1. **What the machine needs.** `tools/prerequisites.txt` is the one list; the
preflight and `doctor` read it. `INSTALL.md` carries it as a generated
region per platform value (`<!-- wikitool:prerequisites -->` for `all`,
`<!-- wikitool:prerequisites-<platform> -->` otherwise), rendered from the
label and minimum version only. The manifest's `why` field stays out: it is
English prose, and the region sits in a document that is not. A region is
never placed by the tool - where it goes is the human document's own
decision - so a missing one is reported, not appended.
label and minimum version only. The manifest's `why` field stays out: it
explains a tool to whoever reads the preflight's own output, while the
region only says what to install. A region is never placed by the tool -
where it goes is the human document's own decision - so a missing one is
reported, not appended.
2. **What the agent asks the user.** Every place `setup-instance.md` puts a
question to the user carries `<!-- setup-question: <key> -->`, and the
bullet in `INSTALL.md` that tells the human about it carries the same
marker. The two key sets must be equal: a question the human guide does not
mention catches them unprepared, and one it mentions that is no longer asked
is a claim about a procedure that no longer exists. The key is the shared
identifier precisely because the surrounding prose is in two languages.
bullet in `INSTALL.md` § "What the agent asks you" that tells the human
about it carries the same marker. The two key sets must be equal: a
question the human guide does not mention catches them unprepared, and one
it mentions that is no longer asked is a claim about a procedure that no
longer exists. The key is the shared identifier because the two texts word
the same question for different readers, and neither wording is stable
enough to match on.
Everything else in `INSTALL.md` is prose no check reads;
`instructions/dev/doc-pull-through.md` names it as session work.
@@ -37,6 +40,10 @@ from chemenu import blocks, config, prerequisites
INSTALL_DOC = "INSTALL.md"
SETUP_INSTRUCTION = "instructions/setup-instance.md"
# The heading in INSTALL.md whose bullets carry the setup-question markers -
# named in check_setup_questions' finding, and held to the real file by a test.
QUESTIONS_SECTION = "What the agent asks you"
REGION_PREFIX = "prerequisites"
QUESTION_RE = re.compile(r"<!-- setup-question: ([a-z][a-z0-9-]*) -->")
@@ -101,7 +108,7 @@ def refresh(text: str, manifest: prerequisites.Manifest) -> tuple[str, list[str]
A region the manifest no longer has a platform for is left alone and
reported by `check_prerequisite_regions`, not deleted here: the prose
introducing it ("Unter Windows zusätzlich:") would otherwise be left
introducing it ("On Windows, additionally ...") would otherwise be left
standing over nothing.
"""
missing = []
@@ -166,8 +173,8 @@ def check_setup_questions() -> list[str]:
named = question_keys(install.read_text(encoding="utf-8"))
issues = [
f"{SETUP_INSTRUCTION} asks the user `{key}`, but {INSTALL_DOC} § \"Was der Agent dich "
f"fragt\" does not name it - add a bullet carrying `<!-- setup-question: {key} -->`"
f"{SETUP_INSTRUCTION} asks the user `{key}`, but {INSTALL_DOC} § \"{QUESTIONS_SECTION}\" "
f"does not name it - add a bullet carrying `<!-- setup-question: {key} -->`"
for key in sorted(asked - named)
]
issues += [
+14 -5
View File
@@ -16,22 +16,22 @@ MANIFEST = prerequisites.Manifest(
CURRENT = """# Installation
Vorher:
You need:
<!-- wikitool:prerequisites -->
- **Python** ≥ 3.11
- **Git**
<!-- /wikitool:prerequisites -->
Unter Windows zusätzlich:
On Windows, additionally:
<!-- wikitool:prerequisites-windows -->
- **PowerShell 7 (pwsh)** ≥ 7
<!-- /wikitool:prerequisites-windows -->
## Was der Agent dich fragt
## What the agent asks you
- <!-- setup-question: identity --> **Autor-Identität** - Name und E-Mail.
- <!-- setup-question: identity --> **Author identity** - name and email.
"""
SETUP = """# Set up
@@ -57,6 +57,14 @@ def test_this_repos_install_doc_names_every_setup_question():
assert install_doc.check_setup_questions() == []
def test_this_repos_install_doc_has_the_section_the_finding_names():
"""A missing question is reported as missing from a named section; that
name is a constant, and a renamed heading would leave the finding pointing
at nothing."""
text = install_doc.install_doc_path().read_text(encoding="utf-8")
assert f"\n## {install_doc.QUESTIONS_SECTION}\n" in text
def test_this_repos_setup_instruction_marks_its_questions():
"""The check compares two sets; an instruction that lost every marker would
compare empty against empty and pass. Guard the real file's own count."""
@@ -133,10 +141,11 @@ def test_a_question_the_install_doc_does_not_name_fails(tmp_path, monkeypatch):
issues = install_doc.check_setup_questions()
assert len(issues) == 1
assert "`remote`" in issues[0] and "does not name it" in issues[0]
assert f'§ "{install_doc.QUESTIONS_SECTION}"' in issues[0]
def test_a_question_no_longer_asked_fails(tmp_path, monkeypatch):
install = CURRENT + "- <!-- setup-question: telemetry --> **Telemetrie**\n"
install = CURRENT + "- <!-- setup-question: telemetry --> **Telemetry**\n"
_tree(tmp_path, monkeypatch, install=install)
issues = install_doc.check_setup_questions()
assert len(issues) == 1