Skip to content

Stage Release - #4338

Open
github-actions[bot] wants to merge 9 commits into
stagefrom
dev
Open

github-actions[bot] wants to merge 9 commits into
stagefrom
dev

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Created by Github action

finnar-bin and others added 9 commits September 17, 2026 04:06
## Summary
- Cherry-pick of `5d7d7d621` from `hotfix/lock-instance-scope` onto
`dev`.
- Entity locks were keyed only by item ZUID, so a duplicated instance
could collide with locks held by the source instance on carried-over
ZUIDs.
- Adds `instanceZUID` to the `door/knock`, `door/unlock`, and
`door/lock` payloads to match the corresponding redis-gateway service
change.

## Test plan
- [ ] Verify locking/unlocking a content item still works as expected on
a single instance.
- [ ] Verify a duplicated instance no longer inherits a lock held by the
source instance on a shared/carried-over ZUID.

## Dependency
- https://github.com/zesty-io/redis-gateway/pull/10

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: shrunyan <shrunyan@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
…rs endpoint (#4313)

Fixes #4298

## Summary
- The "Open auto-fix PR" step in
`.github/workflows/claude-sentry-handler.yml` used to pre-check each
candidate reviewer (`agalin920`, `geodem127`, `finnar-bin`) via `gh api
repos/{owner}/{repo}/collaborators/{username}` before calling `gh pr
create --reviewer`.
- That endpoint can't see access granted via org team membership under
the default `GITHUB_TOKEN`, so it 404'd for all three despite them
having real write access through team membership — the pre-check treated
them as having no access and silently skipped every reviewer request on
every auto-fix PR.
- Fix: create the PR first without `--reviewer`, then request each
candidate individually by POSTing directly to
`repos/{owner}/{repo}/pulls/{n}/requested_reviewers`.
- **Not** `gh pr edit --add-reviewer`: confirmed live against this PR
that its GraphQL query pulls the deprecated Projects (classic)
`projectCards` field, which errors out on *every* invocation in this
repo regardless of the reviewer's validity — using it would have warned
on every single reviewer, every time, masking valid ones just like the
original bug.
- The REST endpoint has its own quirk: it returns HTTP 200 and silently
drops an unknown/nonexistent login instead of erroring, so exit code
alone can't detect a bad login.
- The warning now surfaces the actual reason instead of a generic
message: GitHub's `.message` for a real access error (e.g. "not a
collaborator"), or an explicit note when the login was silently dropped
from a 200 response with no reviewer added.
- Verified against three real response shapes by testing live against
this PR (cleaning up each test review request immediately after):
- valid login, has access → added, appears in `requested_reviewers`, no
warning
- nonexistent login → HTTP 200, silently absent from
`requested_reviewers` → warning: "the login may not exist"
- real user, not a collaborator → HTTP 422 with a message → warning
includes that message verbatim
  
All three are handled correctly, and `set -euo pipefail` does not abort
the step on either failure case (the failing command sits inside
`resp=$(...) || true`, so it isn't part of any `&&`/pipeline chain that
`-e` would catch).
- Single file changed: `.github/workflows/claude-sentry-handler.yml`.

## Test plan
- [x] Validated YAML syntax locally: `python3 -c "import yaml;
yaml.safe_load(open('.github/workflows/claude-sentry-handler.yml'))"`
- [x] Live-tested the REST reviewer-request call against this PR itself
(#4313) for all three outcome shapes (real access, nonexistent login,
real user without access), then removed the test review requests
immediately after
- [x] Confirmed `gh pr edit --add-reviewer` (and `gh pr edit` in
general) fails unconditionally in this repo due to an unrelated Projects
(classic) deprecation, which is why the fix avoids it entirely
- [ ] Full end-to-end verification still requires a real `sentry-rca`
workflow run that produces a `simple` verdict (per the issue's
acceptance criteria), since org team-membership resolution under the
Actions `GITHUB_TOKEN` can only be exercised from within Actions

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
#4301)

Closes #3895

`monaco-editor` 0.25.2's `JSONWorker.getFoldingRanges` passes the result
of `_getTextDocument(uri)` straight into the JSON language service
without checking it. When a folding request has been posted to the
worker and the model is disposed before the worker answers — closing the
`JsonViewer` dialog, or switching files in the Code app, both of which
dispose the model — that lookup returns `null`, the language service
calls `document.getText()`, and the rejection reaches Sentry through
`onUnexpectedError`. That is the reported frame. Upstream added `if
(!document) { return []; }` to the method in **0.31.0**; 0.30.1 is the
last unguarded release. This bumps `monaco-editor` to ^0.31.1, which
carries the same guard for the CSS worker's `getFoldingRanges` and
`findDocumentHighlights` (the sibling crash in the closed #3909), and it
is the substance of #4254. `monaco-editor-webpack-plugin` moves 4.2.0 →
7.1.1 because 4.x peers only 0.25–0.28; `react-monaco-editor` stays at
0.47.0, and its peer on `monaco-editor@^0.31.1` — which `npm ls`
currently reports as unsatisfied — becomes satisfied. No application
code changes: none of the twelve monaco symbols used in `src/` is in the
0.25→0.31 breaking set, and the three feature names in the webpack
allowlist that 0.31.1 no longer knows (`colorDetector`,
`goToDefinitionCommands`, `goToDefinitionMouse`) are already dead
against the 4.2.0 table today, so nothing changes there either. The
guard is present in the emitted artifact, not just in `node_modules` —
`build/json.worker.js:19456`. The whole dependency delta is these two
packages; no transitive version moves across the other 1,528. The dev
bundle gets **smaller**: 75.1 MB → 69.9 MB (−5.1 MB, −6.9%), mostly
`ts.worker.js` and `vendors.js`.

No `reviewer` cold pass ran on this diff — this session's harness ruled
out subagents, so the review gate in `docs/definition-of-done.md` §5 was
not met and the diff has been read only by the context that wrote it.

<!-- zesty-eng-team -->

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Names the five Claude workflows for what they do, and makes the Actions
list and the PR check list read the same way.

| file | workflow name | check name |
|---|---|---|
| `claude-auto-reviewer.yml` | `Claude: Code Review` | Claude Code
Review |
| `claude-change-verifier.yml` | `Claude: Acceptance Criteria QA` |
Claude Acceptance Criteria QA |
| `claude-issue-critique.yml` | `Claude: Issue Triage` | Claude
Duplicate Issue Check / Claude Issue Triage |
| `claude-negative-qa.yml` | `Claude: Adversarial Browser QA` | Claude
Adversarial Browser QA (advisory) |
| `claude-sentry-handler.yml` | `Claude: Sentry Triage & Auto-Fix` |
Claude Sentry Triage & Auto-Fix |

Two names were wrong against behaviour, not just inconsistent:

- **Sentry.** "RCA" names only the `complex` branch. #4231 specifies two
processes, and the workflow implements both: `:509` posts an RCA-only
comment on `verdict == complex`, `:526` opens an auto-fix PR against
`dev` on `verdict == simple`.
- **Negative QA.** The prompt is entirely attack sequences —
delete-while-referenced, double-submit, navigate-mid-save — with a
two-reproductions rule. "Browser QA" named the mechanism and dropped the
intent.

Three prompts also referenced a workflow called `"QA Review"`, which has
never existed under that name; they now name the real sibling workflows.
The comment headings each workflow posts are aligned to the same names
(`## QA Review` → `## Acceptance Criteria QA`, `## Negative QA` → `##
Adversarial Browser QA`).

### Scope

No trigger, permission, secret, model, or step-logic change. Job **ids**
are untouched, so `needs:`, `workflow_dispatch`, and `gh workflow run
claude-negative-qa.yml` all keep working. The HTML markers (`<!--
cv-verifier -->`, `<!-- negative-qa -->`, `<!-- claude-code-review -->`)
are untouched, so comment upsert and every downstream grep still match.

### Verification

- All five parse under `YAML.load`; `prettier --check` clean.
- Adding a job `name:` changes the check-run names on PRs. Ruleset
`16667349` (dev) requires only `all_tests_passed`, so no required check
is affected.
- Not reviewed by the `reviewer` subagent — subagents were unavailable
this session.

<!-- zesty-eng-team -->
…ll contentWindow (#4316)

Resolves #4289

**Severity:** low

## Summary
- MANAGER-UI-3E5: `PreviewMode.js` crashed with `TypeError: Cannot read
properties of null (reading 'postMessage')` when `route()` ran against
an iframe whose `contentWindow` was already null (the ref still pointed
at a detached iframe node), tripping the app's error boundary.
- The fix extends the existing early-return guard in `route()` to also
check `preview.current.contentWindow`, not just `preview.current`,
before calling `postMessage`.

## Classification
- **Root-cause certainty: PASS**. The crash is fully explained by
`preview.current` being truthy while `preview.current.contentWindow` is
null (iframe detached from the DOM), and the existing guard only checked
the former.
- **Blast radius: PASS**. The change is confined to
`src/apps/content-editor/src/app/components/Editor/PreviewMode/PreviewMode.js`,
none of it touches auth, permissions, IndexedDB hydration, RTK Query
base config, webpack config, or workflow files.
- **Verifiable by inspection: PASS**. It's a one-line null-guard
widening (`!preview.current` → `!preview.current?.contentWindow`) that
is a strict improvement in every case, not just the reported one.
- **Cohesion, not count: PASS**. Single file, single guard clause, one
conceptual change.

## Test plan
- [ ] Open the content/block editor preview, then rapidly navigate away
or unmount the editor while a route update is pending, and confirm no
`postMessage` TypeError is thrown and the error boundary doesn't
trigger.

<!-- sentry-rca:33479827307 -->

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Nar Cuenca <narc.ph@gmail.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
## Problem

The `QA Review` verdict is not reproducible. The same PR can report
`PASS` on 4 of 5 criteria on one run and `INCONCLUSIVE` on 3 of 4 on the
next. No linked issue — raised directly by @agalin920.

Three causes, stacked:

1. **The denominator is model-generated.** The prompt asked the agent to
*derive* the criteria list every run with no rule on granularity, so the
same issue yielded 5 criteria one run and 4 the next.
2. **The aggregation rule was ambiguous, and the model applied it.**
"INCONCLUSIVE if nothing is clearly failing but you couldn't confirm"
says nothing about a *mix* — 4 ✅ + 1 ⚠️ is both "nothing failing" and
"couldn't confirm one thing". Bash only grepped the marker the agent had
already written.
3. **The scale offered "I can't judge this" as an outcome.** The agent
was asked to grade criteria it had no way to check, so it manufactured a
mark and the verdict had to absorb it. The ✅/⚠️ boundary — the one that
actually moves — had no tie-break at all.

## Evidence

Pulled the `<!-- cv-verifier -->` comment from the last 12 PRs; nine
have one. **Eight of the nine carry at least one ⚠️** (only #4294 is
clean), and the ⚠️ lines are two unrelated things sharing a mark:

| kind | examples |
|---|---|
| Needs a running app — permanent, not a PR property | #4301.3, #4297.3,
#4296.4, #4293.3, #4290.3 |
| Plainly visible in the diff, softened to ⚠️ by the tie-break | #4295.7
(`data-cy` absent from both Title `TextField`s), #4286.3 (CLAUDE.md left
stale) |
| Genuinely uncertain | #4291.1 |

## Change

`.github/workflows/claude-change-verifier.yml` only.

- **Partition before grading.** The agent splits criteria into
*checkable from the code* and *needs a running app*, then grades only
the first group as ✅ or ❌. No third mark, so the boundary that was
drifting no longer exists.
- **Runtime criteria are listed, unscored,** in a collapsed block.
Dropping them silently would let `2 of 2 confirmed` read as full
coverage when an AC was never looked at. They have no downstream owner —
`claude-negative-qa.yml` explicitly bars AC judgment — so they are the
reviewer's manual checklist.
- **The verdict is computed in the post step** from the marks: any ❌ →
FAIL, otherwise PASS, with the counts in the heading (`✅ PASS — 2/2
code-checkable criteria confirmed, 1 needs a running app`). The agent no
longer writes a verdict; any marker it writes anyway is stripped.
- **INCONCLUSIVE is removed.** It described this workflow's permanent
condition — it never boots the app — not a per-PR result.
- **Criteria are pinned across pushes.** A new `Fetch prior QA comment`
step reads the existing comment; the prompt reuses its list verbatim, so
a `synchronize` push re-judges a fixed list instead of inventing a new
one.

## Merged `dev` 2026-09-18

#4307 renamed this workflow and its report heading while this branch
rewrote the same template, so the two conflicted. Resolved as **#4307's
names over this branch's logic**: the heading is `## Acceptance Criteria
QA`, still bare because the post step completes it. The parser in `Post
or update QA comment` was renamed to match — it keys on the heading it
writes, and git had no reason to flag that coupling. Six fixtures re-run
against the post step extracted verbatim from the merged YAML; all five
Claude workflows parse; prettier clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

<!-- zesty-eng-team -->

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…4308)

Refs #4287. Covers the sweep everywhere it can be made without changing
a rendered value the design system does not already own; what is left is
listed at the bottom and the issue stays open.

Four commits, deliberately separable.

**`c48906bd4` — 26 literals, rendered-identical.** 15 sites at
`14px`/`20px` become `body2`, the two GlobalSearch `ListSubheader`s
become `body3`, and 9 `fontSize: "16px"` declarations on widget
`CardHeader` roots are deleted rather than converted — those roots have
zero direct text nodes, so the declaration renders nothing. Verified as
a `getComputedStyle` before/after diff over the 112 text-bearing
elements of the content-item widget rail: **zero differences** in
font-size, line-height, letter-spacing, weight, display or box size.
`body3` carries `display: inline-block`, which would collapse a sticky
full-width subheader, so `display` is pinned beside the variant.

**`8d19d7826` — the 10 `overline` headers, a deliberate rendered
change.** The item-editor widget headers hand-rolled `overline` and lost
its tracking; they were inheriting `letter-spacing: -0.56px` from
`CardHeader`'s default `h5` variant, not `normal` as the issue assumes.
Adopting the variant moves all ten to `letter-spacing: 1px` — measured,
and it is the only property that changes: font-size stays 12px,
line-height 32px, weight 400, colour `rgb(16,24,40)`, and **every box
stays 287×32**, so nothing reflows or wraps. Eight headers also pick up
`text-transform: uppercase` from the variant with no visible effect,
their titles already being literal uppercase strings.

**`a4694603e` + `7316ff5a8` — the last two exact matches, closing AC 1
at 19 of 19** (`7316ff5a8` is a two-line comment reword, no behaviour).
`CompareDialog.tsx` and `PropertiesDialog.tsx` set `12px`/`18px` through
`secondaryTypographyProps`; they are two of the issue's own four `12/18`
→ `body3` sites and were the reason this PR read 17 of 19. They now take
`variant: "body3"` with `sx: { display: "block" }` pinned beside it —
same token as the GlobalSearch pair, different mechanism: there the
target is a `ListSubheader` so it takes the `typography:` shorthand,
here the target *is* the Typography slot so `variant` is the right tool.
**Two things change, not one.** `letter-spacing` goes `normal` →
`0.15px` (unlike the GlobalSearch pair, these carried no tracking), and
the rendered element goes `<p>` → `<span>` with the class
`MuiTypography-body2` → `MuiTypography-body3`: `ListItemText` renders
its secondary slot with no `component` (`ListItemText.js:145-151`), and
MUI's `defaultVariantMapping` has no `body3` entry, so `Typography`
falls through to `span`. Nothing in `src/` or `cypress/` keys on the old
tag or class. The `display` pin is for determinism, not to stop a
collapse — MUI already ships `display: block` on
`.MuiListItemText-secondary` (`ListItemText.js:57-59`), but inside
`:where()`, which contributes zero specificity, so both that rule and
`body3`'s `inline-block` are 0-1-0 and emotion insertion order would
otherwise decide. **Measured, contrary to what an earlier version of
this description said.** GA property `zesty.pw` *is* connected on the
Cypress dev instance and both dialogs open, so a before/after
`getComputedStyle` diff against `origin/dev` was possible after all:
`tagName` `P` → `SPAN`, class `MuiTypography-body2` → `body3`,
`letter-spacing` `normal` → `0.15px`. Everything else holds — font-size
12px, line-height 18px, weight 400, colour `rgb(71,84,103)`, `display:
block`, and the boxes at **706×18** (PropertiesDialog) and **684×36**
(CompareDialog) are identical on both sides. The compare item already
wraps to two lines at 36px before the change, so the added tracking did
not create a third; that was the one real risk and it did not
materialise.

Raw `fontSize` literals in `src/` go **63 → 25 across 22 files**.

**AC 3 is satisfied on the issue, not here.** The `overline` ruling, its
measured before/after table, the post-sweep count and the disposition of
every remaining occurrence are recorded at [#4287
(comment)](#4287 (comment)),
which is where that criterion asks for them.

**What the 25 remaining occurrences are, and why none of them are in
this PR.** 16 are MUI icons or a `Skeleton` and are out of scope by the
issue's own Scope section — which also means its "`18px` ×5 — no variant
exists" and "`28/20/32` ×5 → `h3`/`h5`/`h2`" rows should not be actioned
at all; they would resize glyphs. 5 have no variant to adopt
(`10px`/`14px` ×2, and three `ListItem` sites measured at a rendered
`14/24`, which is neither `body2` 14/20 nor `subtitle2` 14/22) and go to
design under `docs/design-system.md` §4. 4 sit on surfaces I could not
reach to measure — two empty states, a `FileCard`, and a `Link` in the
code editor's bottom drawer.

Typecheck 0 errors / 0 in `src/`, unchanged from the branch point. `npm
run build:dev` exits 0. `cypress/e2e/content/actions.spec.js` 17/17 and
`cypress/e2e/search/search-bar.spec.js` 4/4 on `8d19d7826`. On
`7316ff5a8`, the two specs that actually drive these dialogs:
`cypress/e2e/content/analyticsDashboard.spec.js` **5/5** and
`cypress/e2e/content/singlePageAnalytics.spec.js` **7/7**, the latter
re-run as a control and **7/7** again.

No `reviewer` pass ran on `c48906bd4` or `8d19d7826` — the session
instruction at the time ruled out subagents, so those two commits were
reviewed only by their author. `a4694603e` did get an independent
adversarial review, and it caught a false claim in an earlier version of
this description: it said no spec reached these two dialogs, and two do.
Corrected above, and the specs were run.

<!-- zesty-eng-team -->

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Removed rounded borders on the top right and top left of the global
search dropdown
Resolves #3470

## Preview
<img width="531" height="181" alt="image"
src="https://github.com/user-attachments/assets/0ba32633-31dc-44ae-bda2-c6f36ad0cbec"
/>

Co-authored-by: Stuart Runyan <shrunyan@gmail.com>
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.

3 participants