[object Object]

← back to Cli Printing Press

test(cli): add golden coverage for generated artifacts (#345)

8617e06dc9336edd2a7987eab2f3c20167259637 · 2026-04-27 10:54:13 -0700 · Trevin Chow

Files touched

Diff

commit 8617e06dc9336edd2a7987eab2f3c20167259637
Author: Trevin Chow <trevin@trevinchow.com>
Date:   Mon Apr 27 10:54:13 2026 -0700

    test(cli): add golden coverage for generated artifacts (#345)
---
 .../golden/cases/generate-golden-api/artifacts.txt |   4 +
 .../cases/schema-traffic-analysis/artifacts.txt    |   1 +
 .../cases/schema-traffic-analysis/command.txt      |   1 +
 .../printing-press-golden/README.md                | 155 +++++++
 .../printing-press-golden/SKILL.md                 | 166 ++++++++
 .../printing-press-golden/internal/cli/doctor.go   | 451 +++++++++++++++++++++
 .../internal/cliutil/verifyenv.go                  |  30 ++
 .../expected/schema-traffic-analysis/exit.txt      |   1 +
 .../expected/schema-traffic-analysis/stderr.txt    |   0
 .../expected/schema-traffic-analysis/stdout.txt    | 185 +++++++++
 10 files changed, 994 insertions(+)

diff --git a/testdata/golden/cases/generate-golden-api/artifacts.txt b/testdata/golden/cases/generate-golden-api/artifacts.txt
index bd427844..35129396 100644
--- a/testdata/golden/cases/generate-golden-api/artifacts.txt
+++ b/testdata/golden/cases/generate-golden-api/artifacts.txt
@@ -16,3 +16,7 @@ printing-press-golden/internal/mcp/tools.go
 printing-press-golden/internal/types/types.go
 dogfood.json
 scorecard.json
+printing-press-golden/README.md
+printing-press-golden/SKILL.md
+printing-press-golden/internal/cli/doctor.go
+printing-press-golden/internal/cliutil/verifyenv.go
diff --git a/testdata/golden/cases/schema-traffic-analysis/artifacts.txt b/testdata/golden/cases/schema-traffic-analysis/artifacts.txt
new file mode 100644
index 00000000..a96ba8e2
--- /dev/null
+++ b/testdata/golden/cases/schema-traffic-analysis/artifacts.txt
@@ -0,0 +1 @@
+# no extra artifacts
diff --git a/testdata/golden/cases/schema-traffic-analysis/command.txt b/testdata/golden/cases/schema-traffic-analysis/command.txt
new file mode 100644
index 00000000..de9c131b
--- /dev/null
+++ b/testdata/golden/cases/schema-traffic-analysis/command.txt
@@ -0,0 +1 @@
+"$BINARY" schema traffic-analysis
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/README.md b/testdata/golden/expected/generate-golden-api/printing-press-golden/README.md
new file mode 100644
index 00000000..58992484
--- /dev/null
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/README.md
@@ -0,0 +1,155 @@
+# Printing Press Golden CLI
+
+Purpose-built fixture for golden generation coverage.
+
+## Install
+
+### Go
+
+```
+go install github.com/mvanhorn/printing-press-library/library/other/printing-press-golden-pp-cli/cmd/printing-press-golden-pp-cli@latest
+```
+
+### Binary
+
+Download from [Releases](https://github.com/mvanhorn/printing-press-library/releases).
+
+## Quick Start
+
+### 1. Install
+
+See [Install](#install) above.
+
+### 2. Set Up Credentials
+
+Get your API key from your API provider's developer portal. The key typically looks like a long alphanumeric string.
+
+```bash
+export PRINTING_PRESS_GOLDEN_API_KEY_AUTH="<paste-your-key>"
+```
+
+You can also persist this in your config file at `~/.config/printing-press-golden-pp-cli/config.toml`.
+
+### 3. Verify Setup
+
+```bash
+printing-press-golden-pp-cli doctor
+```
+
+This checks your configuration and credentials.
+
+### 4. Try Your First Command
+
+```bash
+printing-press-golden-pp-cli projects list
+```
+
+## Usage
+
+Run `printing-press-golden-pp-cli --help` for the full command reference and flag list.
+
+## Commands
+
+### projects
+
+Manage projects
+
+- **`printing-press-golden-pp-cli projects create`** - Create project
+- **`printing-press-golden-pp-cli projects get`** - Get project
+- **`printing-press-golden-pp-cli projects list`** - List projects
+
+### public
+
+Manage public
+
+- **`printing-press-golden-pp-cli public get-status`** - Get public service status
+
+
+## Output Formats
+
+```bash
+# Human-readable table (default in terminal, JSON when piped)
+printing-press-golden-pp-cli projects list
+
+# JSON for scripting and agents
+printing-press-golden-pp-cli projects list --json
+
+# Filter to specific fields
+printing-press-golden-pp-cli projects list --json --select id,name,status
+
+# Dry run — show the request without sending
+printing-press-golden-pp-cli projects list --dry-run
+
+# Agent mode — JSON + compact + no prompts in one flag
+printing-press-golden-pp-cli projects list --agent
+```
+
+## Agent Usage
+
+This CLI is designed for AI agent consumption:
+
+- **Non-interactive** - never prompts, every input is a flag
+- **Pipeable** - `--json` output to stdout, errors to stderr
+- **Filterable** - `--select id,name` returns only fields you need
+- **Previewable** - `--dry-run` shows the request without sending
+- **Retryable** - creates return "already exists" on retry, deletes return "already deleted"
+- **Confirmable** - `--yes` for explicit confirmation of destructive actions
+- **Piped input** - write commands can accept structured input when their help lists `--stdin`
+- **Offline-friendly** - sync/search commands can use the local SQLite store when available
+- **Agent-safe by default** - no colors or formatting unless `--human-friendly` is set
+
+Exit codes: `0` success, `2` usage error, `3` not found, `4` auth error, `5` API error, `7` rate limited, `10` config error.
+
+## Use as MCP Server
+
+This CLI ships a companion MCP server for use with Claude Desktop, Cursor, and other MCP-compatible tools.
+
+### Claude Code
+
+```bash
+claude mcp add printing-press-golden printing-press-golden-pp-mcp -e PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>
+```
+
+### Claude Desktop
+
+Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
+
+```json
+{
+  "mcpServers": {
+    "printing-press-golden": {
+      "command": "printing-press-golden-pp-mcp",
+      "env": {
+        "PRINTING_PRESS_GOLDEN_API_KEY_AUTH": "<your-key>"
+      }
+    }
+  }
+}
+```
+
+## Health Check
+
+```bash
+printing-press-golden-pp-cli doctor
+```
+
+Verifies configuration, credentials, and connectivity to the API.
+
+## Configuration
+
+Config file: `~/.config/printing-press-golden-pp-cli/config.toml`
+
+Environment variables:
+- `PRINTING_PRESS_GOLDEN_API_KEY_AUTH`
+
+## Troubleshooting
+**Authentication errors (exit code 4)**
+- Run `printing-press-golden-pp-cli doctor` to check credentials
+- Verify the environment variable is set: `echo $PRINTING_PRESS_GOLDEN_API_KEY_AUTH`
+**Not found errors (exit code 3)**
+- Check the resource ID is correct
+- Run the `list` command to see available items
+
+---
+
+Generated by [CLI Printing Press](https://github.com/mvanhorn/cli-printing-press)
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/SKILL.md b/testdata/golden/expected/generate-golden-api/printing-press-golden/SKILL.md
new file mode 100644
index 00000000..f247cdc3
--- /dev/null
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/SKILL.md
@@ -0,0 +1,166 @@
+---
+name: pp-printing-press-golden
+description: "Printing Press CLI for Printing Press Golden. Purpose-built fixture for golden generation coverage."
+argument-hint: "<command> [args] | install cli|mcp"
+allowed-tools: "Read Bash"
+metadata: '{"openclaw":{"requires":{"bins":["printing-press-golden-pp-cli"]},"install":[{"id":"go","kind":"shell","command":"go install github.com/mvanhorn/printing-press-library/library/other/printing-press-golden-pp-cli/cmd/printing-press-golden-pp-cli@latest","bins":["printing-press-golden-pp-cli"],"label":"Install via go install"}]}}'
+---
+
+# Printing Press Golden — Printing Press CLI
+
+Purpose-built fixture for golden generation coverage.
+
+## Command Reference
+
+**projects** — Manage projects
+
+- `printing-press-golden-pp-cli projects create` — Create project
+- `printing-press-golden-pp-cli projects get` — Get project
+- `printing-press-golden-pp-cli projects list` — List projects
+
+**public** — Manage public
+
+- `printing-press-golden-pp-cli public` — Get public service status
+
+
+### Finding the right command
+
+When you know what you want to do but not which command does it, ask the CLI directly:
+
+```bash
+printing-press-golden-pp-cli which "<capability in your own words>"
+```
+
+`which` resolves a natural-language capability query to the best matching command from this CLI's curated feature index. Exit code `0` means at least one match; exit code `2` means no confident match — fall back to `--help` or use a narrower query.
+
+## Auth Setup
+
+Set your API key via environment variable:
+
+```bash
+export PRINTING_PRESS_GOLDEN_API_KEY_AUTH="<your-key>"
+```
+
+Or persist it in `~/.config/printing-press-golden-pp-cli/config.toml`.
+
+Run `printing-press-golden-pp-cli doctor` to verify setup.
+
+## Agent Mode
+
+Add `--agent` to any command. Expands to: `--json --compact --no-input --no-color --yes`.
+
+- **Pipeable** — JSON on stdout, errors on stderr
+- **Filterable** — `--select` keeps a subset of fields. Dotted paths descend into nested structures; arrays traverse element-wise. Critical for keeping context small on verbose APIs:
+
+  ```bash
+  printing-press-golden-pp-cli projects list --agent --select id,name,status
+  ```
+- **Previewable** — `--dry-run` shows the request without sending
+- **Offline-friendly** — sync/search commands can use the local SQLite store when available
+- **Non-interactive** — never prompts, every input is a flag
+
+### Response envelope
+
+Commands that read from the local store or the API wrap output in a provenance envelope:
+
+```json
+{
+  "meta": {"source": "live" | "local", "synced_at": "...", "reason": "..."},
+  "results": <data>
+}
+```
+
+Parse `.results` for data and `.meta.source` to know whether it's live or local. A human-readable `N results (live)` summary is printed to stderr only when stdout is a terminal — piped/agent consumers get pure JSON on stdout.
+
+## Agent Feedback
+
+When you (or the agent) notice something off about this CLI, record it:
+
+```
+printing-press-golden-pp-cli feedback "the --since flag is inclusive but docs say exclusive"
+printing-press-golden-pp-cli feedback --stdin < notes.txt
+printing-press-golden-pp-cli feedback list --json --limit 10
+```
+
+Entries are stored locally at `~/.printing-press-golden-pp-cli/feedback.jsonl`. They are never POSTed unless `PRINTING_PRESS_GOLDEN_FEEDBACK_ENDPOINT` is set AND either `--send` is passed or `PRINTING_PRESS_GOLDEN_FEEDBACK_AUTO_SEND=true`. Default behavior is local-only.
+
+Write what *surprised* you, not a bug report. Short, specific, one line: that is the part that compounds.
+
+## Output Delivery
+
+Every command accepts `--deliver <sink>`. The output goes to the named sink in addition to (or instead of) stdout, so agents can route command results without hand-piping. Three sinks are supported:
+
+| Sink | Effect |
+|------|--------|
+| `stdout` | Default; write to stdout only |
+| `file:<path>` | Atomically write output to `<path>` (tmp + rename) |
+| `webhook:<url>` | POST the output body to the URL (`application/json` or `application/x-ndjson` when `--compact`) |
+
+Unknown schemes are refused with a structured error naming the supported set. Webhook failures return non-zero and log the URL + HTTP status on stderr.
+
+## Named Profiles
+
+A profile is a saved set of flag values, reused across invocations. Use it when a scheduled agent calls the same command every run with the same configuration - HeyGen's "Beacon" pattern.
+
+```
+printing-press-golden-pp-cli profile save briefing --json
+printing-press-golden-pp-cli --profile briefing projects list
+printing-press-golden-pp-cli profile list --json
+printing-press-golden-pp-cli profile show briefing
+printing-press-golden-pp-cli profile delete briefing --yes
+```
+
+Explicit flags always win over profile values; profile values win over defaults. `agent-context` lists all available profiles under `available_profiles` so introspecting agents discover them at runtime.
+
+## Exit Codes
+
+| Code | Meaning |
+|------|---------|
+| 0 | Success |
+| 2 | Usage error (wrong arguments) |
+| 3 | Resource not found |
+| 4 | Authentication required |
+| 5 | API error (upstream issue) |
+| 7 | Rate limited (wait and retry) |
+| 10 | Config error |
+
+## Argument Parsing
+
+Parse `$ARGUMENTS`:
+
+1. **Empty, `help`, or `--help`** → show `printing-press-golden-pp-cli --help` output
+2. **Starts with `install`** → ends with `mcp` → MCP installation; otherwise → CLI installation
+3. **Anything else** → Direct Use (execute as CLI command with `--agent`)
+
+## CLI Installation
+
+1. Check Go is installed: `go version` (requires Go 1.23+)
+2. Install:
+   ```bash
+   go install github.com/mvanhorn/printing-press-library/library/other/printing-press-golden-pp-cli/cmd/printing-press-golden-pp-cli@latest
+   ```
+3. Verify: `printing-press-golden-pp-cli --version`
+4. Ensure `$GOPATH/bin` (or `$HOME/go/bin`) is on `$PATH`.
+
+## MCP Server Installation
+
+1. Install the MCP server:
+   ```bash
+   go install github.com/mvanhorn/printing-press-library/library/other/printing-press-golden-pp-cli/cmd/printing-press-golden-pp-mcp@latest
+   ```
+2. Register with Claude Code:
+   ```bash
+   claude mcp add printing-press-golden-pp-mcp -- printing-press-golden-pp-mcp
+   ```
+3. Verify: `claude mcp list`
+
+## Direct Use
+
+1. Check if installed: `which printing-press-golden-pp-cli`
+   If not found, offer to install (see CLI Installation above).
+2. Match the user query to the best command from the Unique Capabilities and Command Reference above.
+3. Execute with the `--agent` flag:
+   ```bash
+   printing-press-golden-pp-cli <command> [subcommand] [args] --agent
+   ```
+4. If ambiguous, drill into subcommand help: `printing-press-golden-pp-cli <command> --help`.
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/doctor.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/doctor.go
new file mode 100644
index 00000000..5d7afdcd
--- /dev/null
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cli/doctor.go
@@ -0,0 +1,451 @@
+// Copyright 2026 printing-press-golden. Licensed under Apache-2.0. See LICENSE.
+// Generated by CLI Printing Press (https://github.com/mvanhorn/cli-printing-press). DO NOT EDIT.
+
+package cli
+
+import (
+	"database/sql"
+	"errors"
+	"fmt"
+	"io"
+	"os"
+	"strings"
+	"time"
+
+	"printing-press-golden-pp-cli/internal/client"
+	"printing-press-golden-pp-cli/internal/config"
+	"printing-press-golden-pp-cli/internal/store"
+	"github.com/spf13/cobra"
+)
+
+// looksLikeDoctorInterstitial reports whether the response body matches a known
+// bot-detection challenge page (Cloudflare, Akamai, Vercel, AWS WAF, DataDome,
+// PerimeterX). Only fires on the doctor probe — used to distinguish "transport
+// reached the wall" from "transport failed entirely." Returns the vendor name
+// when matched, or empty string when no match.
+//
+// Markers are anchored to <title> or vendor-specific strings to avoid
+// false-positives on benign content. For example, a recipe titled "Just A
+// Moment of Pause Cookies" must NOT match the Cloudflare challenge marker;
+// only "<title>just a moment" (the actual interstitial title) does.
+func looksLikeDoctorInterstitial(body []byte) string {
+	if len(body) == 0 {
+		return ""
+	}
+	limit := len(body)
+	if limit > 8192 {
+		limit = 8192
+	}
+	prefix := strings.ToLower(string(body[:limit]))
+	if !strings.Contains(prefix, "<title") {
+		// Every bot interstitial we recognize sets a <title>; bodies without
+		// one are body-only API responses, not challenge pages.
+		return ""
+	}
+	switch {
+	case strings.Contains(prefix, "<title>just a moment") || // CF JS challenge
+		strings.Contains(prefix, "challenges.cloudflare.com") || // CF Turnstile
+		(strings.Contains(prefix, "attention required") && strings.Contains(prefix, "cloudflare")):
+		return "Cloudflare"
+	case strings.Contains(prefix, "akamai") && (strings.Contains(prefix, "request unsuccessful") || strings.Contains(prefix, "access denied")):
+		return "Akamai"
+	case strings.Contains(prefix, "x-vercel-mitigated") || strings.Contains(prefix, "x-vercel-challenge-token") ||
+		(strings.Contains(prefix, "vercel") && strings.Contains(prefix, "challenge")):
+		return "Vercel"
+	case strings.Contains(prefix, "request blocked") && strings.Contains(prefix, "aws waf"):
+		return "AWS WAF"
+	case strings.Contains(prefix, "datadome") && (strings.Contains(prefix, "blocked") || strings.Contains(prefix, "captcha") || strings.Contains(prefix, "challenge")):
+		return "DataDome"
+	case strings.Contains(prefix, "perimeterx") || strings.Contains(prefix, "px-captcha"):
+		return "PerimeterX"
+	}
+	return ""
+}
+
+func newDoctorCmd(flags *rootFlags) *cobra.Command {
+	var failOn string
+	cmd := &cobra.Command{
+		Use:   "doctor",
+		Short: "Check CLI health",
+		RunE: func(cmd *cobra.Command, args []string) error {
+			report := map[string]any{}
+
+			// Check config
+			cfg, err := config.Load(flags.configPath)
+			if err != nil {
+				report["config"] = fmt.Sprintf("error: %s", err)
+			} else {
+				report["config"] = "ok"
+				report["config_path"] = cfg.Path
+				report["base_url"] = cfg.BaseURL
+			}
+
+			// Check auth
+			if cfg != nil {
+				header := cfg.AuthHeader()
+				if header == "" {
+					report["auth"] = "not configured"
+					report["auth_hint"] = "export PRINTING_PRESS_GOLDEN_API_KEY_AUTH=<your-key>"
+				} else {
+					report["auth"] = "configured"
+					report["auth_source"] = cfg.AuthSource
+				}
+			}
+
+			// Check auth environment variables
+			authEnvChecked := 0
+			authEnvSet := 0
+			authEnvChecked++
+			if os.Getenv("PRINTING_PRESS_GOLDEN_API_KEY_AUTH") != "" {
+				authEnvSet++
+			}
+			if authEnvSet == 0 {
+				report["env_vars"] = fmt.Sprintf("none set (checked %d)", authEnvChecked)
+			} else {
+				report["env_vars"] = fmt.Sprintf("%d/%d set", authEnvSet, authEnvChecked)
+			}
+
+			// Check API connectivity and validate credentials.
+			//
+			// The doctor uses the same client every other command uses --
+			// flags.newClient() returns a *client.Client wrapping whatever
+			// transport the spec declared (Surf for browser-chrome, stdlib
+			// for standard). A separate stdlib http.Client would silently
+			// bypass that choice and report false negatives against
+			// Cloudflare-fronted, Akamai-fronted, or otherwise bot-detected
+			// sites. By going through flags.newClient(), the doctor's
+			// reachability verdict matches what real commands experience.
+			if cfg != nil && cfg.BaseURL != "" {
+				c, clientErr := flags.newClient()
+				if clientErr != nil {
+					report["api"] = fmt.Sprintf("client init error: %s", clientErr)
+				} else {
+					// Step 1: Basic reachability via the configured transport.
+					reachBody, reachErr := c.Get("/", nil)
+					var reachAPIErr *client.APIError
+					switch {
+					case reachErr == nil:
+						// 2xx response — clearly reachable. Still inspect the
+						// body for a known interstitial; some bot walls return
+						// 200 with a JS challenge page.
+						if vendor := looksLikeDoctorInterstitial(reachBody); vendor != "" {
+							report["api"] = fmt.Sprintf("blocked by %s interstitial — the configured transport reached the wall. Try a different network, wait for the IP-level rate limit to clear, or check that the browser-chrome transport is bound correctly.", vendor)
+						} else {
+							report["api"] = "reachable"
+						}
+					case errors.As(reachErr, &reachAPIErr):
+						// Non-2xx from the server. The network reached, the
+						// server responded — that's "reachable" for our
+						// purposes. Inspect the response body for a known
+						// interstitial first; otherwise note the status.
+						status := reachAPIErr.StatusCode
+						if vendor := looksLikeDoctorInterstitial([]byte(reachAPIErr.Body)); vendor != "" {
+							report["api"] = fmt.Sprintf("blocked by %s interstitial (HTTP %d) — the configured transport reached the wall.", vendor, status)
+						} else {
+							report["api"] = fmt.Sprintf("reachable (HTTP %d at /)", status)
+						}
+					default:
+						// Network-level failure: DNS, connection refused, TLS,
+						// transport init, etc. The transport itself didn't
+						// connect.
+						report["api"] = fmt.Sprintf("unreachable: %s", reachErr)
+					}
+
+					// Step 2: Validate credentials with an authenticated probe.
+					authHeader := cfg.AuthHeader()
+					if authHeader == "" {
+						// No auth configured — skip credential validation
+					} else if reachErr != nil && !errors.As(reachErr, &reachAPIErr) {
+						report["credentials"] = "skipped (API unreachable)"
+					} else {
+						verifyPath := "/"
+						authParams := map[string]string{}
+						authHeaders := map[string]string{}
+						authHeaders["X-API-Key"] = authHeader
+						authHeaders["X-Api-Version"] = "2026-04-01"
+						authHeaders["User-Agent"] = "printing-press-golden-pp-cli"
+						_, authErr := c.GetWithHeaders(verifyPath, authParams, authHeaders)
+						var authAPIErr *client.APIError
+						switch {
+						case authErr == nil:
+							report["credentials"] = "valid"
+						case errors.As(authErr, &authAPIErr):
+							switch {
+							case authAPIErr.StatusCode == 401 || authAPIErr.StatusCode == 403:
+								// The probe hit the bare base URL because no auth.verify_path
+								// is configured in the spec. Many APIs return 401/403 from a
+								// bare versioned root regardless of token validity (the path
+								// isn't routed but the gateway still demands credentials).
+								// Don't claim invalid without certainty — set verify_path to
+								// a known-good authenticated GET (e.g. /me, /v1/account, /user)
+								// for a definitive verdict.
+								report["credentials"] = fmt.Sprintf("inconclusive (HTTP %d from base URL — set auth.verify_path in spec for a definitive probe)", authAPIErr.StatusCode)
+							default:
+								// Non-auth HTTP error (404, 500, etc.) — don't blame credentials
+								report["credentials"] = fmt.Sprintf("ok (HTTP %d from %s, but auth was accepted)", authAPIErr.StatusCode, verifyPath)
+							}
+						default:
+							report["credentials"] = fmt.Sprintf("error: %s", authErr)
+						}
+					}
+				}
+			} else if cfg != nil && cfg.BaseURL == "" {
+				report["api"] = "not configured (set base_url in config file)"
+			}
+			// Cache health: only reported when this CLI has a local store.
+			// Surfaces rows + last_synced_at per resource, schema version,
+			// and a fresh/stale/unknown verdict so agents can introspect
+			// whether to trust the cached data before issuing queries.
+			report["cache"] = collectCacheReport("")
+
+			report["version"] = version
+
+			if flags.asJSON {
+				if err := flags.printJSON(cmd, report); err != nil {
+					return err
+				}
+				return doctorExitForFailOn(failOn, report)
+			}
+
+			// Human-readable output with color
+			w := cmd.OutOrStdout()
+			checkKeys := []struct{ key, label string }{
+				{"config", "Config"},
+				{"auth", "Auth"},
+				{"api", "API"},
+				{"credentials", "Credentials"},
+			}
+			for _, ck := range checkKeys {
+				v, ok := report[ck.key]
+				if !ok {
+					continue
+				}
+				s := fmt.Sprintf("%v", v)
+				indicator := green("OK")
+				switch {
+				case strings.HasPrefix(s, "optional"):
+					// Optional-auth CLI with no key set — informational, not a failure.
+					indicator = yellow("INFO")
+				case strings.HasPrefix(s, "inconclusive"):
+					// The credential probe could not produce a definitive verdict
+					// (typically because the bare base URL returns 401/403 even for
+					// valid tokens). Surface as WARN, not FAIL — the user's actual
+					// commands will reveal a real auth failure if one exists.
+					indicator = yellow("WARN")
+				case strings.Contains(s, "error") || strings.Contains(s, "not configured") || strings.Contains(s, "unreachable") || strings.Contains(s, "invalid") || strings.Contains(s, "missing"):
+					indicator = red("FAIL")
+				case s == "not required":
+					// Public APIs: no auth needed is a healthy state, not a warning.
+					indicator = green("OK")
+				case strings.Contains(s, "not ") || strings.Contains(s, "skipped") || strings.Contains(s, "inferred"):
+					indicator = yellow("WARN")
+				}
+				fmt.Fprintf(w, "  %s %s: %s\n", indicator, ck.label, s)
+			}
+			// Print info keys without status indicator
+			for _, key := range []string{"config_path", "base_url", "auth_source", "version"} {
+				if v, ok := report[key]; ok {
+					fmt.Fprintf(w, "  %s: %v\n", key, v)
+				}
+			}
+			// Print auth setup hints (indented under Auth line)
+			if hint, ok := report["auth_hint"]; ok {
+				fmt.Fprintf(w, "  hint: %v\n", hint)
+			}
+			// Cache section: render after the primary health block so it
+			// sits next to version info, mirroring the JSON report layout.
+			if cacheAny, ok := report["cache"]; ok {
+				if cacheRep, ok := cacheAny.(map[string]any); ok {
+					renderCacheReport(w, cacheRep)
+				}
+			}
+			return doctorExitForFailOn(failOn, report)
+		},
+	}
+	cmd.Flags().StringVar(&failOn, "fail-on", "", "Exit non-zero when a health level is reached: stale, error. Default is never.")
+	return cmd
+}
+
+// doctorExitForFailOn returns a non-nil error when the report's worst
+// status meets or exceeds the --fail-on threshold. "error" always trips
+// when any section reports an error; "stale" also trips when the cache
+// section is stale. The default empty string means never fail on status.
+func doctorExitForFailOn(failOn string, report map[string]any) error {
+	if failOn == "" {
+		return nil
+	}
+	worstError := false
+	worstStale := false
+	for _, v := range report {
+		s, ok := v.(string)
+		if ok {
+			if strings.Contains(s, "error") || strings.Contains(s, "unreachable") || strings.Contains(s, "invalid") || strings.Contains(s, "missing") {
+				worstError = true
+			}
+		}
+		if m, ok := v.(map[string]any); ok {
+			if st, _ := m["status"].(string); st == "error" {
+				worstError = true
+			} else if st == "stale" {
+				worstStale = true
+			}
+		}
+	}
+	switch failOn {
+	case "error":
+		if worstError {
+			return fmt.Errorf("doctor: --fail-on=error triggered")
+		}
+	case "stale":
+		if worstError || worstStale {
+			return fmt.Errorf("doctor: --fail-on=stale triggered")
+		}
+	default:
+		return fmt.Errorf("doctor: unknown --fail-on value %q (valid: stale, error)", failOn)
+	}
+	return nil
+}
+
+// collectCacheReport opens the local store, reads per-resource sync state,
+// and returns a map summarising cache health. Never panics on missing DB
+// or open failure; returns a map with status=unknown or status=error so the
+// caller can render and agents can interpret.
+//
+// staleAfterSpec is the CLI's configured threshold (e.g. "6h"); empty means
+// use the runtime default. The default is deliberately conservative (6h)
+// because the alternative is no freshness story at all.
+func collectCacheReport(staleAfterSpec string) map[string]any {
+	report := map[string]any{}
+	dbPath := defaultDBPath("printing-press-golden-pp-cli")
+	report["db_path"] = dbPath
+
+	fi, err := os.Stat(dbPath)
+	if err != nil {
+		if os.IsNotExist(err) {
+			report["status"] = "unknown"
+			report["hint"] = "Database not created yet; run 'printing-press-golden-pp-cli sync' to hydrate."
+			return report
+		}
+		report["status"] = "error"
+		report["error"] = err.Error()
+		return report
+	}
+	report["db_bytes"] = fi.Size()
+
+	s, err := store.Open(dbPath)
+	if err != nil {
+		report["status"] = "error"
+		report["error"] = err.Error()
+		return report
+	}
+	defer s.Close()
+
+	if v, verr := s.SchemaVersion(); verr == nil {
+		report["schema_version"] = v
+	}
+
+	staleAfter := 6 * time.Hour
+	if staleAfterSpec != "" {
+		if d, derr := time.ParseDuration(staleAfterSpec); derr == nil {
+			staleAfter = d
+		}
+	}
+
+	rows, qerr := s.DB().Query(`SELECT resource_type, COALESCE(total_count, 0), last_synced_at FROM sync_state ORDER BY resource_type`)
+	if qerr != nil {
+		// sync_state may not exist on a fresh DB that has migrated but not
+		// yet had any sync runs — treat as unknown rather than error.
+		report["status"] = "unknown"
+		report["hint"] = "No sync state recorded; run 'printing-press-golden-pp-cli sync' to populate."
+		return report
+	}
+	defer rows.Close()
+
+	var resources []map[string]any
+	fresh := true
+	haveAny := false
+	oldest := time.Duration(0)
+	for rows.Next() {
+		var rtype string
+		var count int64
+		var lastSynced sql.NullTime
+		if err := rows.Scan(&rtype, &count, &lastSynced); err != nil {
+			continue
+		}
+		r := map[string]any{"type": rtype, "rows": count}
+		if lastSynced.Valid {
+			haveAny = true
+			r["last_synced_at"] = lastSynced.Time.UTC().Format(time.RFC3339)
+			age := time.Since(lastSynced.Time)
+			r["staleness"] = age.Round(time.Minute).String()
+			if age > staleAfter {
+				fresh = false
+			}
+			if age > oldest {
+				oldest = age
+			}
+		} else {
+			r["staleness"] = "never"
+			fresh = false
+		}
+		resources = append(resources, r)
+	}
+	report["resources"] = resources
+	report["stale_after"] = staleAfter.String()
+
+	switch {
+	case !haveAny && len(resources) == 0:
+		report["status"] = "unknown"
+		report["hint"] = "sync_state is empty; run 'printing-press-golden-pp-cli sync' to hydrate."
+	case fresh:
+		report["status"] = "fresh"
+	default:
+		report["status"] = "stale"
+		report["oldest_age"] = oldest.Round(time.Minute).String()
+		report["hint"] = "Some resources are older than stale_after; run 'printing-press-golden-pp-cli sync' to refresh."
+	}
+	return report
+}
+
+func renderCacheReport(w io.Writer, rep map[string]any) {
+	status, _ := rep["status"].(string)
+	indicator := green("OK")
+	switch status {
+	case "stale":
+		indicator = yellow("WARN")
+	case "error":
+		indicator = red("FAIL")
+	case "unknown":
+		indicator = yellow("INFO")
+	}
+	fmt.Fprintf(w, "  %s Cache: %s\n", indicator, status)
+	if v, ok := rep["db_path"]; ok {
+		fmt.Fprintf(w, "    db_path: %v\n", v)
+	}
+	if v, ok := rep["schema_version"]; ok {
+		fmt.Fprintf(w, "    schema_version: %v\n", v)
+	}
+	if v, ok := rep["db_bytes"]; ok {
+		fmt.Fprintf(w, "    db_bytes: %v\n", v)
+	}
+	if v, ok := rep["stale_after"]; ok {
+		fmt.Fprintf(w, "    stale_after: %v\n", v)
+	}
+	if v, ok := rep["oldest_age"]; ok {
+		fmt.Fprintf(w, "    oldest_age: %v\n", v)
+	}
+	if resourcesAny, ok := rep["resources"]; ok {
+		if resources, ok := resourcesAny.([]map[string]any); ok && len(resources) > 0 {
+			fmt.Fprintf(w, "    resources:\n")
+			for _, r := range resources {
+				rtype, _ := r["type"].(string)
+				rows := r["rows"]
+				staleness, _ := r["staleness"].(string)
+				fmt.Fprintf(w, "      - %s: %v rows, %s\n", rtype, rows, staleness)
+			}
+		}
+	}
+	if hint, ok := rep["hint"]; ok {
+		fmt.Fprintf(w, "    hint: %v\n", hint)
+	}
+}
diff --git a/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cliutil/verifyenv.go b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cliutil/verifyenv.go
new file mode 100644
index 00000000..fc409acc
--- /dev/null
+++ b/testdata/golden/expected/generate-golden-api/printing-press-golden/internal/cliutil/verifyenv.go
@@ -0,0 +1,30 @@
+// Copyright 2026 printing-press-golden. Licensed under Apache-2.0. See LICENSE.
+// Generated by CLI Printing Press (https://github.com/mvanhorn/cli-printing-press). DO NOT EDIT.
+
+package cliutil
+
+import "os"
+
+// VerifyEnvVar is the env var the printing-press verifier sets in every
+// mock-mode subprocess. Generated commands that perform visible side
+// effects (open browser tabs, send notifications, dial out to OS
+// handlers) MUST short-circuit when this env var is "1" to avoid
+// spamming the user's environment during verify runs.
+const VerifyEnvVar = "PRINTING_PRESS_VERIFY"
+
+// IsVerifyEnv reports whether the current process is running under the
+// printing-press verifier in mock mode. Generated commands with side
+// effects pair this check with print-by-default + explicit opt-in
+// (--launch, --send, --play) so a verify pass on a fresh CLI does not
+// pop browser tabs or fire off real notifications.
+//
+// Defense-in-depth: even if the verifier's heuristic side-effect
+// classifier misses a command, this env-var short-circuit catches it.
+//
+//	if cliutil.IsVerifyEnv() {
+//	    fmt.Fprintln(cmd.OutOrStdout(), "would launch:", url)
+//	    return nil
+//	}
+func IsVerifyEnv() bool {
+	return os.Getenv(VerifyEnvVar) == "1"
+}
diff --git a/testdata/golden/expected/schema-traffic-analysis/exit.txt b/testdata/golden/expected/schema-traffic-analysis/exit.txt
new file mode 100644
index 00000000..573541ac
--- /dev/null
+++ b/testdata/golden/expected/schema-traffic-analysis/exit.txt
@@ -0,0 +1 @@
+0
diff --git a/testdata/golden/expected/schema-traffic-analysis/stderr.txt b/testdata/golden/expected/schema-traffic-analysis/stderr.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/testdata/golden/expected/schema-traffic-analysis/stdout.txt b/testdata/golden/expected/schema-traffic-analysis/stdout.txt
new file mode 100644
index 00000000..ee5f4079
--- /dev/null
+++ b/testdata/golden/expected/schema-traffic-analysis/stdout.txt
@@ -0,0 +1,185 @@
+{
+  "$schema": "https://json-schema.org/draft/2020-12/schema",
+  "$id": "https://github.com/mvanhorn/cli-printing-press/schemas/traffic-analysis.schema.json",
+  "title": "CLI Printing Press traffic-analysis.json",
+  "type": "object",
+  "additionalProperties": false,
+  "required": ["version", "summary", "protocols", "auth", "endpoint_clusters"],
+  "properties": {
+    "version": {"type": "string"},
+    "summary": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["entry_count", "api_entry_count", "noise_entry_count"],
+      "properties": {
+        "target_url": {"type": "string"},
+        "captured_at": {"type": "string"},
+        "entry_count": {"type": "integer", "minimum": 0},
+        "api_entry_count": {"type": "integer", "minimum": 0},
+        "noise_entry_count": {"type": "integer", "minimum": 0},
+        "host_distribution": {"type": "object", "additionalProperties": {"type": "integer", "minimum": 0}},
+        "time_start": {"type": "string"},
+        "time_end": {"type": "string"}
+      }
+    },
+    "reachability": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["mode", "confidence"],
+      "properties": {
+        "mode": {"type": "string", "enum": ["standard_http", "browser_http", "browser_clearance_http", "browser_required", "blocked", "unknown"]},
+        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
+        "reasons": {"type": "array", "items": {"type": "string"}},
+        "evidence": {"type": "array", "items": {"oneOf": [{"$ref": "#/$defs/evidence_ref"}, {"type": "string"}]}}
+      }
+    },
+    "protocols": {"type": "array", "items": {"$ref": "#/$defs/protocol_observation"}},
+    "auth": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "candidates": {"type": "array", "items": {"$ref": "#/$defs/auth_candidate"}}
+      }
+    },
+    "protections": {"type": "array", "items": {"$ref": "#/$defs/protection_observation"}},
+    "endpoint_clusters": {"type": "array", "items": {"$ref": "#/$defs/endpoint_cluster"}},
+    "request_sequences": {"type": "array", "items": {"$ref": "#/$defs/request_sequence"}},
+    "pagination": {"type": "array", "items": {"$ref": "#/$defs/pagination_signal"}},
+    "candidate_commands": {"type": "array", "items": {"$ref": "#/$defs/candidate_command"}},
+    "generation_hints": {"type": "array", "items": {"type": "string"}},
+    "warnings": {"type": "array", "items": {"$ref": "#/$defs/analysis_warning"}}
+  },
+  "$defs": {
+    "evidence_ref": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["entry_index"],
+      "properties": {
+        "entry_index": {"type": "integer", "minimum": 0},
+        "method": {"type": "string"},
+        "host": {"type": "string"},
+        "path": {"type": "string"},
+        "status": {"type": "integer"},
+        "content_type": {"type": "string"},
+        "reason": {"type": "string"}
+      }
+    },
+    "protocol_observation": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["label", "confidence"],
+      "properties": {
+        "label": {"type": "string"},
+        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
+        "evidence": {"type": "array", "items": {"oneOf": [{"$ref": "#/$defs/evidence_ref"}, {"type": "string"}]}},
+        "details": {"type": "object", "additionalProperties": {"type": "string"}}
+      }
+    },
+    "auth_candidate": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["type", "confidence"],
+      "properties": {
+        "type": {"type": "string"},
+        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
+        "header_names": {"type": "array", "items": {"type": "string"}},
+        "query_names": {"type": "array", "items": {"type": "string"}},
+        "cookie_names": {"type": "array", "items": {"type": "string"}},
+        "domain_hints": {"type": "array", "items": {"type": "string"}},
+        "evidence": {"type": "array", "items": {"$ref": "#/$defs/evidence_ref"}}
+      }
+    },
+    "protection_observation": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["label", "confidence"],
+      "properties": {
+        "label": {"type": "string"},
+        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
+        "evidence": {"type": "array", "items": {"oneOf": [{"$ref": "#/$defs/evidence_ref"}, {"type": "string"}]}},
+        "notes": {"type": "array", "items": {"type": "string"}}
+      }
+    },
+    "endpoint_cluster": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["method", "path", "count"],
+      "properties": {
+        "host": {"type": "string"},
+        "method": {"type": "string"},
+        "path": {"type": "string"},
+        "count": {"type": "integer", "minimum": 0},
+        "statuses": {"type": "array", "items": {"type": "integer"}},
+        "content_types": {"type": "array", "items": {"type": "string"}},
+        "size_class": {"type": "string"},
+        "request_shape": {"$ref": "#/$defs/shape_summary"},
+        "response_shape": {"$ref": "#/$defs/shape_summary"},
+        "evidence": {"type": "array", "items": {"$ref": "#/$defs/evidence_ref"}}
+      }
+    },
+    "shape_summary": {
+      "type": "object",
+      "additionalProperties": false,
+      "properties": {
+        "kind": {"type": "string"},
+        "fields": {"type": "array", "items": {"$ref": "#/$defs/shape_field"}}
+      }
+    },
+    "shape_field": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["name"],
+      "properties": {
+        "name": {"type": "string"},
+        "type": {"type": "string"},
+        "required": {"type": "boolean"},
+        "format": {"type": "string"}
+      }
+    },
+    "request_sequence": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["label", "confidence"],
+      "properties": {
+        "label": {"type": "string"},
+        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
+        "evidence": {"type": "array", "items": {"oneOf": [{"$ref": "#/$defs/evidence_ref"}, {"type": "string"}]}},
+        "notes": {"type": "array", "items": {"type": "string"}}
+      }
+    },
+    "pagination_signal": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["location", "name", "confidence"],
+      "properties": {
+        "location": {"type": "string"},
+        "name": {"type": "string"},
+        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
+        "evidence": {"type": "array", "items": {"$ref": "#/$defs/evidence_ref"}}
+      }
+    },
+    "candidate_command": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["name", "confidence"],
+      "properties": {
+        "name": {"type": "string"},
+        "resource": {"type": "string"},
+        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
+        "rationale": {"type": "string"},
+        "evidence": {"type": "array", "items": {"$ref": "#/$defs/evidence_ref"}}
+      }
+    },
+    "analysis_warning": {
+      "type": "object",
+      "additionalProperties": false,
+      "required": ["type", "message", "confidence"],
+      "properties": {
+        "type": {"type": "string"},
+        "message": {"type": "string"},
+        "confidence": {"type": "number", "minimum": 0, "maximum": 1},
+        "evidence": {"type": "array", "items": {"$ref": "#/$defs/evidence_ref"}}
+      }
+    }
+  }
+}

← d86d3af1 fix(cli): sync dogfood novel features into CLI artifacts (#3  ·  back to Cli Printing Press  ·  ci(ci): improve workflow coverage and guards (#346) 4c64ffe6 →