Skip to content

chore(release): promote next to production (2026-08-03) - #561

Merged
wkoutre merged 14 commits into
mainfrom
release/next-to-main-20260803-194416
Aug 3, 2026
Merged

chore(release): promote next to production (2026-08-03)#561
wkoutre merged 14 commits into
mainfrom
release/next-to-main-20260803-194416

Conversation

@hello-happy-puppy

@hello-happy-puppy hello-happy-puppy commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Production Deployment

This PR promotes the next branch to main for production release.

Commits included (13):

7eb5c55 refactor(development-pr-workflow): convert backtest-change from command to skill (#553)
4d5a387 chore(workflows): update model references to claude-opus-5 (#558)
9b405c7 refactor(ci): review ai-toolkit's own PRs with @uniswap/review-cli (#556)
bb873ee docs(rules): fix stale 5-plugin claims and make plugin inventory drift-resistant (#557)
7aa69ca chore(workflows): update model references to claude-sonnet-5 (#548)
6c0b8a8 fix(skill-management): make PR-open hook matcher actually match MCP create_pull_request tools (#550)
c3aac3c feat(uniswap-integrations): add datadog-cost-tracker skill with gotchas (#544)
c9149d9 feat: new datadog cli skill (#432)
9767306 chore(release): @uniswap/ai-toolkit-notion-publisher@0.0.20-next.0
7fa1f81 chore(release): @uniswap/ai-toolkit-linear-task-utils@0.0.23-next.0
1c5f7d5 chore(release): @uniswap/ai-toolkit-claude-mcp-helper@1.0.26-next.0
09651c3 chore(release): @uniswap/ai-toolkit-nx-claude@0.5.39-next.0
94a7412 chore(deps-dev): bump esbuild from 0.25.12 to 0.28.1 in the npm_and_yarn group across 1 directory (#534)

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-194416 that will be deleted after merge.


This PR was automatically created by the Update Production workflow.


Changes Summary

✨ Features (2)

  • Add datadog-cost-tracker skill with gotchas documentation
  • Add new datadog CLI skill

🐛 Bug Fixes (1)

  • Make PR-open hook matcher actually match MCP create_pull_request tools

📝 Documentation (1)

  • Fix stale 5-plugin claims and make plugin inventory drift-resistant

🔧 Maintenance (8)

  • Convert backtest-change from command to skill
  • Update model references to claude-opus-5
  • Review ai-toolkit's own PRs with @uniswap/review-cli
  • Update model references to claude-sonnet-5
  • Bump esbuild from 0.25.12 to 0.28.1

Full Commit List

7eb5c55 refactor(development-pr-workflow): convert backtest-change from command to skill (#553)
4d5a387 chore(workflows): update model references to claude-opus-5 (#558)
9b405c7 refactor(ci): review ai-toolkit's own PRs with @uniswap/review-cli (#556)
bb873ee docs(rules): fix stale 5-plugin claims and make plugin inventory drift-resistant (#557)
7aa69ca chore(workflows): update model references to claude-sonnet-5 (#548)
6c0b8a8 fix(skill-management): make PR-open hook matcher actually match MCP create_pull_request tools (#550)
c3aac3c feat(uniswap-integrations): add datadog-cost-tracker skill with gotchas (#544)
c9149d9 feat: new datadog cli skill (#432)
94a7412 chore(deps-dev): bump esbuild from 0.25.12 to 0.28.1 in the npm_and_yarn group across 1 directory (#534)

dependabot Bot and others added 13 commits June 30, 2026 17:15
…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>
@hello-happy-puppy
hello-happy-puppy requested a review from a team as a code owner August 3, 2026 19:44
@vercel

vercel Bot commented Aug 3, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
ai-toolkit-slack-oauth-backend Ready Ready Preview Aug 3, 2026 7:47pm

Request Review

@datadog-official

This comment has been minimized.

@socket-security

socket-security Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedesbuild@​0.25.12 ⏵ 0.28.191 +110073 +188100

View full report

@github-actions
github-actions Bot requested a review from wkoutre August 3, 2026 19:46
@wkoutre
wkoutre merged commit 0f7e1a7 into main Aug 3, 2026
9 of 10 checks passed
@wkoutre
wkoutre deleted the release/next-to-main-20260803-194416 branch August 3, 2026 19:46
@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
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 (Lines Changed: 0). Since there are no modifications to inspect, none of the documentation checks apply:\n\n- CLAUDE.md: No directories were touched, so no CLAUDE.md update is required.\n- README.md: No package/API/usage changes to document.\n- Plugin version bump: No files under packages/plugins/ were modified, so no version bump is required.\n- Changelog: No significant changes to note.\n\nNo action needed.

✨ No Documentation Updates Needed

All documentation appears to be up to date with the code changes.


🤖 Generated by Claude Documentation Validator | Mode: suggest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants