chore(release): promote next to production (2026-08-03) - #561
Merged
Conversation
…arn group across 1 directory (#534) * chore(deps-dev): bump esbuild Bumps the npm_and_yarn group with 1 update in the / directory: [esbuild](https://github.com/evanw/esbuild). Updates `esbuild` from 0.25.12 to 0.28.1 - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG-2025.md) - [Commits](evanw/esbuild@v0.25.12...v0.28.1) --- updated-dependencies: - dependency-name: esbuild dependency-version: 0.28.1 dependency-type: direct:development ... Signed-off-by: dependabot[bot] <support@github.com> * chore(deps-dev): regenerate bun.lock for esbuild 0.28.1 bump --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Nick Koutrelakos <wkoutre@users.noreply.github.com> Co-authored-by: Nick Koutrelakos <nick.koutrelakos@uniswap.org>
Co-authored-by: Nick Koutrelakos <nick.koutrelakos@uniswap.org> Co-authored-by: Nick Koutrelakos <wkoutre@users.noreply.github.com>
…as (#544) * feat(uniswap-integrations): add datadog-cost-tracker skill with gotchas Captures two operational gotchas discovered during a Datadog cost-tracker run so future runs avoid the same false-negative / false-positive traps: 1. env:prod filter silently drops Lambda/serverless services (unirpc-v2, notification-service) from estimated_usage.logs.ingested_bytes -- omit env filter and verify tag presence via get_datadog_metric_context. 2. Uniroute APM baseline is invalid before 2026-05-14 (PRs #7996/#7510/#7998 normalised DD_ENV tag, causing a 22x apparent jump) -- mark pre/post comparisons as INCONCLUSIVE, not REGRESSION. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CaswXmq8Xotq8La9SNJrSy * fix(uniswap-integrations): correct datadog-cost-tracker metric and tool names - APM span ingestion metric: apm_hosts (host count, not service-tagged) removed; ingested_spans corrected to datadog.estimated_usage.apm.ingested_spans - Replace bare unprefixed Datadog tool names with intent-based language via the Datadog MCP server, matching the sibling investigate-incident skill's pattern - Note that estimated-usage metric names must be confirmed against the account's Metrics Explorer (querying a nonexistent name returns empty, not an error) Addresses the automated review's blocking finding on PR #544. * chore(uniswap-integrations): bump to 2.6.0 and document datadog-cost-tracker - Bump plugin 2.5.0 -> 2.6.0 (2.5.0 was taken by use-datadog in #432) - Add datadog-cost-tracker to plugin README skills table, plugin CLAUDE.md skills list, and file-structure tree (the review's noted doc gaps) --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Nick Koutrelakos <wkoutre@users.noreply.github.com> Co-authored-by: Nick Koutrelakos <nick.koutrelakos@uniswap.org>
…reate_pull_request tools (#550) The PostToolUse matcher "Bash|create_pull_request" contains only exact-match characters, so Claude Code evaluates it as a list of exact tool names, not a regex. No MCP tool is named bare create_pull_request (they are namespaced, e.g. mcp__github__create_pull_request), so the MCP branch of pr-skill-doctor-prompt.cjs was unreachable and the /skill-mine nudge was silently lost for MCP-created PRs. "Bash|mcp__.+__create_pull_request" contains regex metacharacters, which flips the whole matcher into (unanchored) regex mode and matches any mcp__<server>__create_pull_request tool name. Bumps skill-management to 1.0.2.
* chore: update model references to claude-sonnet-5 * chore(development-codebase-tools): bump plugin to 2.6.2 for agent model frontmatter change Two agent files (context-loader.md, style-enforcer.md) changed their model: frontmatter to claude-sonnet-5; the repo requires a version bump in the same change for any packages/plugins/ modification. Patch bump since the change is internal with no user-facing behavior change. Root CLAUDE.md version table updated to match.
…t-resistant (#557) * docs: fix stale 5-plugin claims and make inventory drift-resistant .claude/rules/plugin-docs.md is loaded into every session's context, so its "## The 5 Plugins" section was actively steering plugin work away from claude-setup, skill-management, and spec-workflow. The repo has had 8 plugins for some time; the root CLAUDE.md already said 8, so the two contradicted each other. Rather than just correcting 5 to 8 (which drifts again on the next addition), both files now name packages/plugins/ and .claude-plugin/marketplace.json as the source of truth, give an enumeration command, and state that the enumerated output wins over the inline snapshot. - plugin-docs.md: rewrite "The 5 Plugins" as "The Plugins" with a source-of-truth block, an enumeration command, a one-line parity check between the directories and marketplace.json, and a dated snapshot that readers are told to repair on mismatch - plugin-docs.md: "Each of the 5 plugins has its own section" -> "Each plugin" - CLAUDE.md: same de-hardcoding for the inventory bullet and the same "Each of the 5 plugins" phrasing in the Notion sync section Left .plan/DEV-218-implementation.md alone: its "5 plugins" is a point-in-time justification in a completed migration plan, and rewriting it would make it wrong about the state it describes. No files under packages/plugins/ changed, so no plugin version bump applies. * docs: check marketplace source paths, not just names, in parity check The parity check compared .plugins[].name against the directory names. That passes even when an entry's `source` is stale or copy-pasted, because `name` is not the field that determines what loads. .github/actions/validate-plugins/action.yml:64-71 resolves .plugins[i].source into PLUGIN_PATH and validates that path; `name` is only used for log output. So an entry named `foo` whose source still points at `./packages/plugins/ skill-management` makes the validator check skill-management twice while `foo` goes unreferenced - and the old check certified that as parity. Reproduced against a scratch fixture: names-vs-dirs passed, sources-vs-dirs caught it. Replaced with two checks: (1) resolved source paths against the directories on disk, (2) each entry's name against its own source basename. Both verified silent against the current marketplace.json, and executed verbatim as extracted from the rendered file to confirm the jq escapes survive prettier.
) * refactor(ci): review ai-toolkit's own PRs with @uniswap/review-cli Point .github/workflows/claude-code-review.yml at @uniswap/review-cli from Uniswap/internal-tools, the shared reviewer already used by Uniswap/universe and Uniswap/backend, instead of this repo's own _claude-code-review.yml. The reusable _claude-code-review.yml is unchanged and still published for its 10+ external consumers, all of which pin it by commit SHA. Only ai-toolkit's own review path moves; build-prompt.ts, post-review.ts, and .github/prompts/pr-review/ stay in place for those callers. Quality parity, verified against `review-cli triage` rather than assumed: - Dependency PRs are still reviewed (skip.authors: [], dependency branch prefixes omitted) so auto-merge-dependabot can keep gating on the review result. - claude[bot] draft PRs are still reviewed on open. review-cli's skip.drafts is a single boolean that cannot express that carve-out, so skip.drafts is false and the draft policy lives in the job-level if:. - Title-based automation detection (chore(release):, chore(sync):) is retained via the shared check-automated-pr action, which review-cli's branch/author skip policy has no equivalent for. - Fork PRs are still never reviewed, resolved via the API in the triage job since the CLI has no fork concept. - workflow_dispatch still takes pr_number and force_review; force_review maps to --force, not --fresh, to preserve iterative review context. The gate deliberately does NOT use --skip-config from review-cli's upstream workflow template. That flag passes no policy at all, which is not the same as using defaults: skip.drafts falls back to true (skipping claude[bot] drafts) while branch and author skips are not applied. A guard step fails the job if .claude/review.yml is missing, because loadConfig treats a missing file as "use defaults" silently. Improvements over the retired path: - claude-opus-5 reviewers with claude-fable-5 synthesis, up from claude-opus-4-8 - Comment triggers restricted to OWNER/MEMBER/COLLABORATOR, which the previous workflow did not check on this public repo - An investigation gate demotes an unsubstantiated empty-findings APPROVE to COMMENT - Two repo-specific reviewers encode house rules that previously lived only in documentation: workflow-security-reviewer (expression injection, SHA pinning, permission scope, Bullfrog steps, reusable workflow contract breaks) and plugin-conventions-reviewer (the mandatory plugin.json version bump, manifest drift, naming) - Workflow-level permissions: {} deny-by-default Verified: actionlint clean, zizmor clean, markdownlint 0 errors across 197 files, nx lint 0 errors, nx typecheck pass, 89 tests pass. * fix(ci): load review tooling from the trusted ref, not the PR head Addresses all four findings from the first review-cli run on this PR. The `review` job checked out `refs/pull/N/head` and then resolved `./.github/actions/install_review_cli` and `.claude/` out of that same workspace. Two problems in one line: - Availability: the composite action does not exist on branches cut before it landed, so every open PR's next review would die with "Can't find 'action.yml'" until it rebased. - Trust: the head branch controlled the installer shell and the agent prompts in a job holding CLAUDE_CODE_OAUTH_TOKEN and a `contents: write` token. `.github/actions/**` is not covered by the `workflow` token scope that guards `.github/workflows/**`. The PR head is now checked out only as the content under analysis, with `.github/actions` + `.claude` sparse-checked-out from the default ref into `.review-tooling/` afterwards (order matters: checkout runs `git clean -ffdx`). The workspace `.claude` is replaced with the trusted copy behind a presence guard, mirroring the triage gate. Config and agent changes now take effect only once merged, which is intended. Also: - Add a step-level `timeout-minutes: 17` to Analyze. The job-level ceiling *cancels*, and `success() || failure()` excludes cancellation, so an overrun skipped Post and left the sticky on "Review running" forever. Not widened to `always()` on purpose: concurrency uses cancellation too, and a dying run would clobber its successor's sticky. - Correct the "structurally cannot write to GitHub" comment. That is a property of review-cli's pipeline, not of the token in the step's environment, and it should not be cited to relax the fork guard. Verified: actionlint clean, markdownlint clean, zizmor unchanged at 8 findings (no new ones introduced). * fix(ci): pin the trusted tooling checkout to the default branch The previous commit's "trusted ref" checkout had no `ref:`, which does not mean the default branch: actions/checkout falls back to GITHUB_SHA, and on a `pull_request` event that is the merge commit (base + head). The head branch therefore still influenced the supposedly-trusted installer and agent set, so the fix did not actually close the hole it described. Pin it to `github.event.repository.default_branch` explicitly. The triage job's checkout stays unpinned on purpose, and now says why: it holds no CLAUDE_CODE_OAUTH_TOKEN and runs no agent, so the worst case there is a PR altering its own review eligibility rather than code execution with a credential. Its fork guard reads the API, not config, so it cannot be disabled from the PR branch. * fix(ci): skip CLI steps when the installer never ran Reproduced live on this PR: the trusted-config guard failed (expected during bootstrap), so `Install review-cli` never ran and its `bin-path` output was empty. `Post` still executed on `success() || failure()`, resolved "$REVIEW_CLI_BIN/review-cli" to `/review-cli`, and failed with exit 127 — burying the real error under a meaningless one. The reaction and reply steps did the same, just non-fatally via continue-on-error. Gate all three on `steps.install-review-cli.outputs.bin-path != ''` so the failure a developer sees is the one that actually happened. Also document the bootstrap corollary: the review job cannot succeed on the PR that introduces the tooling, because the trusted ref has no `.claude/` or `install_review_cli` yet. It goes green from the next PR on. * fix(ci): address review-fix-loop findings on the review-cli migration Independent review (code-reviewer + comment-analyzer + silent-failure-hunter) standing in for the CI reviewer, which cannot review its own bootstrap PR. 15 findings, all verified against review-cli source and real run artifacts. Critical — the trusted checkout silently degraded every review. review-cli gates its full-checkout fast path on `git status --porcelain` being empty, and `.review-tooling/` is untracked inside GITHUB_WORKSPACE, so the tree read dirty on every run and the CLI fell back to extracting only diff-touched files with no .git. Agents kept working and runs stayed green while losing whole-repo Read/Grep/Glob and history — worst for the two reviewers added here, which are told to look outside the diff. Fixed with .git/info/exclude plus `update-index --assume-unchanged` on the .claude paths the trusted copy reverts (exclude cannot hide tracked files), and the step now asserts the tree is clean and warns if not. Verified in a scratch repo. Critical — the investigation gate was inert. Demotion is `wantsDemotion && allowedVerdicts.includes('COMMENT')`, and the default `verdict.allowed` is [APPROVE, REQUEST_CHANGES], so the gate computed the demotion, discarded it, and let the rubber-stamp APPROVE stand. Added `verdict.allowed: [APPROVE, REQUEST_CHANGES, COMMENT]`. Safe for dependency auto-merge, which gates on `needs.review.result == 'success'`, not verdict. High — cancellation was rendered as failure. The reaction and reply steps run under `always()`, which fires on cancellation, and concurrency cancels a comment-triggered run whenever a push supersedes it. Both reported "Review failed" and told the requester to retry a review its successor was about to finish. Reaction now carries `!cancelled()`; reply posts "Superseded". This is the same reasoning already documented for Post, applied to its two siblings. High — the config guards tested presence, not validity. `-s` catches missing and empty but not malformed, and loadConfig treats invalid YAML exactly like a missing file: defaults, no log line. Both guards now assert the parse and `skip.authors == []`, fail-closed. Verified against five cases: real config, malformed YAML, reintroduced bot skip, empty file, non-mapping. Also: guard the two agent files the error message names; raise the job ceiling to 25 so Analyze's step ceiling always fires first (tail budget is `25 - setup - 17`, not a flat 3 minutes); annotate a declining triage gate so it is not a silent green no-review; surface a failed running-state reply (no `set -e` meant it reported success); verify the installed binary is executable, the one case the bin-path gate cannot catch; `permissions: {}` on review-skipped; and correct five factual claims — minimumReleaseAge errors rather than downgrading, react/reply also write to the PR, the bundled agent list omitted 4 of 11 including the two the next paragraph suppresses, `--force` substitutes $20/200-turn defaults for the configured caps, and the `cancelled()` wording in CLAUDE.md. Verified: actionlint clean (it caught `cancelled()` being invalid in `env:` and a duplicate permissions key), zizmor unchanged at 8 findings, markdownlint clean, lefthook green. * fix(ci): cover the third way the trusted copy dirties the tree Round 2 of the review loop found the case the previous commit missed. The tree-cleanliness fix handled untracked `.review-tooling/` and tracked `.claude` files the copy modifies or deletes, but not files the trusted copy lands that are NOT TRACKED at the PR head — every `.claude/**` file added after that branch was cut. `git diff --name-only` never lists untracked paths, so the assume-unchanged pass structurally cannot reach them. This fires on this PR's own merge: `next` tracks none of `.claude/review.yml` or the two agents, so every already-open PR would get three `??` entries, a dirty tree, and a review silently downgraded to diff-only extraction. Fixed by also excluding `/.claude/`, which hides untracked copies while still reporting tracked modifications — verified in a scratch repo reproducing the bug, the fix, and that the assume-unchanged pass is still required. Also from round 2: - Document that restoring a clean tree re-enables review-cli's `verifyFindings` pass, dead in CI until now because it is gated on workspaceShape == 'working-tree'. It resolves cited files from the workspace, where `.claude` is the pre-PR copy, so findings against `.claude/**` files a PR adds are dropped as "file not readable at HEAD". Logged rather than silent, reachable only by reviewer-tuning PRs, and not to be "fixed" by skipping the swap. - Correct the `!cancelled()` rationale. It claimed a successor replaces the 👀; none does, because only a `pull_request` run can cancel this one and such a run has an empty comment_id, so it never reaches that step. The stale ack is the deliberate trade against a false ❌. - Fix a wrong claim in triage.guidance: `auto-merge-dependabot` gates on the job RESULT, not the verdict, and `post` has no non-zero exit path, so REQUEST_CHANGES does not by itself stop a bump. Reviewers are told to say so explicitly in the finding instead. Verified: actionlint clean, zizmor unchanged at 8, review.yml parses.
Anthropic released Claude Opus 5 (claude-opus-5), which supersedes claude-opus-4-8 as the latest Opus model. Per the model-watch job, `next` still referenced claude-opus-4-8 in 19 files even though the prior model-update pass (#548) already moved Sonnet to claude-sonnet-5. Like-for-like ID/prose swap only, pricing unchanged ($5/$25 per 1M tokens for both). claude-sonnet-5 and claude-haiku-4-5 references are untouched (already current). Two files documenting Boris Cherny's personal model preference (claude-setup/README.md and boris-best-practices.md) are intentionally left as-is since they quote him by name; rewriting his stated preference would misrepresent the source rather than update a config value. Bumped development-codebase-tools (2.6.2 -> 2.6.3) and development-planning (2.0.7 -> 2.0.8) plugin.json versions per this repo's mandatory version-bump-on-plugin-file-change convention.
…nd to skill (#553) * refactor(development-pr-workflow): convert backtest-change from command to skill * Update packages/plugins/development-pr-workflow/skills/backtest-change/SKILL.md Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> * fix(development-pr-workflow): register backtest-change skill, bump plugin to 2.3.0 Addresses review on #553: - register ./skills/backtest-change in plugin.json (skills are not auto-discovered in this repo; CLAUDE.md requires the manifest entry) - bump plugin 2.2.0 -> 2.3.0 (minor: new skill) - add model: opus to match sibling skills * docs(development-pr-workflow): add backtest-change to README skills table, sync root version table Addresses review round 2 on #553: - README skills table was missing the new skill (plugin inventory drift) - root CLAUDE.md version table still said 2.2.0 Also picks up pre-existing prettier debt in the README Commands table, which was already non-compliant under the repo's pinned prettier 2.8.8. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Nick Koutrelakos <wkoutre@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
This comment has been minimized.
This comment has been minimized.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
Contributor
📚 Documentation Check ✅Verdict: Passed The PR diff is empty and 0 lines were changed, so there is no code or documentation to evaluate against the CLAUDE.md/README/plugin-version-bump rules. Summary\n\nThe PR context provided contains no changed files and an empty diff (
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Production Deployment
This PR promotes the
nextbranch tomainfor production release.Commits included (13):
Merge Strategy
Using merge commit to preserve full commit history for changelog generation.
Temporary Branch
This PR is created from a temporary branch
release/next-to-main-20260803-194416that will be deleted after merge.This PR was automatically created by the Update Production workflow.
Changes Summary
✨ Features (2)
🐛 Bug Fixes (1)
📝 Documentation (1)
🔧 Maintenance (8)
Full Commit List