tools: one data record per command - -h, index and CONTRACT.md render from cli_contract (#121)
CI / verify (push) Failing after 1m11s
Release / release (push) Successful in 37s

Files changed:
- AGENTS.md
- CHANGES.md
- VERSION
- instructions/dev/doc-pull-through.md
- instructions/dev/stack-close/SKILL.md
- tools/CONTRACT.md
- tools/README.md
- tools/chemenu/cli.py
- tools/chemenu/cli_contract.py
- tools/chemenu/commands/cite_cmd.py
- 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/index_build.py
- tools/chemenu/commands/instructions_cmd.py
- tools/chemenu/commands/links_cmd.py
- tools/chemenu/commands/lint.py
- tools/chemenu/commands/log_append.py
- tools/chemenu/commands/migrate_cmd.py
- tools/chemenu/commands/new_page.py
- tools/chemenu/commands/page_ops.py
- tools/chemenu/commands/provenance_cmd.py
- tools/chemenu/commands/raw_cmd.py
- tools/chemenu/commands/review_cmd.py
- tools/chemenu/commands/run_budget.py
- tools/chemenu/commands/search.py
- tools/chemenu/commands/task_cmd.py
- tools/chemenu/commands/touch.py
- tools/chemenu/commands/types_cmd.py
- tools/chemenu/commands/upload_cmd.py
- tools/chemenu/commands/upstream_cmd.py
- tools/chemenu/commands/version_cmd.py
- tools/chemenu/commands/work_cmd.py
- tools/chemenu/commands/xref.py
- tools/chemenu/tests/test_cli_contract.py
- tools/chemenu/tests/test_docs_verify.py
- tools/chemenu/tests/test_run_budget.py
This commit is contained in:
torben committed 2026-09-26 07:53:10 +02:00
1 parent 919e733e21
commit 26e1018766
39 files changed
+5203 -702

No files matched your search

+24 -14
View File
@@ -4,9 +4,9 @@ Developer documentation for `wikitool` - how the CLI is built, how to change it,
and how to run its tests.
**This is not the command reference.** That is [CONTRACT.md](CONTRACT.md), which
`wikitool docs verify` checks against the registered commands. Copying the
command table here would create a second copy that drifts, so this file
deliberately has none - and `docs verify` now enforces that.
`wikitool docs verify` checks against the registered commands. Copying its
generated command records here would create a second copy that drifts, so this
file deliberately has none - and `docs verify` now enforces that.
| Document | Audience |
|---|---|
@@ -33,7 +33,8 @@ install command rather than degrading silently.
tools/
wikitool entry point
chemenu/
cli.py Typer app: registers every command, runs the budget gate
cli.py Typer app: registers every command, runs the budget gate, renders `-h`/`--help` from cli_contract
cli_contract.py one data record per command (name, synopsis, properties, exit status) - the source `-h`, the index and CONTRACT.md's generated region render from
config.py repo layout: root resolution and every path under it
api.py the in-process entry point - point Chemenu at a corpus and read it
errors.py ChemenuError / ValidationError / BackendError
@@ -79,13 +80,21 @@ bound at import time - `KB_DIR` and friends follow whatever `ROOT` currently is.
1. Write the module under `chemenu/commands/`. A group is a `typer.Typer()`
app; a single command is a plain function.
2. Register it in `cli.py` (`app.add_typer(...)` or `app.command(...)`).
3. Add a row to [CONTRACT.md](CONTRACT.md)'s command table **and** to its error
contract table. `docs verify` fails in both directions - an undocumented
command and a documented non-command are equally reported. Write the rows
without citing an issue number: `docs verify` also refuses any `.md` or
`.template` `dist export` ships that carries one, because the tracker exists
only in this repo (`instructions/dev/issue-tracking.md` § Citing an issue in
the repo).
3. Attach a `@cli_contract.record(cli_contract.CommandRecord(...))` decorator to
the command function, in its own module, and add its path to the matching
group in `cli_contract.GROUPS`. That one record is the source `wikitool
<cmd> -h`, the index (`wikitool -h`, and the top of
[CONTRACT.md](CONTRACT.md)), and CONTRACT.md's generated `#### <path>`
section all render from - see `cli_contract.py`'s own module docstring for
the record's shape. `docs verify` fails in both directions - a command with
no record and a `GROUPS` entry naming no real command are equally reported -
and also checks that every non-hidden flag appears in the record's SYNOPSIS.
Then regenerate the copy: `wikitool docs contract --apply`. Write the
record's prose without citing an issue number: `docs verify` also refuses
one in a command's rendered `--help` text (a docstring above its `\f`
marker, or an option's `help=`) and in any `.md`/`.template` `dist export`
ships, because the tracker exists only in this repo
(`instructions/dev/issue-tracking.md` § Citing an issue in the repo).
4. Add tests. Pure logic belongs in a function separate from the Typer callback
(see `mass_update_gate_message`, `derive_run_key`, `run_export`), so a test
does not need a CLI runner - and a Typer callback called directly from a test
@@ -107,9 +116,10 @@ bound at import time - `KB_DIR` and friends follow whatever `ROOT` currently is.
A new command reaches every future instance, and CI's version gate refuses a
stack change that moved no version.
Every command is counted against the iteration budget unless it is listed in
`run_budget.SKIP_COMMANDS` / `SKIP_COMMAND_PATHS`. Only read-only retrieval
belongs there.
Every command is counted against the iteration budget unless its `cli_contract`
record's `budget:` property says `exempt` (or, for `version regrade`'s own
shape, `exempt_without_args`) - `run_budget.is_exempt` reads it from there,
not from a list of its own. Only read-only retrieval earns it.
## Design notes