for family in graph backend workspace plugin; do
Root cause (GAP-013/015): docs/cli-reference.md was hand-maintained — it drifted from the clap source of truth (4/10 graph subcommands, 0 family docs, max-depth default written as 5 while live help says 10, example flag stale).
Fix loop (each step driven by live clap --help, never by memory):
1. Re-probe live help per command — capture kg <cmd> --help for every command in the graph/backend/workspace/plugin/impact families into help/<fam>-<cmd>.txt (29 files), then generate the doc from those captures:
# gen-docs.sh (excerpt) — regeneration is the fix; the doc is never hand-edited
for family in graph backend workspace plugin; do
# subcommand table + verbatim description: about line == first line of clap help
while read -r name desc; do
[ -z "$name" ] && continue
printf '| `kg %s %s` | %s |\n' "$family" "$name" "$desc"
done < <(awk '/^Commands:/{f=1;next} /^Options:/{f=0} f' "$HELP/$family.txt")
# per-subcommand usage, byte-identical to live help (keeps <MOUNT_POINT> alive)
while read -r name; do
[ -z "$name" ] && continue
echo "### \`kg $family $name\`"; echo "$(head -1 "$HELP/$family-$name.txt")"
echo '```'; grep -m1 '^Usage:' "$HELP/$family-$name.txt"; echo '```'
done < <(awk '/^Commands:/{f=1;next} /^Options:/{f=0} f && NF{print $1}' "$HELP/$family.txt")
done
2. Copy descriptions VERBATIM — the description column is the clap about line (head -1 of the help capture), string-equal, not paraphrased. Example: Run a traversal query over the graph, Show graph statistics — identical to kg graph query --help.
3. Verify examples against live arg shapes — kg workspace mount <MOUNT_POINT> [OPTIONS] makes MOUNT_POINT a required positional; the doc's usage line and any example must include it. The generator emits usage lines verbatim, so the positional survives:
### `kg workspace mount`
Mount a data source into the workspace
Usage: kg workspace mount <MOUNT_POINT> [OPTIONS]
4. Impact fix — never hardcode the default, extract it from live help, and fix the example too:
# gen-docs.sh: default extracted from live options text, example derived from it
maxdepth=$(sed -n 's/.*(\([0-9][0-9]* by default\)).*/\1/p' "$HELP/impact.txt") # "10 by default"
echo "\`--max-depth\`: $maxdepth."
echo "kg impact ABC-123 --max-depth ${maxdepth%% *}" # -> --max-depth 10
Resulting impact section:
`--max-depth`: 10 by default.
Example:
kg impact ABC-123 --max-depth 10
5. AC greps run LITERALLY (grep -F, fixed strings) — see EVIDENCE.
Verified in `/tmp/gap-demo/`: 29 verbatim `clap --help` captures → `gen-docs.sh` → `docs/cli-reference.md`, then `ac-tests.sh` (54 checks, **54 passed / 0 failed**):
- **Coverage:** 10/10 graph subcommands (`init add remove get query list update export import stats`) and all 4 families (`graph backend workspace plugin`) present; pre-fix doc had 4 and 0.
- **Verbatim:** 11 descriptions and all 23 usage lines byte-identical to help captures (`grep -Fq` of the exact string).
- **Arg shapes:** `<MOUNT_POINT>` present in the workspace-mount section; `--uri <URI>`, `<CHANGE_ID>`, `[KIND]` etc. all match live usage.
- **Impact:** doc says `10 by default`; example `--max-depth 10`; `grep -nF "max-depth 5"` → clean.
**Edge cases (both traps reproduced live):**
```
TRAP A — regex ordering: "10 by default" defeats `default.*10`
$ grep -nE "default.*10" docs/cli-reference.md
-> no match # FALSE NEGATIVE: "10" precedes "default", so the
# ordered regex never fires even though 10 is present
$ grep -nF "10 by default" docs/cli-reference.md
267: `--max-depth`: 10 by default. # literal grep is the correct AC
TRAP B — stale example flag line survives a partial fix
OLD doc: "max-depth 5" matched BOTH default line and example flag line
half-fixed doc: default line changed to 10, example left as --max-depth 5
-> grep "max-depth 5" STILL matches line: kg impact ABC-123 --max-depth 5
FIXED doc: no "max-depth 5" match anywhere (the example MUST change too)
```
A third edge case surfaced during the run: family help files contain a blank line between the `Commands:` block and `Options:`, which made the awk subcommand extractor emit an empty name and produce 4 false-positive checks; fixed with `on && NF{print f, $1}` and re-ran clean (58→54 real checks, 0 failures).{"model": "deepseek-v4-flash", "problem_class": "docs-cli-reference-surface-gap", "result": "passed", "tests": 54}