feat: docs/ carries the operator's how-to guides, a configuration reference and the architecture and telemetry explanations carved out of README.md, INSTALL.md, INSTALL-MCP.md and EVALS.md; the last two retired (#190)
CI / verify (push) Successful in 6m17s
CI / pwsh (push) Successful in 1m59s
Release / release (push) Successful in 35s

Files changed:
- .gitea/workflows/ci.yml
- .gitignore
- .vibe/hooks.toml
- AGENTS.md
- CHANGES.md
- EVALS.md
- INSTALL-MCP.md
- INSTALL.md
- README.md
- VERSION
- docs/dev/development.md
- docs/explanation/README.md
- docs/explanation/architecture.md
- docs/explanation/language-boundaries.md
- docs/explanation/telemetry-and-evaluation.md
- docs/how-to/README.md
- docs/how-to/browse-with-obsidian.md
- docs/how-to/capture-repository-docs.md
- docs/how-to/export-guidelines.md
- docs/how-to/ingest-a-source.md
- docs/how-to/maintain-the-wiki.md
- docs/how-to/query-the-wiki.md
- docs/how-to/run-the-weekly-review.md
- docs/how-to/set-up-the-mcp-server.md
- docs/how-to/trace-and-score-sessions.md
- docs/how-to/troubleshoot.md
- docs/how-to/update-an-instance.md
- docs/reference/README.md
- docs/reference/commands/distribution-and-versioning.md
- docs/reference/commands/instance-health.md
- docs/reference/commands/raw-material-and-uploads.md
- docs/reference/commands/telemetry.md
- docs/reference/commands/types-instructions-and-docs.md
- docs/reference/configuration.md
- instructions/dev/dev-setup.md
- instructions/dev/doc-pull-through.md
- instructions/dev/stack-build/SKILL.md
- instructions/dev/testing-conventions.md
- instructions/dev/version-parts.md
- instructions/setup-instance.md
- instructions/upgrade-instance.md
- reports/CONTRACT.md
- tools/.coveragerc
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/commands/dist_cmd.py
- tools/chemenu/commands/docs_verify.py
- tools/chemenu/commands/doctor.py
- tools/chemenu/commands/eval_cmd.py
- tools/chemenu/commands/git_publish.py
- tools/chemenu/commands/upload_cmd.py
- tools/chemenu/commands/version_cmd.py
- tools/chemenu/evals/__init__.py
- tools/chemenu/evals/scorecard.py
- tools/chemenu/evals/trajectory.py
- tools/chemenu/telemetry/policy.py
- tools/chemenu/tests/test_dist_cmd.py
- tools/chemenu/tests/test_git_publish.py
- tools/chemenu/tests/test_instructions_shell.py
- tools/chemenu/tests/test_pipeline_l0.py
- tools/chemenu/toc.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 05:13:56 +02:00
1 parent cff7df4ffa
commit f9056c04f7
61 files changed
+2169 -1772

No files matched your search

