Skip to content

Add promptfoo for testing agent development setup and skills - #80812

Merged
ciampo merged 56 commits into
trunkfrom
add/promptfoo
Sep 4, 2026
Merged

ciampo merged 56 commits into
trunkfrom
add/promptfoo

Conversation

@jeryj

@jeryj jeryj commented Jul 28, 2026 •

Copy link
Copy Markdown
Contributor

What?

Adds a Promptfoo-based evaluation harness for the repository's agent skills so we can evaluate if changes to agent instructions, skills, result in improvement or regression.

Also adds a baseline test as an example that checks to see if our e2e reference is read when asking the agent to write an e2e test, and a second suite that proves the agents really are confined to their workspace.

Why?

We ship guidance for coding agents — AGENTS.md files and .agents/skills/ — with no way to tell whether it is discovered or followed. This makes that measurable rather than assumed.

How?

  • Adds promptfoo as a devDependency. The package is deliberately not a root workspace: Promptfoo's dependency tree is large and only needed by people running evals, so it keeps its own lockfile and install step, and needs a newer Node than the repository (.nvmrc). Promptfoo is pinned to 0.122.1 (0.122.2 adds a dependency affected by GHSA-jmr9-qjv8-65gv), with overrides for two optional dependencies; CI audits the tree at --audit-level=high.
  • One disposable Git workspace is built per run from your working tree, with test/ai-development/ removed so the agent cannot read the assertions grading it. Rows run serially and the workspace is rolled back with git reset --hard between them. This is Promptfoo's documented shape for an agent with side effects — see its claude-agent-sdk/advanced example. Rolling back rather than rebuilding is what makes one workspace practical: archiving Gutenberg once per run is affordable, once per row is not. We can follow-up with parallel test runs.
  • Because .claude/ is .gitignored, the workspace regenerates .claude/skills from .agents/skills by calling the repository's own setup-skills tool, as npm run agents:setup does at postinstall. Before it removes settings or generates skills, the harness replaces a repository-supplied .claude symlink with a local directory so host cleanup cannot follow it outside the workspace.
  • Confinement is two layers, because neither covers the other's ground. Promptfoo implements no sandboxing of its own — it passes the sandbox block verbatim to the Claude Agent SDK — so lib/sandbox.js declares both:
    • sandbox.filesystem is OS-enforced and covers Bash and every process it starts. Writes need no rules (a sandboxed command can only write to its working directory and session temporary directory); reads are denied by region — the home directory, this checkout, and the temp directory — with the workspace re-allowed inside it. (Denying / instead does not work: it takes the system libraries with it, and a profile no command can run under either fails everything or is discarded.)
    • Read() / Edit() permission rules cover every other tool. These resolve deny before allow and ignore specificity, so the workspace lives in the system temp directory rather than inside the checkout — otherwise the rules keeping the agent out of the source would lock it out of its own working directory.
    • The network is unreachable — the empty allowlist is made a deterministic denial with strictAllowlist, since an unlisted host otherwise prompts and a headless run resolves that as an allow — and Docker is pointed at a dead socket, so the agent cannot look up answers or start containers the sandbox can't clean up.
    • Hooks and project settings go around both layers: hooks are disabled programmatically (disableAllHooks), and the workspace build strips .claude/settings*.json because filesystem.allowRead and network.allowedDomains merge from every settings source — a branch under evaluation could otherwise re-open reads and the network for its own run.
    • The inherited environment is blanked to a minimal keep-list. Promptfoo restores ANTHROPIC_API_KEY after that step, so the sandbox's credential rules also deny it by name.
  • Assertions check what tools returned, not what the agent said. Promptfoo records each call's real output on metadata.toolCalls, which is the provider metadata its guide points at for asserting the path an agent took. So "did it read the reference?" requires successful output containing the file's contents. Path matching remains diagnostic only, which lets a successful relative-path read recover from an earlier failed full-path attempt. The sandbox suite proves denial from the recorded error rather than trusting the agent to quote it.
  • utils/ holds what specs import, leaving lib/ to the harness, the way test/e2e separates its configuration from the fixtures its specs pull in. assertRead / assertNotRead work on any text file: landmarks are sampled evenly through it, so output that stops early is missing one, and they are read from the file at load time. Reads can get scored by a full read (1) partial read (1 > score > 0) or no read (0).
  • Alongside skill-used and command-trajectory checks, an agent-rubric reviews the change itself.
  • The harness captures the diff, rather than the grader going to find it. Promptfoo's coding-agent guide notes that an agent's output is "its final text response describing what it did, not the file contents", and that file-level verification means reading the files after the eval. A transform stages the workspace and appends git status and the diff to the response before any assertion runs. The grader then keeps Promptfoo's documented configuration — working_dir and nothing else, which gives it read-only Read/Grep/Glob/LS already confined to the workspace — so it needs no shell and no sandbox of its own, and can still open .agents/skills/ to check the change against the reference rather than a copy of it pasted into the rubric. Otherwise, we'd need to give the grading agent more access, which would undo our attempts to sandbox it. Before host-side Git stages, diffs, or resets the workspace, the agent-controlled .git is replaced with a trusted copy and global/system Git configuration is disabled, so a repository-local clean filter cannot escape the sandbox. The grader also gets no settings sources, no hooks, and the same blanked environment as the subject.
  • Configuration is JavaScript. A spec spreads lib/base.js and adds only its own prompt and assertions; one directory per suite under specs/.
  • A static-checks CI job installs the package and runs the unit tests and configuration validation on Node 22 (Linux, macOS, Windows) and Node 24 (Linux). No model calls in CI.
  • To simplify this initial PR, Claude is the only agent added for testing. Codex is added in Agent evals: Add Codex as a second agent #82001.

Testing Instructions

  1. cd test/ai-development && nvm use && npm install
  2. npm run test:utils — unit-tests the read assertions against recorded tool calls, and the workspace lifecycle against a real disposable checkout. No model calls; about half a minute. Two live sandbox tests are skipped unless AI_EVAL_LIVE=1 is set.
  3. npm run test:agent-evals — runs every spec. Add --config specs/testing-skill-routing/test-skill-routing.eval.js to run just one.
  4. npm --prefix test/ai-development run view opens the local viewer against results/.promptfoo, the same storage directory used by evaluation runs.
  5. Confirm the skill-routing result shows separate metrics for invoking the testing skill, reading the e2e reference, skipping the Jest and PHPUnit references, and the agent review.
  6. The skill-routing test might fail! That's fine. We're setting up the framework, not trying to solidify the e2e reference reading right now — that's a follow-up. It currently routes through the skill roughly 50% of the time. Notably the rubric passes either way: the agent writes a decent test whether or not it invokes the skill, so it's the routing that's unreliable.

Verifying the sandbox

specs/sandbox proves the boundary by behaviour rather than by inspecting configuration. Each probe has to show the attempt in the trajectory and the canary absent from the output, so an agent that simply declines cannot pass it, plus a control read of the workspace that must succeed — otherwise a wholly broken workspace would pass by failing everything.

To confirm it is testing something real, set sandbox.enabled to false in lib/sandbox.js and empty permissions.deny, then re-run. The suite must go red, reporting the reads that succeeded.

AI_EVAL_LIVE=1 npm run test:utils proves the filesystem shape itself through the raw Agent SDK, without Promptfoo in between: denying / never yields a working boundary (it either fails every command, the workspace read included, or is discarded and leaves reads open), while the shipped region denies read the workspace and refuse canaries in the home directory, the checkout, and the temp directory.

The read assertions have the same property without costing anything: npm run test:utils covers a full read, a chunked read, a read that stopped early, a grep, an ls, a denied read, an unopened file, and the inverses.

Notes before running:

  • Each run makes real model calls against your own Claude quota and takes 1–2 minutes.
  • Results under results/ are gitignored and may contain source code and tool output.

Possible follow ups:

Testing Instructions for Keyboard

Not applicable; this PR does not change the user interface.

Screenshots or screencast

Not applicable.

Use of AI Tools

Codex (GPT-5) and Claude Code (Opus) were used to implement, review, revise, and document this. All output was reviewed and verified by running the harness.

Summary by CodeRabbit

  • New Features

    • Added an AI development evaluation package for assessing agent behavior, sandbox boundaries, workspace isolation, and testing-skill routing.
    • Added commands to validate, run, and review evaluation results.
    • Added cross-platform automated checks across supported Node.js versions.
  • Documentation

    • Added setup, usage, security, sandbox, grading, and evaluation-authoring guidance.
  • Tests

    • Added coverage for Node.js compatibility, filesystem and network restrictions, environment protection, workspace cleanup, Git isolation, and file-read verification.

@jeryj
jeryj requested a review from desrosj as a code owner July 28, 2026 20:57
@github-actions

github-actions Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Co-authored-by: jeryj <jeryj@git.wordpress.org>
Co-authored-by: ciampo <mciampini@git.wordpress.org>
Co-authored-by: manzoorwanijk <manzoorwanijk@git.wordpress.org>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@jeryj jeryj changed the title Add/promptfoo Add promptfoo for testing agent development setup and skills Jul 28, 2026
@github-actions

github-actions Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

Size Change: 0 B

Total Size: 7.92 MB

compressed-size-action

@jeryj
jeryj marked this pull request as draft July 28, 2026 21:12
@github-actions

github-actions Bot commented Jul 28, 2026 •

Copy link
Copy Markdown

Flaky tests detected in a6b8365.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/33421468408
📝 Reported tests:

