Skip to content

docs(#260): document app list/view/pull, scope the anonymous-reads claim, add a TOC - #268

Merged
ZacxDev merged 2 commits into
mainfrom
docs/260-dogfood-docs-gaps
Aug 7, 2026
Merged

docs(#260): document app list/view/pull, scope the anonymous-reads claim, add a TOC#268
ZacxDev merged 2 commits into
mainfrom
docs/260-dogfood-docs-gaps

Conversation

@ZacxDev

@ZacxDev ZacxDev commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Four of the seven sub-items in the #260 dogfood umbrella, plus the navigation
work. The other three (app_init.go's scaffold-validation and --from leak;
the icon/cover on-ramp) are elsewhere or blocked.

The false claims (issue #260 A1–A4)

These are not cosmetics — the docs asserted things the binary does not do.

A1 — three commands existed and the README documented none of them.
civitai app --help lists list, view and pull; the command-reference table
had rows for none. app pull is the significant one: its own --help calls it
"the read side of git authoring", it lazily provisions a Forgejo identity, and it
carries a 10-line ⚠ SECURITY — TOKEN-IN-URL LEAKAGE warning. A README-only
reader did not know a git authoring path existed, let alone its hazards.

All three now have rows. app pull and the App-store commands get sections; the
security warning is mirrored from the real --help text (both halves — the
clone path persists the token to .git/config, the sync path only exposes it
transiently in the git child's argv).

A2 — the README contradicted the binary on anonymous reads. Reads are **anonymous** — no login needed and root --help's "Reading is anonymous"
were both false for civitai app list / app view, which exit 3 with
no token configured — … to browse the App store. Verified against the source
(newLoginGatedReader in internal/cmd/apps.go), not assumed: the public
model/image/article commands genuinely are anonymous, and only these two store
reads are not. The claim is now scoped to the public catalog on all three
surfaces, and the App-store section says so at the top.

A3 — app metrics recommended a login that will be refused. The no-token
branch returned the generic run 'civitai login' — the one credential the
full-scope analytics proc refuses with 403 — so following the CLI's own advice
landed the author on a second refusal. It now names the personal-API-key route
and where to mint one, from a constant app metrics --help renders too.

A4 — unknown flag offered no next step. civitai app validate --stict
printed only unknown flag: --stict, while an unknown command already said
Run '… --help'. SetFlagErrorFunc now appends the help command for the
command actually being parsed:

$ civitai app validate --stict
Error: unknown flag: --stict
Run 'civitai app validate --help' for the available flags.
$ echo $?
2

Navigation (issue #260 B)

  • A table of contents with verified anchors.
  • The four essay-length table cells — generate (280 words / 1859 chars in one
    markdown column), app dev-tunnel (222), app listing (124), app dev-token
    (105) — condensed to a one-line summary plus a link. Content was relocated,
    not deleted
    : generate's detail was already fully covered by ## Generate;
    dev-tunnel got a new section; dev-token's unique bits (--budget, the
    manifest-scope read) went into the Local dev loop section.
  • civitai --help now shows Usage: and Available Commands: before the
    ~60-line exit-code taxonomy, which used to sit above the fold.

⚠ Reconciliation note for the exit-code work

The exit-code section moved out of root's Long and into a help
template. Its text is untouched and still generated from exitCodeDocs, and
the README's generated exit-code table is untouched — but
TestRootHelpExitCodesAreGenerated had to change from reading cmd.Long to
reading the rendered --help output (a strictly stronger assertion: it is what
the user sees). If exitcodes_doc.go is being edited concurrently, that is the
one point of contact.

The {{if not .HasParent}} gate is load-bearing: cobra's HelpTemplate() walks
up to the parent, so without it every subcommand help would grow a copy of the
root taxonomy. TestSubcommandHelpDoesNotRepeatTheExitCodeSection pins it.

Guards

Guard What it pins
TestREADMEAnchorLinksResolve every ](#…) target is a heading that exists
TestREADMEAnchorSlugMatchesKnownGitHubAnchors the slug algorithm, against 8 anchors that already worked on github.com
TestREADMETableOfContentsCoversEverySection every ## section is reachable from the TOC
TestREADMECommandTableDocumentsEveryAppSubcommand derived from the cobra tree, so a new app subcommand cannot ship undocumented
TestAppMetricsNoTokenNamesTheRouteThatWorks errors.Is(civitai.ErrUnauthorized) for the exit code, the specific route substrings for the message
TestAppMetricsCredentialRouteIsNotTheSpendRoute that the constant is not collapsed into spendCredentialRoutes, which would reintroduce the defect
TestUnknownFlagNamesTheHelpCommandForThatCommand errors.Is(ErrUsage), plus a case a root-hardcoded hint would fail
TestRootHelpShowsUsageBeforeExitCodes indices, not presence — "contains both" is satisfied by the broken order

Every exit-code assertion is errors.Is, never message text (AGENTS item 7).

Mutation results (each injected, watched red, reverted):

  • an injected [x](#no-such-heading-zz)TestREADMEAnchorLinksResolve fails,
    naming the dangling slug;
  • deleting the civitai app pull table row →
    TestREADMECommandTableDocumentsEveryAppSubcommand fails, naming the command.

TestReadmeDevTunnelRowMatchesTheCommandHelp was widened to follow the row's own
cross-reference into the section it links to, so relocating detail out of a table
cell is a supported move — and a broken link now fails it.

Gate

make ci green. Counted from go test ./... -count=1 -v, not the exit code:
2708 === RUN, 2704 --- PASS, 0 --- FAIL, 4 --- SKIP, 0 build failed,
0 timeout panics.
gofmt -s -l . clean over 299 .go files.

Behaviour verified against the built binary (./bin/civitai), not only tests:
the --stict invocation above, civitai app --help carrying zero copies of the
exit-code block, and civitai --help showing Usage: at line 32 with
Exit codes: after the flag list.

🤖 Generated with Claude Code

…aim, add a TOC

A blind dogfood run against v0.1.90-21-gf56aa72 (#260) found the docs
asserting things the binary does not do, and a 1616-line README with no
navigation. Four false claims and the navigation gap:

A1. `app list`, `app view` and `app pull` are all in `civitai app --help`
    and were in NO README row. `app pull` is not minor — it is "the read
    side of git authoring" and carries a token-in-URL leakage hazard a
    README-only reader had no way to reach. All three now have rows, and
    `app pull` / the App store have sections carrying the real caveats.

A2. "Reads are anonymous — no login needed" was false for `app list` and
    `app view`, which exit 3 with `no token configured`. The claim is now
    scoped to the public catalog, and the App-store commands are described
    as needing a credential in the README, the row, and root --help.

A3. `app metrics` with no token said "run `civitai login`" — the ONE
    credential the full-scope analytics proc refuses (403). It now names
    the personal-API-key route and where to mint one, from a constant the
    command's own --help renders too. Still ErrUnauthorized-tagged (exit 3).

A4. A mistyped flag printed a bare `unknown flag: --stict` with no next
    step, while a mistyped COMMAND already got `Run '… --help'`. The
    FlagErrorFunc now appends the help command for the command actually
    being parsed. Cobra's wording is appended to, never replaced; exit 2
    is unchanged.

B.  A table of contents with verified anchors; the four essay-length table
    cells (generate 280w, dev-tunnel 222w, listing 124w, dev-token 105w)
    condensed to a summary plus a link, with the detail RELOCATED into
    sections rather than deleted. `civitai --help` now shows Usage and
    Available Commands BEFORE the ~60-line exit-code taxonomy.

The exit-code section moved out of root's Long and into a help TEMPLATE
gated on `{{if not .HasParent}}` (a template set on the root is otherwise
inherited by every subcommand). Its TEXT is untouched and still generated
from exitCodeDocs; the README's generated exit-code table is untouched.

Guards:
- TestREADMEAnchorLinksResolve — every `](#…)` target is a real heading.
  The slug algorithm is positive-controlled against eight anchors that
  already worked on github.com. Mutation-verified: an injected
  `#no-such-heading-zz` reddens it by name.
- TestREADMETableOfContentsCoversEverySection — every `##` section is
  reachable from the TOC.
- TestREADMECommandTableDocumentsEveryAppSubcommand — derived from the
  COBRA TREE, not a list. Mutation-verified: deleting the `app pull` row
  reddens it by name.
- TestAppMetricsNoTokenNamesTheRouteThatWorks — errors.Is(ErrUnauthorized)
  for the exit code, specific substrings for the route, plus a check that
  the constant has not been collapsed into spendCredentialRoutes.
- TestUnknownFlagNamesTheHelpCommandForThatCommand — errors.Is(ErrUsage),
  with a discriminating case that a root-hardcoded hint would fail.
- TestRootHelpShowsUsageBeforeExitCodes asserts INDICES (both-present is
  satisfied by the broken order); TestSubcommandHelpDoesNotRepeatThe
  ExitCodeSection pins the template gate.

TestReadmeDevTunnelRowMatchesTheCommandHelp now follows the row's own
cross-reference into the section, so relocating detail out of a cell is a
supported move and a broken link fails it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
golangci-lint's staticcheck ST1005 rejects an error string ending in
punctuation, and the CI lint gate on this branch was red on exactly one
issue: internal/cmd/root.go:214.

Verified with the pinned linter (v2.12.2, matching .github/workflows/ci.yml):
reproduced the identical ST1005 error on an unmodified checkout of this
branch's tip, then confirmed 0 issues after the change. go build ./... clean
and ./internal/cmd passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ZacxDev
ZacxDev merged commit 1eb4095 into main Aug 7, 2026
12 checks passed
ZacxDev added a commit that referenced this pull request Aug 7, 2026
My README.md edits collided with #268 (which added a TOC and the app
list/view/pull docs). Measured by exit code, not by grepping for markers:
`git merge-tree --write-tree origin/main <ref>` exits 0 for the audited tip
a4807f4 and 1 for my tip, so the conflict is mine and not pre-existing.

Merged rather than rebased, deliberately: a rebase would rewrite a4807f4, which
the PR must keep, and five sibling PRs are in flight against these same files.

The conflict was one 3-row hunk of the command table where each side edited a
DIFFERENT row — #268 rewrote `app dev-token` and `app dev-tunnel`, I rewrote
`app validate`. Resolved row-by-row against the merge BASE rather than by
picking a side: main's row wherever main changed it, mine wherever I changed it,
with the resolver refusing outright if both had touched one row. Neither side's
block was correct on its own.

Verified on the MERGED tree, which is the tree that matters and the one neither
side's review saw: make ci green — 18 packages ok, `--- FAIL` 0, `build failed`
0, timeout panics 0, gofmt clean — including the readme-nav, root-help-order and
login-help guards main added while this branch was open.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant