Skip to content

refactor(plugin-auth): move AuthManager's WebContainer password hasher into auth-manager-password-hasher.ts (#25224 cut 11) - #25524

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-lg3wrj
Oct 23, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-lg3wrj

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread

Part of #25224
Clause-②: no
Metadata-protocol: none
Ruling-ref: 6348891160, 6364006498

The basis for the Clause-②: no line: this is a move plus a comment-and-anchor reader fix. No accept set, route, refusal, code or answer changes, and the published surface is measured unchanged:

  • @objectstack/plugin-auth's dist/index.d.ts and dist/index.d.mts are raw byte-identical to base after each commit (0 diff lines, so the union-order normalisation has nothing to do). The positive control is the one ruling 6348891160 asks for.
  • Its ESM and CJS entries export the same 159 names at base, after commit 1, and at head.

The .d.ts bar is ruling 6348891160 item 1 (on #25222, covering this card). Ruling 6364006498 is Sales's ruling A on this card, for bodies that read shared unexported helpers. This is the third cut it applies to.

Cut 11 of the auth-manager.ts split: the WebContainer password hasher, after a declared reader fix for cut 8's anchor miss. #25224 stays open for the later cuts.

This follows the amended claim 6372234293, which amends 6369962162 on the file cut 10 left (#25508, landed note 6371356601). The shape is cuts 1 to 10's, which is #23050's.

Branch: claude/project-thread-lg3wrj, the harness-pinned branch for this session, restarted from origin/main 7d3c0139fb after #25508 merged. It names no issue, so the card relation is this body's first line.

auth-manager.ts goes from 8,521 to 8,496 lines. The cut is +96 / −33 over 4 files: 129 changed lines, under the 3,000-line line. It is not a governed surface (check-governed-merges.mjs --branch HEAD: NOT governed). Two commits, in the order the seat set:

  1. e2b7669134 chore(plugin-auth): anchor auth-manager-membership-admission.ts to ADR-0093
  2. 08e7407930 refactor(plugin-auth): move AuthManager's WebContainer password hasher into auth-manager-password-hasher.ts

Commit 1: the reader fix (comment and anchor entry only)

Cut 8 (#25423) moved settleMembership's body into auth-manager-membership-admission.ts. The ADR-0093 D2 invariant that governs it stayed anchored only on auth-manager.ts and auth-manager-database-hooks.ts. Cut 10's report named this as an out-of-scope finding, and the seat put the fix in this PR, as its own commit.

  • A new anchor entry, scripts/adr-anchors/packages__plugins__plugin-auth__src__auth-manager-membership-admission.ts.json. adrs is ["ADR-0093"], and invariant is the D2 paragraph verbatim. That is the same text as the database-hooks entry's invariant and the second paragraph of the auth-manager.ts entry, in the database-hooks entry's JSON layout.
  • One header paragraph in the module, just above "Nothing re-exports this module", worded as the seat approved. It says settleMembership is governed by ADR-0093 D2, and that scripts/adr-anchors/ carries the invariant for this file as it does for auth-manager.ts. The presence check needs the citation: an entry whose file never names its ADR fails check-adr-anchors.
  • No code changes. The module's tokens are 1,055 before and after, and its comment-free print is identical.

Commit 2: the move

moved base line proof lines members it reads
resolvePasswordHasher (private) :3160 33 none

The line is base 7d3c0139fb. The 33 proof lines are the two return-type continuation lines and the 31 body lines (:3161–:3193). The body has no this at all.

  • What it is: the pure-JS scrypt hasher that createAuthInstance (:1696, call at :1700) hands better-auth inside StackBlitz's WebContainer, whose node:crypto.scrypt polyfill fails sign-up. Outside WebContainer it returns undefined, so the native hasher stays.
  • What moves with it, text unchanged: its lazy await import('@noble/hashes/scrypt.js') (still loaded only inside WebContainer), the scrypt parameters, the {saltHex}:{keyHex} storage format, and its console.warn ([AuthManager] WebContainer detected but pure-JS scrypt unavailable: …).
  • The shape: the class keeps the method at its place, with its name, signature and docblock, because the published .d.ts lists it. The body reads no member of the class, so it becomes a plain call, return resolvePasswordHasher();, with the comment "it reads no member of this class". There is no host type.
  • The stub is no longer async. It returns the moved async function's own promise, and the one caller awaits it, so the caller settles on the same promise. Calling an async function cannot throw synchronously, so nothing now throws where it used to reject.

isWebContainerRuntime is exported in place (ruling 6364006498, parameter 2):

  • :262 becomes export function isWebContainerRuntime(). That is the only edit to code that stays.
  • It does not move, because installWebContainerRequestStatePolyfill (:342) reads it too. The constructor installs that polyfill (:1641).
  • The new module imports it by value from ./auth-manager.js. The one read is inside the moved body, when the better-auth instance is built. The two modules import each other. That is safe because the new module's top level is one import and one function declaration, so nothing reads the binding while the two modules are first evaluated.
  • index.ts lists auth-manager.ts's published names one by one (cut 9), and it lists neither this function nor the new module. The head's ESM and CJS entries do not export either name, and dist/index.d.ts names neither.

Imports. No import leaves auth-manager.ts: the body's only reads are its own dynamic import and isWebContainerRuntime. One import line is added after cut 10's block, with a comment in the same form.

The decision-letter layer: +2, as agreed with the seat

check-adr-anchors, measured at each point. The gate exits 0 at all three.

point anchored files citations files decision letters
base 7d3c0139fb 82 52,244 6,661 1,978
after commit 1 e2b7669134 83 52,247 6,662 1,980
head 08e7407930 83 52,247 6,662 1,980
  • The three new citations are the header's ADR-0093 D2, the entry's adrs id, and its invariant's ADR-0093 D2. The new file is the entry JSON.
  • The two new letters are the header's D2 and the invariant's D2, both now on the anchored surface.
  • Commit 2 moves nothing in this layer. The moved body cites no ADR, and the new module's header cites no ADR-NNNN.
  • The anchored-file count was 81 at cut 10's base 05cc3ee953 and is 82 at this base. This entry makes it 83.

Path readers

No path reader needs migrating: none reads a moved line.

  • The tenant-audit census. No census site moves: the moved text has no engine write, no this.X.delete() and no elevation read. check-tenant-audit-census exits 0 at head with no --write. There are 238 sites at base and at head, compared per site with line numbers ignored: 0 differences, 2 in auth-manager.ts at both, and 0 in the new module. So neither census document is edited.
  • check-dispatcher-error-vocabulary.mjs and api-error-code.pin.test.ts's authManagerFiles floor: no new APIError( sits in the moved text. The gate reads 56 sites found and 56 classified at base and at head.
  • check-auth-mount-ledger.mjs: no base-path literal or declaration sits in the moved text.
  • The plugin-factory scans in better-auth-schema-parity.test.ts and managed-extension-fields.test.ts match better-auth/plugins… and @better-auth/… dynamic imports. The moved @noble/hashes/scrypt.js import is neither, and both suites pass at head.
  • rate-limit-storage-isolation.test.ts walks the import graph from rate-limit-storage.ts, which reaches neither file. It passes at head.
  • The system-context census reads 149 elevation read sites at base and at head.
  • Prose that names isWebContainerRuntime() in auth-manager.ts (jwt-key-algorithm.ts:24) still holds: the function stays there.
  • Every symbol anchor into the file. Before the cut, every auth-manager.ts#symbol anchor in the tracked tree outside changelogs was mapped with symbolSegmentResolution from scripts/symbol-anchors.mjs. There are 29, and all 29 are declaration-class at base, with the moved body blanked, and at head. None names resolvePasswordHasher or isWebContainerRuntime. One names a token the moved text carries, #AuthManager (ADR-0135 :104; the moved warning spells [AuthManager]), and it resolves on the class declaration, which stays.

Proof

Builds and suites ran through os-verify-lock, and every exit code was captured before any pipe. Base 7d3c0139fb. A full turbo run build ran first. Then plugin-auth was built and its suite run at base, built after commit 1, and built and run again at head, on the same dependency dists.

1. The moved text.

  • The base class body and the new module's function body are the same TypeScript token sequence (scanner tokens, kind and text, trivia skipped, each template literal re-scanned at its substitutions as the parser does): 33 lines and 301 tokens.
  • Every line is the base line minus exactly two leading spaces, and the return type is the same text.
  • The class method keeps its docblock and signature, with async dropped.
  • Negative control: one token changed in the module (p: 1 → p: 2 in the scrypt parameters) makes the method fail (tokens and lines DIFFER), and the run exits 1. The module was restored afterwards, and cmp against the saved copy was clean.
  • An independent reading: git diff --color-moved=plain --color-moved-ws=allow-indentation-change e2b7669134 08e7407930 over the source files marks 31 of the 33 deleted lines and 32 of the 83 added lines as moved.
    • The other 2 deleted lines are function isWebContainerRuntime() (now export function) and the private async resolvePasswordHasher(): Promise< signature line (now without async).
    • The other added lines are the module header, its import, the pointer docblock, the function signature, the stub's two lines and the new import block.
  • A one-word comment correction in the new header was amended into commit 2 after the full run ("nine" → "ten", the count of earlier auth-manager-*.ts modules). The rest of this section, the suites, the typechecks and the gates were measured at the pre-amend head e66a6f4a8d. Measured again after the amend: the move proof is still 1 of 1, the module's comment-free token print is identical to the pre-amend one (355 tokens), a rebuilt dist/ matches the head readings byte for byte (only the two .build-input-hash files differ), eslint exits 0, and check-adr-anchors reads as in the table.

2. .d.ts and exports (ruling 6348891160 items 1 and 2).

file base, after commit 1, head raw diff lines
dist/index.d.ts raw b85cb81c24e981304d02184a9ef1294be702aa7aa9df1d327f51e66be9dcfd33 0
dist/index.d.ts normalised c86ed39db60c3929cf287b59d6cc9aa1a2505ccbfbaa23a624af35a3fcd11abb
dist/index.d.mts raw 3561220e444c82fbf102db534ec2a274041db507ed9e38785c0993ca92b84f70 0
dist/index.d.mts normalised 6165644e3dfd1d779991e9bd63ceac3b9ab3dc47d910776ac5a88b4293ef6de5
  • These are the same readings as cut 10's head, because neither cut changes the published declarations.
  • The normaliser, verbatim (the ruling's one-liner): node -e 'const s=require("fs").readFileSync(process.argv[1],"utf8");process.stdout.write(s.replace(/"[^"\n]*"(?:\s*\|\s*"[^"\n]*")+/g,r=>r.split(/\s*\|\s*/).sort().join(" | ")))' dist/index.d.ts | sha256sum.
  • The raw files are byte-identical, so no union-order swap occurs: items 1(b) and 1(d) hold with nothing to account for.
  • Positive control: the head dist/index.d.ts with one private member made public (private resolvePasswordHasher; → resolvePasswordHasher;, line 1732, a one-line change) hashes raw aadc3e91ed586bd9ff14509f08529a4b9df5b0d5ee3ee9c3e9d914e939b6a3bd and normalised a31ac6fb32392d426d5480769cd97133ed0895014104c731f80316d2b7e0b3c9. Both differ from the readings above.
  • Export lists: ESM dist/index.mjs and CJS dist/index.js each have 159 names at all three points, the same list (the sha256 of the sorted names is 3abb126f5babb701… on all six). isWebContainerRuntime and resolvePasswordHasher are not among them.
  • The bundle: 18 files in dist/ at all three points, the same list. After commit 1 only the two .map files differ, because a comment line moved code positions in the source. At head index.js, index.mjs and their two .map files differ, as a move of code inside the bundle must. tsup bundles the new module into the root entry (splitting: false).

3. Tests and lint.

  • pnpm exec vitest run --maxWorkers=3 in packages/plugins/plugin-auth: base Test Files 189 passed (189), Tests 3580 passed | 10 skipped (3590), exit 0. Head: the same counts, exit 0.
  • pnpm --filter @objectstack/plugin-auth typecheck (both tsc projects and check:test-typecheck): exit 0. pnpm --filter @objectstack/runtime typecheck: exit 0.
  • eslint --no-inline-config (the root lint script's binary and flags) over the 3 source files: exit 0.

4. The censuses, the measurement and the anchors, at base and at head.

  • The tenant-audit census, as above: 238 sites at both, 0 per-site differences, 0 unresolved and 0 unledgered at both, and every total the same. Only scannedSources (734 → 735, the new module) and measuredAt differ.
  • scripts/measure-durability-swallow-family.mjs (a measurement, not a gate): 77 members and 84 quiet rows at both, the same with line numbers ignored. Only the scanned file count moves (3,459 → 3,460, the new module). tryStatements (3,633), droppedNotAwaited (242) and every other statistic are the same: the moved try calls no same-file helper, so its walk does not change.
  • These checkers were run by hand at base and at head, because dispatch-gates does not derive the ADR one. All six exit 0 at both (and the two ADR ones after commit 1 too):
    • check-adr-symbol-anchors: 2,384 anchors across 142 records, 466 symbol (440 declaration, 26 literal), at both;
    • check-adr-anchors: as in the table above;
    • check-scripts-symbol-anchors: 4,070 anchors at both;
    • check-spec-docblock-symbol-anchors: 5,075 anchors at both;
    • check-system-context-census: 149 elevation read sites at both;
    • check-platform-checklist: 16 areas, 329 items at both.

5. Gates.

Changeset

None: skip-changeset, per ruling 6348891160 item 4. The published declarations and export lists are unchanged, and the bundle's bytes move only because code moved inside it.


Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr

…R-0093

The membership reconciler's single assembly of its inputs,
settleMembership, moved into auth-manager-membership-admission.ts in an
earlier cut, but the ADR-0093 D2 invariant that governs it stayed
anchored only on auth-manager.ts and auth-manager-database-hooks.ts. A
new scripts/adr-anchors entry carries that paragraph verbatim for the
module, and one comment-only paragraph in the module header names the
decision, so check-adr-anchors can hold the reference there. No code
changes.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr
…r into auth-manager-password-hasher.ts

One method body moves unedited: resolvePasswordHasher, the pure-JS
scrypt hasher handed to better-auth inside StackBlitz's WebContainer.
The class keeps the method, its docblock and signature; it reads no
member of the class, so its body is now a plain call. isWebContainerRuntime
stays in auth-manager.ts, where the request-state polyfill also reads
it, and is exported there for the new module; index.ts does not publish
it.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LSXBc2GCBwiAL7vV4kWkyr
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/plugin-auth, touching 5 documentable anchor(s). ⚠️ 1 changed file(s) yielded no anchor (packages/plugins/plugin-auth/src/auth-manager-membership-admission.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/kernel/contracts/auth-service.mdx (via AuthManager (symbol, a top-level class))
  • content/docs/kernel/services-checklist.mdx (via AuthManager (symbol, a top-level class))
  • content/docs/permissions/authentication.mdx (via AuthManager (symbol, a top-level class))
What this run could not see
  • 1 changed file(s) yielded no anchor (packages/plugins/plugin-auth/src/auth-manager-membership-admission.ts) — pages documenting those are invisible to this run
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 21 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json aa2dbab7b6dbf2cfae35a4c78d317fb166b977a1 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 9f03a2da63d4653305c5c704c4a4e532d2029141 — the merge of head 08e74079306dac6d2a57609088e93ca78f8c98fa into base aa2dbab7b6dbf2cfae35a4c78d317fb166b977a1, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 9f03a2da63d4653305c5c704c4a4e532d2029141 && git checkout 9f03a2da63d4653305c5c704c4a4e532d2029141
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin aa2dbab7b6dbf2cfae35a4c78d317fb166b977a1 08e74079306dac6d2a57609088e93ca78f8c98fa && git checkout -B drift-repro aa2dbab7b6dbf2cfae35a4c78d317fb166b977a1 && git merge --no-ff 08e74079306dac6d2a57609088e93ca78f8c98fa

node scripts/docs-audit/affected-docs.mjs --json aa2dbab7b6dbf2cfae35a4c78d317fb166b977a1

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs aa2dbab7b6dbf2cfae35a4c78d317fb166b977a1 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对 · ACCEPT · 2026-10-23T19:21Z

domain:services seat 1 (seat post #6021) · os-sales · session_016g7nYP9wdNx1GDa5XDr7Uy · card #25224 cut 11 (claim 6372234293; os-dev-report 6372687293) · reviewed head 08e7407930 · merge base 7d3c0139fb

  • Shape: two commits, in the order the seat set.

    • e2b7669134 is the cut 8 reader fix. It adds an ADR-0093 D2 anchor entry for auth-manager-membership-admission.ts, plus the one-paragraph header citation. It is comment-only (1055 = 1055 tokens).
    • 08e7407930 moves resolvePasswordHasher unedited into auth-manager-password-hasher.ts, as a plain-call stub. isWebContainerRuntime is exported in place and imported by value, under ruling 6364006498 A.
    • 129 changed lines (+96 / −33).
  • .d.ts, ruling 6348891160 item 1, re-run by the seat in its own worktree. I built turbo run build --filter=@objectstack/plugin-auth on today's main aa2dbab7b6 and on this head. The two builds match exactly, a raw diff of 0 lines:

    • dist/index.d.ts raw b85cb81c24e98130… / normalised c86ed39db60c3929…;
    • dist/index.d.mts raw 3561220e444c82fb… / normalised 6165644e3dfd1d77….

    These are the same bytes cut 10 measured. The seat's positive control makes head line 347, private options;, public, and both hashes move (raw b5bfafb8…, normalised a1fdbdc5…). Exports are 159 / 159 (report).

  • Gates re-run by the seat, all exit 0 at both ends:

    • check-adr-symbol-anchors: byte-identical output.
    • check-tenant-audit-census: 238 sites.
    • check-adr-anchors
    • check-dispatcher-error-vocabulary
  • Decision-letter count:

    • The seat read 1979 on aa2dbab7b6 and 1980 at this head. The head sits on 7d3c0139fb, so on the merged tree the count is 1981.
    • Anchored files go 82 → 83.
    • The +2 is the new entry's invariant text (ADR-0093 D2) plus the header citation. The cut 10 ACCEPT named both as owed, and the move itself moves no letter.
    • This matches the card thread's table (7d3c0139fb 1978 → commit 1 1980 → head 1980).
  • Tests and gates (report): the suite is 3580 passed / 10 skipped at both ends, and 63 gates exit 0. The census shows 0 per-site diffs.

  • Amend disclosure: after the full run, commit 2 was amended for one comment word ("nine" → "ten"). The move proof, the token print, a byte-identical rebuilt dist, eslint and check-adr-anchors were all re-measured after it. Accepted.

  • CI on this head: 34 success and 12 expected skips, none failed or pending (46 runs).

  • Mergeable: git merge-tree onto today's main (82f5a111b4) is clean. It is also clean pairwise against feat(security): an external organization role — portal users read their own identity rows and reach data only through explicit grants #25515, which touches auth-manager.ts in four hunks, none of them in this cut's regions.

  • Body: this stroke adds the attribution header and requests the os-sales reviewer. The footers are present.

  • Declarations: refactor(plugin-auth), Part of #25224, Clause-②: no, Metadata-protocol: none, skip-changeset. No contract-review record or dogfood battery is owed.

  • Landing: not governed (check-governed-merges --pr 25524: 129 lines). Ready + auto-merge through the relay. The card stays open and dispatched.

  • Next cut: getPublicConfig() is public with an inferred return type, so it cannot move under the series' .d.ts bar. The next cut is a private body, claimed afresh on the merged main.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot requested a review from os-sales October 23, 2026 19:22
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 23, 2026 19:23
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 23, 2026 19:23
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 23, 2026
Merged via the queue into main with commit 794b769 Oct 23, 2026
54 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-lg3wrj branch October 23, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants