docs(agents): record the three app metrics decisions that look wrong - #191
Merged
Conversation
Adds items 5-7 to "Intentional decisions that look wrong (read before 'fixing')" and updates the section's framing sentence. 5. `civitai app metrics` calls tRPC, not REST — because there is no REST route to call. Owner analytics exist only as `blocks.getMyAppAnalytics`; there is no /api/v1 equivalent. The command therefore resolves slug -> appBlockId via the existing REST GET /api/v1/blocks/submissions and then issues the non-batched tRPC GET, reusing the authedDo + result.data.json unwrap pattern GetForgejoCloneInfo established. Documented so nobody "fixes" it into a REST call that does not exist. 6. `notOwned` is a cross-repo contract. The proc sits behind the `appBlocksAuthor` flag and answers a non-entitled caller with HTTP 200 and every counter zeroed, so a renderer that ignores it prints a plausible empty dashboard for a permission failure. The human view refuses to render on `notOwned`; `--json` deliberately passes it through and still exits 0, so scripts must branch on it themselves. Whoever changes the payload server-side has to keep the field. 7. The exit-code contract is pinned by errors.Is, never by message text. The sentinels carry no visible text (Tag/TagStatus preserve Error() byte-for- byte), so a message assertion says nothing about the exit code. Measured on the metrics PR: stripping the classification while leaving every message identical left the ENTIRE suite green, and the README's 403 -> exit 3 / not-found -> exit 4 promise was unpinned. Generalised to every command that claims an exit code. Sentinel names verified against the code, not paraphrased: the HTTP kinds are `civitai.ErrUnauthorized`/`ErrNotFound` in pkg/civitai/errkind.go, but the usage sentinel is `cmd.ErrUsage` in internal/cmd/usage_error.go (there is no `civitai.ErrUsage`) — the item says so explicitly. DEPENDS ON #190: internal/cmd/app_metrics.go and internal/appapi/analytics.go exist only on `feat/app-metrics` and are NOT on main. Merge this AFTER #190 or AGENTS.md will describe a command the tree does not have. `make ci` green: tidy + vet clean, 16/16 packages ok, 0 FAIL; `gofmt -s -l` prints nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01858ymA3tEJQi83435u7npi
ZacxDev
added a commit
that referenced
this pull request
Aug 3, 2026
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01858ymA3tEJQi83435u7npi
ZacxDev
added a commit
that referenced
this pull request
Aug 3, 2026
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01858ymA3tEJQi83435u7npi
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds items 5–7 to
AGENTS.md→ "Intentional decisions that look wrong (read before 'fixing')", and updates the section's framing sentence (items 1–3 mirrors, 4 a deliberate non-mirror, 5–7 the analytics read path).5. It calls tRPC, not REST — because there is no REST route to call
Owner analytics exist only as
blocks.getMyAppAnalytics(civitai/civitai → src/server/routers/blocks.router.ts); there is no/api/v1equivalent. So the command resolves<slug>→appBlockIdthrough the existing RESTGET /api/v1/blocks/submissions, then issues the non-batched tRPC GET (?input={"json":{…}}, unwrappingresult.data.json) reusing theauthedDo+ envelope-unwrap patternGetForgejoCloneInfoalready established. Written down so nobody "fixes" the two-hop shape into a REST call that does not exist.6.
notOwnedis a cross-repo contractThe proc sits behind the
appBlocksAuthorfeature flag and answers a caller who isn't entitled (or doesn't own the app) with HTTP 200 and every counter zeroed, not an error — so a renderer that ignores the field prints a plausible empty dashboard for what is really a permission failure.runAppMetricsrefuses to render when it's true. Whoever changes that payload server-side has to keep the field.--jsondeliberately passes the payload through and still exits 0, so scripts must branch onnotOwnedthemselves.7. The exit-code contract needs
errors.Is, not message assertionsThe classification sentinels carry no visible text —
Tag/TagStatusattach them whileError()stays byte-for-byte identical (pkg/civitai/errkind.go) — so a message assertion says nothing about the exit code. Measured on #190: stripping the classification while leaving every message identical left the entire suite green, and the README's 403 → exit 3 / not-found → exit 4 promise was unpinned. Generalised in the text to any command claiming an exit code.One correction to the brief I was given, made from the code rather than paraphrased: there is no
civitai.ErrUsage. The HTTP kinds (ErrUnauthorized,ErrNotFound) live inpkg/civitai/errkind.go; the usage sentinel isErrUsageininternal/cmd/usage_error.go. The item states the split explicitly so the guidance is actionable rather than a name that won't compile.Verification
make cigreen in a clean worktree offorigin/main:go mod tidyandgo vetsilent, 16/16 packagesok, zeroFAIL, build succeeded.gofmt -s -l .prints nothing. Docs-only change, so no behaviour is claimed to be verified beyond the gate.🤖 Generated with Claude Code
https://claude.ai/code/session_01858ymA3tEJQi83435u7npi