Add prerelease-test skill for release QA campaigns - #7001
Conversation
Captures the workflow used to validate the 0.9.9 release train as a repeatable skill, so the same analysis can be kicked off before any release. SKILL.md lays out the phases: discover what shipped from the pre-release branch changelogs and confirm every package published to PyPI, de-risk with a smoke test, fan out feature clusters that build real apps and drive them in a browser, upgrade-test reflex-examples apps from the previous stable, regression-test reflex-enterprise demos, audit wheel/sdist packaging, then triage into fix-before-release vs file-as-issue. Testing installs only published packages, baselines against the previous stable to tell regressions from pre-existing bugs, and verifies each claimed issue with an independent reproducer before reporting it. references/ holds the brief handed to each test agent (hard rules, environment traps, known-benign console noise), cluster decomposition guidance, the Workflow explore/verify pipeline with schemas and a port map, and report templates. scripts/ bundles three helpers, each validated against the released 0.9.9 train: - check_release_versions.py: changelog versions -> PyPI publication check (16 packages, all published) - audit_pyi.py: stubs present in both wheel and sdist, byte-identical, no foreign stubs, counts vs pyi_hashes.json (121 stubs, clean) - drive_app.py: Chromium driver with console/network capture, a small JSON action language and benign-noise filtering Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
ruff-format runs on markdown in pre-commit, so embedded python blocks are formatted too; the import/assert one-liner becomes two statements. Reproduced locally with the locked ruff 0.16.3, which now reports the whole skill directory as already formatted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
Merging this PR will not alter performance
Comparing Footnotes
|
There was a problem hiding this comment.
8 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:192">
P2: When the initial page cannot connect or times out, `page.goto` raises before the driver writes `--report` or prints the captured failure details. Catch startup navigation errors, record them in the report, close the browser, and return the documented failure status.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:70">
P2: When a `never-publish-packages` entry also has a `CHANGELOG.md`, `changelog_paths` includes it and `main` reports its missing PyPI version as a release blocker. Read the release configuration and exclude never-published packages before scanning changelogs.
(Based on your team's feedback about excluding never-published packages from release paths.)</violation>
<violation number="2" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:123">
P2: When PyPI is temporarily unreachable, `pypi_status` returns `published=False`, so `main` counts the package as missing and reports it as unpublished. Track verification errors separately, exclude them from `missing`, and report an indeterminate check without a false publication blocker.</violation>
</file>
<file name=".claude/skills/prerelease-test/references/orchestration.md">
<violation number="1" location=".claude/skills/prerelease-test/references/orchestration.md:87">
P2: When a verify agent dies and its `agent(...)` call resolves to a falsy value, the `.then((v) => ({ issue: iss, verdict: v }))` wrapper turns it into a truthy `{ issue, verdict: null }` entry, so `.filter(Boolean)` keeps it. The explore branch in the same pipeline explicitly guards `if (!res) return { .., agent_died: true }`, but verification has no equivalent guard, so a dead verifier leaves an issue with `verdict: null` in `verified_issues`. Later report parsing (VERDICT_SCHEMA requires `confirmed` and `notes`) will then crash or treat an unverified issue as real in the report. Return `null` from the `.then` when `v` is falsy so the filter drops it.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:156">
P2: When PyPI lacks either artifact, `audit()` omits `expected`, so `main()` raises `KeyError` instead of reporting the missing artifact and aborts the remaining package audits. Include `expected` in this early-return record.</violation>
<violation number="2" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:201">
P2: When a package has no manifest entry, `want` is `None` and the audit accepts any number of own stubs instead of enforcing the documented zero-stub expectation. Track whether a manifest was loaded and treat an absent package entry as an expected count of zero.</violation>
</file>
<file name=".claude/skills/prerelease-test/SKILL.md">
<violation number="1" location=".claude/skills/prerelease-test/SKILL.md:51">
P2: The documented invocation `scripts/check_release_versions.py <git-ref>` is wrong: the script requires the git ref via the `--ref` flag (argparse: `parser.add_argument("--ref", required=True)`). Running the documented form exits with `error: the following arguments are required: --ref` and extracts nothing. Change it to `scripts/check_release_versions.py --ref <git-ref>` so agents following Phase 0 don't hit the argparse error.</violation>
<violation number="2" location=".claude/skills/prerelease-test/SKILL.md:62">
P2: The `scripts/...` paths (check_release_versions.py, drive_app.py, audit_pyi.py) resolve only when run from the skill directory, but the skill's agents operate from the repo root (it says to commit under `prerelease-testing/...` in the repo). These three scripts were added under `.claude/skills/prerelease-test/scripts/`, not repo-root `scripts/` (repo-root `scripts/` has no such files). An agent following the skill from the repo root gets 'command not found'. Use the skill-relative path (e.g. `.claude/skills/prerelease-test/scripts/...`) or state the CWD explicitly.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Greptile SummaryThe PR adds a reusable pre-release QA skill covering release discovery, published-package smoke testing, browser-driven feature validation, upgrade and enterprise regression testing, packaging audits, and adversarial finding verification.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| .claude/skills/prerelease-test/SKILL.md | Defines the complete release-QA workflow and now correctly gates packaging audits on successful release discovery. |
| .claude/skills/prerelease-test/scripts/check_release_versions.py | Discovers release versions and distinguishes confirmed missing publications from indeterminate PyPI lookup failures. |
| .claude/skills/prerelease-test/scripts/audit_pyi.py | Audits stub packaging while consistently reporting missing artifacts and separating infrastructure failures from packaging defects. |
| .claude/skills/prerelease-test/scripts/drive_app.py | Provides browser-driven smoke-test actions with console and network capture plus early action validation. |
| pyproject.toml | Adds a narrowly scoped Ruff allowance for print-based reporting in the QA helper scripts. |
Reviews (12): Last reviewed commit: "Make the documented commands runnable an..." | Re-trigger Greptile
There was a problem hiding this comment.
8 issues found across 9 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/SKILL.md">
<violation number="1" location=".claude/skills/prerelease-test/SKILL.md:51">
P2: The documented invocation `scripts/check_release_versions.py <git-ref>` fails because the script requires a `--ref <git-ref>` flag (argparse `--ref`, required=True). Document the correct form so a user following Phase 0 doesn't hit an argparse error.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:70">
P2: When a never-published package has a stray `CHANGELOG.md`, `changelog_paths` treats it as part of the release train and can fail QA because that package is not on PyPI. Read the release configuration at `ref` and exclude `never-publish-packages` before checking versions.</violation>
<violation number="2" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:167">
P2: When PyPI returns a non-404 or the lookup fails, `pypi_status()` still sets `published` false, so this list reports a transient outage as an unpublished release blocker. Distinguish confirmed 404s from lookup failures before populating `missing`.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:109">
P2: When auditing packages whose import root differs from their distribution name, this heuristic rejects the packageβs own stubs as foreign. Read the packageβs actual top-level roots or provide an explicit distribution-to-import mapping instead of assuming hyphens are the only difference.</violation>
<violation number="2" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:156">
P2: When a published version has only one artifact kind, this branch omits `expected`, so `main()` crashes with `KeyError` while printing the result. Include the expected-manifest value in this return record so missing artifacts produce the intended audit failure summary.</violation>
<violation number="3" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:201">
P2: When a package has no entry in a loaded manifest, this check treats it as unchecked instead of expecting zero stubs. Distinguish an unavailable manifest from a loaded manifest, then flag own stubs for packages omitted from the loaded manifest.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:76">
P2: Inline action JSON longer than a filesystem filename makes `candidate.exists()` raise `OSError` before parsing, so documented inline scripts fail instead of running. Catch path-stat errors and parse `raw` as JSON.</violation>
<violation number="2" location=".claude/skills/prerelease-test/scripts/drive_app.py:202">
P2: After the final `click`, `fill`, or `press`, Playwright returns before Reflex's asynchronous event and network work finishes. Reading the report and closing the browser immediately can miss late page errors or failed requests; wait for settlement after the action loop.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
All eight were valid. check_release_versions: publication status is now tri-state so a network failure is indeterminate (exit 2) rather than a false 'unpublished' blocker, and never-publish-packages from the release config are excluded from the scan. audit_pyi: the missing-artifact early return omitted 'expected' and crashed main() with KeyError, and a package absent from the manifest is now held to zero stubs instead of going unchecked. drive_app: a server that never came up raised out of page.goto before the report was written; startup failures are captured and exit 1. orchestration: a dead verifier no longer leaves verdict:null in verified_issues. SKILL.md: the documented invocation omitted --ref and bare scripts/... paths collide with the repo's own scripts/ directory. Re-validated after the changes: discovery finds 16 published packages, the documented Phase 5 pipe audits 121 stubs clean, and the driver's clean, action-failure and dead-server paths all behave as documented. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
Four further valid findings, distinct from the first round: - drive_app: inline action JSON longer than the filesystem's filename limit made Path(raw).exists() raise OSError before parsing, so the documented inline form failed for any non-trivial script (verified: a 1109-byte payload raised 'File name too long' before, runs now). - drive_app: the report was read immediately after the last action, so anything it triggered could land after the browser closed. - audit_pyi: the import root came from a dist-name heuristic; it now comes from the stub manifest, which is authoritative and β unlike deriving it from the artifact β keeps the foreign-stub check meaningful. - scripts: dropped bare python3 shebangs for PEP 723 metadata and 'uv run --script', matching scripts/check_min_deps.py and CLAUDE.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Both bot review rounds are addressed β all twelve distinct findings were valid, and each fix was verified by reproducing the reported failure first. Pushed as 0487b40 and e59fdbd. Round one
Round two
On the import-root one specifically: deriving the root from the artifact's own top-level directories would be circular β foreign stubs would define themselves as native and the leak check could never fail β so the manifest is the right source of truth, with the heuristic left as the fallback for a package the manifest doesn't know. End-to-end re-check after both rounds: discovery finds 16 published packages, the documented Phase 5 pipe audits 121 stubs clean, and the driver passes its clean, long-inline-JSON, action-failure and dead-server paths. Generated by Claude Code |
There was a problem hiding this comment.
4 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:95">
P1: When a tracked `CHANGELOG.md` has no matching version heading, `main()` silently omits that package and can return 0, so the QA campaign misses its publication check. Fail the run or record an error for the changelog instead of continuing.</violation>
<violation number="2" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:141">
P2: When all PyPI files for a version are yanked, this code still reports `published`, so the release check can call a version installable even though normal resolution ignores it. Filter out yanked URLs and treat an all-yanked release as unavailable.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:45">
P2: When a requested release is missing from PyPI or the metadata request fails, `download_artifacts` aborts the whole campaign with a traceback. Catch download failures per spec, record them as problems, and continue to return a controlled nonzero result.</violation>
</file>
<file name=".claude/skills/prerelease-test/references/clusters.md">
<violation number="1" location=".claude/skills/prerelease-test/references/clusters.md:51">
P3: The `scripts/audit_pyi.py` path here is wrong: the repo-root `scripts/` directory (which `SKILL.md` explicitly warns is an unrelated directory) contains no `audit_pyi.py`. The script lives at `.claude/skills/prerelease-test/scripts/audit_pyi.py`, and `SKILL.md` states that skill script paths are repo-root-relative with the `.claude/skills/prerelease-test/` prefix required. An agent following this packaging-cluster brief will get a "No such file or directory" failure. Reference the full path as phase 5 of `SKILL.md` does.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
--specs feeds a downloader, so a package whose PyPI check could not complete was turning a controlled indeterminate result into a traceback one stage later. Emit only confirmed-published rows, and report the skipped ones on stderr so a short list is never mistaken for a complete one. Guard the download in audit() too, so a package that cannot be fetched for any other reason fails on its own row instead of aborting the whole audit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
There was a problem hiding this comment.
3 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:98">
P1: When a tracked changelog has no versioned section, `main` silently omits it and can report a clean release with no packages. Treat a missing version heading as an error and return non-zero instead of continuing.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:212">
P2: When `--actions` contains invalid JSON or `null`, `load_actions` raises before `try_action` runs, so the CLI exits with a traceback and never writes the requested report. Parse and validate the action list inside the reporting path, then record the parse error as `action_error`.</violation>
</file>
<file name=".claude/skills/prerelease-test/references/orchestration.md">
<violation number="1" location=".claude/skills/prerelease-test/references/orchestration.md:95">
P3: The pipeline example claims `results.filter(Boolean)` drops dead explorers, but the explorer-died branch returns a truthy marker object (`{ cluster: c.key, agent_died: true }`), so `filter(Boolean)` keeps every one of them. Anyone building this workflow from the doc will expect the final `results` to contain only clusters with genuine (schema-conforming) findings, yet dead clusters survive as `agent_died` objects that do not satisfy FINDINGS_SCHEMA (missing `summary`/`tests`/`issues`/`artifacts_dir`). Either drop died explorers explicitly (e.g. `results.filter(r => !r.agent_died)`) or correct the comment to state dead explorers are kept as markers the orchestrator must handle.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
A changelog with no version heading was skipped silently, so the one package whose publication went unverified was also the one the report never mentioned. Record it as indeterminate, which keeps it out of --specs and exits 2. Also treat a fully yanked release as not installable, note partial yanks in the detail column, and give the packaging cluster the same repo-root-relative script path the rest of the skill uses. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Rounds 3 and 4 addressed β five findings, all valid.
Verification
Generated by Claude Code |
There was a problem hiding this comment.
3 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:87">
P2: When `--actions` contains malformed JSON or an unreadable path, `load_actions` raises before the normal failure handling, so the CLI prints a traceback and never writes `--report`. Catch action-script parsing errors in `main`, record them as `action_error`, and continue through the normal report and exit-1 path.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:59">
P2: When a PyPI artifact transfer stalls, `urlretrieve` has no timeout, so the release audit can hang indefinitely instead of recording a fetch failure. Download through `urlopen(..., timeout=60)` or otherwise apply a bounded read timeout.</violation>
<violation number="2" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:229">
P2: When a published wheel or sdist is corrupt, the archive reader raises outside the per-package error handling, aborting the audit and preventing later packages from being checked. Catch archive-read errors here and record them as package problems, as fetch errors already are.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Documenting phase 5 as a shell pipe meant the audit's exit status replaced the discovery script's, so a package dropped for an incomplete PyPI check took the audit's PASS with it. Document it as two commands instead. Parse --actions before launching the browser: doing it after spent a launch and a page load on a typo and left a traceback where the report should be. A list that is not a list now says so too. Say plainly in the orchestration example that dead explorers are kept as markers, since filter(Boolean) does not drop them and should not. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Round 5 β three new findings, all valid, plus one CI note.
The remaining P1 in that round ( Verification
CI: Generated by Claude Code |
There was a problem hiding this comment.
5 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:100">
P2: When an `internal-packages` entry also has `CHANGELOG.md`, this code treats its ignored changelog heading as the release version and can report a false PyPI blocker. Exclude internal packages from this discovery path as well, matching `reflex-release`'s changelog rules.</violation>
</file>
<file name=".claude/skills/prerelease-test/references/orchestration.md">
<violation number="1" location=".claude/skills/prerelease-test/references/orchestration.md:98">
P3: The comment "results.filter(Boolean) drops dead explorers" is wrong: a dead explorer is already replaced with the truthy placeholder `{ cluster: c.key, agent_died: true }` by `if (!res) return ...`, so `filter(Boolean)` only removes falsy values and the dead-explorer entries survive into the returned results. The placeholder also omits the FINDINGS_SCHEMA-required `tests`, `issues`, and `artifacts_dir`, so downstream report parsing sees an entry shaped like a valid cluster. Either return a falsy value (e.g. `return null`) for dead explorers so the filter drops them, or drop `agent_died` entries explicitly and update the comment.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:53">
P2: When a version has both live and yanked wheel or sdist files, this loop can select the yanked file for auditing. Skip yanked entries before selecting artifacts.</violation>
<violation number="2" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:59">
P2: When a PyPI artifact download stalls, `urlretrieve` calls `urlopen` without a timeout, so this campaign can hang indefinitely despite the 60-second metadata timeout. Download through `urlopen(..., timeout=60)` instead.</violation>
<violation number="3" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:229">
P2: When PyPI serves a corrupt archive, `wheel_stubs` or `sdist_stubs` aborts the audit outside its per-package error handler. Catch archive-read failures around both calls and record the package problem.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
urlretrieve honours only the global socket timeout, which is unset, so a stalled PyPI transfer would hang the whole audit instead of failing one row. Stream the download through urlopen with a timeout. A corrupt wheel or sdist raised out of audit() and took the rest of the train with it, the same way an unreachable package used to. Handle it per package. Every exit from audit() now goes through one record builder, so the reporting loop can no longer meet a record that is missing a key it reads. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Round 6 β two more in
A corrupt wheel or sdist aborted the run (P2). While fixing these I collapsed the four exits from Verification
The three round-5 threads and the greptile Generated by Claude Code |
Internal packages are patch-released on every push to main rather than through the changelog, so a changelog heading in one names a version that was never cut and would be checked against PyPI as a false blocker. Exclude them alongside the never-published ones, which the release config already groups the same way. Never audit a yanked artifact when a live one of the same kind exists: it is not what a user installs, so the audit would be reporting on the wrong file. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Round 7 β five raised, two new and valid, three already fixed in the previous push. Internal packages not excluded from discovery (P2, new). Valid, and the same reasoning that made the Yanked artifacts could be audited (P2, new). Valid:
Verification
Generated by Claude Code |
An unreachable PyPI or an unreadable archive was being recorded as a packaging defect, so a healthy package would fail the release on infrastructure trouble. Track those as unchecked instead and exit 2, the same missing-versus-unknown split check_release_versions.py already makes, and exit 1 only for a defect observed in artifacts that were actually read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
One more, and a good one: "download failures become packaging defects" (greptile P1). Valid β
Verification of all three exit paths
Generated by Claude Code |
There was a problem hiding this comment.
2 issues found and verified against the latest diff
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:235">
P2: When the first or only action fails after triggering page work, the script skips the settle wait and can miss late anomalies. Wait whenever an action was attempted, including failed actions.</violation>
</file>
<file name=".claude/skills/prerelease-test/references/orchestration.md">
<violation number="1" location=".claude/skills/prerelease-test/references/orchestration.md:89">
P2: Dead verifiers are silently filtered out of `verified_issues`, while dead explorers are deliberately kept as `agent_died: true` markers - and this doc's own rationale for the explorer policy applies equally to verifiers. A died verify agent leaves its issue absent from `verified_issues` but still present in the returned full `res.issues`, so downstream it is indistinguishable from an issue excluded by the `slice(0, 4)` fan-out cap or one the verifier never reached. A report writer (whom the doc tells to handle dead explorers explicitly but says nothing about verifiers) can therefore mistake a verification hole for a clean result - the exact silent-drop-looks-clean failure this document warns against for explorers. Record died verifiers as an explicit marker instead of filtering them to `null`.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
|
Round 9 β two findings, both valid, and the second one catches a real inconsistency in my own reasoning.
Dead verifiers were silently dropped while dead explorers are kept (P2). This one is a fair hit. In round 1 the guidance was to drop a dead verifier rather than record Verification β A/B on the settle change, using a page whose only action fails while still doing work (a
Generated by Claude Code |
The shared preamble handed every agent a 20-port range, but the map gives a verify agent only 4, so a verifier following the bootstrap verbatim would reach into its sibling's range β the collision the map exists to prevent. Take the ends from the table instead of a fixed span. Say which venv the checkout-shadowing guard should name. It is the brief's most important instruction and it was the one placeholder with three plausible fills. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Round 10 β four raised, two new and valid, one already fixed, one I'm declining. The agent preamble overpromised ports (P2, new). A genuine inconsistency in my own doc, and the kind that only bites under load: the shared preamble handed every agent The shadowing guard didn't say which venv (P3, new). Fair: Dead verifier marker (P2) β fixed in ef6815a, one push ahead of this review. Two threads in this round carry no body at all (just "P2:"); they sit on the verifier and port lines, so I've treated them as duplicates of the bodied findings and resolved them with those. Declining: root package in This looks like the learned rule from round 1 (exclude never-published packages from release paths) being applied one step past where it holds; the round-7 Generated by Claude Code |
There was a problem hiding this comment.
1 existing issue remains and 3 new issues found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:159">
P2: When PyPI or a proxy returns HTTP 200 JSON without `urls`, `pypi_status()` treats the response as a confirmed missing release and blocks QA. Validate the response shape and return `error` for an indeterminate response instead.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:271">
P2: When a truncated gzip sdist raises `EOFError`, this handler misses it and the audit aborts instead of reporting the package as indeterminate. Catch `EOFError` here so interrupted downloads follow the documented exit-2 path.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:222">
P2: If an action closes the page, this post-action settle call raises outside `try_action` and aborts before the report and `RESULT` line are emitted. Catch the settle failure and guard subsequent page operations so closed-page actions become a recorded anomaly.</violation>
</file>
Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Re-trigger cubic
A 200 response that is not PyPI's shape was read as a confirmed missing release: only urls present and empty means that, so anything else is now indeterminate rather than a false blocker. A truncated gzip sdist raises EOFError, which is neither OSError nor TarError, so the audit aborted on exactly the interrupted download the surrounding handler was written for. A page an action crashes or closes made the settle and the screenshot raise outside every guard, so the run ended in a traceback with no report at all -- the report being the one thing the caller was waiting for. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Round 11 β three findings, all valid, all fixed in 0e1c17d. A 200 that isn't PyPI's shape read as a missing release. A truncated gzip sdist aborted the audit. Verified before fixing β A crashed or closed page killed the run before the report. The best of the three. The post-action settle and the screenshot both sat outside every guard, so a page an action crashes took down the whole invocation β losing the report, which is the one thing the caller wanted. Both guarded now, with a Verification
On the process: that's eleven rounds and 27 findings, 26 of them valid β a good hit rate, and these three were real bugs rather than polish. But each push draws the next review, so the loop is now self-sustaining and the returns are narrowing to error paths I keep adding guards to. I'll stay responsive to anything substantive; if you'd rather freeze it here for human review, say the word and I'll stand down. The one thread I've left open is the round-10 Generated by Claude Code |
There was a problem hiding this comment.
1 issue found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:68">
P2: When a download fails after writing part of an artifact and `--keep` is used, this leaves the partial file at the final path, so the next run skips downloading it and remains stuck on the truncated artifact. Download to a temporary `.part` path and atomically rename it only after the copy succeeds, removing the temporary file on failure.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
A download that died partway wrote its bytes straight to the final path, and --keep skips whatever already exists, so every later run reused the truncated file. The EOFError handling added last commit made that worse: it tells you to re-run to tell a bad download from a bad artifact, and re-running could not clear the bad download. Write to .part and rename only once the copy completes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Round 12 β one finding, valid, fixed in 778ac15. A partial download stuck at the final path. A transfer that died partway wrote its bytes straight to the destination, and Verification
Generated by Claude Code |
There was a problem hiding this comment.
3 issues found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:279">
P2: When a wheel has corrupted compressed stub data, `wheel_stubs()` raises `zlib.error`, which this handler does not catch. Catch `zlib.error` along with the other archive-read failures so one unreadable artifact is reported as unchecked and does not abort the remaining package audits.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:166">
P2: When a proxy returns a malformed `urls` list, `pypi_status` crashes instead of reporting an indeterminate check. Validate each entry before calling `.get` or indexing `packagetype`, and return the existing `"error", "unexpected PyPI response shape"` result for malformed file records.</violation>
</file>
<file name=".claude/skills/prerelease-test/SKILL.md">
<violation number="1" location=".claude/skills/prerelease-test/SKILL.md:129">
P2: The two-command form does not actually gate the audit on the discovery check's exit status. If both lines are executed together, the second runs regardless of the first command's non-zero exit, so the truncated-list PASS the prose says it avoids still happens unless the exit code is acted on. Preface with `set -e` (or chain with `&&`) so the audit is skipped when the check returns 1 or 2, and state that the audit must only run after the check exits 0.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Two commands on separate lines never gated anything: the audit ran whatever discovery returned, so the truncated-list PASS the prose claims to prevent still happened. Chain them with && so a non-zero discovery skips the audit. A urls list whose entries are not PyPI's raised out of pypi_status instead of reporting one bad check, and a corrupted deflate stream raises zlib.error, which subclasses only Exception and so missed the archive handler entirely. Name exceptions module-qualified unless they are builtins: zlib.error is called just "error", and "could not read artifacts: error" tells the reader nothing. Report an unknown --ref rather than letting CalledProcessError print a stack about subprocess internals over what is almost always a typo. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
There was a problem hiding this comment.
1 existing issue remains and 2 new issues found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:166">
P2: When a proxy returns a `urls` list with a malformed entry, `pypi_status` raises instead of returning the documented `error` status, aborting the release check without its exit-2 handling. Validate each URL record and its `packagetype` before filtering it.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:82">
P2: When the screenshot destination cannot be prepared, `mkdir` raises before this guard, so the driver still exits with a traceback instead of reporting `SCREENSHOT FAILED` and writing the QA result. Move screenshot-directory creation inside the same exception handler and record setup failures in `screenshot_error`.</violation>
</file>
Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Re-trigger cubic
|
Round 13 β three findings, all valid, fixed in 5bf408a, plus two things I found while verifying them. The two-command form didn't actually gate anything. The sharpest of the three, because it's a hole in my own round-5 fix: I replaced the pipe to preserve the discovery exit status, then left the two commands on separate lines where the audit runs regardless. The prose described a guarantee the snippet didn't provide. Chained with Malformed A corrupted deflate stream aborted the audit. Verified before fixing β a wheel with scribbled compressed payload raises Two things the verification turned up on its own:
Verification
Generated by Claude Code |
The screenshot's mkdir sat outside the handler added for the screenshot itself, so a destination that cannot be created still ended the run in a traceback -- the same hole the handler was there to close, one line above it. The report write had no guard at all: losing the file should not also lose the findings, so the summary now prints either way. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
One more, valid, fixed in c356b8b β and it's a hole one line above the guard I added for it last round. The screenshot's Verification β with a plain file where the parent directory would have to be:
That's 14 rounds and 34 findings, 33 of them valid β a hit rate worth saying out loud. The last several have all been one shape: a raise escaping a guard, or a guard that didn't quite cover its own setup line. That's a real class of bug and I've been fixing them, but it's also a surface with no natural end, and every push draws the next review. I'm going to stop actively iterating here unless something lands that's materially different in kind β a wrong result, a broken workflow, a security issue β or you tell me to keep going. The PR is in a good state for human review: greptile is at 5/5 with no blocking failure, and the one thread I've deliberately left open is the round-10 root-package claim I declined and explained. Generated by Claude Code |
There was a problem hiding this comment.
1 existing issue remains and 2 new issues found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:112">
P2: When the root package is listed in `never-publish-packages` or `internal-packages`, discovery still checks the root `CHANGELOG.md` and can report a false PyPI blocker or emit that package in `--specs`. Apply the exclusion to the root changelog using the configured root package name before appending it.
(Based on your team's feedback about never-publish packages being excluded from all release paths.)</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:253">
P2: When the target page closes or becomes unreadable after a successful load/action, this fallback hides the inspection failure while `clean` remains true. Record the read exception and include it in the failure criteria.</violation>
</file>
Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:301">
P2: When `--report` cannot be created or written, this handler only prints a warning and leaves `clean` unchanged. A healthy app therefore returns 0 and prints `RESULT: clean`; mark the run failed after this catch so automation cannot treat a missing requested QA artifact as a pass.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Reading the title and body was guarded, but the failure only reached the body text, so a page that died after a successful load and actions produced RESULT: clean and exit 0. A QA driver that says clean when it inspected nothing is the one result it must never produce, so the read failure is now recorded and counts against the run. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
I said I'd stop unless something materially different turned up. This is it β fixed in dd3dbac. An unreadable page could report a clean run. Not another missing guard: a wrong result. The title/body read was already wrapped, but the failure only reached the body text, never the Verification β forced the page read to fail on a page with no other anomaly (a static page with an inline favicon, so not even a 404 in the console), and A/B'd the
The baseline row matters as much as the others: a genuinely quiet page still reports clean, so this didn't make the driver paranoid. The failure also prints as
The other finding in this round is the root-package Generated by Claude Code |
SKILL.md moved to && so a failed discovery cannot hand its dropped packages to a passing audit, but this script still documented the pipe it warns about, so anyone reading the script instead of the skill would copy the masking form. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
One more, valid, fixed in e860265 β greptile's P1 on When I moved I also removed a
Standing state: the only open thread is the root-package Generated by Claude Code |
The guard added two commits ago printed REPORT NOT WRITTEN and carried on, so a healthy app with an unwritable --report path still printed RESULT: clean and exited 0. A caller that asked for a report and got none has no result to trust, and automation would have read that as a pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Same class as the last one, and this time it's a bug I introduced. Fixed in e2bbca3. An unwritable Verification β three cases on a page with no console noise:
The third row is the one that matters for not over-correcting: a run that never asked for a report is still clean.
Generated by Claude Code |
There was a problem hiding this comment.
1 existing issue remains and 1 new issue found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:305">
P2: When `--report` points to an unwritable path, this handler only prints a warning, so a clean page still reports `RESULT: clean` and exits 0 despite the requested QA artifact being missing. Track the report-write failure as a run error while retaining the console summary.</violation>
</file>
Requires human review: Auto-approval blocked because this review re-detected 1 unresolved issue already reported by Cubic.
Re-trigger cubic
There was a problem hiding this comment.
3 issues found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/drive_app.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/drive_app.py:91">
P2: When `--actions` is a list containing a non-object or multi-key action, `load_actions` accepts it and the driver launches Chromium before reporting an action failure. Validate that every item is a single-entry object before returning the action list so malformed input follows the early `INVALID --actions` path.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/audit_pyi.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/audit_pyi.py:23">
P2: Copying this documented chain fails because neither script is executable and neither has a shebang. Invoke both scripts with `uv run --script`, as the skill's canonical command does.</violation>
</file>
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:176">
P2: When a response entry has a valid `packagetype` but no boolean `yanked`, this treats it as live and reports `published`; validate `yanked` in the response-shape guard.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
There was a problem hiding this comment.
1 issue found across 7 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid β if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name=".claude/skills/prerelease-test/scripts/check_release_versions.py">
<violation number="1" location=".claude/skills/prerelease-test/scripts/check_release_versions.py:36">
P2: When `root-package` is listed in `internal-packages`, this new exclusion does not apply to the root `CHANGELOG.md`, so the script checks a patch-released package against PyPI and can report a false blocker. Apply the exclusion check to the root changelog before appending it.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
Both usage docstrings showed bare script invocations, but these scripts have no shebang and no exec bit by design -- the PEP 723 metadata is there so uv builds the environment. Copying either documented line failed. Show uv run --script, the same form the skill's canonical command uses. A list whose items are not single-key objects passed validation and failed later inside the action loop, spending a browser launch and a page load on a typo the early exit was added to catch. A yanked flag that is present but not a boolean no longer reads as live: absent still means not yanked, but a value that is not PyPI's cannot be interpreted. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
|
Three findings, all valid, fixed in 3b965b9. The documented invocations didn't run. My own regression from the docstring rewrite one commit earlier: both scripts show bare A list of malformed actions slipped past validation. A non-boolean Verification
Generated by Claude Code |
|
Thread housekeeping, so the open list means something when you review. The root-package Three open threads all saying that makes the open list unreadable, so I've resolved the two later duplicates and left the original β r3884855428 β open as the single place the disagreement lives. I'm not resolving my own declined judgement away; it's still there for you to overrule, and it's now the only thread standing between this PR and a clean board. Everything else is resolved and fixed. Final state: 16 review rounds, 40 findings, 39 of them valid. Generated by Claude Code |
All Submissions:
Type of change
Tooling only β no framework code changes, nothing shipped in any package.
New Feature Submission:
Description
Captures the pre-release QA campaign run against the 0.9.9 train as a repeatable skill, so the same analysis can be kicked off before any release instead of being reconstructed from scratch each time. That campaign found 29 verified issues, 11 of which were fixed before 0.9.9 shipped (#6971, #6984, #6985, #6986, #6987, #6989, #6990, #6991, #6992, #6994) with the rest filed as #6972β#6983.
.claude/skills/prerelease-test/SKILL.mdlays out the phases: discover what shipped from the pre-release branch changelogs and confirm every package published to PyPI, de-risk with a smoke test, fan out feature clusters that build real apps and drive them in a browser, upgrade-test reflex-examples apps from the previous stable, regression-test reflex-enterprise demos, audit wheel/sdist packaging, then triage into fix-before-release vs file-as-issue.Three habits are what made the campaign's output actionable, so they are written in explicitly rather than left to chance:
references/holds the brief given to each test agent (hard rules, environment traps like checkout shadowing ofimport reflex, and the known-benign console noise list), cluster decomposition guidance, the Workflow explore/verify pipeline with schemas and a port map, and report templates.scripts/bundles three helpers the test agents kept rewriting independently:check_release_versions.pyaudit_pyi.pypyi_hashes.jsondrive_app.pyNote on the pyproject change
The one non-skill change is two lines in
pyproject.toml. Ruff selectsALLwith no.claudeexclude, so these scripts are linted by CI. Everything ruff flagged is fixed in the scripts themselves (Args/Returns docstring sections, annotations,EM102, and an action-loop restructure that avoids bothPERF401andPERF203while still preserving the record of actions that succeeded before a failure). The exception isT201β printing a report is these scripts' entire purpose β which is whitelisted exactly the wayscripts/check_min_deps.pyalready is.Test Plan
uvx ruff@0.16.3 check .claude/skills/prerelease-test/scripts/andruff format --checkβ both clean, using the version locked inuv.lock.drive_app.pywas additionally checked for its failure path (a failing action reports the error, keeps the already-successful actions, skips the rest, exits 1) and its noise filter (--all-consoleshows the lines it normally suppresses).π€ Generated with Claude Code
https://claude.ai/code/session_01EMjBXPozsNeQNSBZecNH8x
Generated by Claude Code