feat!: docs/ sorted into tutorials, how-to, reference, explanation plus unshipped docs/dev/; explanation pages and developer guide moved, human docs English (#187)
The seven explanation pages move to docs/explanation/ without a stub, DEVELOPMENT.md becomes docs/dev/development.md (translated to English), dist export leaves docs/dev/ out, docs verify rejects a file outside the five areas, and AGENTS.md states that the stack's human documentation is English. Required migration 9.0.0-docs-diataxis rewrites the old path in an instance's own kb/CONVENTIONS.md. Files changed: - .wikitool-kb.json - AGENTS.md - CHANGES.md - CLAUDE.md - DEVELOPMENT.md - INSTALL.md - README.md - VERSION - docs/dev/development.md - docs/explanation/README.md - docs/explanation/knowledge-and-commitment.md - docs/explanation/language-boundaries.md - docs/explanation/model-and-effort-selection.md - docs/explanation/ownership-and-templates.md - docs/explanation/pipeline-rationale.md - docs/explanation/version-model.md - docs/explanation/why-gates-are-code.md - docs/how-to/README.md - docs/knowledge-and-commitment.md - docs/language-boundaries.md - docs/model-and-effort-selection.md - docs/ownership-and-templates.md - docs/pipeline-rationale.md - docs/reference/README.md - docs/tutorials/README.md - docs/version-model.md - docs/why-gates-are-code.md - instructions/CONTRACT.md - instructions/dev/dev-setup.md - instructions/dev/doc-pull-through.md - instructions/dev/stack-close/SKILL.md - instructions/dev/stack-mode.md - instructions/gtd-weekly-review/SKILL.md - instructions/ingest-queue.md - instructions/migrations/6.0.0-type-guidance-split.md - instructions/migrations/9.0.0-docs-diataxis.md - instructions/upgrade-instance.md - kb/CONVENTIONS.md - kb/CONVENTIONS.md.template - tools/CONTRACT.md - tools/chemenu/commands/dist_cmd.py - tools/chemenu/commands/docs_verify.py - tools/chemenu/commands/new_page.py - tools/chemenu/commands/task_cmd.py - tools/chemenu/tasks/protocol.py - tools/chemenu/tests/test_dist_cmd.py - tools/chemenu/tests/test_docs_verify.py - tools/chemenu/tests/test_git_publish.py - tools/chemenu/tests/test_toc.py - types/type-guidance.md Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SnAJ7Z3CpVD3PRbN73QtU2
This commit is contained in:
1 parent
0e15972ee7
commit
d66a3f65f4
43 files changed
+756
-324
No files matched your search
@@ -149,8 +149,12 @@ def repo(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
|
||||
)
|
||||
|
||||
docs_dir = root / "docs"
|
||||
docs_dir.mkdir()
|
||||
(docs_dir / "why-gates-are-code.md").write_text("# Why gates are code\n", encoding="utf-8")
|
||||
(docs_dir / "explanation").mkdir(parents=True)
|
||||
(docs_dir / "explanation" / "why-gates-are-code.md").write_text(
|
||||
"# Why gates are code\n", encoding="utf-8"
|
||||
)
|
||||
(docs_dir / "dev").mkdir()
|
||||
(docs_dir / "dev" / "development.md").write_text("# Developing this stack\n", encoding="utf-8")
|
||||
|
||||
for relative in ("raw/CONTRACT.md", "reports/CONTRACT.md", "work/CONTRACT.md"):
|
||||
path = root / relative
|
||||
@@ -175,7 +179,16 @@ def test_plan_never_includes_commonplace(repo):
|
||||
|
||||
def test_plan_ships_docs_verbatim(repo):
|
||||
plan = dist_cmd.build_plan()
|
||||
assert plan["docs/why-gates-are-code.md"].content == "# Why gates are code\n"
|
||||
assert plan["docs/explanation/why-gates-are-code.md"].content == "# Why gates are code\n"
|
||||
|
||||
|
||||
def test_plan_never_includes_docs_dev(repo):
|
||||
"""docs/dev/ is the human half of instructions/dev/ - the release workflow
|
||||
and the development environment - and is pruned with it, while the other
|
||||
docs/ areas still ship."""
|
||||
plan = dist_cmd.build_plan()
|
||||
assert not any(relative.startswith("docs/dev/") for relative in plan)
|
||||
assert "docs/explanation/why-gates-are-code.md" in plan
|
||||
|
||||
|
||||
def test_plan_never_includes_instructions_dev(repo):
|
||||
|
||||
@@ -290,12 +290,13 @@ def test_install_md_is_checked_too(tmp_path, monkeypatch):
|
||||
assert any("`doctor`" in issue for issue in issues)
|
||||
|
||||
|
||||
def test_development_md_is_checked_too(tmp_path, monkeypatch):
|
||||
"""DEVELOPMENT.md drifted exactly this way once (Gitea #47): a table
|
||||
describing what each verify command checks, removed by hand because nothing
|
||||
compared it to anything."""
|
||||
def test_the_developer_guide_is_checked_too(tmp_path, monkeypatch):
|
||||
"""The developer guide drifted exactly this way once (Gitea #47, as the root
|
||||
DEVELOPMENT.md it was then): a table describing what each verify command
|
||||
checks, removed by hand because nothing compared it to anything."""
|
||||
root = tmp_path
|
||||
(root / "DEVELOPMENT.md").write_text(
|
||||
(root / "docs" / "dev").mkdir(parents=True)
|
||||
(root / "docs" / "dev" / "development.md").write_text(
|
||||
"| Command | Purpose |\n| `docs verify` | checks docs |\n", encoding="utf-8"
|
||||
)
|
||||
monkeypatch.setattr(docs_verify.config, "ROOT", root)
|
||||
@@ -305,7 +306,7 @@ def test_development_md_is_checked_too(tmp_path, monkeypatch):
|
||||
|
||||
|
||||
def test_an_absent_listed_doc_is_skipped_not_reported(tmp_path, monkeypatch):
|
||||
"""The distributed-instance case: DEVELOPMENT.md is not shipped, so listing
|
||||
"""The distributed-instance case: docs/dev/ is not shipped, so listing
|
||||
it must stay inert where the file does not exist rather than failing a tree
|
||||
that is correct."""
|
||||
root = tmp_path
|
||||
@@ -906,6 +907,113 @@ def test_a_target_with_neither_the_file_nor_a_template_is_still_dead(tmp_path, m
|
||||
assert "CONVENTIONS.md" in issues[0]
|
||||
|
||||
|
||||
# --- docs/ layout ------------------------------------------------------------
|
||||
|
||||
|
||||
def test_this_repos_docs_are_laid_out_in_areas():
|
||||
assert docs_verify.check_docs_layout() == []
|
||||
|
||||
|
||||
def _docs_tree(tmp_path, monkeypatch, files: tuple[str, ...]):
|
||||
from chemenu import config
|
||||
|
||||
monkeypatch.setattr(config, "ROOT", tmp_path)
|
||||
for relative in files:
|
||||
path = tmp_path / relative
|
||||
path.parent.mkdir(parents=True, exist_ok=True)
|
||||
path.write_text("# Page\n", encoding="utf-8")
|
||||
|
||||
|
||||
def test_a_file_directly_in_docs_is_reported(tmp_path, monkeypatch):
|
||||
"""The layout before 9.0.0, when every page sat directly in docs/: a page
|
||||
there belongs to no kind of documentation."""
|
||||
_docs_tree(tmp_path, monkeypatch, ("docs/explanation/a.md", "docs/stray.md"))
|
||||
issues = docs_verify.check_docs_layout()
|
||||
assert len(issues) == 1
|
||||
assert "docs/stray.md" in issues[0] and "directly in docs/" in issues[0]
|
||||
|
||||
|
||||
def test_a_file_in_a_directory_that_is_no_area_is_reported(tmp_path, monkeypatch):
|
||||
_docs_tree(tmp_path, monkeypatch, ("docs/guides/a.md",))
|
||||
issues = docs_verify.check_docs_layout()
|
||||
assert len(issues) == 1
|
||||
assert "docs/guides/" in issues[0]
|
||||
|
||||
|
||||
def test_every_area_and_nesting_inside_one_is_accepted(tmp_path, monkeypatch):
|
||||
_docs_tree(tmp_path, monkeypatch, tuple(
|
||||
f"docs/{area}/README.md" for area in docs_verify.DOCS_AREAS
|
||||
) + ("docs/how-to/mcp/setup.md",))
|
||||
assert docs_verify.check_docs_layout() == []
|
||||
|
||||
|
||||
def test_a_tree_without_docs_passes_the_layout_check(tmp_path, monkeypatch):
|
||||
_docs_tree(tmp_path, monkeypatch, ())
|
||||
assert docs_verify.check_docs_layout() == []
|
||||
|
||||
|
||||
def test_verify_raises_when_a_docs_file_is_outside_every_area(monkeypatch):
|
||||
monkeypatch.setattr(docs_verify, "check_docs_layout", lambda: ["stray"])
|
||||
with pytest.raises(typer.Exit):
|
||||
docs_verify.verify()
|
||||
|
||||
|
||||
# The rewrite instructions/migrations/9.0.0-docs-diataxis.md tells an instance
|
||||
# to run, as the regex it spells out for `sed -E`.
|
||||
_DIATAXIS_NAMES = (
|
||||
"pipeline-rationale|ownership-and-templates|language-boundaries|why-gates-are-code|"
|
||||
"version-model|knowledge-and-commitment|model-and-effort-selection"
|
||||
)
|
||||
_DIATAXIS_SED = f"s#docs/({_DIATAXIS_NAMES})\\.md#docs/explanation/\\1.md#g"
|
||||
|
||||
|
||||
def test_the_9_0_0_upgrade_breaks_an_old_conventions_link_until_the_migration_ran(
|
||||
tmp_path, monkeypatch
|
||||
):
|
||||
"""The breaking change 9.0.0 declares, end to end on the check that reports
|
||||
it: an instance adopted `kb/CONVENTIONS.md` from a template linking
|
||||
`../docs/language-boundaries.md`, and the upgrade never touches that
|
||||
instance-owned file while it deletes the page at its old path. After the
|
||||
swap `docs verify` reports the link; after the migration document's
|
||||
rewrite it does not."""
|
||||
import re
|
||||
|
||||
from chemenu import config
|
||||
|
||||
document = (
|
||||
config.ROOT / "instructions" / "migrations" / "9.0.0-docs-diataxis.md"
|
||||
).read_text(encoding="utf-8")
|
||||
monkeypatch.setattr(config, "ROOT", tmp_path)
|
||||
(tmp_path / "kb").mkdir()
|
||||
conventions = tmp_path / "kb" / "CONVENTIONS.md"
|
||||
conventions.write_text(
|
||||
"# Conventions\n\nWhy the KB language is a value: "
|
||||
"[docs/language-boundaries.md](../docs/language-boundaries.md).\n",
|
||||
encoding="utf-8",
|
||||
)
|
||||
# The machinery as 9.0.0 installs it: the page only under its new path.
|
||||
(tmp_path / "docs" / "explanation").mkdir(parents=True)
|
||||
(tmp_path / "docs" / "explanation" / "language-boundaries.md").write_text(
|
||||
"# Language boundaries\n", encoding="utf-8"
|
||||
)
|
||||
|
||||
issues = docs_verify.check_reference_targets()
|
||||
assert len(issues) == 1
|
||||
assert "kb/CONVENTIONS.md:3" in issues[0]
|
||||
assert "../docs/language-boundaries.md" in issues[0]
|
||||
|
||||
# The migration document's rewrite, the same expression it gives to `sed -E`.
|
||||
assert _DIATAXIS_SED in document
|
||||
_, pattern, replacement, _ = _DIATAXIS_SED.split("#")
|
||||
conventions.write_text(
|
||||
re.sub(pattern, replacement, conventions.read_text(encoding="utf-8")),
|
||||
encoding="utf-8",
|
||||
)
|
||||
|
||||
assert "../docs/explanation/language-boundaries.md" in conventions.read_text(encoding="utf-8")
|
||||
assert docs_verify.check_reference_targets() == []
|
||||
|
||||
|
||||
def test_every_reference_files_link_targets_resolve():
|
||||
"""Forward direction, against the real tree: every relative link in a file
|
||||
`toc.target_files()` covers must resolve - this is what a `../` count
|
||||
|
||||
@@ -289,7 +289,7 @@ def test_stack_machinery_excludes_ordinary_content():
|
||||
"""kb/ content, docs/ prose and work/ scratch carry no normative sentence
|
||||
and are not what the closing-phase reminder is about."""
|
||||
assert not touches_stack_machinery(["kb/entities/systems/Foo.md"])
|
||||
assert not touches_stack_machinery(["docs/why-gates-are-code.md"])
|
||||
assert not touches_stack_machinery(["docs/explanation/why-gates-are-code.md"])
|
||||
assert not touches_stack_machinery(["work/ingest-x/extract-0.md"])
|
||||
assert not touches_stack_machinery([])
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ def test_target_files_matches_the_documented_scope():
|
||||
assert "instructions/CONTRACT.md" in relatives
|
||||
assert "instructions/dev/version-parts.md" in relatives # flat, still instructions/**.md
|
||||
assert "types/source.md" in relatives # a page type-spec, not only the stage contract
|
||||
assert "docs/version-model.md" in relatives
|
||||
assert "docs/explanation/version-model.md" in relatives
|
||||
assert not any(rel.endswith("SKILL.md") for rel in relatives)
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user