+12 -14
View File
@@ -88,17 +88,14 @@ DIST_TEMPLATES_DIR = Path(__file__).resolve().parent.parent / "dist_templates"
# `.claude/settings.json` does - a distributed instance running that harness
# would otherwise start every session without the control plane.
#
# `INSTALL-MCP.md` ships beside `INSTALL.md` and for the same reason: the MCP
# read server is part of what an instance *has*, even though its dependency is
# optional. A distribution whose server is present but undocumented is one
# whose operator finds the module by reading the source.
#
# The developer documentation (the release workflow, the development
# environment) is not a root file at all: it lives under `docs/dev/`, which
# `build_plan` excludes the way it excludes `instructions/dev/` - see
# DOCS_DEV_ONLY.
# The rest of the human documentation is not a root file at all: it lives under
# `docs/`, which ships whole - the operator's how-to guides (the MCP read
# server's setup among them), the reference and the explanation pages. The one
# exception is the developer documentation (the release workflow, the
# development environment) under `docs/dev/`, which `build_plan` excludes the
# way it excludes `instructions/dev/` - see DOCS_DEV_ONLY.
ROOT_FILES = (
"AGENTS.md", "CLAUDE.md", "README.md", "EVALS.md", "INSTALL.md", "INSTALL-MCP.md",
"AGENTS.md", "CLAUDE.md", "README.md", "INSTALL.md",
".gitignore", ".gitattributes", "VERSION",
*config.LICENSE_FILES,
*config.PERSONALIZATION_TEMPLATES,
@@ -114,7 +111,8 @@ ROOT_FILES = (
REQUIRED_ROOT_FILES = config.LICENSE_FILES
# Harness-specific session-tracing config: generic machinery (feeds
# tools/chemenu/telemetry/ and tools/trace_ingest.py via EVALS.md), not
# tools/chemenu/telemetry/ and tools/trace_ingest.py, see
# docs/explanation/telemetry-and-evaluation.md), not
# personal state - unlike `.obsidian/`/`.vscode/`, which are never copied.
HOOK_DIRS = (".github/hooks", ".vibe")
@@ -632,7 +630,7 @@ def _write_plan(target: Path, plan: dict[str, PlannedFile]) -> None:
notes=(
"Writes a contentless, distributable copy of this repo's machinery into an empty or "
"new `<target>` directory.",
"Ships `AGENTS.md`/`README.md`/`EVALS.md` with any `dist:strip-start`...`dist:strip-end` "
"Ships `AGENTS.md`/`README.md`/`INSTALL.md` with any `dist:strip-start`...`dist:strip-end` "
"marker region removed, `instructions/` (minus `instructions/dev/`), `types/` (the "
"`root: kb` page type-specs, their schemas and their subtype templates "
"`types/<type>.<value>.md` re-keyed as `.template`, the stack's own verbatim), `docs/` "
@@ -1518,7 +1516,7 @@ def _report_plan(
"`wikitool version check` - finds out whether an update exists",
"`wikitool version notes` - the notes of the release `--expect` should name",
"`instructions/upgrade-instance.md` - the order after the swap",
"`INSTALL.md` § \"Version und Updates\" - which release, whether to take it, where "
"`docs/how-to/update-an-instance.md` - which release, whether to take it, where "
"the tarball comes from",
"`wikitool migrate status` - the migrations the report names",
),
@@ -1580,7 +1578,7 @@ def upgrade_command(
Refuses on a missing local release stamp, a downgrade, a pre-release
source without `--pre`, a dirty working tree, or a `--take-release` path
that is not locally changed. Never touches git.
See Gitea #7 and `INSTALL.md` § "Eine Instanz aktualisieren"."""
See Gitea #7 and `docs/how-to/update-an-instance.md`."""
run_upgrade(
source,
dry_run=dry_run,
+2 -2
View File
@@ -1484,8 +1484,8 @@ def verify():
"`<name>.template` it ships as, where one exists.",
"The scope is computed from those categories rather than listed, so a file added later "
"is in scope without a code change.",
"Out of scope: every `SKILL.md`, the human docs (`README.md`, `CHANGES.md`, "
"`EVALS.md`, `INSTALL.md`, `tools/README.md`), and every subtype template "
"Out of scope: every `SKILL.md`, the human docs at the root and beside the code "
"(`README.md`, `CHANGES.md`, `INSTALL.md`, `tools/README.md`), and every subtype template "
"`types/<type>.<value>.md` - `new` copies it into a page, so it never carries a region "
"whatever its length.",
"Dry-run by default (prints which files would change); `--apply` writes. Idempotent: a "
+2 -2
View File
@@ -805,8 +805,8 @@ def run_doctor() -> list[Check]:
see_also=(
"`instructions/setup-instance.md` - the setup steps most findings point back to",
"`instructions/preflight.md` - what `tool-paths` and `install-dir` point back to",
"`INSTALL.md` § \"Konfiguration\" - the per-checkout configuration files",
"`EVALS.md` - telemetry state and caps",
"`docs/reference/configuration.md` - the per-checkout configuration files",
"`docs/explanation/telemetry-and-evaluation.md` - telemetry state and caps",
"`instructions/session-setup.md` - setting `WIKITOOL_SESSION_ID`",
),
))
+3 -3
View File
@@ -20,7 +20,7 @@ from chemenu.session import session_id as current_session_id
from chemenu.telemetry import reader
from chemenu.telemetry.writer import trace_root
app = typer.Typer(help="Score a traced session (see EVALS.md).")
app = typer.Typer(help="Score a traced session (see docs/explanation/telemetry-and-evaluation.md).")
EVALS_DIR = config.REPORTS_DIR / "evals"
@@ -48,7 +48,7 @@ EVALS_DIR = config.REPORTS_DIR / "evals"
),
see_also=(
"`wikitool eval score` - scores one of them",
"`EVALS.md` - how telemetry and evaluation work",
"`docs/explanation/telemetry-and-evaluation.md` - how telemetry and evaluation work",
),
))
def sessions_command(
@@ -113,7 +113,7 @@ def sessions_command(
),
see_also=(
"`wikitool eval sessions` - which session ids exist",
"`EVALS.md` - the scoring levels",
"`docs/explanation/telemetry-and-evaluation.md` - the scoring levels",
),
))
def score_command(
+1 -1
View File
@@ -480,7 +480,7 @@ FILE_GROUPS: tuple[tuple[str, tuple[str, ...], str], ...] = (
("Tooling", ("tools/",), "the compiler itself"),
("Harness config", (".claude/", ".github/", ".vibe/", ".agents/"),
"hooks and permissions - affects what the harness lets an agent do"),
("Human docs", ("README.md", "INSTALL.md", "EVALS.md", "CHANGES.md"), "prose, no runtime effect"),
("Human docs", ("README.md", "INSTALL.md", "CHANGES.md", "docs/"), "prose, no runtime effect"),
("Workshop", ("work/",), "scratch state, deleted when the run closes"),
)
OTHER_GROUP = ("Other", (), "")
+1 -1
View File
@@ -58,7 +58,7 @@ def _call(fn, *args, **kwargs):
),
see_also=(
"`wikitool upload show` - one submission's manifest",
"`INSTALL-MCP.md` § \"Schritt 7: Optional - den `submit`-Pfad freischalten\"",
"`docs/how-to/set-up-the-mcp-server.md` § \"Optional: the submit path\"",
),
))
def upload_list_command(
+4 -4
View File
@@ -170,7 +170,7 @@ def show_command(
"built-in origin. `$WIKITOOL_UPDATE_TOKEN` is only needed if that feed is not readable "
"anonymously.",
"For `update` or `migration` it prints that applying the release is a separate, manual "
"step (`INSTALL.md` § \"Eine Instanz aktualisieren\").",
"step (`docs/how-to/update-an-instance.md`).",
"Read-only; exempt from the Iteration Budget Gate.",
),
failures=(
@@ -196,7 +196,7 @@ def show_command(
see_also=(
"`wikitool dist upgrade` - applies the update this reports",
"`wikitool version notes` - prints the release notes",
"`INSTALL.md` § \"Version und Updates\" - what the operator decides before an update",
"`docs/how-to/update-an-instance.md` - what the operator decides before an update",
),
))
@app.command("check")
@@ -262,8 +262,8 @@ def check_command(
console.print(f"release: {status.release_url}")
if status.state in ("update", "migration"):
console.print(
"Applying it is a separate, manual step - see INSTALL.md "
"§ 'Eine Instanz aktualisieren'."
"Applying it is a separate, manual step - see "
"docs/how-to/update-an-instance.md."
)
+5 -1
View File
@@ -1,4 +1,8 @@
"""Scoring a traced session. See EVALS.md for the levels and what they mean."""
"""Scoring a traced session.
See docs/explanation/telemetry-and-evaluation.md for the levels and what
they mean.
"""
from chemenu.evals.scorecard import failed, render_markdown, score, structural_score
__all__ = ["failed", "render_markdown", "score", "structural_score"]
+2 -1
View File
@@ -9,7 +9,8 @@ Two levels, deliberately both hard-oracle:
way. This is the half unit tests cannot reach.
There is no judge here and no rubric. Soft-oracle scoring waits until a failure
taxonomy exists - see EVALS.md on the phase gate.
taxonomy exists - see docs/explanation/telemetry-and-evaluation.md on the
phase gate.
"""
from __future__ import annotations
+1 -1
View File
@@ -52,7 +52,7 @@ class Rule:
severity: str = "error"
findings: list[dict] = field(default_factory=list)
# A rule this trace cannot answer - not a pass, and never a fail. The
# degradation rule (EVALS.md): a harness that cannot report the event a
# degradation rule (docs/explanation/telemetry-and-evaluation.md): a harness that cannot report the event a
# rule depends on must read as "cannot say", never as a silent zero that
# looks like a clean pass or a finding that looks like a violation.
skipped: bool = False
+2 -1
View File
@@ -11,7 +11,8 @@ this module, see AGENTS.md invariant 8).
form is read off `config.RELEASE_STAMP_FILENAME`: present means an exported/
distributed tree (default *off* - an operator never asked for telemetry),
absent means the dev checkout this package ships from (default *on* - the
traces are this stack's own measuring instrument, see EVALS.md).
traces are this stack's own measuring instrument, see
docs/explanation/telemetry-and-evaluation.md).
**Caching.** Only the filesystem-derived half - the release stamp and the
config file - is cached, keyed on the resolved root. `WIKI_TRACE` and the two
+12 -1
View File
@@ -38,7 +38,6 @@ def repo(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
"<!-- dist:strip-start -->\n```\n└── commonplace/\n```\n<!-- dist:strip-end -->\n",
encoding="utf-8",
)
(root / "EVALS.md").write_text("# EVALS\n", encoding="utf-8")
(root / "CLAUDE.md").write_text("# CLAUDE\n\n@AGENTS.md\n", encoding="utf-8")
(root / ".gitignore").write_text("*.pyc\n", encoding="utf-8")
(root / ".gitattributes").write_text("* text=auto eol=lf\n", encoding="utf-8")
@@ -191,6 +190,18 @@ def test_plan_never_includes_docs_dev(repo):
assert "docs/explanation/why-gates-are-code.md" in plan
def test_plan_ships_no_retired_root_docs(repo):
"""`EVALS.md` and `INSTALL-MCP.md` became pages under docs/. A stray copy
left at the root of a source tree is not shipped, so an upgraded instance
loses them as retired files instead of carrying a stale second copy."""
(repo / "EVALS.md").write_text("# EVALS\n", encoding="utf-8")
(repo / "INSTALL-MCP.md").write_text("# MCP\n", encoding="utf-8")
plan = dist_cmd.build_plan()
assert "EVALS.md" not in plan
assert "INSTALL-MCP.md" not in plan
assert "README.md" in plan
def test_plan_never_includes_instructions_dev(repo):
"""instructions/dev/ - flat dev-only instructions and the nested skill
that switches a session into tool-development mode - is pruned
+1
View File
@@ -532,6 +532,7 @@ def test_paths_land_in_the_group_a_reviewer_expects():
assert group_of("tools/chemenu/cli.py")[0] == "Tooling"
assert group_of(".claude/settings.json")[0] == "Harness config"
assert group_of("README.md")[0] == "Human docs"
assert group_of("docs/how-to/ingest-a-source.md")[0] == "Human docs"
assert group_of("work/run/plan.md")[0] == "Workshop"
assert group_of("something-else.txt")[0] == "Other"
+12 -2
View File
@@ -99,7 +99,17 @@ def test_every_exception_is_still_in_use():
assert ALLOWED <= used, ALLOWED - used
SHIPPED_DOCS = ("AGENTS.md", "README.md", "INSTALL.md", "EVALS.md")
SHIPPED_ROOT_DOCS = ("AGENTS.md", "README.md", "INSTALL.md")
def shipped_docs() -> list[Path]:
"""The root documents an operator reads, plus every page `dist export` ships under `docs/` -
the how-to guides among them name the preflight call an operator types."""
docs = REPO / "docs"
pages = sorted(
path for path in docs.rglob("*.md") if path.relative_to(docs).parts[0] != "dev"
)
return [REPO / name for name in SHIPPED_ROOT_DOCS] + pages
# A line that starts the PowerShell preflight - bare (`.\tools\preflight.ps1`, `& preflight.ps1`)
# or through pwsh - as opposed to one that merely names the file (a comment, a download).
@@ -109,7 +119,7 @@ BYPASS = "pwsh -NoProfile -ExecutionPolicy Bypass -File "
@pytest.mark.parametrize(
"path",
[REPO / name for name in SHIPPED_DOCS] + shipped_instructions(),
shipped_docs() + shipped_instructions(),
ids=lambda p: str(p.relative_to(REPO)),
)
def test_every_powershell_preflight_call_carries_the_bypass(path):
+2 -1
View File
@@ -5,7 +5,8 @@ asks whether the commands compose - whether a wiki assembled the documented way
comes out structurally clean, and whether the catalog is a fixed point rather
than something that keeps changing every time it is rebuilt.
That is the hard-oracle floor the eval ladder in EVALS.md rests on: before a
That is the hard-oracle floor the eval ladder in
docs/explanation/telemetry-and-evaluation.md rests on: before a
score can say anything about how an agent worked, running the tools correctly has
to be known to produce a clean tree.
+1 -1
View File
@@ -34,7 +34,7 @@ recorded reason at all.
calls a page in one of its four areas "Humans and agents ... | By link, or on
explicit request" - agent-loaded, at a second hop, which is precisely the preview mechanic
`instructions/CONTRACT.md` § "Reference depth" treats as real. The exclusion of
the human docs (`README.md`, `CHANGES.md`, `EVALS.md`, `INSTALL.md`,
the human docs (`README.md`, `CHANGES.md`, `INSTALL.md`,
`tools/README.md`) rests on a sentence that does not stretch to cover it: those
are "Never loaded by an agent as instruction," while a `docs/` page is not
loaded *as instruction* but is very much loaded.