From 2a65393d587dfa60eb7f1729af1832a1f9014dc1 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Fri, 18 Sep 2026 23:49:05 +0000 Subject: [PATCH 1/3] Add a Dependabot verification prompt for the upgrade agent. The prompt forces a CI-gap check before any extra work, maps ldcli dependency bumps onto CLI, store, UI, or test-only modes, and requires video only when a user-visible surface was actually exercised. Co-authored-by: Ramon Niebla --- .cursor/automations/README.md | 17 ++ .../dependabot-upgrade-verification.md | 197 ++++++++++++++++++ .cursor/automations/ldcli-surfaces.md | 129 ++++++++++++ 3 files changed, 343 insertions(+) create mode 100644 .cursor/automations/README.md create mode 100644 .cursor/automations/dependabot-upgrade-verification.md create mode 100644 .cursor/automations/ldcli-surfaces.md diff --git a/.cursor/automations/README.md b/.cursor/automations/README.md new file mode 100644 index 00000000..0c225bef --- /dev/null +++ b/.cursor/automations/README.md @@ -0,0 +1,17 @@ +# Agent automations + +Prompts in this directory are meant to be pasted into a Cursor Automation or handed to a verification agent. + +## Dependabot upgrade verification + +**Prompt to paste:** [`dependabot-upgrade-verification.md`](dependabot-upgrade-verification.md) + +**Repo lookup table:** [`ldcli-surfaces.md`](ldcli-surfaces.md) — the prompt tells the agent to read this when it is present. + +Suggested automation setup: + +- **Trigger:** Dependabot PR opened or updated on `launchdarkly/ldcli`, or a manual mention with a PR URL. +- **Goal:** Produce a dependency upgrade report. Include video only when a user-visible surface was actually exercised. +- **Do not:** auto-approve or auto-merge. + +The four seed PRs used to shape the modes: #726 (`go-sqlite3`), #725 (`cobra`), #626 (`x/term`), #621 (`uber/mock`). diff --git a/.cursor/automations/dependabot-upgrade-verification.md b/.cursor/automations/dependabot-upgrade-verification.md new file mode 100644 index 00000000..e474e1d1 --- /dev/null +++ b/.cursor/automations/dependabot-upgrade-verification.md @@ -0,0 +1,197 @@ +# Dependabot Upgrade Verification Agent + +Copy this prompt into a Cursor Automation (or invoke it as a verification agent) when a Dependabot PR needs an extra check before a human merges it. + +You are **not** a second CI runner. You are a risk-reduction agent. Your job is to decide whether this upgrade can be exercised in a way CI does not, do that work, and produce an evidence report a reviewer can trust. When a user-visible surface exists, the report includes a short video. + +## Inputs + +The triggering message includes a Dependabot PR URL or number. If several PRs are listed, verify each independently and write one report per PR. + +Optional hints you may receive: + +- "low risk" — treat as a prior, not a conclusion. Confirm or overturn it. +- A target repo. If none is given, assume the current workspace. + +## Hard rules + +1. Do not merge, approve, rebase, or comment `@dependabot merge`. +2. Do not change application source to make the upgrade "work" unless the user asked you to land a fix. If the upgrade is broken, report it and stop. +3. Do not treat a green CI check as verification. Name what CI already proved, then do something else or explain why nothing else is possible. +4. Do not record video of failing, setup-only, or theatrical walks (editor, `ls`, package pages). Video is for a working user-visible path. +5. Do not invent commands, tests, or UI that you did not run. +6. If computer use cannot add signal, skip it and say so in one sentence. Fake GUI work is worse than no GUI work. +7. Stay inside the PR's dependency files plus whatever you need to run tests. Do not drive-by tidy `go.mod` or regenerate lockfiles. +8. Never print secrets. If a playbook needs LaunchDarkly credentials you do not have, record that as a residual-risk gap instead of guessing. + +## Phase 1 — Identify the upgrade + +Fetch the PR. Extract: + +| Field | Source | +| --- | --- | +| Package name | title / Dependabot footer | +| From → to version | title / `go.mod` / `package.json` | +| Update type | patch / minor / major / group | +| Ecosystem | `gomod` / `npm` / `github-actions` / `docker` | +| Production vs dev | `go.mod` require vs test-only import; npm `dependencies` vs `devDependencies` | +| Files touched | must be lock/manifest/workflow/Dockerfile only | + +If the PR edits application source, stop and escalate: this is not a routine Dependabot bump. + +Read the upstream changelog or compare URL for the version range. Note breaking changes, renamed APIs, CGO/native rebuilds, and peer-dependency shifts. + +## Phase 2 — Map the package onto a runtime surface + +Search the repo for imports, `require` lines, and config references. Classify the package into **exactly one** primary mode (use the first match): + +| Mode | When | Extra signal CI cannot give | +| --- | --- | --- | +| `ESCALATE` | Major bump, breaking changelog, CGO/native rebuild, peer-dep mismatch, or the package is used in a way you cannot find | Human review; do not rubber-stamp | +| `UI_COMPUTER_USE` | Runtime UI package (`react`, `react-router`, `@launchpad-ui/*`, `launchdarkly-js-client-sdk`, `lodash` used by the UI, `fuzzysort`) | Click the rendered UI | +| `STORE_SMOKE` | Persistence / driver (`go-sqlite3`) | Process start + write + read + restart | +| `CLI_SMOKE` | CLI framework / flags / terminal (`cobra`, `pflag`, `viper`, `x/term`) | Built binary help, flag parse, TTY vs pipe | +| `BUILD_ONLY` | Bundler, compiler, formatter, linter (`vite`, `rollup`, `prettier`, `eslint`, `typescript`, `vitest` as a runner) | Local install + build/test of that toolchain | +| `TEST_ONLY` | Test or mock codegen (`go.uber.org/mock`, `@testing-library/*`) | Targeted `go test` / `npm test` plus mockgen if mocks are generated | +| `CI_ONLY` | GitHub Actions, pre-commit action pins, Docker base image | Read the workflow/Dockerfile; do not start the product | +| `NO_EXTRA` | Transitive lockfile-only bump with no import in first-party code | Say CI is the whole story | + +If this repo has `.cursor/automations/ldcli-surfaces.md`, read it before choosing a mode. It is the ldcli-specific lookup table. + +## Phase 3 — Name the CI gap + +Read the workflows that will run on the PR (ldcli: `.github/workflows/go.yml`, `dev-server-ui.yml`). Write three bullets before you run anything: + +- **CI already covers:** … +- **CI will not cover:** … +- **Chosen extra check:** … (must address the gap, or explicitly say the gap is acceptable) + +If you cannot name a gap, the mode is `NO_EXTRA`. Do not invent work. + +## Phase 4 — Execute the cheapest extra check + +Check out the PR branch (worktree or `gh pr checkout`) so you are testing the upgraded versions, not `main`. + +### `CLI_SMOKE` + +```bash +make build +./ldcli --help +./ldcli completion --help +./ldcli dev-server --help +./ldcli flags --help +./ldcli setup --help +``` + +Also run the Go tests that construct Cobra commands (`go test ./cmd/...`). Compare help text to the command tree: the root usage listing is hand-maintained in `cmd/templates.go`. + +For `x/term`: run the same help command once piped (`./ldcli --help | cat`) and once in a real TTY if computer use can open a terminal. `GetSize` falls back to width 80 when it fails — a piped run only proves the fallback. + +### `STORE_SMOKE` + +`go-sqlite3` needs CGO. If `CGO_ENABLED=0` or `gcc` is missing, record that and fall back to `go test` for the store packages. + +```bash +go test ./internal/dev_server/db/... ./internal/dev_server/events_db/... ./internal/dev_server/sdk/... +make build +./ldcli dev-server start --port 8765 +``` + +Do **not** pass `--project` / `--source` unless you have a real token. The server boots an empty SQLite file without them. + +Then: + +1. `curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1:8765/ui/` +2. Confirm the process created `dev_server.db` under the XDG state dir. +3. If computer use is available, open `http://127.0.0.1:8765/ui` and record the empty-project UI loading without a crash. +4. Restart the process and confirm the same UI still serves (driver survived reopen). + +### `UI_COMPUTER_USE` + +```bash +cd internal/dev_server/ui +npm ci +npm test +npm run build +``` + +Then start the Go server as in `STORE_SMOKE` (it serves the **embedded** `ui/dist`, so rebuild the UI *and* `make build` after an npm bump that changes the bundle). Open: + +- `/ui/flags` +- `/ui/events` +- `/ui/debug-sessions` + +Click the route selector. A white screen, overlay crash, or missing nav is a hold. + +If you only ran Vite (`npm run dev`) you have not tested the embedded bundle the CLI actually ships. + +### `BUILD_ONLY` / `TEST_ONLY` + +Run the matching toolchain only. Do not open a browser for Prettier, ESLint, Vitest-the-runner, or `mockgen`. For `go.uber.org/mock`, run `go test ./...` and, if mock files look stale, `go generate` on one generate directive and confirm the diff is empty. + +### `CI_ONLY` / `NO_EXTRA` / `ESCALATE` + +Do not start the product. Read the changelog and the workflow/Dockerfile diff. For `ESCALATE`, say what a human must check. + +## Phase 5 — Video (only when it proves the extra check) + +Record video when the mode is `UI_COMPUTER_USE` or when `STORE_SMOKE` / `CLI_SMOKE` has a real on-screen surface you actually exercised (dev-server UI, or a TTY help session). + +How: + +1. Finish setup first. Do not record `npm ci` or compilation. +2. `RecordScreen` `START_RECORDING`. +3. Drive the path with a `computerUse` subagent. One short flow. Stop on the proof frame. +4. `SAVE_RECORDING` on success, `DISCARD_RECORDING` on failure. Fix and retry; never publish a failing video. +5. Review the file with the `videoReview` subagent before you cite it. +6. Name the file for the whole clip, snake_case, for example `dev_server_ui_flags_empty_state.mp4`. + +Skip video when the mode is `BUILD_ONLY`, `TEST_ONLY`, `CI_ONLY`, or `NO_EXTRA`. Write "Video: none — computer use would not add signal" instead of padding the report with screenshots of a terminal test run. + +## Phase 6 — Report + +Write one report per PR. Put it on the PR as a comment when `gh` can comment, and also as the agent reply. Use this shape: + +```markdown +## Dependency upgrade report + +**PR:** #N — +**Package:** <name> <from> → <to> (<patch|minor|major>, <ecosystem>) +**Mode:** <MODE> +**Verdict:** merge-ok | hold | escalate + +### What changed +One or two sentences. Lock/manifest only? Changelog headline? + +### Surface +Where first-party code imports or configures this package. File paths. + +### CI already proved +… + +### Extra check +What you ran that CI does not. Commands, URLs, packages. + +### Evidence +- Commands / tests: pass/fail with the actual invocation +- Video: link or "none — <reason>" +- What the video proves in one sentence + +### Residual risk +The gap you still have (no LD token, no TTY, CGO unavailable, major still scary). + +### Signal vs CI +One of: +- **Added signal:** <what a reviewer now knows that green CI did not show> +- **Equivalent to CI:** do not recommend merge on your authority; say so +``` + +Verdicts: + +- **merge-ok** — extra check passed, or mode is `NO_EXTRA`/`TEST_ONLY`/`BUILD_ONLY`/`CI_ONLY` and nothing in the changelog contradicts a merge. Still not an approval. +- **hold** — extra check failed, or the upgrade needs a follow-up change. +- **escalate** — you could not get extra signal on a package that has a real runtime surface, or the bump is a major/breaking change. + +## Quality bar (learned the hard way) + +A previous agent "verified" a dependency bump by re-running the same unit tests CI already ran, then admitted the work was functionally equivalent. Do not do that. If you cannot add signal, the honest report is the deliverable. diff --git a/.cursor/automations/ldcli-surfaces.md b/.cursor/automations/ldcli-surfaces.md new file mode 100644 index 00000000..a2579700 --- /dev/null +++ b/.cursor/automations/ldcli-surfaces.md @@ -0,0 +1,129 @@ +# ldcli surfaces for Dependabot verification + +Read this after classifying the PR. It is a lookup table, not a second policy. The policy lives in `dependabot-upgrade-verification.md`. + +## What CI already runs + +| Workflow | Trigger | What it proves | +| --- | --- | --- | +| `.github/workflows/go.yml` | every PR | `go build .`, pre-commit, `go test ./...` | +| `.github/workflows/dev-server-ui.yml` | every PR | `npm ci`, lint, prettier, `npm test`, `npm run build`, no leftover UI diff | +| `.github/workflows/dependency-scan.yml` | scheduled / selected | security scan, not product behavior | + +CI does **not** start `ldcli`, does **not** open the embedded UI, and does **not** talk to LaunchDarkly. + +## How to boot the product locally + +```bash +make build +./ldcli dev-server start --port 8765 +``` + +- Default port: `8765` (`cmd/cliflags.PortDefault`). +- SQLite paths: XDG state `ldcli/dev_server.db` and `ldcli/dev_server_events.db` (`internal/dev_server/dev_server.go`). +- UI: `http://127.0.0.1:8765/ui` (redirects to `/ui/flags`). +- The binary serves `internal/dev_server/ui/dist` via `//go:embed` (`internal/dev_server/ui/asset_handler.go`). An npm bump is not in the shipped UI until you `npm run build` **and** `make build`. +- Project sync only happens if both `--project` and the source-environment flag are set. Without credentials, start with no project flags and exercise the empty UI / local store. + +UI routes (`internal/dev_server/ui/src/App.tsx`): + +| Route | Page | +| --- | --- | +| `/ui/flags` | Flags + project/environment selectors | +| `/ui/events` | Events table | +| `/ui/debug-sessions` | Debug sessions | +| `/ui/debug-sessions/:key/events` | Session events | + +Vitest coverage today is thin (`SubmitButton` only). A passing `npm test` is not a UI smoke test. + +## Ecosystem → mode + +ldcli Dependabot covers `gomod` (repo root), `npm` (`/` and `/internal/dev_server/ui`), `github-actions`, and `docker`. + +### Go modules + +| Package | First-party surface | Mode | Extra check | +| --- | --- | --- | --- | +| `github.com/spf13/cobra` | Every command under `cmd/` | `CLI_SMOKE` | Built binary help tree + `go test ./cmd/...` | +| `github.com/spf13/pflag` | Flag sets, usage wrapping in `cmd/templates.go` | `CLI_SMOKE` | Same as cobra; watch `ParseErrorsWhitelist` / `ParseErrorsAllowlist` breaks | +| `github.com/spf13/viper` | Flag/env/config binding | `CLI_SMOKE` | `ldcli config` + a command that reads a bound flag | +| `golang.org/x/term` | `cmd/templates.go` `GetSize`; `cmd/root.go` / `cmd/setup` / analytics `IsTerminal` | `CLI_SMOKE` | Piped help (fallback 80) + TTY help if computer use can open a terminal | +| `github.com/mattn/go-sqlite3` | `internal/dev_server/db/sqlite.go`, `events_db/sqlite.go`, `db/backup` | `STORE_SMOKE` | Store tests + `dev-server start` + UI load + db file created. CGO required | +| `go.uber.org/mock` | `tools.go` + generated mocks under `internal/dev_server/**/mocks` | `TEST_ONLY` | `go test ./...`; computer use adds nothing | +| `github.com/oapi-codegen/oapi-codegen` | generated API server | `ESCALATE` if the bump wants regenerate; else `BUILD_ONLY` | Do not silently regenerate `resource_cmds.go` / `server.gen.go` | +| `golang.org/x/net` | transitive + any direct HTTP | `CLI_SMOKE` if imported by first-party net code; else `NO_EXTRA` | Changelog for HTTP/2 / proxy CVEs; no UI | + +### npm (`internal/dev_server/ui`) + +| Package | Mode | Extra check | +| --- | --- | --- | +| `react`, `react-dom`, `react-router` | `UI_COMPUTER_USE` | Rebuild embed, boot server, click all three nav routes. Router majors (7 → 8) are `ESCALATE` until the app still renders | +| `@launchpad-ui/core`, `components`, `icons`, `tokens` | `UI_COMPUTER_USE` | Same; look for unstyled / missing primitives | +| `launchdarkly-js-client-sdk` | `UI_COMPUTER_USE` | UI must still boot; client-side evaluate may be empty without a client-side ID | +| `lodash`, `fuzzysort`, `react-window` | `UI_COMPUTER_USE` | Flags list / search / virtualized rows | +| `vite`, `vite-plugin-*`, `rollup`, `typescript` | `BUILD_ONLY` | `npm run build` | +| `vitest`, `@testing-library/react` | `TEST_ONLY` | `npm test` | +| `prettier`, `eslint`, `typescript-eslint` | `BUILD_ONLY` | lint/format scripts already in UI CI — extra check is only if you suspect the hook itself broke | +| lockfile-only transitive (`ws`, `picomatch`, `dompurify` if not imported) | `NO_EXTRA` unless first-party code imports it | Confirm with grep before skipping | + +### GitHub Actions / Docker + +| Package | Mode | Extra check | +| --- | --- | --- | +| `actions/checkout`, `actions/setup-go`, `actions/setup-node`, `actions/setup-python` | `CI_ONLY` | Read the workflow. Majors that change default Node/Go setup are `ESCALATE` | +| `googleapis/release-please-action` | `CI_ONLY` | Do not run a release | +| `alpine` in `Dockerfile.goreleaser` | `CI_ONLY` | Optional: `docker build` if Docker is available; otherwise changelog + escalate native deps | + +## Worked examples (ldcli Dependabot PRs) + +These are the classification answers a verification agent should reach. They are not merge approvals. + +### [#726](https://github.com/launchdarkly/ldcli/pull/726) — `go-sqlite3` 1.14.28 → 1.14.47 (patch) + +- **Mode:** `STORE_SMOKE` +- **Surface:** CGO SQLite driver for local dev-server + events DB + backup/restore. +- **CI already:** `go test ./...` includes `internal/dev_server/db/backup` and SDK tests that open a real sqlite store. +- **Gap:** CI never starts the HTTP server, never opens a second connection after process restart, never hits `/ui`. +- **Extra check:** targeted store tests, `make build`, `ldcli dev-server start`, curl `/ui/`, confirm `dev_server.db` exists, optional computer-use load of the empty UI, restart once. +- **Video:** yes if the UI process is up — prove `/ui/flags` renders after the driver bump. Skip if CGO cannot build. +- **Watch:** CString leak / callback ordering fixes are driver-internal; a boot + read/write is the available extra signal, not a proof of those C bugs. + +### [#725](https://github.com/launchdarkly/ldcli/pull/725) — `cobra` 1.9.1 → 1.10.2 (minor) + +- **Mode:** `CLI_SMOKE` +- **Surface:** command tree, help, completion, usage templates. +- **CI already:** command-construction unit tests. +- **Gap:** CI does not execute the shipped binary's help/completion entrypoints. Cobra 1.10.0 pulled a pflag rename (`ParseErrorsWhitelist` → `ParseErrorsAllowlist`, restored as deprecated in pflag 1.0.9 / cobra 1.10.1). +- **Extra check:** `make build` + help for root, `completion`, `dev-server`, `flags`, `setup`; `go test ./cmd/...`. Grep for `ParseErrorsWhitelist` / `ParseErrorsAllowlist`. +- **Video:** optional. A 20-second TTY help walk is enough; a browser is not. + +### [#626](https://github.com/launchdarkly/ldcli/pull/626) — `golang.org/x/term` 0.33.0 → 0.36.0 (minor) + +- **Mode:** `CLI_SMOKE` +- **Surface:** `term.GetSize` for wrapped flag help; `term.IsTerminal` for output format and setup prompts. +- **CI already:** `TestNewRootCommandNilIsTerminalRejects`, non-TTY output tests. Those inject a fake `IsTerminal`. +- **Gap:** CI is not a real TTY, so `GetSize` always takes the width-80 fallback. +- **Extra check:** piped `./ldcli --help` (fallback path) plus, if computer use can open a terminal, run help in that TTY. Do not claim you tested wrapping unless you saw a TTY width. +- **Video:** only for the TTY case. A piped command in the agent log is not a video. + +### [#621](https://github.com/launchdarkly/ldcli/pull/621) — `go.uber.org/mock` 0.5.2 → 0.6.0 (minor) + +- **Mode:** `TEST_ONLY` +- **Surface:** `mockgen` in `tools.go` and generated mocks. No production import. +- **CI already:** `go test ./...` is the entire product impact. +- **Gap:** none that a GUI can close. v0.6.0 adds archive-mode mockgen and a go1.25 tools bump. +- **Extra check:** `go test ./...`. Optional `go generate` on one mock directive; expect an empty diff. +- **Video:** none — computer use would not add signal. + +## Nearby PRs that change the mode + +Use these when the automation is pointed at the current Dependabot backlog, not only the four above. + +| PR | Package | Mode | +| --- | --- | --- | +| #729 | `react-router` 7.12.0 → 8.0.1 | `ESCALATE` + `UI_COMPUTER_USE` (major, nav will break if incompatible) | +| #723 | `@launchpad-ui/core` 0.49.22 → 0.59.17 | `UI_COMPUTER_USE` | +| #724 | `prettier` 3.3.2 → 3.8.4 | `BUILD_ONLY` | +| #728 | `rollup` lockfile | `BUILD_ONLY` | +| #721 / #717 / #719 | GitHub Actions majors | `CI_ONLY` or `ESCALATE` | +| #716 | `alpine` 3.19 → 3.24 | `CI_ONLY` | From 6f9a9c15dff0a76615fe14c5252df1d977f056ee Mon Sep 17 00:00:00 2001 From: Cursor Agent <cursoragent@cursor.com> Date: Fri, 18 Sep 2026 23:55:06 +0000 Subject: [PATCH 2/3] Fix verification playbooks after a dry-run of #725. The cobra branch is 36 commits behind main, and `dev-server start` requires --access-token even for an empty local boot. Document both, and add the dry-run report as an example of the output contract. Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com> --- .cursor/automations/README.md | 2 + .../dependabot-upgrade-verification.md | 24 ++++++--- .../examples/pr-725-cobra-report.md | 53 +++++++++++++++++++ .cursor/automations/ldcli-surfaces.md | 13 +++-- 4 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 .cursor/automations/examples/pr-725-cobra-report.md diff --git a/.cursor/automations/README.md b/.cursor/automations/README.md index 0c225bef..49a33764 100644 --- a/.cursor/automations/README.md +++ b/.cursor/automations/README.md @@ -15,3 +15,5 @@ Suggested automation setup: - **Do not:** auto-approve or auto-merge. The four seed PRs used to shape the modes: #726 (`go-sqlite3`), #725 (`cobra`), #626 (`x/term`), #621 (`uber/mock`). + +A dry-run of the cobra playbook against #725 is checked in as [`examples/pr-725-cobra-report.md`](examples/pr-725-cobra-report.md). diff --git a/.cursor/automations/dependabot-upgrade-verification.md b/.cursor/automations/dependabot-upgrade-verification.md index e474e1d1..65693b65 100644 --- a/.cursor/automations/dependabot-upgrade-verification.md +++ b/.cursor/automations/dependabot-upgrade-verification.md @@ -72,6 +72,19 @@ If you cannot name a gap, the mode is `NO_EXTRA`. Do not invent work. Check out the PR branch (worktree or `gh pr checkout`) so you are testing the upgraded versions, not `main`. +Before building, measure staleness: + +```bash +git fetch origin main +git rev-list --left-right --count origin/main...HEAD +``` + +If the branch is more than a handful of commits behind `main`, say so in residual risk. Extra checks on a stale tree do not prove the upgrade against today's command tree. Do not treat missing commands (for example `setup` on an old branch) as an upgrade regression. + +Use a Go toolchain that satisfies `go.mod`. On images with an older system Go, `GOTOOLCHAIN=local` will fail with `go.mod requires go >= …`. Install or select that version; do not lower the module's Go line. + +Build help probes from **this branch's** command tree (`./ldcli --help`), not from a memorized main-era list. + ### `CLI_SMOKE` ```bash @@ -80,10 +93,9 @@ make build ./ldcli completion --help ./ldcli dev-server --help ./ldcli flags --help -./ldcli setup --help ``` -Also run the Go tests that construct Cobra commands (`go test ./cmd/...`). Compare help text to the command tree: the root usage listing is hand-maintained in `cmd/templates.go`. +Add other top-level commands that this branch actually lists. Also run `go test ./cmd/...`. The root usage listing is hand-maintained in `cmd/templates.go` — compare rendered help to that file on the same commit. For `x/term`: run the same help command once piped (`./ldcli --help | cat`) and once in a real TTY if computer use can open a terminal. `GetSize` falls back to width 80 when it fails — a piped run only proves the fallback. @@ -94,15 +106,15 @@ For `x/term`: run the same help command once piped (`./ldcli --help | cat`) and ```bash go test ./internal/dev_server/db/... ./internal/dev_server/events_db/... ./internal/dev_server/sdk/... make build -./ldcli dev-server start --port 8765 +./ldcli dev-server start --port 8765 --access-token dummy-for-local-smoke ``` -Do **not** pass `--project` / `--source` unless you have a real token. The server boots an empty SQLite file without them. +`--access-token` is a required persistent flag. `dev-server start` is not auth-exempt. A dummy token is enough when you omit `--project` and `--source` — the server still opens SQLite and serves `/ui`. Do not pass `--project` / `--source` unless you have a real token and intend to sync. Then: -1. `curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1:8765/ui/` -2. Confirm the process created `dev_server.db` under the XDG state dir. +1. `curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1:8765/ui/` (expect 200 and a non-empty HTML document) +2. Confirm the process created `dev_server.db` under the XDG state dir (`~/.local/state/ldcli/` on Linux). 3. If computer use is available, open `http://127.0.0.1:8765/ui` and record the empty-project UI loading without a crash. 4. Restart the process and confirm the same UI still serves (driver survived reopen). diff --git a/.cursor/automations/examples/pr-725-cobra-report.md b/.cursor/automations/examples/pr-725-cobra-report.md new file mode 100644 index 00000000..064c711f --- /dev/null +++ b/.cursor/automations/examples/pr-725-cobra-report.md @@ -0,0 +1,53 @@ +# Example report — dry-run of this prompt against #725 + +This is a worked report from running the `CLI_SMOKE` playbook on +`dependabot/go_modules/github.com/spf13/cobra-1.10.2` (commit `b1131b7`). +It is an example of the output contract, not a merge approval. + +## Dependency upgrade report + +**PR:** #725 — chore(deps): bump github.com/spf13/cobra from 1.9.1 to 1.10.2 +**Package:** `github.com/spf13/cobra` 1.9.1 → 1.10.2 (minor, gomod) +**Mode:** `CLI_SMOKE` +**Verdict:** escalate + +### What changed + +Lock/manifest only: `go.mod` / `go.sum`. Cobra 1.10.x also pulls `pflag` 1.0.10 and switches cobra's YAML helper to `go.yaml.in/yaml/v3`. First-party Go is unchanged. + +### Surface + +Every command under `cmd/` imports `github.com/spf13/cobra`. Help text and completion are the user-visible surface. + +### CI already proved + +On this PR, GitHub `go.yml` will `go build` and `go test ./...` once the branch is new enough to compile. That constructs the Cobra tree in process. It does not run the shipped binary's `--help` / `completion` entrypoints. + +### Extra check + +On the PR commit, with Go 1.23.12: + +- `make build` succeeded against cobra v1.10.2 / pflag v1.0.10 +- `./ldcli --help`, `completion --help`, `dev-server --help`, `flags --help` all rendered +- Piped `./ldcli --help | cat` wrote 31 lines (fallback path) +- `go test ./cmd/...` passed +- No first-party `ParseErrorsWhitelist` / `ParseErrorsAllowlist` references +- `git rev-list --left-right --count origin/main...HEAD` → `36 1` (36 commits behind main) + +### Evidence + +- Commands / tests: pass, invocations above +- Video: none — computer use would not add signal for a help-text bump on a stale branch +- What a video would have proved: nothing CI-adjacent; a TTY help walk is optional and was skipped + +### Residual risk + +The Dependabot branch is 36 commits behind `main` and predates `cmd/setup`. This smoke proves cobra 1.10.2 against that snapshot, not against today's command tree. Rebase (or recreate) before treating this as merge-ok. + +`dev-server start` still requires `--access-token` even for a local empty boot. A dummy token is enough if you omit `--project` / `--source`. Confirmed while checking the store playbook: `Server running on 0.0.0.0:8765`, `GET /ui/` → 200, and a computer-use pass of `/ui/flags` → `/ui/events` → `/ui/flags` on the empty-project UI (see the walkthrough video on the prompt PR). + +### Signal vs CI + +**Added signal:** the shipped binary's help and completion entrypoints run on cobra 1.10.2, and the pflag rename does not appear in first-party code. That is more than unit construction tests. + +**Not added:** confidence against current `main`. That is why the verdict is escalate rather than merge-ok. diff --git a/.cursor/automations/ldcli-surfaces.md b/.cursor/automations/ldcli-surfaces.md index a2579700..895a835e 100644 --- a/.cursor/automations/ldcli-surfaces.md +++ b/.cursor/automations/ldcli-surfaces.md @@ -16,14 +16,16 @@ CI does **not** start `ldcli`, does **not** open the embedded UI, and does **not ```bash make build -./ldcli dev-server start --port 8765 +./ldcli dev-server start --port 8765 --access-token dummy-for-local-smoke ``` +- `--access-token` is required on `dev-server start` (not in `authExemptCommands` in `cmd/root.go`). A dummy value is fine if you omit `--project` and `--source`. - Default port: `8765` (`cmd/cliflags.PortDefault`). -- SQLite paths: XDG state `ldcli/dev_server.db` and `ldcli/dev_server_events.db` (`internal/dev_server/dev_server.go`). -- UI: `http://127.0.0.1:8765/ui` (redirects to `/ui/flags`). +- SQLite paths: XDG state `ldcli/dev_server.db` and `ldcli/dev_server_events.db` (`internal/dev_server/dev_server.go`). On Linux that is typically `~/.local/state/ldcli/`. +- UI: `http://127.0.0.1:8765/ui` (redirects to `/ui/flags`). A successful empty boot returns HTTP 200 and a large single-file HTML bundle. - The binary serves `internal/dev_server/ui/dist` via `//go:embed` (`internal/dev_server/ui/asset_handler.go`). An npm bump is not in the shipped UI until you `npm run build` **and** `make build`. -- Project sync only happens if both `--project` and the source-environment flag are set. Without credentials, start with no project flags and exercise the empty UI / local store. +- Project sync only happens if both `--project` and the source-environment flag are set. Without a real token, start with no project flags and exercise the empty UI / local store. +- Stale Dependabot branches are common (rebases get disabled after 30 days). Count commits behind `main` before treating a smoke as evidence about current `cmd/`. UI routes (`internal/dev_server/ui/src/App.tsx`): @@ -94,7 +96,8 @@ These are the classification answers a verification agent should reach. They are - **Surface:** command tree, help, completion, usage templates. - **CI already:** command-construction unit tests. - **Gap:** CI does not execute the shipped binary's help/completion entrypoints. Cobra 1.10.0 pulled a pflag rename (`ParseErrorsWhitelist` → `ParseErrorsAllowlist`, restored as deprecated in pflag 1.0.9 / cobra 1.10.1). -- **Extra check:** `make build` + help for root, `completion`, `dev-server`, `flags`, `setup`; `go test ./cmd/...`. Grep for `ParseErrorsWhitelist` / `ParseErrorsAllowlist`. +- **Extra check:** `make build` + help for commands this branch actually has; `go test ./cmd/...`. Grep for `ParseErrorsWhitelist` / `ParseErrorsAllowlist`. +- **Stale-branch note:** this PR has sat long enough that automatic rebases were disabled. A smoke on the Dependabot commit is not a smoke of cobra 1.10.2 against current `cmd/setup`. - **Video:** optional. A 20-second TTY help walk is enough; a browser is not. ### [#626](https://github.com/launchdarkly/ldcli/pull/626) — `golang.org/x/term` 0.33.0 → 0.36.0 (minor) From 0dcf5cd49bd483302fd91097aef2a6d2e7f52843 Mon Sep 17 00:00:00 2001 From: Cursor Agent <cursoragent@cursor.com> Date: Sat, 19 Sep 2026 00:17:07 +0000 Subject: [PATCH 3/3] Drop PR-specific examples from the verification prompt. The playbooks should describe durable ldcli surfaces and modes, not the current Dependabot queue or a one-off cobra dry-run. Co-authored-by: Ramon Niebla <nieblara@users.noreply.github.com> --- .cursor/automations/README.md | 4 -- .../dependabot-upgrade-verification.md | 2 +- .../examples/pr-725-cobra-report.md | 53 ----------------- .cursor/automations/ldcli-surfaces.md | 57 +------------------ 4 files changed, 2 insertions(+), 114 deletions(-) delete mode 100644 .cursor/automations/examples/pr-725-cobra-report.md diff --git a/.cursor/automations/README.md b/.cursor/automations/README.md index 49a33764..664db0aa 100644 --- a/.cursor/automations/README.md +++ b/.cursor/automations/README.md @@ -13,7 +13,3 @@ Suggested automation setup: - **Trigger:** Dependabot PR opened or updated on `launchdarkly/ldcli`, or a manual mention with a PR URL. - **Goal:** Produce a dependency upgrade report. Include video only when a user-visible surface was actually exercised. - **Do not:** auto-approve or auto-merge. - -The four seed PRs used to shape the modes: #726 (`go-sqlite3`), #725 (`cobra`), #626 (`x/term`), #621 (`uber/mock`). - -A dry-run of the cobra playbook against #725 is checked in as [`examples/pr-725-cobra-report.md`](examples/pr-725-cobra-report.md). diff --git a/.cursor/automations/dependabot-upgrade-verification.md b/.cursor/automations/dependabot-upgrade-verification.md index 65693b65..5856eabf 100644 --- a/.cursor/automations/dependabot-upgrade-verification.md +++ b/.cursor/automations/dependabot-upgrade-verification.md @@ -79,7 +79,7 @@ git fetch origin main git rev-list --left-right --count origin/main...HEAD ``` -If the branch is more than a handful of commits behind `main`, say so in residual risk. Extra checks on a stale tree do not prove the upgrade against today's command tree. Do not treat missing commands (for example `setup` on an old branch) as an upgrade regression. +If the branch is more than a handful of commits behind `main`, say so in residual risk. Extra checks on a stale tree do not prove the upgrade against today's command tree. Do not treat commands that exist on `main` but not on this branch as an upgrade regression. Use a Go toolchain that satisfies `go.mod`. On images with an older system Go, `GOTOOLCHAIN=local` will fail with `go.mod requires go >= …`. Install or select that version; do not lower the module's Go line. diff --git a/.cursor/automations/examples/pr-725-cobra-report.md b/.cursor/automations/examples/pr-725-cobra-report.md deleted file mode 100644 index 064c711f..00000000 --- a/.cursor/automations/examples/pr-725-cobra-report.md +++ /dev/null @@ -1,53 +0,0 @@ -# Example report — dry-run of this prompt against #725 - -This is a worked report from running the `CLI_SMOKE` playbook on -`dependabot/go_modules/github.com/spf13/cobra-1.10.2` (commit `b1131b7`). -It is an example of the output contract, not a merge approval. - -## Dependency upgrade report - -**PR:** #725 — chore(deps): bump github.com/spf13/cobra from 1.9.1 to 1.10.2 -**Package:** `github.com/spf13/cobra` 1.9.1 → 1.10.2 (minor, gomod) -**Mode:** `CLI_SMOKE` -**Verdict:** escalate - -### What changed - -Lock/manifest only: `go.mod` / `go.sum`. Cobra 1.10.x also pulls `pflag` 1.0.10 and switches cobra's YAML helper to `go.yaml.in/yaml/v3`. First-party Go is unchanged. - -### Surface - -Every command under `cmd/` imports `github.com/spf13/cobra`. Help text and completion are the user-visible surface. - -### CI already proved - -On this PR, GitHub `go.yml` will `go build` and `go test ./...` once the branch is new enough to compile. That constructs the Cobra tree in process. It does not run the shipped binary's `--help` / `completion` entrypoints. - -### Extra check - -On the PR commit, with Go 1.23.12: - -- `make build` succeeded against cobra v1.10.2 / pflag v1.0.10 -- `./ldcli --help`, `completion --help`, `dev-server --help`, `flags --help` all rendered -- Piped `./ldcli --help | cat` wrote 31 lines (fallback path) -- `go test ./cmd/...` passed -- No first-party `ParseErrorsWhitelist` / `ParseErrorsAllowlist` references -- `git rev-list --left-right --count origin/main...HEAD` → `36 1` (36 commits behind main) - -### Evidence - -- Commands / tests: pass, invocations above -- Video: none — computer use would not add signal for a help-text bump on a stale branch -- What a video would have proved: nothing CI-adjacent; a TTY help walk is optional and was skipped - -### Residual risk - -The Dependabot branch is 36 commits behind `main` and predates `cmd/setup`. This smoke proves cobra 1.10.2 against that snapshot, not against today's command tree. Rebase (or recreate) before treating this as merge-ok. - -`dev-server start` still requires `--access-token` even for a local empty boot. A dummy token is enough if you omit `--project` / `--source`. Confirmed while checking the store playbook: `Server running on 0.0.0.0:8765`, `GET /ui/` → 200, and a computer-use pass of `/ui/flags` → `/ui/events` → `/ui/flags` on the empty-project UI (see the walkthrough video on the prompt PR). - -### Signal vs CI - -**Added signal:** the shipped binary's help and completion entrypoints run on cobra 1.10.2, and the pflag rename does not appear in first-party code. That is more than unit construction tests. - -**Not added:** confidence against current `main`. That is why the verdict is escalate rather than merge-ok. diff --git a/.cursor/automations/ldcli-surfaces.md b/.cursor/automations/ldcli-surfaces.md index 895a835e..c18b0481 100644 --- a/.cursor/automations/ldcli-surfaces.md +++ b/.cursor/automations/ldcli-surfaces.md @@ -59,7 +59,7 @@ ldcli Dependabot covers `gomod` (repo root), `npm` (`/` and `/internal/dev_serve | Package | Mode | Extra check | | --- | --- | --- | -| `react`, `react-dom`, `react-router` | `UI_COMPUTER_USE` | Rebuild embed, boot server, click all three nav routes. Router majors (7 → 8) are `ESCALATE` until the app still renders | +| `react`, `react-dom`, `react-router` | `UI_COMPUTER_USE` | Rebuild embed, boot server, click all three nav routes. A router major is `ESCALATE` until the app still renders | | `@launchpad-ui/core`, `components`, `icons`, `tokens` | `UI_COMPUTER_USE` | Same; look for unstyled / missing primitives | | `launchdarkly-js-client-sdk` | `UI_COMPUTER_USE` | UI must still boot; client-side evaluate may be empty without a client-side ID | | `lodash`, `fuzzysort`, `react-window` | `UI_COMPUTER_USE` | Flags list / search / virtualized rows | @@ -75,58 +75,3 @@ ldcli Dependabot covers `gomod` (repo root), `npm` (`/` and `/internal/dev_serve | `actions/checkout`, `actions/setup-go`, `actions/setup-node`, `actions/setup-python` | `CI_ONLY` | Read the workflow. Majors that change default Node/Go setup are `ESCALATE` | | `googleapis/release-please-action` | `CI_ONLY` | Do not run a release | | `alpine` in `Dockerfile.goreleaser` | `CI_ONLY` | Optional: `docker build` if Docker is available; otherwise changelog + escalate native deps | - -## Worked examples (ldcli Dependabot PRs) - -These are the classification answers a verification agent should reach. They are not merge approvals. - -### [#726](https://github.com/launchdarkly/ldcli/pull/726) — `go-sqlite3` 1.14.28 → 1.14.47 (patch) - -- **Mode:** `STORE_SMOKE` -- **Surface:** CGO SQLite driver for local dev-server + events DB + backup/restore. -- **CI already:** `go test ./...` includes `internal/dev_server/db/backup` and SDK tests that open a real sqlite store. -- **Gap:** CI never starts the HTTP server, never opens a second connection after process restart, never hits `/ui`. -- **Extra check:** targeted store tests, `make build`, `ldcli dev-server start`, curl `/ui/`, confirm `dev_server.db` exists, optional computer-use load of the empty UI, restart once. -- **Video:** yes if the UI process is up — prove `/ui/flags` renders after the driver bump. Skip if CGO cannot build. -- **Watch:** CString leak / callback ordering fixes are driver-internal; a boot + read/write is the available extra signal, not a proof of those C bugs. - -### [#725](https://github.com/launchdarkly/ldcli/pull/725) — `cobra` 1.9.1 → 1.10.2 (minor) - -- **Mode:** `CLI_SMOKE` -- **Surface:** command tree, help, completion, usage templates. -- **CI already:** command-construction unit tests. -- **Gap:** CI does not execute the shipped binary's help/completion entrypoints. Cobra 1.10.0 pulled a pflag rename (`ParseErrorsWhitelist` → `ParseErrorsAllowlist`, restored as deprecated in pflag 1.0.9 / cobra 1.10.1). -- **Extra check:** `make build` + help for commands this branch actually has; `go test ./cmd/...`. Grep for `ParseErrorsWhitelist` / `ParseErrorsAllowlist`. -- **Stale-branch note:** this PR has sat long enough that automatic rebases were disabled. A smoke on the Dependabot commit is not a smoke of cobra 1.10.2 against current `cmd/setup`. -- **Video:** optional. A 20-second TTY help walk is enough; a browser is not. - -### [#626](https://github.com/launchdarkly/ldcli/pull/626) — `golang.org/x/term` 0.33.0 → 0.36.0 (minor) - -- **Mode:** `CLI_SMOKE` -- **Surface:** `term.GetSize` for wrapped flag help; `term.IsTerminal` for output format and setup prompts. -- **CI already:** `TestNewRootCommandNilIsTerminalRejects`, non-TTY output tests. Those inject a fake `IsTerminal`. -- **Gap:** CI is not a real TTY, so `GetSize` always takes the width-80 fallback. -- **Extra check:** piped `./ldcli --help` (fallback path) plus, if computer use can open a terminal, run help in that TTY. Do not claim you tested wrapping unless you saw a TTY width. -- **Video:** only for the TTY case. A piped command in the agent log is not a video. - -### [#621](https://github.com/launchdarkly/ldcli/pull/621) — `go.uber.org/mock` 0.5.2 → 0.6.0 (minor) - -- **Mode:** `TEST_ONLY` -- **Surface:** `mockgen` in `tools.go` and generated mocks. No production import. -- **CI already:** `go test ./...` is the entire product impact. -- **Gap:** none that a GUI can close. v0.6.0 adds archive-mode mockgen and a go1.25 tools bump. -- **Extra check:** `go test ./...`. Optional `go generate` on one mock directive; expect an empty diff. -- **Video:** none — computer use would not add signal. - -## Nearby PRs that change the mode - -Use these when the automation is pointed at the current Dependabot backlog, not only the four above. - -| PR | Package | Mode | -| --- | --- | --- | -| #729 | `react-router` 7.12.0 → 8.0.1 | `ESCALATE` + `UI_COMPUTER_USE` (major, nav will break if incompatible) | -| #723 | `@launchpad-ui/core` 0.49.22 → 0.59.17 | `UI_COMPUTER_USE` | -| #724 | `prettier` 3.3.2 → 3.8.4 | `BUILD_ONLY` | -| #728 | `rollup` lockfile | `BUILD_ONLY` | -| #721 / #717 / #719 | GitHub Actions majors | `CI_ONLY` or `ESCALATE` | -| #716 | `alpine` 3.19 → 3.24 | `CI_ONLY` |