Release sample sweep (chrome-devtools)
Before a release, every user-facing surface is exercised the way a user
exercises it. This skill is that procedure written down.
Three surfaces, three drivers — all three are release gates:
| Surface |
What |
Driver |
| Samples (33) |
samples/*, booted from packaged artifacts |
chrome-devtools MCP, or the wire protocol for the headless ones |
| Expo client (1) |
samples/spring-boot-ai-classroom/expo-client/ |
iOS simulator MCP — it is a native app, chrome-devtools cannot reach it |
| CLI |
atmosphere run / new / compose / import / checkpoint + its four distributions |
Shell, then chrome-devtools against what atmosphere run booted |
When to run it
- Before cutting any release. Non-negotiable — it is the last gate before
release-4x.yml.
- After a change to the Console bundle (
modules/spring-boot-starter/frontend/),
since the Console is both the shipped sample UI and the validation surface.
- After a change to a shared module that every sample transitively depends on
(
modules/cpr, modules/ai, modules/spring-boot-starter, modules/admin).
- After a dependency bump wave — two of the last three sweeps found a
version-skew bug that compiled clean and only failed at runtime.
What it catches that CI does not
CI builds and tests modules; this sweep exercises packaged artifacts in a
browser. The gap between those is where the real bugs live:
| Sweep |
Bug found |
Why CI was green |
| 2026-06-30 |
quarkus-ai-chat would not start — OTel api/common version skew from a Dependabot bump |
Module tests never boot the sample's fast-jar |
| 2026-07-17 |
spring-boot-orchestration-demo crashed on every tool turn — the sample pom hardcoded langchain4j-open-ai:1.15.0 while the reactor manages 1.17.0 |
The module built against 1.17.0; only the sample's own jar bundled 1.15.0 |
scripts/release-gate-samples.sh automates the boot-and-assert half of this in
CI. This sweep is the browser half on top of it — the layer that sees
rendering, streaming, transport headers, tool cards, and console errors.
The shape of the sweep
Step 0 Preconditions — build everything, start Ollama, free the ports, open the ledger
Step 1a Samples — 33 samples: launch → drive → collect → verdict → teardown
Step 1b Expo client — the RN client in the iOS simulator
Step 1c CLI — atmosphere run/new/compose/import/checkpoint + distributions
ALL OF PHASE 1 IS COLLECT-ONLY. Do not fix anything mid-sweep.
Step 2 Triage — classify every finding, rank by blast radius
Step 3 Fix — root-cause fix + a regression test per issue, in the right
suite, each proven to bite
Step 4 Re-test — the failed surfaces in full, plus the blast-radius subset
of already-passing ones
Step 5 Report — vault report, CI green, memory updated
Step 1 is deliberately fix-free. Fixing mid-sweep changes the artifact under
test and invalidates every sample already verified against the old one. The one
exception: a defect that blocks the sweep itself from continuing — fix it,
say so in the ledger, and note which already-passed samples were re-run.
Non-negotiables
- chrome-devtools, never curl, for validation.
curl is allowed only for
port readiness and for headless wire protocols (A2A/MCP/REST) that serve no
HTML. A "works via curl" claim skips the whole JS layer and is a false pass.
- The Atmosphere Console is the UI. Drive
/atmosphere/console/ (Spring
Boot samples redirect / there). A sample that needs a bespoke page instead
of the Console is itself a finding.
- Assert the rendered element, not the payload. An
image node with a
src is a rendered screenshot; the same base64 in a StaticText node means
nothing rendered it. "Server started", "HTTP 200", and "bytes present in the
DOM" are not passes.
- Boot the packaged artifact.
java -jar (or quarkus-run.jar), never
spring-boot:run / quarkus:dev. Both historical bugs above existed only
at artifact level.
- Kill by PID, never
pkill -f. Never touch a port or process the sweep
did not start — if a port is occupied, move to another port. The same rule
covers the machine's network: never run networksetup, never take an
interface down, never touch VPN/DNS/proxy settings. The host's Wi-Fi carries
every session the maintainer has open, and a sweep interrupted mid-toggle can
leave the machine offline indefinitely. Any assertion that needs real network
loss is recorded PARTIAL with its unit coverage cited — see
references/expo-sweep.md.
- Model limitation ≠ framework bug. A small local model emitting invalid
tool-call arguments is a model limitation; record it as such and prove it by
re-running the same flow on a capable model before calling it a regression.
- Never write "flaky". Reproduce it, or explain the mechanism. If neither
is possible yet, it is a FAIL with an open question, not a dismissal.
- Report honestly. PASS / PARTIAL / FAIL with one line of concrete
evidence each. PARTIAL must name what was not proven and why.
Step 0 — Preconditions
git status --porcelain # must be clean
git rev-parse --short HEAD # record this SHA in the ledger
grep -m1 '<version>' pom.xml # record the version under test
./mvnw install -DskipTests -Pfastinstall # full reactor: framework + every sample jar
./scripts/sync-console-bundle.sh --check # the Console you will drive must be current
ollama list # qwen2.5:3b + qwen2.5:7b-instruct-q4_K_M
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:11434/v1/models
LLM backend is local Ollama, keyless. Use qwen2.5:3b for streaming
samples and qwen2.5:7b-instruct-q4_K_M for tool-heavy agents — 3b emits
invalid tool-call arguments and Ollama answers 400. Note real-ollama is a
CI-harness alias only; AiConfig matches the literal local.
The launcher scrubs ambient LLM env (LLM_API_KEY, LLM_BASE_URL,
LLM_MODE, LLM_MODEL, and the provider keys) from every sample it boots, so
the sweep is reproducible on any machine. SWEEP_KEEP_ENV=1 inherits instead.
If you boot a sample by hand, scrub them yourself — a maintainer's profile
routinely exports these.
Always read the resolved endpoint out of the boot log before driving:
grep 'AI config:' target/sweep/<sample>.log
Expect mode=local … endpoint=http://localhost:11434/v1. Anything else means
the sample is not talking to Ollama and the turn's result says nothing about
this build. An explicit LLM_BASE_URL outranks the mode by design, so an
inherited one silently redirects a "local" run to a remote provider — that is
what happened on the 2026-08-07 shakedown before the scrub existed.
Do not use a paid key. The paid-LLM lane is retired; quota starvation is
what made the 2026-06 sweep report nine samples as plumbing-only.
Do not use embacle (embacle-server --provider claude_code) for
tool-calling samples — it applies the host CLI's own configuration to
responses and its tool-call fidelity is inconsistent. It is only useful to
demonstrate "a capable model completes this flow cleanly", then stop it.
Ports: the sweep runs on the 9101+ block so it never collides with the
samples' own defaults or the Playwright fixture's 8080–8104. Assignments are
in references/sample-matrix.md.
Open the ledger at claude_docs/sample-sweep-<YYYY-MM-DD>.md (a gitignored
symlink into the vault, so it survives context compaction). Template:
assets/ledger-template.md. Write each row as you finish that sample,
never in a batch at the end.
Step 1a — The per-sample loop
Work through references/sample-matrix.md in order. For each sample:
# 1. Launch (the helper refuses to boot if the port is already answering)
.claude/skills/release-sample-sweep/scripts/sweep-sample.sh start <sample> \
--port <9101+n> --ready-path <path> --env LLM_MODE=local --env LLM_MODEL=qwen2.5:3b
- Fresh browser page per sample —
new_page on the drive URL. Never reuse
the previous sample's page: stale state and leftover console noise both
corrupt the evidence.
- Snapshot —
take_snapshot. Confirm the Console mounted and the transport
badge reads what the matrix expects (Connected · websocket /
· webtransport / · grpc / · ag-ui). A transport that silently fell back
is a finding.
- Drive the headline flow for that sample — the exact interaction is in the
matrix, the mechanics per surface class are in
references/driving-recipes.md.
- Wait for the rendered result —
wait_for the expected text/element, then
re-take_snapshot and confirm the node type (see non-negotiable #3).
- Collect the evidence, all three sources:
list_console_messages — every error and warning, verbatim
list_network_requests — any non-2xx/failed request
sweep-sample.sh warnings <sample> — server-side WARN/ERROR/exception/SLF4J
Record warnings even when the sample passes. The warning inventory is half
the value of the sweep and is what the next release's triage starts from.
- Verdict + one-line evidence into the ledger:
- PASS — headline feature observed rendered, no unexplained console error,
no server exception.
- PARTIAL — plumbing proven, headline feature not observed, reason named
(missing third-party key, Docker unavailable, model limitation).
- FAIL — feature broken, error frame, exception, or the sample won't boot.
- Teardown —
close_page, then
sweep-sample.sh stop <sample>. The helper verifies the port is actually
released; if it is not, stop and investigate before the next sample claims it.
Step 1b — The Expo client
samples/spring-boot-ai-classroom/expo-client/ is a native Expo/RN app. It is
not a Maven module, not in cli/samples.json, and unreachable by the
Playwright suites — this sweep is its only gate. It links atmosphere.js by
file path, so it is also the only pre-release check that the client library's
./react-native export works in a real RN runtime.
Driven with the iOS simulator MCP, not chrome-devtools. Full procedure,
including the SERVER_URL port trap and the AppState/NetInfo assertions nothing
else covers: references/expo-sweep.md.
Step 1c — The CLI
The CLI is the documented Quick Start and ships as four distributions
(curl installer, npx, Homebrew tap, SDKMAN). CI covers list/info, argument
validation, the runtime overlays, and the installers — it never boots a sample
through atmosphere run and looks at the UI, and it has no coverage for
compose or checkpoint.
The manual pass closes that: atmosphere run → browser-driven, atmosphere new
→ scaffold + compile against Maven Central, plus the thin-coverage commands and
a post-publish check of the actually-shipped artifacts. Watch the jar cache —
a stale $ATMOSPHERE_HOME/cache/v<version> boots the previous release and fakes
a pass. Full procedure: references/cli-sweep.md.
Step 2 — Triage
With all samples tested, classify each finding before touching any code:
| Class |
Meaning |
Action |
| Framework bug |
A module under modules/ is wrong |
Fix + regression spec. Release-blocking. |
| Sample bug |
Only that sample's code/pom/config is wrong |
Fix + regression spec. Release-blocking if the sample ships. |
| Config/env |
Sample needs a key, Docker, a collector |
Not a bug — document the graceful-degradation behaviour and assert that |
| Model limitation |
Small local model can't drive the flow |
Prove with a capable model, record, no code change |
| Sweep environment |
Port conflict, stale ~/.m2, half-built reactor |
Fix the environment and re-run that sample |
Rank by blast radius: shared-module findings first (they can invalidate other
samples' passes), then per-sample.
Step 3 — Fix, with a regression test per issue
Every issue gets a test, but in the suite that can actually run it:
| Surface the issue is on |
Regression home |
| Sample / Console / framework |
Playwright spec → references/regression-specs.md |
| CLI |
A case in cli/test-cli.sh (a Playwright spec is the wrong vehicle for a shell CLI) |
| Expo / React Native |
An atmosphere.js vitest covering the ./react-native export path; if the defect is genuinely RN-runtime-only, name it in the report as manual-sweep-only rather than faking a gate |
For every issue in the framework-bug or sample-bug class:
- Root-cause it first. Read the failing path; do not pattern-match a fix.
- Smallest change that fixes the cause — the 2026-07 langchain4j fix was a
single pom property.
- Write a Playwright e2e spec that reproduces the failure, in the right
home, wired into the right CI lane, and proven to bite: it must fail
against the pre-fix artifact and pass after. Recording only "it passes now"
proves nothing. Full authoring + wiring recipe:
references/regression-specs.md.
- Where a build-time lint can close the whole class, add that too — the
langchain4j fix shipped both a spec and
SampleLangChain4jVersionLintTest,
which fails the build if any sample pom hardcodes a LangChain4j version.
- Rebuild the affected modules and samples before re-testing.
- One commit per fix class, conventional-commit prefixed. No CHANGELOG edits —
the CHANGELOG is touched only at release time.
Step 4 — Re-test
- Re-run the failed sample end to end — the full headline flow, not just
the broken step.
- Re-run the blast-radius subset of already-passing samples. The fix
changed the artifact those passes were recorded against, so their evidence is
only still valid if the fix could not reach them. The mapping from
"what the fix touched" to "which passing samples must be re-driven" is in
references/retest-subset.md.
- Say what you did not re-run and why. A subset is a deliberate scope
decision; leaving it unstated reads as "everything was re-verified".
- Repeat triage → fix → re-test until the sweep is clean.
Step 5 — Report
- Vault report via the
obsidian-writer skill →
Claude Outputs/Sample-Sweep-chrome-devtools-<date>.md. Promote the ledger:
full matrix with the evidence column, the issues-found-and-fixed section with
commit hashes, methodology caveats, and non-blocking follow-ups.
- Every number verified — sample count from
ls samples/ (minus
shared-resources) and cli/samples.json, never from memory.
- CI green on the fix commits before the release proceeds — all workflows,
not just the one you were watching.
- Update memory with anything reusable: a new trap, a new drive recipe, a
changed port, a sample added or removed.
Files in this skill
| File |
Use |
references/sample-matrix.md |
Every sample: boot type, sweep port, drive surface, headline assertion, gating |
references/driving-recipes.md |
chrome-devtools call sequences per surface class + browser-layer traps |
references/expo-sweep.md |
Step 1b — the RN client in the iOS simulator |
references/cli-sweep.md |
Step 1c — what CI already covers, the real gaps, and the CLI pass |
references/regression-specs.md |
Where a Playwright spec lives, how to wire it into CI, how to prove it bites |
references/retest-subset.md |
Blast radius → which passing samples to re-drive after a fix |
references/troubleshooting.md |
Known traps: PNA, long-poll probes, stale jars, port collisions, Quarkus LLM config |
assets/ledger-template.md |
The sweep ledger to copy into claude_docs/ |
scripts/sweep-sample.sh |
Boot one sample from its packaged artifact on a sweep port and leave it running |
1---2name: release-sample-sweep3description: Run the pre-release end-to-end sweep of every user-facing surface — the 33 samples under samples/ (booted from their packaged artifacts and driven in a real browser via chrome-devtools MCP), the Expo/React Native client, and the atmosphere CLI. Use before cutting a release, and after any change to the Console bundle, a shared module, atmosphere.js, the CLI, or several samples at once. Covers preconditions, the keyless Ollama backend, the per-sample launch/drive/collect/teardown loop, the evidence ledger, the fix phase (every issue gets a biting regression test in the right suite), the re-test subset, and the report.4---56# Release sample sweep (chrome-devtools)78Before a release, every user-facing surface is exercised the way a user9exercises it. This skill is that procedure written down.1011Three surfaces, three drivers — all three are release gates:1213| Surface | What | Driver |14|---|---|---|15| **Samples** (33) | `samples/*`, booted from packaged artifacts | chrome-devtools MCP, or the wire protocol for the headless ones |16| **Expo client** (1) | `samples/spring-boot-ai-classroom/expo-client/` | iOS simulator MCP — it is a native app, chrome-devtools cannot reach it |17| **CLI** | `atmosphere run` / `new` / `compose` / `import` / `checkpoint` + its four distributions | Shell, then chrome-devtools against what `atmosphere run` booted |1819## When to run it2021- **Before cutting any release.** Non-negotiable — it is the last gate before22 `release-4x.yml`.23- After a change to the **Console bundle** (`modules/spring-boot-starter/frontend/`),24 since the Console is both the shipped sample UI and the validation surface.25- After a change to a **shared module** that every sample transitively depends on26 (`modules/cpr`, `modules/ai`, `modules/spring-boot-starter`, `modules/admin`).27- After a **dependency bump wave** — two of the last three sweeps found a28 version-skew bug that compiled clean and only failed at runtime.2930## What it catches that CI does not3132CI builds and tests modules; this sweep exercises **packaged artifacts in a33browser**. The gap between those is where the real bugs live:3435| Sweep | Bug found | Why CI was green |36|---|---|---|37| 2026-06-30 | `quarkus-ai-chat` would not start — OTel api/common version skew from a Dependabot bump | Module tests never boot the sample's fast-jar |38| 2026-07-17 | `spring-boot-orchestration-demo` crashed on every tool turn — the sample pom hardcoded `langchain4j-open-ai:1.15.0` while the reactor manages 1.17.0 | The module built against 1.17.0; only the sample's own jar bundled 1.15.0 |3940`scripts/release-gate-samples.sh` automates the boot-and-assert half of this in41CI. This sweep is the **browser half** on top of it — the layer that sees42rendering, streaming, transport headers, tool cards, and console errors.4344## The shape of the sweep4546```47Step 0 Preconditions — build everything, start Ollama, free the ports, open the ledger48Step 1a Samples — 33 samples: launch → drive → collect → verdict → teardown49Step 1b Expo client — the RN client in the iOS simulator50Step 1c CLI — atmosphere run/new/compose/import/checkpoint + distributions51 ALL OF PHASE 1 IS COLLECT-ONLY. Do not fix anything mid-sweep.52Step 2 Triage — classify every finding, rank by blast radius53Step 3 Fix — root-cause fix + a regression test per issue, in the right54 suite, each proven to bite55Step 4 Re-test — the failed surfaces in full, plus the blast-radius subset56 of already-passing ones57Step 5 Report — vault report, CI green, memory updated58```5960Step 1 is deliberately fix-free. Fixing mid-sweep changes the artifact under61test and invalidates every sample already verified against the old one. The one62exception: a defect that **blocks the sweep itself** from continuing — fix it,63say so in the ledger, and note which already-passed samples were re-run.6465## Non-negotiables66671. **chrome-devtools, never curl, for validation.** `curl` is allowed only for68 port readiness and for headless wire protocols (A2A/MCP/REST) that serve no69 HTML. A "works via curl" claim skips the whole JS layer and is a false pass.702. **The Atmosphere Console is the UI.** Drive `/atmosphere/console/` (Spring71 Boot samples redirect `/` there). A sample that needs a bespoke page instead72 of the Console is itself a finding.733. **Assert the rendered element, not the payload.** An `image` node with a74 `src` is a rendered screenshot; the same base64 in a `StaticText` node means75 nothing rendered it. "Server started", "HTTP 200", and "bytes present in the76 DOM" are not passes.774. **Boot the packaged artifact.** `java -jar` (or `quarkus-run.jar`), never78 `spring-boot:run` / `quarkus:dev`. Both historical bugs above existed *only*79 at artifact level.805. **Kill by PID, never `pkill -f`.** Never touch a port or process the sweep81 did not start — if a port is occupied, move to another port. The same rule82 covers the machine's **network**: never run `networksetup`, never take an83 interface down, never touch VPN/DNS/proxy settings. The host's Wi-Fi carries84 every session the maintainer has open, and a sweep interrupted mid-toggle can85 leave the machine offline indefinitely. Any assertion that needs real network86 loss is recorded PARTIAL with its unit coverage cited — see87 `references/expo-sweep.md`.886. **Model limitation ≠ framework bug.** A small local model emitting invalid89 tool-call arguments is a model limitation; record it as such and prove it by90 re-running the same flow on a capable model before calling it a regression.917. **Never write "flaky".** Reproduce it, or explain the mechanism. If neither92 is possible yet, it is a FAIL with an open question, not a dismissal.938. **Report honestly.** PASS / PARTIAL / FAIL with one line of concrete94 evidence each. PARTIAL must name what was not proven and why.9596## Step 0 — Preconditions9798```bash99git status --porcelain # must be clean100git rev-parse --short HEAD # record this SHA in the ledger101grep -m1 '<version>' pom.xml # record the version under test102103./mvnw install -DskipTests -Pfastinstall # full reactor: framework + every sample jar104./scripts/sync-console-bundle.sh --check # the Console you will drive must be current105106ollama list # qwen2.5:3b + qwen2.5:7b-instruct-q4_K_M107curl -s -o /dev/null -w '%{http_code}\n' http://localhost:11434/v1/models108```109110- **LLM backend is local Ollama, keyless.** Use `qwen2.5:3b` for streaming111 samples and `qwen2.5:7b-instruct-q4_K_M` for tool-heavy agents — 3b emits112 invalid tool-call arguments and Ollama answers 400. Note `real-ollama` is a113 CI-harness alias only; `AiConfig` matches the literal `local`.114- **The launcher scrubs ambient LLM env** (`LLM_API_KEY`, `LLM_BASE_URL`,115 `LLM_MODE`, `LLM_MODEL`, and the provider keys) from every sample it boots, so116 the sweep is reproducible on any machine. `SWEEP_KEEP_ENV=1` inherits instead.117 If you boot a sample by hand, scrub them yourself — a maintainer's profile118 routinely exports these.119- **Always read the resolved endpoint out of the boot log before driving:**120121 ```122 grep 'AI config:' target/sweep/<sample>.log123 ```124125 Expect `mode=local … endpoint=http://localhost:11434/v1`. Anything else means126 the sample is not talking to Ollama and the turn's result says nothing about127 this build. An explicit `LLM_BASE_URL` outranks the mode by design, so an128 inherited one silently redirects a "local" run to a remote provider — that is129 what happened on the 2026-08-07 shakedown before the scrub existed.130- **Do not use a paid key.** The paid-LLM lane is retired; quota starvation is131 what made the 2026-06 sweep report nine samples as plumbing-only.132- **Do not use embacle** (`embacle-server --provider claude_code`) for133 tool-calling samples — it applies the host CLI's own configuration to134 responses and its tool-call fidelity is inconsistent. It is only useful to135 demonstrate "a capable model completes this flow cleanly", then stop it.136- **Ports:** the sweep runs on the 9101+ block so it never collides with the137 samples' own defaults or the Playwright fixture's 8080–8104. Assignments are138 in `references/sample-matrix.md`.139- **Open the ledger** at `claude_docs/sample-sweep-<YYYY-MM-DD>.md` (a gitignored140 symlink into the vault, so it survives context compaction). Template:141 `assets/ledger-template.md`. Write each row **as you finish that sample**,142 never in a batch at the end.143144## Step 1a — The per-sample loop145146Work through `references/sample-matrix.md` in order. For each sample:147148```bash149# 1. Launch (the helper refuses to boot if the port is already answering)150.claude/skills/release-sample-sweep/scripts/sweep-sample.sh start <sample> \151 --port <9101+n> --ready-path <path> --env LLM_MODE=local --env LLM_MODEL=qwen2.5:3b152```1531542. **Fresh browser page per sample** — `new_page` on the drive URL. Never reuse155 the previous sample's page: stale state and leftover console noise both156 corrupt the evidence.1573. **Snapshot** — `take_snapshot`. Confirm the Console mounted and the transport158 badge reads what the matrix expects (`Connected · websocket` /159 `· webtransport` / `· grpc` / `· ag-ui`). A transport that silently fell back160 is a finding.1614. **Drive the headline flow** for that sample — the exact interaction is in the162 matrix, the mechanics per surface class are in `references/driving-recipes.md`.1635. **Wait for the rendered result** — `wait_for` the expected text/element, then164 re-`take_snapshot` and confirm the node type (see non-negotiable #3).1656. **Collect the evidence, all three sources:**166 - `list_console_messages` — every error and warning, verbatim167 - `list_network_requests` — any non-2xx/failed request168 - `sweep-sample.sh warnings <sample>` — server-side WARN/ERROR/exception/SLF4J169 Record warnings even when the sample passes. The warning inventory is half170 the value of the sweep and is what the next release's triage starts from.1717. **Verdict + one-line evidence** into the ledger:172 - **PASS** — headline feature observed rendered, no unexplained console error,173 no server exception.174 - **PARTIAL** — plumbing proven, headline feature not observed, *reason named*175 (missing third-party key, Docker unavailable, model limitation).176 - **FAIL** — feature broken, error frame, exception, or the sample won't boot.1778. **Teardown** — `close_page`, then178 `sweep-sample.sh stop <sample>`. The helper verifies the port is actually179 released; if it is not, stop and investigate before the next sample claims it.180181## Step 1b — The Expo client182183`samples/spring-boot-ai-classroom/expo-client/` is a native Expo/RN app. It is184**not** a Maven module, **not** in `cli/samples.json`, and unreachable by the185Playwright suites — this sweep is its only gate. It links `atmosphere.js` by186file path, so it is also the only pre-release check that the client library's187`./react-native` export works in a real RN runtime.188189Driven with the **iOS simulator MCP**, not chrome-devtools. Full procedure,190including the `SERVER_URL` port trap and the AppState/NetInfo assertions nothing191else covers: `references/expo-sweep.md`.192193## Step 1c — The CLI194195The CLI is the documented Quick Start and ships as four distributions196(curl installer, npx, Homebrew tap, SDKMAN). CI covers `list`/`info`, argument197validation, the runtime overlays, and the installers — it never boots a sample198through `atmosphere run` and looks at the UI, and it has no coverage for199`compose` or `checkpoint`.200201The manual pass closes that: `atmosphere run` → browser-driven, `atmosphere new`202→ scaffold + compile against Maven Central, plus the thin-coverage commands and203a post-publish check of the actually-shipped artifacts. Watch the jar cache —204a stale `$ATMOSPHERE_HOME/cache/v<version>` boots the previous release and fakes205a pass. Full procedure: `references/cli-sweep.md`.206207## Step 2 — Triage208209With all samples tested, classify each finding before touching any code:210211| Class | Meaning | Action |212|---|---|---|213| Framework bug | A module under `modules/` is wrong | Fix + regression spec. Release-blocking. |214| Sample bug | Only that sample's code/pom/config is wrong | Fix + regression spec. Release-blocking if the sample ships. |215| Config/env | Sample needs a key, Docker, a collector | Not a bug — document the graceful-degradation behaviour and assert *that* |216| Model limitation | Small local model can't drive the flow | Prove with a capable model, record, no code change |217| Sweep environment | Port conflict, stale `~/.m2`, half-built reactor | Fix the environment and re-run that sample |218219Rank by blast radius: shared-module findings first (they can invalidate other220samples' passes), then per-sample.221222## Step 3 — Fix, with a regression test per issue223224Every issue gets a test, but **in the suite that can actually run it**:225226| Surface the issue is on | Regression home |227|---|---|228| Sample / Console / framework | Playwright spec → `references/regression-specs.md` |229| CLI | A case in `cli/test-cli.sh` (a Playwright spec is the wrong vehicle for a shell CLI) |230| Expo / React Native | An `atmosphere.js` vitest covering the `./react-native` export path; if the defect is genuinely RN-runtime-only, name it in the report as manual-sweep-only rather than faking a gate |231232For **every** issue in the framework-bug or sample-bug class:2332341. **Root-cause it first.** Read the failing path; do not pattern-match a fix.2352. **Smallest change that fixes the cause** — the 2026-07 langchain4j fix was a236 single pom property.2373. **Write a Playwright e2e spec that reproduces the failure**, in the right238 home, wired into the right CI lane, and **proven to bite**: it must fail239 against the pre-fix artifact and pass after. Recording only "it passes now"240 proves nothing. Full authoring + wiring recipe:241 `references/regression-specs.md`.2424. **Where a build-time lint can close the whole class, add that too** — the243 langchain4j fix shipped both a spec and `SampleLangChain4jVersionLintTest`,244 which fails the build if any sample pom hardcodes a LangChain4j version.2455. **Rebuild** the affected modules and samples before re-testing.2466. One commit per fix class, conventional-commit prefixed. No CHANGELOG edits —247 the CHANGELOG is touched only at release time.248249## Step 4 — Re-test2502511. **Re-run the failed sample end to end** — the full headline flow, not just252 the broken step.2532. **Re-run the blast-radius subset** of already-passing samples. The fix254 changed the artifact those passes were recorded against, so their evidence is255 only still valid if the fix could not reach them. The mapping from256 "what the fix touched" to "which passing samples must be re-driven" is in257 `references/retest-subset.md`.2583. **Say what you did not re-run and why.** A subset is a deliberate scope259 decision; leaving it unstated reads as "everything was re-verified".2604. Repeat triage → fix → re-test until the sweep is clean.261262## Step 5 — Report263264- **Vault report** via the `obsidian-writer` skill →265 `Claude Outputs/Sample-Sweep-chrome-devtools-<date>.md`. Promote the ledger:266 full matrix with the evidence column, the issues-found-and-fixed section with267 commit hashes, methodology caveats, and non-blocking follow-ups.268- **Every number verified** — sample count from `ls samples/` (minus269 `shared-resources`) and `cli/samples.json`, never from memory.270- **CI green** on the fix commits before the release proceeds — all workflows,271 not just the one you were watching.272- **Update memory** with anything reusable: a new trap, a new drive recipe, a273 changed port, a sample added or removed.274275## Files in this skill276277| File | Use |278|---|---|279| `references/sample-matrix.md` | Every sample: boot type, sweep port, drive surface, headline assertion, gating |280| `references/driving-recipes.md` | chrome-devtools call sequences per surface class + browser-layer traps |281| `references/expo-sweep.md` | Step 1b — the RN client in the iOS simulator |282| `references/cli-sweep.md` | Step 1c — what CI already covers, the real gaps, and the CLI pass |283| `references/regression-specs.md` | Where a Playwright spec lives, how to wire it into CI, how to prove it bites |284| `references/retest-subset.md` | Blast radius → which passing samples to re-drive after a fix |285| `references/troubleshooting.md` | Known traps: PNA, long-poll probes, stale jars, port collisions, Quarkus LLM config |286| `assets/ledger-template.md` | The sweep ledger to copy into `claude_docs/` |287| `scripts/sweep-sample.sh` | Boot one sample from its packaged artifact on a sweep port and leave it running |