inserts synced patterns by dragging and dropping from the global inserter in /test/e2e/specs/editor/various/inserting-blocks.spec.js, passed after 1 failed attempt.
Error: apiRequestContext.fetch: socket hang up
Call log:
  - → GET http://localhost:8889/wp-json/wp/v2/blocks?per_page=100&status=publish%2Cfuture%2Cdraft%2Cpending%2Cprivate%2Ctrash
    - user-agent: Playwright/1.62.1 (x64; ubuntu 24.04) node/20.20 CI/1
    - accept: */*
    - accept-encoding: gzip,deflate,br
    - X-WP-Nonce: 81a975a6ae
    - cookie: wordpress_test_cookie=WP%20Cookie%20check; wordpress_logged_in_23778236db82f19306f247e20a353a99=admin%7C1788371609%7CLrW3EMW8MrHFGuKRBIn7nD10GH2rqn2H5oG0qQvjafR%7Ca6b6956c434435a5146e6fe42c51e3e68945a9af5c7d3fbef945f1ec77ef8e1c; wp-settings-time-1=1788199224

    at RequestUtils.rest (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/rest.ts:112:39)
    at RequestUtils.deleteAllBlocks (/home/runner/work/gutenberg/gutenberg/packages/e2e-test-utils-playwright/src/request-utils/blocks.ts:23:28)
    at /home/runner/work/gutenberg/gutenberg/test/e2e/specs/editor/various/inserting-blocks.spec.js:11:22

@jeryj

jeryj commented Aug 24, 2026

Copy link
Copy Markdown
Contributor Author

I'm picking up this PR again this week.

@jeryj jeryj self-assigned this Aug 24, 2026
@jeryj jeryj added the [Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests. label Aug 24, 2026
@jeryj
jeryj requested a review from ciampo August 25, 2026 21:15
@jeryj

jeryj commented Aug 25, 2026 •

Copy link
Copy Markdown
Contributor Author

@ciampo I think this is ready for a review. Hopefully it helps our AI skill project work :)

@ciampo ciampo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the work here!

left a few initial comments

Comment thread test/ai-development/lib/base.js
Comment thread test/ai-development/lib/default-test.js Outdated
Comment on lines +23 to +34
// Grades the `agent-rubric` assertions. It reads the workspace to
// judge what the agent actually did, rather than what it reported.
provider: {
id: 'anthropic:claude-agent-sdk',
config: {
apiKeyRequired: false,
model: 'opus',
// The grader inspects the workspace; it never edits it.
tools: [ 'Bash' ],
custom_allowed_tools: [ 'Bash' ],
disallowed_tools: [ 'WebFetch', 'WebSearch' ],
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Also flagged by an AI agent]

The grader gets auto-approved Bash, but withWorkspace() adds only working_dir to its provider. The sandbox below is attached to the subject test options and is not propagated to the grader. The grader can therefore modify the artifact it is judging, access the original checkout and host, call the network or Docker through shell commands, and create a direct false-positive result.

Please use constrained read/search tools, or apply a separate fail-closed grader sandbox that disables hooks, denies writes/network/Docker, and exposes only a minimal environment. A regression case should ask the rubric to create the expected file and prove that the grader cannot do so. This matches Promptfoo's warning that shell, write, and network tools enabled for an agent-rubric are actions performed by the grader itself.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think my agent has been over-focused on the deterministic file read and trying to do all kinds of extra work with tools. I'm going to strip this back to the default promptfoo set-up and see what the shape looks like.

Comment thread test/ai-development/lib/workspace-extension.mjs Outdated
Comment thread test/ai-development/package.json Outdated
Comment on lines +33 to +41
// It should read the e2e reference file
{
type: 'trajectory:step-count',
value: {
type: 'command',
pattern: '*skills/testing/references/e2e.md*',
min: 1,
},
metric: 'Read the e2e reference',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assertion passes for any shell command containing the path, ie. it doesn't seem to require a successful read or evidence that the file contents were returned.

Should we assert a successful Read invocation for the exact file, or assert successful tool-result evidence containing a canary from the reference?

Potentially we could also add negative fixtures for "path listed", "read failed", and "contents read" so this central metric proves the behavior named in the README?

Not sure if we want to somehow abstract this pattern, since I assume that reading specific docs will be a frequent aspect that we'll want to check in our evals

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — same flaw was in specs/sandbox, which asserted on the agent's own report. Both fixed.

Added an abstracted assertRead / assertNotRead. A read has to have succeeded and returned the file's contents — landmark lines sampled through the file, so ls, a grep, a denied read, or a head all fail, while a chunked read passes.

Reads are scored by how much came back, so skimming the guidance (0.8) is distinguishable from ignoring it (0). assertNotRead got stronger too — skipping now means none of its contents came back, not just that no command mentioned the path.

The assertRead and assertNotRead also have test coverage: specs/utils/test-grader.mjs.

As for the Read invocation, Bash-only is a deliberate cross-provider choice so Claude's Bash and Codex's exec_command share one assertion; adding Read wouldn't replace Bash and would make the "Skipped" assertions pass vacuously. Better revisited with Codex in #82001.

Comment thread test/ai-development/lib/workspace-extension.mjs Outdated
Comment thread test/ai-development/.nvmrc

@ciampo ciampo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding a few more comments.

Also, a bit nitty, but the PR description is now out of date under a few aspects, it could be confusing for someone approaching this PR.

Comment thread package.json
Comment thread test/ai-development/lib/workspace-extension.mjs Outdated
...sandbox,
filesystem: {
...( sandbox.filesystem || {} ),
allowRead: [ workspace ],

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous comment

Comment thread test/ai-development/lib/default-test.js Outdated
Comment on lines +16 to +21
sandbox: {
enabled: true,
autoAllowBashIfSandboxed: true,
allowUnsandboxedCommands: false,
network: { allowedDomains: [] },
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(can't verify because I don't have an anthropic sub, flagged by Codex)

Promptfoo passes the host environment to Claude, including ANTHROPIC_API_KEY when set. Bash can expose these values in model requests and saved results. Please give both providers a minimal environment, remove credentials, and add a test proving that a secret value cannot appear in the output.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both providers now have a minimal environment and overwrite the credentials with null values. We can't remove credentials that already exist for the environment, but we can blank them.

The test for this is in specs/sandbox: a marker goes into the environment before the config loads, the agent is asked to echo $EVAL_SANDBOX_PROBE, and the assertion reads the command's recorded output rather than the agent's account of it. It fails if the marker comes back.

Comment thread test/ai-development/lib/default-test.js Outdated
Comment on lines +39 to +44
sandbox: {
enabled: true,
autoAllowBashIfSandboxed: true,
allowUnsandboxedCommands: false,
network: { allowedDomains: [] },
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous comment

Comment thread test/ai-development/lib/base.js Outdated
Comment on lines +58 to +71
tools: [ 'Bash', 'Edit', 'Write', 'Task', 'Skill' ],
custom_allowed_tools: [
'Bash',
'Edit',
'Write',
'Task',
'Skill',
],
// We want to limit the test to only accessing the repo.
disallowed_tools: [ 'WebFetch', 'WebSearch' ],
// Points Docker at a socket that does not exist, so `docker`
// and `wp-env` fail instead of starting containers, which the
// sandbox cannot reach to clean up.
env: { DOCKER_HOST: 'unix:///nonexistent/docker.sock' },

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous point

@jeryj

jeryj commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Yesterday I was caught up in the RC1 Release. Picking this up again today and will update the PR description. Thanks for the review, @ciampo!

@ciampo

ciampo commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor

Of course! In the meantime, I'll wait until you explicitly tag me again for a new round of review.

@jeryj

jeryj commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

Made some big changes to align it closer to the default promptfoo recommendations. We can diverge when absolutely necessary, but we should lean on their recommendations for now. Here's what has changed:

Agent summary:
The eval harness gave every test row its own temp workspace, so no path could be written in a config file — the extension rebuilt both agents' working_dir and sandbox blocks at runtime instead. That was 253 lines, plus a 136-line unit test asserting the rebuild produced the right shape.

It now builds one workspace per run, rolls it back between rows, and runs rows serially — promptfoo's documented pattern for agents with side effects. Paths are known up front, so the rules are just written down.

That also fixed a boundary that didn't hold. Promptfoo implements no sandboxing; it passes sandbox verbatim to the Claude Agent SDK, where allowRead is a re-allow within denied regions, not a whitelist. The old allowRead: [workspace] was close to a no-op. Confinement is now two layers: the OS sandbox for Bash, permission rules for everything else. specs/sandbox proves it behaviourally, and goes red if you disable either.

Separately, the grader no longer holds Bash. It had one only to run git diff, which is what forced it to have a sandbox at all. The harness now captures the diff in a transform and hands it over; the grader keeps promptfoo's default read-only tools.

@jeryj

jeryj commented Aug 28, 2026

Copy link
Copy Markdown
Contributor Author

@ciampo This is worth another review when you get a chance.

jeryj and others added 10 commits September 4, 2026 13:02
Setup covered Node and npm and then said Claude uses your existing Claude Code
login, without saying that having one is a requirement or how to get there.
Someone without it gets authentication failures from a step the instructions
never mentioned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0196WjFhuq12CQPS7JuWpwSr
`Read()` and `Edit()` rules need `//` to mean an absolute path; a single slash
anchors to the settings source instead. These paths already start with one, so
building them as `Read(//${ homeDirectory }/**)` produced `Read(///Users/...)`,
which parses as a settings-relative pattern and matches nothing.

Claude Code's own debug output shows it, with `debug: true` on the provider:

    Adding 4 deny rule(s): ["Read(///Users/jj/**)", "Edit(///Users/jj/**)", ...]

and the corrected form:

    Adding 4 deny rule(s): ["Read(//Users/jj/**)", "Edit(//Users/jj/**)", ...]

The boundary held anyway, because the OS sandbox denies the same paths and is
the layer that covers Bash. This restores the layer meant to cover everything
else.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0196WjFhuq12CQPS7JuWpwSr
The sandbox suite was red: the probes read the home directory, the
checkout, and the temp directory, and curl reached example.com, while
only writes held. Two of the causes were in this configuration.

Denying `/` takes the system libraries with it, so no command can run
under the profile, and a profile like that does not survive to enforce
anything. Run directly through the Agent SDK it is applied literally and
every command fails, the workspace read included; run through Promptfoo
the unusable profile is discarded and reads are open. Neither is a
boundary. Reads are now confined the way they were before the root
deny — by region — with the temp directory added so the canary beside
the workspace stays covered, and the workspace re-allowed inside it
because for sandbox paths the narrower rule wins.

An empty `network.allowedDomains` alone does not block either: a host
outside the list prompts, and a headless run resolves that prompt as an
allow. `strictAllowlist` turns the empty list into a deterministic
denial — the proxy answers `deny network-outbound` instead of asking.

The new unit tests pin the shape so CI, which cannot make model calls,
still catches a regression: no bare `/` in `denyRead`, a denied region
around the re-allowed workspace, the strict empty allowlist, and
permission rules anchored as `//` absolute paths.

The suite stays red after this commit: its own hook fixture plants a
workspace settings file that re-opens reads and the network, which the
next commit addresses.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0179vmL26umaCiFhS1YWDPGA
The hook probe's fixture planted a workspace `.claude/settings.json`
carrying more than the hook it exists to test: an `allowRead` of `/`, a
`*` network allowlist, and `enabled: false`. The comment above it
claimed project settings must not be able to weaken the programmatic
boundary — but for two of those fields the claim is wrong.
`filesystem.allowRead` and `network.allowedDomains` merge from every
settings source, project settings included; only switches like
`enabled` and `strictAllowlist` are restricted to trusted sources.
So the fixture re-opened every denied read region and the network for
the whole suite, which is why every probe escaped while writes — a
default the fixture could not reach — still held. The spawned CLI's
`--settings` showed the harness passing the right configuration all
along; the fixture was overriding it from inside the workspace.

That is also a real hole, not just a test artifact: a branch under
evaluation that force-added a settings file would weaken its own
evaluation's sandbox the same way. Hooks have a programmatic off
switch to point a probe at; sandbox weakening has none, so the
workspace build now strips `.claude/settings.json` and
`.claude/settings.local.json` before the base commit is made, which
also keeps them out of every rollback. The fixture now plants only its
hook — after the strip, because `disableAllHooks` is the defence it
tests.

With the previous commit's region denies, `specs/sandbox` now passes
every metric: the control read succeeds and each probe is attempted
and blocked.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0179vmL26umaCiFhS1YWDPGA
The unit tests pin the configuration; these two prove the behavior
behind it, through the real CLI, without Promptfoo in between. One
probe function runs a session that must attempt a workspace read and
canaries in the home directory, the checkout, and beside the workspace
in the temp directory, judged from the recorded tool calls rather than
the agent's account. Only the filesystem block differs between the two
tests, so they cross-validate: if denying the root ever produced a
working boundary the first test would fail and the region shape would
be unnecessary; if the region shape leaked or broke, the second would
name the region.

Denying the root asserts the conjunction a boundary requires — the
workspace readable and every canary denied — never holds, which stays
true in both of the observed failure modes: the profile enforced
literally, where every command fails, and the profile discarded as
unusable, where reads are open.

Each test is a real model call needing a logged-in Claude, so both are
skipped unless AI_EVAL_LIVE=1 is set and cost nothing in CI or
`npm run test:utils`.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0179vmL26umaCiFhS1YWDPGA
Four review findings, each a way a check could pass without proving
what it claims:

- The region containment test joined paths with a literal `/`, which
  never matches the `\` in a Windows workspace path, so the unit test
  would false-fail there. It now joins with `path.sep`.
- `assertNotRead` scanned only successful tool output, but a command
  can return a file's contents and still exit non-zero
  (`cat file; false`), hiding a real read behind the error flag. It now
  scans every call's output; the new regression case fails against the
  old code.
- The probe commands interpolated host paths unquoted, so a path with
  whitespace would split the argument and fail before reaching any
  sandbox rule — and every affected assertion reads failure as denial.
  Worst in the hook probe, where an unwritten marker reads as the hook
  having been stopped. All interpolated paths are quoted now.
- The outside canary derived its base from its own
  `realpathSync( os.tmpdir() )` rather than the `temporaryDirectory`
  constant the deny rules use, leaving room for the two to drift apart.
  It now uses the same constant, and the README's write-scope table
  cell matches the bullet under it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0179vmL26umaCiFhS1YWDPGA
Four high-severity fast-uri advisories published upstream tripped the
CI audit gate on a tree that had not changed. `npm audit fix` moves
fast-uri (and qs, moderate) to patched releases within their existing
ranges; `npm audit --audit-level=high` reports zero vulnerabilities
again.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0179vmL26umaCiFhS1YWDPGA
The rule-anchoring unit test failed on Windows CI, and the failure was
the rule's, not the test's: composing `Read(/${ homeDirectory }/**)`
from `C:\Users\runneradmin` produces a pattern with a drive-letter
colon and backslashes, which matches nothing. Claude Code matches
permission patterns in POSIX form — on Windows `C:\Users\alice`
matches as `/c/Users/alice`, drive letter lowercased, forward slashes
throughout (code.claude.com/docs/en/permissions).

A `pathRule` helper now normalizes the OS path into that form before
anchoring it, so the same construction yields `Read(//Users/jj/**)` on
POSIX — unchanged — and `Read(//c/Users/runneradmin/**)` on Windows.
The helper is exercised directly with a Windows-shaped path, so every
platform's CI covers the drive-letter case, and the anchoring test now
also rejects backslashes and colons in a rendered rule.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0179vmL26umaCiFhS1YWDPGA
@jeryj

jeryj commented Sep 4, 2026

Copy link
Copy Markdown
Contributor Author

@ciampo Should we bring this in and iterate?

@ciampo

ciampo commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

A couple of extra updates:

  • fixed Windows permission handling;
  • protected trusted Git metadata from sandbox writes;
  • removed unused Chromium downloads from CI.

Regression coverage and documentation were updated, and all non-live checks pass.

I'll give it one last deep review check and approve + merge

@ciampo ciampo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀

Let's merge, test, iterate.

@ciampo
ciampo enabled auto-merge (squash) September 4, 2026 20:58
@ciampo
ciampo merged commit c9e00c1 into trunk Sep 4, 2026
75 checks passed
@ciampo
ciampo deleted the add/promptfoo branch September 4, 2026 21:21
@github-actions github-actions Bot added this to the Gutenberg 24.0 milestone Sep 4, 2026
wporg-sync pushed a commit to WordPress/wordpress-develop that referenced this pull request Sep 8, 2026
This updates the pinned commit hash of the Gutenberg repository from `658c8cbe89db5d90279051d3bb816ca210fe4646 ` (version `23.8.0`) to `5a4cc502d43016f1efa66f8f6d9bd3bb4bb24d85`, which contains the latest changes up until the Node.js version was bumped from 20.x to 24.x.

A full list of changes included in this commit can be found on GitHub: https://github.com/WordPress/gutenberg/compare/658c8cbe89db5d90279051d3bb816ca210fe4646..5a4cc502d43016f1efa66f8f6d9bd3bb4bb24d85.

- Menu: Stabilize iframe reload test (WordPress/gutenberg#82081)
- Packages: Recover August 26 npm release metadata (WordPress/gutenberg#82085)
- Storybook: Demonstrate light, dark, and nested themes (WordPress/gutenberg#82039)
- Project Management: Add validation for missing GitHub labels configuration (WordPress/gutenberg#76263)
- Automated Testing: Enforce `.tsx` for all new React files (WordPress/gutenberg#80123)
- UI: Use root theme for portaled overlays (WordPress/gutenberg#82038)
- Menu: Stabilize portaled iframe test (WordPress/gutenberg#82092)
- Theme: Move post-release changelog entry to Unreleased (WordPress/gutenberg#82093)
- Media: Refuse a multi-file drop on a placeholder that takes one file (WordPress/gutenberg#82046)
- Font Library: Keep CSS custom properties unquoted in font previews (WordPress/gutenberg#82010)
- Add "reading settings" link to Front Page template (WordPress/gutenberg#81987)
- Docs: Fix grammar in documentation (WordPress/gutenberg#82032)
- Media Editor: refactor the panel layout (WordPress/gutenberg#81840)
- DataViews layout storybook: action names and primary status (WordPress/gutenberg#82104)
- Make `@wordpress/reusable-blocks` a no-op compatibility package (WordPress/gutenberg#79186)
- Widget Dashboard: add a Policy provider to govern what users may do (WordPress/gutenberg#81967)
- Build Package: Restore Core Boot layout compatibility (WordPress/gutenberg#82112)
- Edit Widgets: Guard canInsertBlockInWidgetArea against an empty block list (WordPress/gutenberg#82107)
- Build: Enforce NodeNext resolution for ESM packages (WordPress/gutenberg#82088)
- UI: Remove unused outset-ring--focus-within-visible class. (WordPress/gutenberg#82077)
- Inserter: Keep the block preview inside the viewport (WordPress/gutenberg#82060)
- Test: Enforce Vitest conventions and CI guardrails (WordPress/gutenberg#81040)
- Editor: Apply the showListViewByDefault preference in the shared editor (WordPress/gutenberg#82119)
- Release: Use CLI runtime for package publishing (WordPress/gutenberg#82122)
- Reusable Blocks: Remove leftover merge conflict markers from the changelog (WordPress/gutenberg#82126)
- chore: Update grep settings and remove comments (WordPress/gutenberg#82121)
- Fix: Content Guidelines: UX/UI Accessibility issues (WordPress/gutenberg#80306)
- Extensible Site Editor: Let menu items be added from the navigation screen (WordPress/gutenberg#82125)
- Navigation: Change WCText to Text (WordPress/gutenberg#82130)
- Storybook: Persist sidebar theme in URL (WordPress/gutenberg#82111)
- Editor assets endpoint: prime the theme JSON resolver before capturing (WordPress/gutenberg#82134)
- Remove unused dependencies across the monorepo (WordPress/gutenberg#82103)
- Update changelog instructions for agents (WordPress/gutenberg#82097)
- Build: Normalize JSX file extensions (WordPress/gutenberg#80990)
- Fix pattern export filenames by normalizing special characters (WordPress/gutenberg#77033)
- Site editor v2: navigation takes view config from endpoint (WordPress/gutenberg#82138)
- Extensible Site Editor: Load media assets before the media fields open (WordPress/gutenberg#82135)
- Site editor v2: pages take view config from endpoint (WordPress/gutenberg#82140)
- Extensible site editor: Add a revisions entry point to the Styles route (WordPress/gutenberg#82142)
- List: outdent an empty middle item without adding an item (WordPress/gutenberg#82011)
- Extensible site editor: Fall back to the raw title in edit route document titles (WordPress/gutenberg#82143)
- Blocks: Make BlockTransform a discriminated union over its type (WordPress/gutenberg#81831)
- Theme: add LightningCSS WPDS token fallback plugin (WordPress/gutenberg#80401)
- UI: Add popupWidth prop to item popup components (WordPress/gutenberg#82087)
- Snackbar: Restart timeout when a notice is recreated (WordPress/gutenberg#81764)
- Media: Report server upload failures in plain language (WordPress/gutenberg#81735)
- Format library: visualise non-breaking spaces (WordPress/gutenberg#74040)
- Bump the github-actions group across 1 directory with 2 updates (WordPress/gutenberg#81932)
- Try adding a Grid block variation to Gallery (WordPress/gutenberg#81909)
- Components: Keep foreign items out of a ToolsPanel menu (WordPress/gutenberg#82127)
- Enable Gallery columns and crop controls in viewport states (WordPress/gutenberg#82003)
- Query: Don't write excludeCurrent into blocks that never had it (WordPress/gutenberg#82147)
- Site title: Add fit-text support. (WordPress/gutenberg#82074)
- Accordion Panel: Reset padding-block when panel is hidden (WordPress/gutenberg#81782)
- Replace npm-run-all with native npm script chaining (WordPress/gutenberg#82166)
- Grid: per-item tile size limits (WordPress/gutenberg#81899)
- Fix: Tabs block: Anchor links in tab panels are not functional (WordPress/gutenberg#81744)
- Validate tsconfig references against declared dependencies (WordPress/gutenberg#82106)
- Performance tests: Build once and shard the suites across parallel CI jobs (WordPress/gutenberg#82160)
- Site Health widget: route the body's review link through the host (WordPress/gutenberg#82066)
- Build: allow wp-theme 2.x peer deps (WordPress/gutenberg#82139)
- Bundled packages: Add a check for transitive private API usage (WordPress/gutenberg#82027)
- List: try to preserve indentation level of children after outdenting+merging their parent (WordPress/gutenberg#82145)
- Block Library: Fix categories block handling of invalid taxonomy (WordPress/gutenberg#82153)
- useViewConfig: don't request the view config twice (WordPress/gutenberg#82141)
- Documentation: Remove invalid references to Babel in packages README (WordPress/gutenberg#82176)
- Automated Testing: Fix failing categories test on trunk (WordPress/gutenberg#82182)
- Jest: Update to 30.5.0 (WordPress/gutenberg#82181)
- Fix: Retain focus and caret position after Backspace undo of a prefix block transform (WordPress/gutenberg#82116)
- Scaffold e2e tests for the editor inspector consolidation experiment (WordPress/gutenberg#82178)
- Package lock: Deduplicate Jest dependencies (WordPress/gutenberg#82187)
- Components: Migrate remaining JSX files to TypeScript (WordPress/gutenberg#82132)
- Text: Use pretty wrapping by default (WordPress/gutenberg#82133)
- Build Tooling: Add browserslist config for build targeting (WordPress/gutenberg#82179)
- Columns: Fix appender drop zone visibility when dragging into empty column (WordPress/gutenberg#77852)
- Build: Require explicit JSX file extensions (WordPress/gutenberg#82189)
- Icons: Redraw 35 prominent icons with consistent stroke widths (WordPress/gutenberg#78808)
- Test: Classify and enforce unit test environments by filename (WordPress/gutenberg#80991)
- Test: Fix CI failures on trunk (WordPress/gutenberg#82201)
- Fix editor link colour cascade order for nested blocks (WordPress/gutenberg#77833)
- Add New Template: Show the design system focus ring instead of legacy box-shadow rings (WordPress/gutenberg#82164)
- List View: Don’t focus the last Table cell on keyboard activation (WordPress/gutenberg#81964)
- Fix spelling typos in docs and inline comments (WordPress/gutenberg#82217)
- CI: Pin npm version in the private API check job (WordPress/gutenberg#82222)
- Private APIs: Add back '@wordpress/dataviews' to the allowed core modules (WordPress/gutenberg#82221)
- Editor: Mark __unstableSaveForPreview options as optional (WordPress/gutenberg#81858)
- Docs: Explain when the Cover block's overlay controls appear (WordPress/gutenberg#82234)
- Menu: Use Text for item labels and descriptions (WordPress/gutenberg#82237)
- Test: Type pipe's supported array inputs (WordPress/gutenberg#82210)
- Widget Dashboard: keep the plain anchor for an empty-string download (WordPress/gutenberg#82073)
- CI: Read the required npm version from a single source (WordPress/gutenberg#82235)
- Components: Add `defaultShown`, `onShownChange` to `ToolsPanelItem` (WordPress/gutenberg#78010)
- Storybook: Drop unused support for js-as-jsx (WordPress/gutenberg#82192)
-  Math: Declare clientNavigation interactivity support (WordPress/gutenberg#82248)
- Point to docmumentation about release assets (WordPress/gutenberg#82250)
- Change stray `ubuntu-latest` to `ubuntu-24.04`. (WordPress/gutenberg#82156)
- Performance tests: Reuse the plugin an earlier trunk run already built (WordPress/gutenberg#82223)
- Breadcrumb: Add UI component (WordPress/gutenberg#80425)
- Components: Cut the ToolsPanel render cascade (WordPress/gutenberg#82180)
- Fix: alert dialog box cancel button color (WordPress/gutenberg#82261)
- UI: Add Form best practices Storybook page (WordPress/gutenberg#82197)
- Media: Stop claiming "Upload complete" when upload failed (WordPress/gutenberg#81397)
- Boot, Site Editor: Seed content surfaces with default background color (WordPress/gutenberg#81646)
- Format Library: Fix Edit as HTML crash with background-only highlight (WordPress/gutenberg#82215)
- Remove the template activation experiment (WordPress/gutenberg#82241)
- Packages: Add cross-version compatibility skill (WordPress/gutenberg#81890)
- Show the block outline where the grab cursor shows (WordPress/gutenberg#81798)
- DataViews: Scope the search field's fixed width to the default UI search row (WordPress/gutenberg#82128)
- Background image: support setting the image from a URL (WordPress/gutenberg#82230)
- Border Box Control: Try moving the unlink button to the label row, and rename the panel to Borders (WordPress/gutenberg#82163)
- Widget Dashboard: govern Reset to default through the policy (WordPress/gutenberg#82255)
- Media: Attach unattached media to the current post on save/publish (WordPress/gutenberg#81977)
- Widget Dashboard: make the column count a host decision (WordPress/gutenberg#82204)
- Global styles: resolve theme-relative background image URLs for display (WordPress/gutenberg#82242)
- CI: Unify the automation comments into a single PR comment (WordPress/gutenberg#82249)
- Core Data: Convert hooks tests to renderHook and drop JSX (WordPress/gutenberg#82276)
- Release: Map [Type] Flaky Test to the Tools changelog section (WordPress/gutenberg#82078)
- DateTime tests: freeze the clock in the empty-value calendar test (WordPress/gutenberg#82282)
- DataForm: treat combined form fields purely as layout containers (WordPress/gutenberg#82175)
- Global styles engine: return a copy from getResolvedValue instead of mutating (WordPress/gutenberg#82278)
- Test: Migrate Node unit tests to Vitest (WordPress/gutenberg#82211)
- Icons: Redraw 64 icons to be stroke-based. (WordPress/gutenberg#78812)
- Tests: Fix Vitest setup and stale jest types under non-hoisting installs (WordPress/gutenberg#82290)
- UI: Rename Popup `popupWidth` prop to `width` (WordPress/gutenberg#82193)
- Query: Replace the "Reload full page enabled" modal with a snackbar notice (WordPress/gutenberg#82246)
- Project Management: Update CODEOWNERS to reflect current participation (WordPress/gutenberg#82262)
- Editor: Refactor the Options menu to use the Menu component (WordPress/gutenberg#81564)
- UI: Add Field.VisualLabel (WordPress/gutenberg#82095)
- Update Stylelint to v17 and related packages (WordPress/gutenberg#80738)
- Media: keep indexed PNG sub-sizes indexed (WordPress/gutenberg#81884)
- UI: Add Combobox and Autocomplete Status (WordPress/gutenberg#82195)
- UI: Drop Status and Empty live region test assertions (WordPress/gutenberg#82300)
- Project Management: Remove empty entries from CODEOWNERS (WordPress/gutenberg#82292)
- Documentation: Add recommended bulk suppressions configuration for ESLint (WordPress/gutenberg#82303)
- UI: Hide Input field ring when a slot control is focused (WordPress/gutenberg#82257)
- Widgets: Surface debugging details in the ErrorBoundary (WordPress/gutenberg#82099)
- TypeScript: Migrate format-library package to TS (WordPress/gutenberg#79486)
- BorderBoxControl: Make sure the group of controls is associated with the label (WordPress/gutenberg#82279)
- Image block cropping: Sync image size and link destination settings (WordPress/gutenberg#82316)
- Menu: Support multiple item descriptions (WordPress/gutenberg#81825)
- CI: Do not fail the type label check on a newly opened pull request (WordPress/gutenberg#82322)
- UI: Align overlay Trigger props with Base UI (WordPress/gutenberg#81824)
- Gallery block: Fix 'Crop images to fit' broken in editor (WordPress/gutenberg#82318)
- Widget Dashboard: enforce the policy on the staging layer for every instance operation (WordPress/gutenberg#82256)
- DataForm: Communicate the timezone in the datetime control (WordPress/gutenberg#82291)
- Add more e2e tests for the editor inspector consolidation experiment (WordPress/gutenberg#82239)
- Framework: Error on npm versions older than the required floor (WordPress/gutenberg#82320)
- Document every type for DataViews/DataForm/Field API (WordPress/gutenberg#82326)
- ESLint plugin: remove usage of Babel parser (WordPress/gutenberg#82144)
- DataViews: remove the rich text options from the control config type (WordPress/gutenberg#82330)
- Meta Boxes: Move meta box markup with moveBefore to keep classic editors alive (WordPress/gutenberg#82243)
- Add more e2e tests for the editor inspector consolidation experiment (WordPress/gutenberg#82327)
- Test: Enforce JavaScript test runner ownership (WordPress/gutenberg#82299)
- DataViews: clamp page after delete (WordPress/gutenberg#82244)
- Stylelint tools: Resolve test config extends from the workspace (WordPress/gutenberg#82336)
- Editor: Deprecate the `as` prop of the plugin menu item components (WordPress/gutenberg#82319)
- Icons: Convert Search icon to strokes (WordPress/gutenberg#82338)
- DataViews: Document that table column styles do not apply to the primary column (WordPress/gutenberg#82238)
- DataViews: add hierarchical levels story (WordPress/gutenberg#82344)
- CI: Add "Required changes from trunk" PR check (WordPress/gutenberg#82272)
- feat: Improve TypeScript definitions in the getEntityRecord function (WordPress/gutenberg#81863)
- Framework: Update Node.js to v24 LTS and npm to v11 (WordPress/gutenberg#80395)
- Revert "Framework: Update Node.js to v24 LTS and npm to v11 (WordPress/gutenberg#80395)" (WordPress/gutenberg#82355)
- UI: Remove ValidityIndicator outer margin (WordPress/gutenberg#82267)
- Span the writing flow focus capture elements over the canvas (WordPress/gutenberg#82354)
- Fields: Hide the slug field for posts without a permalink (WordPress/gutenberg#82341)
- Fix: Responsive horizontal orientation does not override a vertical layout. (WordPress/gutenberg#82364)
- View Config: Move the table column style descriptions to the 7.2 compat layer (WordPress/gutenberg#82372)
- Block Library: Allow themes to override the padding added via background color (WordPress/gutenberg#82024)
- DataViews: Append an ellipsis to action labels that open a dialog (WordPress/gutenberg#81994)
- Pages: require authentication and a capability to render generated standalone pages (WordPress/gutenberg#82254)
- Build/Test Tools: Replace npx with npm exec --no (WordPress/gutenberg#82331)
- Navigation: restore flex-grow on container when accessible label is present (WordPress/gutenberg#78447)
- DOM Ready: Exclude src from published package files (WordPress/gutenberg#77302)
- UI: Support custom targets on Link and Menu.LinkItem (WordPress/gutenberg#82347)
- Escape HTML: Exclude src from published package files (WordPress/gutenberg#77304)
- keycodes: Exclude src from published files (WordPress/gutenberg#77306)
- Packages: Exclude src from block-serialization-default-parser published package (WordPress/gutenberg#77307)
- A11y: Exclude src from published package files (WordPress/gutenberg#77309)
- Packages: Exclude src from autop published package (WordPress/gutenberg#77283)
- Blob: Exclude src from published package files (WordPress/gutenberg#77289)
- Packages: Exclude src from deprecated published package (WordPress/gutenberg#77303)
- fix(list-reusable-blocks): exclude src from published files (WordPress/gutenberg#77305)
- Admin UI: Exclude src from published files and sideEffects (WordPress/gutenberg#77285)
- Standardize 'Back' and 'Go back' labels (WordPress/gutenberg#79211)
- Audio: Update autoplay help text for clarity (WordPress/gutenberg#69978)
- Theme JSON: Avoid rebuilding identical block schemas during sanitization (WordPress/gutenberg#82203)
- Docs: Improve setAttributes updater function wording (WordPress/gutenberg#82405)
- Query Loop: Rename the "Keyword" filter to "Search terms" and add help text (WordPress/gutenberg#82387)
- CI: add a per-workflow status check job and filter paths (WordPress/gutenberg#81015)
- ESLint: Thin use-recommended-components tests (WordPress/gutenberg#82407)
- UI: Fix enabled input placeholder contrast (WordPress/gutenberg#82304)
- Tab trap escape hatch: leave/enter the canvas with Escape/Enter (WordPress/gutenberg#82314)
- List: preserve client IDs on indent, just like outdent (WordPress/gutenberg#59216)
- Templates REST API: prevent fatal error when a null template reaches prepare_item_for_response (WordPress/gutenberg#82374)
- Editor: Refactor the View menu to use the Menu component (WordPress/gutenberg#82321)
- CSS Styling: Cleanup focus outline override for grid component (WordPress/gutenberg#82337)
- E2E: Run the site editor suite against the extensible site editor too (WordPress/gutenberg#82117)
- Fields: Remove unused CSS rule from slug field control (WordPress/gutenberg#77961)
- Fix: Footnote IDs can start with a digit and break CSS selectors (WordPress/gutenberg#82398)
- feat: Introduce 'Add Media' in the block controls for media-text block (WordPress/gutenberg#82420)
- fix: Audio element to have it's own name (WordPress/gutenberg#82389)
- Docs: Update Playground CLI wording (WordPress/gutenberg#77579)
- Upgrade React 19 to 19.2.8, read version from package.json (WordPress/gutenberg#82439)
- Tab Panel: Show focus with outline instead of legacy box-shadow ring (WordPress/gutenberg#82421)
- Editor: Fix disabled and link items of the more menu adapter (WordPress/gutenberg#82428)
- UI: Fix Menu.LinkItem target detection (WordPress/gutenberg#82442)
- SearchableSelect: Add form primitive to @wordpress/ui (WordPress/gutenberg#80961)
- Validated form controls: Use design token for invalid focus rings (WordPress/gutenberg#82410)
- feat: Update layout icons (WordPress/gutenberg#82025)
- Widgets: Replace {TODO} placeholder with PR number in changelog entries (WordPress/gutenberg#82450)
- UI: Remove ESLint ref suppressions and refactor AlertDialog state (WordPress/gutenberg#82131)
- Menu: Align selection indicators and prefix icons with item labels (WordPress/gutenberg#82346)
- ToggleGroupControl: Honor the root disabled prop (WordPress/gutenberg#82259)
- Block Library: Remove the form blocks experiment (WordPress/gutenberg#82451)
- List: indent and outdent multi-selected items with Tab (WordPress/gutenberg#82411)
- CodeRabbit: Only review on request, keep PR descriptions untouched (WordPress/gutenberg#82448)
- Privacy policy page badge: make it visible in Site Editor > Pages and Editor Inspector (WordPress/gutenberg#82422)
- Support `isAny` and `isNone` filter operators for numeric fields. (WordPress/gutenberg#77942)
- UI: Keep focus rings visible in overlay content (WordPress/gutenberg#82443)
- Menu: Correct alignment documentation and changelog (WordPress/gutenberg#82455)
- UI: Name unlabeled form primitive stories (WordPress/gutenberg#82311)
- UI: Re-read the native validity on blur in ControlWithError (WordPress/gutenberg#82376)
- Media Utils: Preserve arrays in multipart form data (WordPress/gutenberg#82353)
- fix: Remove stories from performance tests (WordPress/gutenberg#82459)
- Add the template e2e tests for the editor inspector consolidation experiment (WordPress/gutenberg#82394)
- UI: Fix Link target detection (WordPress/gutenberg#82447)
- Fix privacy policy page setting unit test on multisite (WordPress/gutenberg#82467)
- UI, DataViews: Give input and selection controls solid backgrounds (WordPress/gutenberg#82391)
- Fix LocationPicker popover alignment with InputGroup (WordPress/gutenberg#82090)
- List: indent and outdent a fully selected list item with Tab (WordPress/gutenberg#82460)
- UI: Fix Minimal Select popup width (WordPress/gutenberg#82461)
- Rich text: resolve owned event listeners once instead of per subscriber (WordPress/gutenberg#80605)
- UI: Keep borderless InputLayout chrome when disabled (WordPress/gutenberg#82468)
- Theme: Cache luminance for contrast checks (WordPress/gutenberg#82445)
- Add promptfoo for testing agent development setup and skills (WordPress/gutenberg#80812)
- wp-env: Fix Docker build errors with Debian Bullseye repositories (WordPress/gutenberg#82478)
- Query Loop: Fall back to `post` when the query has no `postType` (WordPress/gutenberg#82465)
- Block Supports: Bail early in state styles when a block has no style attribute (WordPress/gutenberg#81908)
- CSS Styling: Represent focus with outline for list view component (WordPress/gutenberg#82129)
- Icons: Remove the obsolete forced colors mode hack (WordPress/gutenberg#82481)
- Docs: Remove invalid `@return` tag from the `block_core_social_link_get_services` hook docblock (WordPress/gutenberg#82488)
- Site Editor: Add a root error boundary to prevent a blank screen (WordPress/gutenberg#82486)
- Writing Flow: Bail out of Enter handling when no block is selected (WordPress/gutenberg#82424)
- Docs: Remove the blank line between @PARAM and @return in test docblocks (WordPress/gutenberg#81907)
- List View: Disable block icon colors while the block is selected (WordPress/gutenberg#82498)
- Fix: Restore layout styles for block style variations (WordPress/gutenberg#82335)
- Post slug: prefer server sanitization in the editor (WordPress/gutenberg#78135)
- Media Modal Experiment: Allow filtering by attached to the post, or unattached (WordPress/gutenberg#81974)
- Media editor: Lock the editing tools while a save is running (WordPress/gutenberg#82417)
- DataViews: Restrict the isAll filter operator to array fields (WordPress/gutenberg#82463)
- Media Fields: Pass the field's disabled state to the textarea controls (WordPress/gutenberg#82516)
- Theme: Make chroma capacity caching deterministic (WordPress/gutenberg#82505)
- Global Styles: Remove the color randomizer experiment (WordPress/gutenberg#82452)
- DataViews: Fix Field.sort TypeScript type definition (WordPress/gutenberg#82162)
- Migrate __experimentalText and __experimentalHeading to @wordpress/ui Text in Inspector Popover Header (WordPress/gutenberg#77449)
- Migrate __experimentalText to @wordpress/ui Text in Block switcher bindings hint (WordPress/gutenberg#77366)
- UI: Add Radio form primitive (WordPress/gutenberg#82214)
- Migrate __experimentalText to @wordpress/ui Text in Allowed Blocks Modal (WordPress/gutenberg#78119)
- UI: Add CheckboxControl (WordPress/gutenberg#82213)
- Core Data: Scope revisionId to the entity it is provided for (WordPress/gutenberg#82517)
- Migrate __experimentalText to @wordpress/ui Text in Pattern Overrides Dropdown (WordPress/gutenberg#77492)
- ProgressBar: Respect reduced motion preferences (WordPress/gutenberg#82490)
- Theme: Clarify color seed and warning guarantees (WordPress/gutenberg#82526)
- Theme: Build default ramps before token artifacts (WordPress/gutenberg#82525)
- CodeRabbit: Disable the review status comment (WordPress/gutenberg#82534)
- Project Management: Restore CODEOWNERS exclusions for suppression lists (WordPress/gutenberg#82538)
- Editor: merge duplicate "Enhancements" changelog sections (WordPress/gutenberg#82533)
- UI: Validate compound component context (WordPress/gutenberg#82510)
- Docs: Document isolated worktree setup (WordPress/gutenberg#82524)
- DataForm: render untyped fields without an edit control that are read-only (WordPress/gutenberg#82514)
- API Fetch: Add unregister to remove a registered middleware (WordPress/gutenberg#82408)
- Editor: Show revision data in Post Title component (WordPress/gutenberg#82536)
- Components: Add compound component composition diagnostics (WordPress/gutenberg#82509)
- Fieldset: Fix gap token to match spec (WordPress/gutenberg#75479)
- Test: Migrate deterministic JSDOM tests and harden Vitest isolation (WordPress/gutenberg#82212)
- Release: Make npm publication verification resumable (WordPress/gutenberg#82089)
- Block Library: Use 'useEntityProp' in Site Title and Tagline blocks (WordPress/gutenberg#82518)
- Theme: Migrate Terrazzo modes to resolvers (WordPress/gutenberg#82537)
- Fix auto-capitalization after Enter on iOS Safari (WordPress/gutenberg#82475)
- Update navigation link block name, use a default variation for custom link (WordPress/gutenberg#82375)
- API Fetch: Expose defaultFetchHandler so overrides can restore it (WordPress/gutenberg#82553)
- Core Data: Return a stable record for equivalent `_fields` queries (WordPress/gutenberg#82552)
- API Fetch: Rename defaultFetchHandler parameter to options (WordPress/gutenberg#82588)
- Fields: remove unused custom sort from the author fields (WordPress/gutenberg#82559)
- Fields: Declare the caption, alt text, description and ping status controls through the Field API (WordPress/gutenberg#82539)
- Docs: Align @PARAM tag columns in phpunit/ docblocks (WordPress/gutenberg#81904)
- Docs: Align @PARAM tag columns in lib/ docblocks (WordPress/gutenberg#81902)
- Docs: Align @PARAM tag columns in packages/ docblocks (WordPress/gutenberg#81903)
- Fix help paragraph color contrast ratio in the Connectors page. (WordPress/gutenberg#82378)
- DataViews: Declare transitive dependencies imported by the ./wp bundle (WordPress/gutenberg#81843)
- DataForm: Add a `showPlaceholderIfEmpty` option to the panel layout (WordPress/gutenberg#82527)
- Global Styles UI: migrate revisions Active Badge to UI Badge (WordPress/gutenberg#82560)
- UI: Put overflow on Select.List instead of a nested wrapper (WordPress/gutenberg#82470)
- Editor: migrate post-card-panel Badge to UI Badge (WordPress/gutenberg#82500)
- Fields: migrate page-title Badge to UI Badge (WordPress/gutenberg#82499)
- DataViews: Skip table columns for field ids without a field definition (WordPress/gutenberg#82601)
- View config: remove stale fields from the wp_template default view (WordPress/gutenberg#82602)
- Rich text: restore contenteditable on pointercancel (WordPress/gutenberg#82598)
- Components: Add an Emotion-to-SCSS migration skill and guide (WordPress/gutenberg#82567)

See #66070.

git-svn-id: https://develop.svn.wordpress.org/trunk@63538 602fd350-edb4-49c9-b593-d223f7449a82
wporg-sync pushed a commit to WordPress/WordPress that referenced this pull request Sep 8, 2026
This updates the pinned commit hash of the Gutenberg repository from `658c8cbe89db5d90279051d3bb816ca210fe4646 ` (version `23.8.0`) to `5a4cc502d43016f1efa66f8f6d9bd3bb4bb24d85`, which contains the latest changes up until the Node.js version was bumped from 20.x to 24.x.

A full list of changes included in this commit can be found on GitHub: https://github.com/WordPress/gutenberg/compare/658c8cbe89db5d90279051d3bb816ca210fe4646..5a4cc502d43016f1efa66f8f6d9bd3bb4bb24d85.

- Menu: Stabilize iframe reload test (WordPress/gutenberg#82081)
- Packages: Recover August 26 npm release metadata (WordPress/gutenberg#82085)
- Storybook: Demonstrate light, dark, and nested themes (WordPress/gutenberg#82039)
- Project Management: Add validation for missing GitHub labels configuration (WordPress/gutenberg#76263)
- Automated Testing: Enforce `.tsx` for all new React files (WordPress/gutenberg#80123)
- UI: Use root theme for portaled overlays (WordPress/gutenberg#82038)
- Menu: Stabilize portaled iframe test (WordPress/gutenberg#82092)
- Theme: Move post-release changelog entry to Unreleased (WordPress/gutenberg#82093)
- Media: Refuse a multi-file drop on a placeholder that takes one file (WordPress/gutenberg#82046)
- Font Library: Keep CSS custom properties unquoted in font previews (WordPress/gutenberg#82010)
- Add "reading settings" link to Front Page template (WordPress/gutenberg#81987)
- Docs: Fix grammar in documentation (WordPress/gutenberg#82032)
- Media Editor: refactor the panel layout (WordPress/gutenberg#81840)
- DataViews layout storybook: action names and primary status (WordPress/gutenberg#82104)
- Make `@wordpress/reusable-blocks` a no-op compatibility package (WordPress/gutenberg#79186)
- Widget Dashboard: add a Policy provider to govern what users may do (WordPress/gutenberg#81967)
- Build Package: Restore Core Boot layout compatibility (WordPress/gutenberg#82112)
- Edit Widgets: Guard canInsertBlockInWidgetArea against an empty block list (WordPress/gutenberg#82107)
- Build: Enforce NodeNext resolution for ESM packages (WordPress/gutenberg#82088)
- UI: Remove unused outset-ring--focus-within-visible class. (WordPress/gutenberg#82077)
- Inserter: Keep the block preview inside the viewport (WordPress/gutenberg#82060)
- Test: Enforce Vitest conventions and CI guardrails (WordPress/gutenberg#81040)
- Editor: Apply the showListViewByDefault preference in the shared editor (WordPress/gutenberg#82119)
- Release: Use CLI runtime for package publishing (WordPress/gutenberg#82122)
- Reusable Blocks: Remove leftover merge conflict markers from the changelog (WordPress/gutenberg#82126)
- chore: Update grep settings and remove comments (WordPress/gutenberg#82121)
- Fix: Content Guidelines: UX/UI Accessibility issues (WordPress/gutenberg#80306)
- Extensible Site Editor: Let menu items be added from the navigation screen (WordPress/gutenberg#82125)
- Navigation: Change WCText to Text (WordPress/gutenberg#82130)
- Storybook: Persist sidebar theme in URL (WordPress/gutenberg#82111)
- Editor assets endpoint: prime the theme JSON resolver before capturing (WordPress/gutenberg#82134)
- Remove unused dependencies across the monorepo (WordPress/gutenberg#82103)
- Update changelog instructions for agents (WordPress/gutenberg#82097)
- Build: Normalize JSX file extensions (WordPress/gutenberg#80990)
- Fix pattern export filenames by normalizing special characters (WordPress/gutenberg#77033)
- Site editor v2: navigation takes view config from endpoint (WordPress/gutenberg#82138)
- Extensible Site Editor: Load media assets before the media fields open (WordPress/gutenberg#82135)
- Site editor v2: pages take view config from endpoint (WordPress/gutenberg#82140)
- Extensible site editor: Add a revisions entry point to the Styles route (WordPress/gutenberg#82142)
- List: outdent an empty middle item without adding an item (WordPress/gutenberg#82011)
- Extensible site editor: Fall back to the raw title in edit route document titles (WordPress/gutenberg#82143)
- Blocks: Make BlockTransform a discriminated union over its type (WordPress/gutenberg#81831)
- Theme: add LightningCSS WPDS token fallback plugin (WordPress/gutenberg#80401)
- UI: Add popupWidth prop to item popup components (WordPress/gutenberg#82087)
- Snackbar: Restart timeout when a notice is recreated (WordPress/gutenberg#81764)
- Media: Report server upload failures in plain language (WordPress/gutenberg#81735)
- Format library: visualise non-breaking spaces (WordPress/gutenberg#74040)
- Bump the github-actions group across 1 directory with 2 updates (WordPress/gutenberg#81932)
- Try adding a Grid block variation to Gallery (WordPress/gutenberg#81909)
- Components: Keep foreign items out of a ToolsPanel menu (WordPress/gutenberg#82127)
- Enable Gallery columns and crop controls in viewport states (WordPress/gutenberg#82003)
- Query: Don't write excludeCurrent into blocks that never had it (WordPress/gutenberg#82147)
- Site title: Add fit-text support. (WordPress/gutenberg#82074)
- Accordion Panel: Reset padding-block when panel is hidden (WordPress/gutenberg#81782)
- Replace npm-run-all with native npm script chaining (WordPress/gutenberg#82166)
- Grid: per-item tile size limits (WordPress/gutenberg#81899)
- Fix: Tabs block: Anchor links in tab panels are not functional (WordPress/gutenberg#81744)
- Validate tsconfig references against declared dependencies (WordPress/gutenberg#82106)
- Performance tests: Build once and shard the suites across parallel CI jobs (WordPress/gutenberg#82160)
- Site Health widget: route the body's review link through the host (WordPress/gutenberg#82066)
- Build: allow wp-theme 2.x peer deps (WordPress/gutenberg#82139)
- Bundled packages: Add a check for transitive private API usage (WordPress/gutenberg#82027)
- List: try to preserve indentation level of children after outdenting+merging their parent (WordPress/gutenberg#82145)
- Block Library: Fix categories block handling of invalid taxonomy (WordPress/gutenberg#82153)
- useViewConfig: don't request the view config twice (WordPress/gutenberg#82141)
- Documentation: Remove invalid references to Babel in packages README (WordPress/gutenberg#82176)
- Automated Testing: Fix failing categories test on trunk (WordPress/gutenberg#82182)
- Jest: Update to 30.5.0 (WordPress/gutenberg#82181)
- Fix: Retain focus and caret position after Backspace undo of a prefix block transform (WordPress/gutenberg#82116)
- Scaffold e2e tests for the editor inspector consolidation experiment (WordPress/gutenberg#82178)
- Package lock: Deduplicate Jest dependencies (WordPress/gutenberg#82187)
- Components: Migrate remaining JSX files to TypeScript (WordPress/gutenberg#82132)
- Text: Use pretty wrapping by default (WordPress/gutenberg#82133)
- Build Tooling: Add browserslist config for build targeting (WordPress/gutenberg#82179)
- Columns: Fix appender drop zone visibility when dragging into empty column (WordPress/gutenberg#77852)
- Build: Require explicit JSX file extensions (WordPress/gutenberg#82189)
- Icons: Redraw 35 prominent icons with consistent stroke widths (WordPress/gutenberg#78808)
- Test: Classify and enforce unit test environments by filename (WordPress/gutenberg#80991)
- Test: Fix CI failures on trunk (WordPress/gutenberg#82201)
- Fix editor link colour cascade order for nested blocks (WordPress/gutenberg#77833)
- Add New Template: Show the design system focus ring instead of legacy box-shadow rings (WordPress/gutenberg#82164)
- List View: Don’t focus the last Table cell on keyboard activation (WordPress/gutenberg#81964)
- Fix spelling typos in docs and inline comments (WordPress/gutenberg#82217)
- CI: Pin npm version in the private API check job (WordPress/gutenberg#82222)
- Private APIs: Add back '@wordpress/dataviews' to the allowed core modules (WordPress/gutenberg#82221)
- Editor: Mark __unstableSaveForPreview options as optional (WordPress/gutenberg#81858)
- Docs: Explain when the Cover block's overlay controls appear (WordPress/gutenberg#82234)
- Menu: Use Text for item labels and descriptions (WordPress/gutenberg#82237)
- Test: Type pipe's supported array inputs (WordPress/gutenberg#82210)
- Widget Dashboard: keep the plain anchor for an empty-string download (WordPress/gutenberg#82073)
- CI: Read the required npm version from a single source (WordPress/gutenberg#82235)
- Components: Add `defaultShown`, `onShownChange` to `ToolsPanelItem` (WordPress/gutenberg#78010)
- Storybook: Drop unused support for js-as-jsx (WordPress/gutenberg#82192)
-  Math: Declare clientNavigation interactivity support (WordPress/gutenberg#82248)
- Point to docmumentation about release assets (WordPress/gutenberg#82250)
- Change stray `ubuntu-latest` to `ubuntu-24.04`. (WordPress/gutenberg#82156)
- Performance tests: Reuse the plugin an earlier trunk run already built (WordPress/gutenberg#82223)
- Breadcrumb: Add UI component (WordPress/gutenberg#80425)
- Components: Cut the ToolsPanel render cascade (WordPress/gutenberg#82180)
- Fix: alert dialog box cancel button color (WordPress/gutenberg#82261)
- UI: Add Form best practices Storybook page (WordPress/gutenberg#82197)
- Media: Stop claiming "Upload complete" when upload failed (WordPress/gutenberg#81397)
- Boot, Site Editor: Seed content surfaces with default background color (WordPress/gutenberg#81646)
- Format Library: Fix Edit as HTML crash with background-only highlight (WordPress/gutenberg#82215)
- Remove the template activation experiment (WordPress/gutenberg#82241)
- Packages: Add cross-version compatibility skill (WordPress/gutenberg#81890)
- Show the block outline where the grab cursor shows (WordPress/gutenberg#81798)
- DataViews: Scope the search field's fixed width to the default UI search row (WordPress/gutenberg#82128)
- Background image: support setting the image from a URL (WordPress/gutenberg#82230)
- Border Box Control: Try moving the unlink button to the label row, and rename the panel to Borders (WordPress/gutenberg#82163)
- Widget Dashboard: govern Reset to default through the policy (WordPress/gutenberg#82255)
- Media: Attach unattached media to the current post on save/publish (WordPress/gutenberg#81977)
- Widget Dashboard: make the column count a host decision (WordPress/gutenberg#82204)
- Global styles: resolve theme-relative background image URLs for display (WordPress/gutenberg#82242)
- CI: Unify the automation comments into a single PR comment (WordPress/gutenberg#82249)
- Core Data: Convert hooks tests to renderHook and drop JSX (WordPress/gutenberg#82276)
- Release: Map [Type] Flaky Test to the Tools changelog section (WordPress/gutenberg#82078)
- DateTime tests: freeze the clock in the empty-value calendar test (WordPress/gutenberg#82282)
- DataForm: treat combined form fields purely as layout containers (WordPress/gutenberg#82175)
- Global styles engine: return a copy from getResolvedValue instead of mutating (WordPress/gutenberg#82278)
- Test: Migrate Node unit tests to Vitest (WordPress/gutenberg#82211)
- Icons: Redraw 64 icons to be stroke-based. (WordPress/gutenberg#78812)
- Tests: Fix Vitest setup and stale jest types under non-hoisting installs (WordPress/gutenberg#82290)
- UI: Rename Popup `popupWidth` prop to `width` (WordPress/gutenberg#82193)
- Query: Replace the "Reload full page enabled" modal with a snackbar notice (WordPress/gutenberg#82246)
- Project Management: Update CODEOWNERS to reflect current participation (WordPress/gutenberg#82262)
- Editor: Refactor the Options menu to use the Menu component (WordPress/gutenberg#81564)
- UI: Add Field.VisualLabel (WordPress/gutenberg#82095)
- Update Stylelint to v17 and related packages (WordPress/gutenberg#80738)
- Media: keep indexed PNG sub-sizes indexed (WordPress/gutenberg#81884)
- UI: Add Combobox and Autocomplete Status (WordPress/gutenberg#82195)
- UI: Drop Status and Empty live region test assertions (WordPress/gutenberg#82300)
- Project Management: Remove empty entries from CODEOWNERS (WordPress/gutenberg#82292)
- Documentation: Add recommended bulk suppressions configuration for ESLint (WordPress/gutenberg#82303)
- UI: Hide Input field ring when a slot control is focused (WordPress/gutenberg#82257)
- Widgets: Surface debugging details in the ErrorBoundary (WordPress/gutenberg#82099)
- TypeScript: Migrate format-library package to TS (WordPress/gutenberg#79486)
- BorderBoxControl: Make sure the group of controls is associated with the label (WordPress/gutenberg#82279)
- Image block cropping: Sync image size and link destination settings (WordPress/gutenberg#82316)
- Menu: Support multiple item descriptions (WordPress/gutenberg#81825)
- CI: Do not fail the type label check on a newly opened pull request (WordPress/gutenberg#82322)
- UI: Align overlay Trigger props with Base UI (WordPress/gutenberg#81824)
- Gallery block: Fix 'Crop images to fit' broken in editor (WordPress/gutenberg#82318)
- Widget Dashboard: enforce the policy on the staging layer for every instance operation (WordPress/gutenberg#82256)
- DataForm: Communicate the timezone in the datetime control (WordPress/gutenberg#82291)
- Add more e2e tests for the editor inspector consolidation experiment (WordPress/gutenberg#82239)
- Framework: Error on npm versions older than the required floor (WordPress/gutenberg#82320)
- Document every type for DataViews/DataForm/Field API (WordPress/gutenberg#82326)
- ESLint plugin: remove usage of Babel parser (WordPress/gutenberg#82144)
- DataViews: remove the rich text options from the control config type (WordPress/gutenberg#82330)
- Meta Boxes: Move meta box markup with moveBefore to keep classic editors alive (WordPress/gutenberg#82243)
- Add more e2e tests for the editor inspector consolidation experiment (WordPress/gutenberg#82327)
- Test: Enforce JavaScript test runner ownership (WordPress/gutenberg#82299)
- DataViews: clamp page after delete (WordPress/gutenberg#82244)
- Stylelint tools: Resolve test config extends from the workspace (WordPress/gutenberg#82336)
- Editor: Deprecate the `as` prop of the plugin menu item components (WordPress/gutenberg#82319)
- Icons: Convert Search icon to strokes (WordPress/gutenberg#82338)
- DataViews: Document that table column styles do not apply to the primary column (WordPress/gutenberg#82238)
- DataViews: add hierarchical levels story (WordPress/gutenberg#82344)
- CI: Add "Required changes from trunk" PR check (WordPress/gutenberg#82272)
- feat: Improve TypeScript definitions in the getEntityRecord function (WordPress/gutenberg#81863)
- Framework: Update Node.js to v24 LTS and npm to v11 (WordPress/gutenberg#80395)
- Revert "Framework: Update Node.js to v24 LTS and npm to v11 (WordPress/gutenberg#80395)" (WordPress/gutenberg#82355)
- UI: Remove ValidityIndicator outer margin (WordPress/gutenberg#82267)
- Span the writing flow focus capture elements over the canvas (WordPress/gutenberg#82354)
- Fields: Hide the slug field for posts without a permalink (WordPress/gutenberg#82341)
- Fix: Responsive horizontal orientation does not override a vertical layout. (WordPress/gutenberg#82364)
- View Config: Move the table column style descriptions to the 7.2 compat layer (WordPress/gutenberg#82372)
- Block Library: Allow themes to override the padding added via background color (WordPress/gutenberg#82024)
- DataViews: Append an ellipsis to action labels that open a dialog (WordPress/gutenberg#81994)
- Pages: require authentication and a capability to render generated standalone pages (WordPress/gutenberg#82254)
- Build/Test Tools: Replace npx with npm exec --no (WordPress/gutenberg#82331)
- Navigation: restore flex-grow on container when accessible label is present (WordPress/gutenberg#78447)
- DOM Ready: Exclude src from published package files (WordPress/gutenberg#77302)
- UI: Support custom targets on Link and Menu.LinkItem (WordPress/gutenberg#82347)
- Escape HTML: Exclude src from published package files (WordPress/gutenberg#77304)
- keycodes: Exclude src from published files (WordPress/gutenberg#77306)
- Packages: Exclude src from block-serialization-default-parser published package (WordPress/gutenberg#77307)
- A11y: Exclude src from published package files (WordPress/gutenberg#77309)
- Packages: Exclude src from autop published package (WordPress/gutenberg#77283)
- Blob: Exclude src from published package files (WordPress/gutenberg#77289)
- Packages: Exclude src from deprecated published package (WordPress/gutenberg#77303)
- fix(list-reusable-blocks): exclude src from published files (WordPress/gutenberg#77305)
- Admin UI: Exclude src from published files and sideEffects (WordPress/gutenberg#77285)
- Standardize 'Back' and 'Go back' labels (WordPress/gutenberg#79211)
- Audio: Update autoplay help text for clarity (WordPress/gutenberg#69978)
- Theme JSON: Avoid rebuilding identical block schemas during sanitization (WordPress/gutenberg#82203)
- Docs: Improve setAttributes updater function wording (WordPress/gutenberg#82405)
- Query Loop: Rename the "Keyword" filter to "Search terms" and add help text (WordPress/gutenberg#82387)
- CI: add a per-workflow status check job and filter paths (WordPress/gutenberg#81015)
- ESLint: Thin use-recommended-components tests (WordPress/gutenberg#82407)
- UI: Fix enabled input placeholder contrast (WordPress/gutenberg#82304)
- Tab trap escape hatch: leave/enter the canvas with Escape/Enter (WordPress/gutenberg#82314)
- List: preserve client IDs on indent, just like outdent (WordPress/gutenberg#59216)
- Templates REST API: prevent fatal error when a null template reaches prepare_item_for_response (WordPress/gutenberg#82374)
- Editor: Refactor the View menu to use the Menu component (WordPress/gutenberg#82321)
- CSS Styling: Cleanup focus outline override for grid component (WordPress/gutenberg#82337)
- E2E: Run the site editor suite against the extensible site editor too (WordPress/gutenberg#82117)
- Fields: Remove unused CSS rule from slug field control (WordPress/gutenberg#77961)
- Fix: Footnote IDs can start with a digit and break CSS selectors (WordPress/gutenberg#82398)
- feat: Introduce 'Add Media' in the block controls for media-text block (WordPress/gutenberg#82420)
- fix: Audio element to have it's own name (WordPress/gutenberg#82389)
- Docs: Update Playground CLI wording (WordPress/gutenberg#77579)
- Upgrade React 19 to 19.2.8, read version from package.json (WordPress/gutenberg#82439)
- Tab Panel: Show focus with outline instead of legacy box-shadow ring (WordPress/gutenberg#82421)
- Editor: Fix disabled and link items of the more menu adapter (WordPress/gutenberg#82428)
- UI: Fix Menu.LinkItem target detection (WordPress/gutenberg#82442)
- SearchableSelect: Add form primitive to @wordpress/ui (WordPress/gutenberg#80961)
- Validated form controls: Use design token for invalid focus rings (WordPress/gutenberg#82410)
- feat: Update layout icons (WordPress/gutenberg#82025)
- Widgets: Replace {TODO} placeholder with PR number in changelog entries (WordPress/gutenberg#82450)
- UI: Remove ESLint ref suppressions and refactor AlertDialog state (WordPress/gutenberg#82131)
- Menu: Align selection indicators and prefix icons with item labels (WordPress/gutenberg#82346)
- ToggleGroupControl: Honor the root disabled prop (WordPress/gutenberg#82259)
- Block Library: Remove the form blocks experiment (WordPress/gutenberg#82451)
- List: indent and outdent multi-selected items with Tab (WordPress/gutenberg#82411)
- CodeRabbit: Only review on request, keep PR descriptions untouched (WordPress/gutenberg#82448)
- Privacy policy page badge: make it visible in Site Editor > Pages and Editor Inspector (WordPress/gutenberg#82422)
- Support `isAny` and `isNone` filter operators for numeric fields. (WordPress/gutenberg#77942)
- UI: Keep focus rings visible in overlay content (WordPress/gutenberg#82443)
- Menu: Correct alignment documentation and changelog (WordPress/gutenberg#82455)
- UI: Name unlabeled form primitive stories (WordPress/gutenberg#82311)
- UI: Re-read the native validity on blur in ControlWithError (WordPress/gutenberg#82376)
- Media Utils: Preserve arrays in multipart form data (WordPress/gutenberg#82353)
- fix: Remove stories from performance tests (WordPress/gutenberg#82459)
- Add the template e2e tests for the editor inspector consolidation experiment (WordPress/gutenberg#82394)
- UI: Fix Link target detection (WordPress/gutenberg#82447)
- Fix privacy policy page setting unit test on multisite (WordPress/gutenberg#82467)
- UI, DataViews: Give input and selection controls solid backgrounds (WordPress/gutenberg#82391)
- Fix LocationPicker popover alignment with InputGroup (WordPress/gutenberg#82090)
- List: indent and outdent a fully selected list item with Tab (WordPress/gutenberg#82460)
- UI: Fix Minimal Select popup width (WordPress/gutenberg#82461)
- Rich text: resolve owned event listeners once instead of per subscriber (WordPress/gutenberg#80605)
- UI: Keep borderless InputLayout chrome when disabled (WordPress/gutenberg#82468)
- Theme: Cache luminance for contrast checks (WordPress/gutenberg#82445)
- Add promptfoo for testing agent development setup and skills (WordPress/gutenberg#80812)
- wp-env: Fix Docker build errors with Debian Bullseye repositories (WordPress/gutenberg#82478)
- Query Loop: Fall back to `post` when the query has no `postType` (WordPress/gutenberg#82465)
- Block Supports: Bail early in state styles when a block has no style attribute (WordPress/gutenberg#81908)
- CSS Styling: Represent focus with outline for list view component (WordPress/gutenberg#82129)
- Icons: Remove the obsolete forced colors mode hack (WordPress/gutenberg#82481)
- Docs: Remove invalid `@return` tag from the `block_core_social_link_get_services` hook docblock (WordPress/gutenberg#82488)
- Site Editor: Add a root error boundary to prevent a blank screen (WordPress/gutenberg#82486)
- Writing Flow: Bail out of Enter handling when no block is selected (WordPress/gutenberg#82424)
- Docs: Remove the blank line between @PARAM and @return in test docblocks (WordPress/gutenberg#81907)
- List View: Disable block icon colors while the block is selected (WordPress/gutenberg#82498)
- Fix: Restore layout styles for block style variations (WordPress/gutenberg#82335)
- Post slug: prefer server sanitization in the editor (WordPress/gutenberg#78135)
- Media Modal Experiment: Allow filtering by attached to the post, or unattached (WordPress/gutenberg#81974)
- Media editor: Lock the editing tools while a save is running (WordPress/gutenberg#82417)
- DataViews: Restrict the isAll filter operator to array fields (WordPress/gutenberg#82463)
- Media Fields: Pass the field's disabled state to the textarea controls (WordPress/gutenberg#82516)
- Theme: Make chroma capacity caching deterministic (WordPress/gutenberg#82505)
- Global Styles: Remove the color randomizer experiment (WordPress/gutenberg#82452)
- DataViews: Fix Field.sort TypeScript type definition (WordPress/gutenberg#82162)
- Migrate __experimentalText and __experimentalHeading to @wordpress/ui Text in Inspector Popover Header (WordPress/gutenberg#77449)
- Migrate __experimentalText to @wordpress/ui Text in Block switcher bindings hint (WordPress/gutenberg#77366)
- UI: Add Radio form primitive (WordPress/gutenberg#82214)
- Migrate __experimentalText to @wordpress/ui Text in Allowed Blocks Modal (WordPress/gutenberg#78119)
- UI: Add CheckboxControl (WordPress/gutenberg#82213)
- Core Data: Scope revisionId to the entity it is provided for (WordPress/gutenberg#82517)
- Migrate __experimentalText to @wordpress/ui Text in Pattern Overrides Dropdown (WordPress/gutenberg#77492)
- ProgressBar: Respect reduced motion preferences (WordPress/gutenberg#82490)
- Theme: Clarify color seed and warning guarantees (WordPress/gutenberg#82526)
- Theme: Build default ramps before token artifacts (WordPress/gutenberg#82525)
- CodeRabbit: Disable the review status comment (WordPress/gutenberg#82534)
- Project Management: Restore CODEOWNERS exclusions for suppression lists (WordPress/gutenberg#82538)
- Editor: merge duplicate "Enhancements" changelog sections (WordPress/gutenberg#82533)
- UI: Validate compound component context (WordPress/gutenberg#82510)
- Docs: Document isolated worktree setup (WordPress/gutenberg#82524)
- DataForm: render untyped fields without an edit control that are read-only (WordPress/gutenberg#82514)
- API Fetch: Add unregister to remove a registered middleware (WordPress/gutenberg#82408)
- Editor: Show revision data in Post Title component (WordPress/gutenberg#82536)
- Components: Add compound component composition diagnostics (WordPress/gutenberg#82509)
- Fieldset: Fix gap token to match spec (WordPress/gutenberg#75479)
- Test: Migrate deterministic JSDOM tests and harden Vitest isolation (WordPress/gutenberg#82212)
- Release: Make npm publication verification resumable (WordPress/gutenberg#82089)
- Block Library: Use 'useEntityProp' in Site Title and Tagline blocks (WordPress/gutenberg#82518)
- Theme: Migrate Terrazzo modes to resolvers (WordPress/gutenberg#82537)
- Fix auto-capitalization after Enter on iOS Safari (WordPress/gutenberg#82475)
- Update navigation link block name, use a default variation for custom link (WordPress/gutenberg#82375)
- API Fetch: Expose defaultFetchHandler so overrides can restore it (WordPress/gutenberg#82553)
- Core Data: Return a stable record for equivalent `_fields` queries (WordPress/gutenberg#82552)
- API Fetch: Rename defaultFetchHandler parameter to options (WordPress/gutenberg#82588)
- Fields: remove unused custom sort from the author fields (WordPress/gutenberg#82559)
- Fields: Declare the caption, alt text, description and ping status controls through the Field API (WordPress/gutenberg#82539)
- Docs: Align @PARAM tag columns in phpunit/ docblocks (WordPress/gutenberg#81904)
- Docs: Align @PARAM tag columns in lib/ docblocks (WordPress/gutenberg#81902)
- Docs: Align @PARAM tag columns in packages/ docblocks (WordPress/gutenberg#81903)
- Fix help paragraph color contrast ratio in the Connectors page. (WordPress/gutenberg#82378)
- DataViews: Declare transitive dependencies imported by the ./wp bundle (WordPress/gutenberg#81843)
- DataForm: Add a `showPlaceholderIfEmpty` option to the panel layout (WordPress/gutenberg#82527)
- Global Styles UI: migrate revisions Active Badge to UI Badge (WordPress/gutenberg#82560)
- UI: Put overflow on Select.List instead of a nested wrapper (WordPress/gutenberg#82470)
- Editor: migrate post-card-panel Badge to UI Badge (WordPress/gutenberg#82500)
- Fields: migrate page-title Badge to UI Badge (WordPress/gutenberg#82499)
- DataViews: Skip table columns for field ids without a field definition (WordPress/gutenberg#82601)
- View config: remove stale fields from the wp_template default view (WordPress/gutenberg#82602)
- Rich text: restore contenteditable on pointercancel (WordPress/gutenberg#82598)
- Components: Add an Emotion-to-SCSS migration skill and guide (WordPress/gutenberg#82567)

See #66070.
Built from https://develop.svn.wordpress.org/trunk@63538


git-svn-id: http://core.svn.wordpress.org/trunk@62714 1a063a9b-81f0-0310-95a4-ce76da25c4cd
@manzoorwanijk

manzoorwanijk commented Sep 9, 2026 •

Copy link
Copy Markdown
Member

The package is deliberately not a root workspace: Promptfoo's dependency tree is large and only needed by people running evals, so it keeps its own lockfile and install step, and needs a newer Node than the repository (.nvmrc).

We should avoid this because such isolated islands can be a security nightmare, as tools like Dependabot and other security audits do not usually find such lockfiles.

Now that we have Node 24 in the repo, we could probably clean this up. Also, the workflows here still run on Node 22. We should update those as well. Also, we can switch to ./.github/setup-node instead of actions/setup-node

@manzoorwanijk

Copy link
Copy Markdown
Member

I have created #82665 to update it to use Node 24.

@jeryj

jeryj commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

We should avoid this because such isolated islands can be a security nightmare, as tools like Dependabot and other security audits do not usually find such lockfiles.

@manzoorwanijk I was on the fence about this originally. The big kicker was that the root npm version was behind. Now that that's cleared up, very happy to go with it being a root workspace.

Comment on lines +186 to +188
- name: Audit AI development test dependencies
if: matrix.os == 'ubuntu-24.04' && matrix.node == '22'
run: npm --prefix test/ai-development audit --audit-level=high

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This audit seems excessive, as the results vary depending on what is in the npm advisory DB when the CI runs, and it impacts every PR. See #83170

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

Labels

[Type] Automated Testing Testing infrastructure changes impacting the execution of end-to-end (E2E) and/or unit tests.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants