Skip to content

feat(agent-setup): the managed block links example apps, as ONE docs URL - #549

Merged
ZacxDev merged 1 commit into
mainfrom
feat/agents-block-example-apps-link
Sep 11, 2026
Merged

feat(agent-setup): the managed block links example apps, as ONE docs URL#549
ZacxDev merged 1 commit into
mainfrom
feat/agents-block-example-apps-link

Conversation

@ZacxDev

@ZacxDev ZacxDev commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

🔴 DO NOT MERGE YET — the link this PR ships does not resolve

https://developer.civitai.com/apps/examples answers 404 today, with and
without a trailing slash, while the other three links in the same section answer
200. The docs page is authored in a separate repository, in parallel, and
is still an open PR there. Merge this only once the page is live, and re-run the
probe below to confirm — including the exact spelling, because the trailing
slash is load-bearing on that host (/apps/showcase is 200,
/apps/showcase/ is 404). If the docs side lands a different spelling, the URL
is in exactly two places (below) and both must move.

CIVITAI_CHECK_DOCS_LINKS=1 go test -count=1 -run TestBlockDocsLinksResolve -v ./internal/cmd/

What this does

civitai agent-setup's managed AGENTS.md block reached the guide, the
reference and llms.txt in its ### Docs section, and nothing in it reached a
worked example
. An author's agent had four sentences of gotchas and no App
Block it could read end to end. One line is added:

- Example apps you can read end-to-end:
  https://developer.civitai.com/apps/examples

🔴 ONE URL, never a list of repositories — and that is structural

The obvious "helpful" edit is to spell the seven example repos into the block.
It is refused because this block is written to disk in somebody else's
project
: a repo URL embedded here is copied into every directory agent-setup
has ever run in, and nothing can recall it — only another agent-setup run in
that same directory
rewrites the block, which most authors never do. A
docs-site page is corrected once, for every reader, by the people who own the
list. The CLI ships the address; the docs repo ships the contents.

Measured anonymously over real HTTP and recorded in the decision file:

Probe Result
developer.civitai.com/apps/guide/ 200 (positive control)
developer.civitai.com/apps/reference/ 200 (positive control)
developer.civitai.com/llms.txt 200 (positive control)
developer.civitai.com/apps/examples 404 — not live yet
developer.civitai.com/apps/showcase 200 (no trailing slash)
developer.civitai.com/apps/showcase/ 404 (with one)
civitai.com/models 200 (control: the site answers anonymous GETs)
civitai.com/apps 404
civitai.com/apps/run/gen-matrix 404

Three residuals follow, each of which killed a different candidate line:

  1. A run-URL is not an example. civitai.com/apps/run/<slug> 404s for a
    logged-out reader — and it does so because the whole /apps route family
    does, not because that slug is wrong. So the page links repositories, which
    an agent can clone and read, not running instances.
  2. /apps/showcase is the COMPONENT showcase, and was conflated with an
    example gallery in the handoff this came from. It answers 200, which is
    exactly what makes the conflation survivable — a link there resolves and sends
    the reader to the wrong thing.
  3. GitHub topics are already an unreliable enumeration, so "just query the
    topic" is not a durable substitute for a curated page: topic:civitai-app-block
    returns 6 repos, a different set from the seven example apps — two of the
    seven carry no topics, and one repo the query does return is not one of the
    seven.

Where the URL lives

Exactly two places, verified by grep across the repo:

  • internal/cmd/templates/agents-app.md — the literal that ships
  • wantDocsSection in internal/cmd/agent_setup_docs_test.go — the golden

Both failure messages name both files, so correcting the URL is those two edits.

Tests — internal/cmd/agent_setup_docs_test.go

  • TestTheBlocksDocsSectionIsPinnedForEveryProjectKind — pins the WHOLE
    normalised ### Docs section for every project shape (npm with and
    without recognised scripts, no-build, none). Per-shape because the
    template's three {{ if }} branches are what a mis-nested edit drops the
    section out of. Two assertions with different messages: the link SET, and
    the whole string — a word-level guard on prose is walkable by rewording,
    and the wording is the claim about what a reader gets from following the link.
  • TestDocsSectionExtractorCanFail — negative control for docsSectionOf,
    both directions.
  • TestBlockDocsLinksResolve — the liveness probe, opt-in behind
    CIVITAI_CHECK_DOCS_LINKS=1
    , following internal/scaffold's
    CIVITAI_CHECK_PUBLISHED_PINS pattern so an offline make ci stays green. It
    carries its own must-404 negative control and skips on transport failure
    ("the network is down" and "the page is gone" are different findings).
    🔴 No CI job sets it — editing .github/workflows/* is "ask first" in
    AGENTS.md — so it is a manual pre-merge check and nothing runs it on a
    schedule. Saying so is the honest version of "the links are verified".

Red/green matrix — four isolated mutations, each watched fail with its own assertion

# Mutation Red at Assertion that fired Isolation it proves
0 new test file only, template untouched origin/main 8e7d2dc docs_test.go:122 + :130, all 4 shapes the guard sees the missing line
A reword only (Example apps you can read end-to-end:Examples:), URLs untouched HEAD :130 only:122 did NOT fire the whole-string pin is reachable and not shadowed by the set assertion
B URL spelling only — one added trailing slash HEAD :122 and :130 the load-bearing character is caught
C Docs section wrapped in {{ if ne .Kind "no-build" }} HEAD :113, for no-build only — other 3 shapes green the per-shape loop genuinely reaches each branch separately
D docsSectionOf returns ("", true) when the heading is absent HEAD :156 ×2 the extractor's negative control is not vacuous

Mutation A's exact text:

--- FAIL: TestTheBlocksDocsSectionIsPinnedForEveryProjectKind
    agent_setup_docs_test.go:130: the `### Docs` section for kind "npm" is not what is pinned.
        ... - Example apps you can read end-to-end:  (want)
        ... - Examples:                              (got)
        The WHOLE section is pinned, not individual words, because a reworded line
        is still a changed claim about what a reader gets from following it.

Mutation C's exact text:

--- FAIL: TestTheBlocksDocsSectionIsPinnedForEveryProjectKind
    agent_setup_docs_test.go:113: the rendered block for kind "no-build" (0 recognised script(s))
        has NO `### Docs` section at all. Every branch of the template must keep it ...

All four restored; green at HEAD c2c1b7f.

Docs

Extends AGENTS.md item 36's trigger with the Docs-section situation rather
than minting item 39: item 36 is the managed block's content record and already
carries two such sections. Net +1 byteAGENTS.md is 30,443 of the
30,500 ceiling (agents_size_test.go), leaving 57 bytes of headroom; the
body goes in claudedocs/decisions/36-agents-block-per-project.md §"Third", which
costs zero session bytes.

README: grepped the three surfaces AGENTS.md names — the command table
(line 596), the exit-code table (generated from exitCodeDocs) and the
Troubleshooting index — plus every developer.civitai.com occurrence. Nothing
in the README enumerates the block's ### Docs section or its links
, and this
change adds no error string, exit code or flag, so no surface goes stale. The
narrative at §"Set up your coding agent" summarises the block as "the commands and
the gotchas", which already omitted Docs before this change.

Gates

  • make circ 0, 21 packages ok, build succeeded
  • make lint (nix-shell -p golangci-lint) — rc 0, 0 issues.
    Instrument validated: a deliberately unused func + empty branch made it report
    2 issues (staticcheck SA9003 + unused) and exit 1, then was reverted.
  • make ci-shallowrc 0 at c2c1b7f, 21/21 in a depth-1 clone (this
    touches AGENTS.md, which the git-history tests read)
  • gofmt -s -l . — clean, with a positive control confirming it still flags a
    malformed file

🤖 Generated with Claude Code

https://claude.ai/code/session_018mJg86oQbTwuyPo5zcq3qP

The block's `### Docs` section reached the guide, the reference and
`llms.txt`, and nothing in it reached a worked example. An author's agent
had four sentences of gotchas and no App Block it could read end to end.

Adds one line:

    - Example apps you can read end-to-end:
      https://developer.civitai.com/apps/examples

🔴 ONE URL, NEVER A LIST OF REPOSITORIES, AND THAT IS STRUCTURAL. This
block is written to disk in somebody else's project, so a repo URL
embedded here is copied into every directory `agent-setup` has ever run
in and nothing can recall it — only another `agent-setup` run in that
same directory rewrites it, which most authors never do. A docs-site
page is corrected once, for every reader, by the people who own the
list. The CLI ships the address; the docs repo ships the contents.

Measured, anonymously over real HTTP, and recorded in the decision file:
`civitai.com/apps` 404s (while `civitai.com/models` 200s), so a
`civitai.com/apps/run/<slug>` link is unreachable for a logged-out
reader and the page links repositories rather than running instances;
`topic:civitai-app-block` returns 6 repos, a different set from the
seven example apps, so the topic query is not a durable substitute;
and `/apps/showcase` is the COMPONENT showcase, not an example gallery.

🔴 THE LINK IS NOT LIVE YET. `developer.civitai.com/apps/examples`
answers 404, with and without a trailing slash, while the other three
links in the same section answer 200. The docs page is authored in a
separate repository in parallel. DO NOT MERGE until it resolves, and
note that the trailing slash is load-bearing on that host
(`/apps/showcase` is 200, `/apps/showcase/` is 404).

Guards (internal/cmd/agent_setup_docs_test.go):

- TestTheBlocksDocsSectionIsPinnedForEveryProjectKind pins the WHOLE
  normalised section for every project shape, since the template's three
  `{{ if }}` branches are what an edit can drop it out of. Two
  assertions: the link SET, and the whole string (prose reworded is a
  changed claim, and a word-level guard is walkable by rewording).
- TestDocsSectionExtractorCanFail is the extractor's control, both ways.
- TestBlockDocsLinksResolve probes the links, opt-in behind
  CIVITAI_CHECK_DOCS_LINKS=1 exactly like internal/scaffold's
  CIVITAI_CHECK_PUBLISHED_PINS, so an offline `make ci` stays green. It
  carries its own must-404 negative control and SKIPS on transport
  failure.

AGENTS.md item 36's trigger gains the Docs-section situation (+1 byte;
file is 30,443 of 30,500) rather than minting item 39: the item is the
managed block's content record and already carries two such sections.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018mJg86oQbTwuyPo5zcq3qP
@ZacxDev

ZacxDev commented Sep 11, 2026

Copy link
Copy Markdown
Contributor Author

✅ The merge gate is released — the page is live and the link resolves

The blocker at the top of this PR body ("the link this PR ships does not resolve")
is now satisfied, measured rather than assumed.

  • civitai/civitai-developer-docs#71 is MERGED (75035bce, 2026-09-11T05:42:46Z),
    15/15 checks green.
  • 🔴 MERGED ≠ SERVED, and the gap was measurable here. The origin kept serving the
    previous build for ~340 s after the merge — last-modified stayed pinned at
    Wed, 09 Sep 2026 18:33:36 GMT on every page, so this was the ORIGIN, not a CDN
    cache. For scale, the precedent is 91 s: ddb4729 merged 18:32:05Z and the site's
    last-modified moved to 18:33:36Z. Anyone re-running the probe inside the first
    five minutes would have read a correct deploy as a failed one.
  • The spelling in this PR is the right one, and the trailing slash is still load-bearing:
    …/apps/examples200, …/apps/examples/404. The block ships the
    no-slash form.
  • Verified by content, not just status: 88,641 B of text/html carrying all
    8 example repos (7 under ZacxDev/ + civitai/app-panorama-360).
    Negative control: …/apps/examples-nope404, so the 200 is about this page
    and not a catch-all route.

The opt-in probe this PR names — CI does not run it

CIVITAI_CHECK_DOCS_LINKS=1 go test -count=1 -run TestBlockDocsLinksResolve -v ./internal/cmd/
apps/guide/ -> 200 · apps/reference/ -> 200 · apps/examples -> 200 · llms.txt -> 200
--- PASS: TestBlockDocsLinksResolve

The guard was mutation-tested, because a green it cannot fail proves nothing

The handoff recorded agent_setup_docs_test.go as UNVERIFIED — no red/green matrix
was ever reported
. Closing that for the link assertion specifically: mutating the
shipped URL in templates/agents-app.md to a path that 404s makes the test fail with
its own message —

agent_setup_docs_test.go:243: DEAD LINK IN THE MANAGED BLOCK — this URL is written
into every project `civitai agent-setup` runs in, and nothing can recall it.

— and restoring the file returns it to green, with the other three links reporting 200
in both runs (so the failure is attributable to the mutated link, not a collapsed
harness). ⚠ Scope of that claim: it covers the link assertion. The remaining
assertions in this 256-line file were not individually mutation-tested, and this
comment does not claim they were.

Gate

make ci rc 0 (21 packages reported ok, against the workflow's floor of 15 —
so the suite ran rather than exiting 0 empty) · make lint rc 0, 0 issues
(make ci does not run lint).

@ZacxDev
ZacxDev merged commit 7b7d5f1 into main Sep 11, 2026
13 checks passed
@ZacxDev
ZacxDev deleted the feat/agents-block-example-apps-link branch September 11, 2026 05:52
ZacxDev added a commit that referenced this pull request Sep 11, 2026
…the link (#549 audit) (#553)

An adversarial audit of #549 found five defects in the GUARDS around the managed
block's `### Docs` section, not in the section itself. Each was reproduced on the
merged tree before it was fixed.

1. The gate could pass without probing the link it exists to check. The per-link
   loop did `case err != nil: t.Skipf(...)`, abandoning the whole run on the first
   transport error. With only the FIRST link's host made unresolvable and
   `/apps/examples` pointed at a known-404 path, the pre-change test printed one
   skip line and exited `ok` — the dead link was never fetched. Every link is now
   probed before anything is diagnosed; transport errors are collected per URL and
   a run that could not reach them all reports SKIP with `checked n of m`.

2. Negative control present, positive control absent. `mustNotResolve >= 400` is
   satisfied by an edge that 403s everything — which is also what makes every real
   link >= 400. Against a local server answering 403 to every path, the pre-change
   test emitted four `DEAD LINK IN THE MANAGED BLOCK … correct it in
   internal/cmd/templates/agents-app.md` errors, the exact wrong instruction; this
   host is known to hard-block non-browser agents with Cloudflare `error code:
   1010`. Statuses are now split into gone (404/410) and CANNOT TELL
   (401/403/429/5xx), with different messages, and the run skips rather than
   guesses when no link answered < 300.

3. The probe followed redirects while the comment claimed the spelling was
   measured. Go's default CheckRedirect follows up to 10 hops; `/apps/guide`
   301s to `http://developer.civitai.com/apps/guide/` — a different spelling AND a
   downgrade to cleartext http — which a following probe scores as a clean 200.
   CheckRedirect now returns ErrUseLastResponse and a 3xx is reported as MOVED,
   with its Location.

   The comment at the foot of the file also carried a false measurement: it said
   `/apps/showcase` is 200 while `/apps/showcase/` 404s (true) "while `/apps/guide/`
   is the other way round", implying `/apps/guide` 404s. It does not — it 301s.
   Re-measured all nine paths; the claim is withdrawn, not replaced with a
   narrower one, because the table shows no rule to state.

4. "Correcting the URL is those two edits and nothing else" was false when it was
   written — #549 itself added a third spelling, in
   claudedocs/decisions/36-agents-block-per-project.md. Measured over the whole
   tree, ignored files included: 9 lines in 4 files name
   developer.civitai.com/apps/examples. Replaced by
   `TestEveryDocsURLSpellingIsLedgered`, a bidirectional ledger that walks the
   repo and fails both when an unledgered file spells a docs URL and when a
   ledgered one stops. Dated `claudedocs/handoff-` records are exempt: they record
   what was true when written and are not corrected.

5. The three-branch control counted shapes, not kinds. `len(shapes) < 3` is
   satisfied by three shapes of one kind. The wanted set is now read from
   `agent_setup_project.go`'s own `projectKind` constants — which also repairs an
   adjacent comment the audit flagged: `allProjectShapesForTest` claimed to be
   "derived from the projectKind constants' own list rather than from a literal"
   while being a literal. `TestAllProjectShapesCoversEveryDeclaredKind` is the
   derivation that makes the sentence true.

Red-then-green matrix, `make ci` and `make lint` output are in the PR body.


Claude-Session: https://claude.ai/code/session_018mJg86oQbTwuyPo5zcq3qP

Co-authored-by: Claude Opus 5 <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