Documentation
¶
Overview ¶
Purpose: decide whether the env vars a command's own source reads are
documented in .github/wiki/Config-Env-Vars.md.
Inputs: cmd/commands/<name>*.go (per cli/.claude/rules/go.md, a
command's subcommands split into "<name>_<subgroup>.go" files sharing the same prefix — the same convention tools/wikigen and tools/cmdinventory rely on for one-command-per-file), plus the Config-Env-Vars.md wiki page.
Outputs: scoreEnvVars returns "n/a" (no direct env reads found),
"documented" (every found var is documented), or "undocumented: VAR, VAR" (lists the gaps).
Constraints: DELIBERATELY CONSERVATIVE / UNDER-COUNTS. Only direct
os.Getenv/os.LookupEnv/viper.Get*/viper.IsSet/viper.BindEnv calls in the command's own cmd/commands files are seen — env vars read transitively through internal/* packages (the common case; most commands delegate to internal/config, internal/database, etc.) are invisible to this check and will not appear here. That is a known, documented limitation, not a bug: a false "n/a" undercounts but never wrongly flags a documented var as missing. This is why the CI gate treats this column as a WARN, never a FAIL.
Purpose: load the committed command inventory (tools/cmdinventory's
output) as the parity matrix's list of top-level commands.
Inputs: path to .github/command-inventory.json. Outputs: one inventoryEntry per top-level command, sorted as committed. Constraints: the JSON shape must mirror tools/cmdinventory.Command; only the
top-level fields are read here, subcommands are intentionally ignored — CLI-R17 scores top-level commands only.
Command parity builds the four-surface parity matrix: one row per top-level CLI command, scored against wiki docs, MCP tool coverage, env var docs, and OpenAPI routes.
Purpose: CLI-R17. The four surfaces a command can ship on (wiki page,
MCP tool, documented env vars, OpenAPI route) drift independently today — nothing catches a new command that ships without a wiki page, or an MCP tool whose backing command got renamed. This generator makes the gap visible and, for the wiki column, blocks CI on it.
Inputs: .github/command-inventory.json (tools/cmdinventory's output —
reused as the authoritative top-level command list rather than re-walking the cobra tree, so this tool needs no cmd/commands import), .github/wiki/cmd-<name>.md (wiki column), cmd/commands/ mcp.go + mcp_sentry.go (MCP column, read as text — see mcptools.go for the matching rule), cmd/commands/<name>*.go + .github/wiki/ Config-Env-Vars.md (env column, see envvars.go for the extraction rule).
Outputs: .github/surface-parity.md (human table) and
.github/surface-parity.json (machine-readable) by default; -check verifies the committed copies match and writes nothing.
Constraints: read-only against everything except its own two output files.
The OpenAPI Route column is always "n/a": internal/apidocs exists and is wired into `nself build` (internal/build/orchestrator.go), but it documents the generated backend's HTTP surface, not the CLI's own commands — see openapi.go in this package for the full investigation and citations. Idempotent: running twice with no source changes produces byte-identical output (see internal/repoqa's drift test).
Purpose: decide which top-level commands are covered by an MCP tool.
Inputs: the two files that register MCP tools: cmd/commands/mcp.go
(6 infra tools) and cmd/commands/mcp_sentry.go (5 ɳSentry tools), read as plain text — this tool does not import cmd/commands.
Outputs: a set of command names considered MCP-covered.
Constraints: MATCHING RULE (deliberately conservative, exact-token only —
no fuzzy/substring matching, so it never over-claims coverage):
every mcp.NewTool("tool_name", ...) call is split on '_' into
tokens (e.g. "sentry_monitors_list" -> sentry, monitors, list).
A command is covered iff its exact Name appears as one of those
tokens for ANY registered tool. This intentionally does NOT
credit near-misses: nself_run_migration does not cover "migrate"
(token is "migration", not "migrate"), nself_list_plugins does not
cover "plugin" (token is "plugins", not "plugin"). It DOES credit
nself_doctor -> doctor, nself_tail_logs -> logs, sentry_* -> sentry,
and sentry_status -> status. Verified by main_test.go against the
actual tool names registered as of CLI-R17.
Purpose: decide what the OpenAPI Route column reports.
Inputs: none at runtime — this file records a one-time investigation
of internal/apidocs/{openapi.go,plugin_routes.go} done for CLI-R17.
Outputs: openAPIColumnValue, the constant string used for every row.
Constraints: internal/apidocs DOES exist (openapi.go, openapi_test.go,
plugin_routes.go, scalar.html) and IS wired into the CLI, from internal/build/orchestrator.go (apidocs.Generate / apidocs.CollectPluginRoutes / apidocs.NginxConf are all called from there, guarded by cfg.ApiDocs.Enabled during `nself build`). An earlier version of this file wrongly claimed the package did not exist; it does, and the finding below is corrected accordingly. What it does NOT do is describe the CLI's own commands. Reading internal/apidocs/openapi.go's buildSpec: the paths it emits are (a) five hardcoded /auth/v1/* endpoints, (b) /v1/graphql (+ its /subscriptions variant) when cfg.GraphQLEnabled, and (c) REST routes read from each installed plugin's plugin.json rest_routes key at build time (plugin_routes.go's CollectPluginRoutes walks ~/.nself/plugins/*/plugin.json, not this repo's source tree). All three describe the HTTP surface of the *generated backend stack* nself provisions (Hasura/Auth/GraphQL/plugin REST) — served at docs.<domain>/api-docs — not the `nself <command>` CLI surface this matrix's other three columns score. There is no field on either side (cobra.Command, OpenAPIOperation, PluginRoute) linking a CLI command name to an OpenAPI path, so no per-command match is possible without inventing one. Grepped cmd/commands/api.go too (the closest-named top-level command): it never references the apidocs package, confirming the two surfaces are unrelated.
Purpose: render the parity matrix as committed markdown + JSON. Inputs: the scored []Row from buildMatrix. Outputs: renderMarkdown returns the full .github/surface-parity.md
content (with the GENERATED BY header and column-rule notes); renderJSON returns the .github/surface-parity.json bytes.
Constraints: both must be pure functions of rows (no timestamps, no
non-deterministic map iteration) so two runs against the same source produce byte-identical output — required by internal/repoqa's drift test and by the idempotency requirement in the CLI-R17 ticket.
Purpose: check whether a top-level command has a published wiki page. Inputs: the wiki directory and a command name. Outputs: bool — true when .github/wiki/cmd-<name>.md exists. Constraints: matches tools/wikigen's pageName convention (cmd-<name>.md,
pages live at the wiki root per its CLI-R08 flattening note) so this column can never disagree with what wikigen itself expects.