Skip to content

FE-1917: Upgrade Changesets to v3 to enable publishConfig - #9973

Open
claude[bot] wants to merge 13 commits into
mainfrom
claude/fe-1917-changesets-v3
Open

claude[bot] wants to merge 13 commits into
mainfrom
claude/fe-1917-changesets-v3

Conversation

@claude

@claude claude Bot commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Requested via Slack thread

🌟 Purpose

Changesets v2 publishes a Yarn workspace with npm publish. npm ignores Yarn's publishConfig field overrides (main, types, exports, bin) and cannot read workspace: ranges, so our packages cannot use publishConfig. Changesets v3 publishes with yarn npm publish when the repository uses Yarn, and Yarn applies both at pack time.

This PR moves to @changesets/cli 3.0.3, the current latest release (v3 has been stable since 3.0.0 on 2026-08-11; 2.31.1 is now on maintenance-v2), and makes the release workflows work with Yarn as the publisher.

🔍 Changes

Patches

  • @changesets/assemble-release-plan patch: removed. It stopped a minor bump from bumping peer dependents to a major. v3 depends on assemble-release-plan 7.0.0, which no longer has shouldBumpMajor and gives peer dependents a patch bump. Running changeset status --output against the 163 changesets pending on main: unpatched v2 plans @hashintel/petrinaut 0.0.19 → 1.0.0 (it peer-depends on @hashintel/ds-components, which gets a minor), while patched v2 and unpatched v3 both plan 0.0.20. The whole release plan is identical between patched v2 and v3.
  • @changesets/cli patch: regenerated for 3.0.3 as .yarn/patches/@changesets-cli-npm-3.0.3-37da92ed6c.patch (with yarn patch / yarn patch-commit), keeping one of its two hunks.
    • Publish concurrency 1: kept. v3 still hard-codes createPromiseQueue(10) for publishing (dist/getPublishPlan.mjs) and has no option for it, and packages still build in their prepack hook, so parallel publishes could again race on shared build output, the failure H-6772: Serialise npm publishing and verify package payloads at pack time #9244 fixed by serialising.
    • changeset status exiting 0 when packages changed without a changeset: removed. Nothing in the repository or .github runs changeset status, so v3's exit code 1 there affects nothing.

Publishing through Yarn

  • changesets/action moves from v1.8.0 to v2.1.2 (pinned SHA). v2 is the release for CLI v3: v1.8.0 finds published packages by matching New tag: in the CLI's output, which v3 no longer prints, so it would create no GitHub releases. v2 reads the CHANGESETS_OUTPUT file instead. Inputs are renamed (publish-script, version-script), the token moves to github-token, and commitMode: github-api is dropped because API pushes are now the default and v2 refuses the old input. GITHUB_TOKEN is no longer set on the step: v2 refuses a GITHUB_TOKEN that differs from github-token, and sets it itself for the version and publish scripts, which the changelog formatter reads. The step that recreates the Version Packages PR stays: v2 still resets changeset-release/main to main and force-writes it through the API.
  • The build before publishing moves out of prepublishOnly, which yarn npm publish never runs (nor postpublish), into a build:pack turbo task. Every published package's prepack is turbo run build:pack; the task depends on the package's build (on codegen for @hashintel/ds-helpers), runs the payload check as its own script, and is uncached so the check reads what is on disk at pack time. Yarn's lifecycle scripts page recommends prepack for building and prepublish only for side-effect-free checks. As a result, yarn pack and changeset pack build too. @hashintel/refractive used yarn build directly; it now builds through turbo like the rest, with byte-identical output.
  • The Block Protocol packages no longer edit their working tree to publish. Their prepublishOnly ran a scripts/prepublish.ts that deleted devDependencies from package.json (and, for @blockprotocol/type-system, replaced the @local/hash-codec Real import in src/generated with type Real = number and rebuilt), and their postpublish restored the package directory with git restore and git clean -fdx. Yarn never runs postpublish, so those edits would have stayed behind. Their main, types and exports already point at dist, so there was nothing for publishConfig to override:
    • @blockprotocol/type-system inlines Real while its Rollup build copies the generated declarations into dist, leaving src untouched.
    • devDependencies are no longer stripped. Yarn publishes them with resolved ranges, as the other five packages already do; consumers never install them.
    • @blockprotocol/graph lists dist in files instead of its .npmignore allow-list, which Yarn reads differently and which packed tsconfig*.json, turbo.json and eslint.config.js.
    • Both prepublish.ts scripts go, as do @local/repo-chores's shared prepublish.ts/postpublish.ts and their helpers (errors, git, package-infos, update-json, the fix-esm-import-path dependency). Besides the Block Protocol packages, only four private, changeset-ignored packages (block-design-system, design-system, query-editor, type-editor) hooked them, and private packages never publish, so their hooks are removed too.
  • scripts/resolve-workspace-ranges.mjs and the changeset:resolve-workspace-ranges script are removed: Yarn resolves workspace: ranges when packing. changeset:publish is now just changeset publish.
  • scripts/check-package-payload.mjs checks a publishConfig override in place of the top-level field, since that is what Yarn packs.
  • The hand-written ## Unreleased section in @hashintel/petrinaut's CHANGELOG (added in H-6763: Add a generic Petrinaut composer submission API #9355) is removed: it repeats the pending stable-composer-controls changeset, which writes the 0.0.20 entry.
  • The "Install npm with trusted publishing support" steps and NPM_CONFIG_LOGLEVEL are removed, and the release job's npm debug-log dump is replaced by Yarn's logs. Yarn writes each lifecycle script's output (prepack, postpack, prepublish) to <tmpdir>/xfs-*/<script>.log and keeps the file only when the script fails; changesets v3 prints the error, which names that path, under "Some packages failed to publish". On failure the job now prints /tmp/xfs-*/*.log and adds them to the release-debug-logs artifact. Checked locally by publishing a fixture whose prepublish writes to stdout and stderr and exits 3 (a prepack failure takes the same path): the CLI printed YN0036: Prepublish script failed (exit code 3, logs can be found here: …/xfs-a422bd7e/prepublish.log) and the file held both lines. Yarn 4.18.1 does the OIDC token exchange itself during yarn npm publish in GitHub Actions when no npmAuthToken is set (none is). Two Yarn settings are set on the publish steps to keep current behaviour: YARN_NPM_PUBLISH_PROVENANCE (npm generated provenance automatically, Yarn does not; current releases carry provenance) and YARN_NPM_PUBLISH_REGISTRY (Yarn otherwise publishes to registry.yarnpkg.com).
  • .changeset/config.json points $schema at @changesets/config@4.0.1. The existing options, including ___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH, are all in the v3 schema.

Checked locally

  • publishConfig end to end: a two-package Yarn 4.18.1 fixture published by the patched 3.0.3 CLI to a local Verdaccio registry. Package A has main/types/exports pointing at src and publishConfig overrides pointing at dist; package B depends on A with workspace:^. After changeset version and changeset publish (exit 0, two git tags, two CHANGESETS_OUTPUT events), the registry manifest for A has "main": "./dist/index.js", "types": "./dist/index.d.ts" and the dist exports map, the tarball's package.json matches, and B's published dependency is "@fixture/a": "^0.1.0". Marker files showed prepublish ran and prepublishOnly/postpublish did not. For comparison, v2.30.0's getPublishTool returns npm for anything but pnpm.
  • changeset version on this branch with the GitHub GraphQL call stubbed: v3 loads @local/repo-chores/changesets-changelog, writes the CHANGELOGs, detects oxfmt and formats them; oxfmt --check on the results passes.
  • changeset publish-plan against npm: No projects to publish or tag., so yarn npm info resolves all seven packages.
  • yarn pack with prepack building: in @hashintel/refractive (from an empty dist) the prepack runs yarn build, then the payload check, and the tarball matches 0.0.4 file for file. In @blockprotocol/graph and @blockprotocol/type-system, prepack ran turbo run build and then the payload check; turbo was restricted to the package's own build with --only (the type-system crate's wasm and types were built beforehand, as mise is not available here). Both tarballs match the ones verified before. Earlier, yarn npm publish --dry-run in refractive targeted https://registry.npmjs.org with the provenance setting picked up.
  • Packed manifests against the last published versions (yarn pack after building, compared with npm pack <pkg>@<version>): @blockprotocol/type-system and @blockprotocol/graph (built locally, including the type-system wasm) have identical main, types, exports, typesVersions, type, sideEffects, files, dependencies and peerDependencies, with @blockprotocol/type-system: workspace:^ published as ^0.2.2. The type-system tarball's dist/*/generated/types.d.ts has type Real = number; and nothing in dist mentions hash-codec; it also now ships dist/*/generated/*.d.ts, which the 0.2.2 tarball lacked. Graph's file list matches 0.5.0 plus CHANGELOG.md, which Yarn always includes. @hashintel/refractive matches 0.0.4 file for file. @hashintel/petrinaut and @hashintel/ds-components (manifest only, stub entry files) publish their @hashintel/* ranges exactly as 0.0.19 and 0.3.1 did. The working tree was clean after every pack.
  • changeset version with GraphQL stubbed, after the CHANGELOG fix: ## 0.0.20 sits directly under the Petrinaut title and the Voice mode text appears once.
  • yarn install --immutable (4.18.1), yarn constraints, yarn dedupe --strategy highest --check, yarn lint:format, yarn lint:license-in-workspaces, and lint:eslint/lint:tsc for @blockprotocol/graph, @blockprotocol/type-system and @local/repo-chores.

⚠️ Known issues

  • Trusted publishing and provenance through Yarn only run inside GitHub Actions, so the first canary or release run after merge is their real test.

🤖 Generated with Claude Code

https://claude.ai/code/session_01L4xQyzV5Mb61k3XbH9J8ZA

Changesets v3 publishes Yarn workspaces with `yarn npm publish`, which
applies `publishConfig` overrides and resolves `workspace:` ranges.

- Bump `@changesets/cli` to 3.0.3 and port the publish-concurrency and
  `changeset status` hunks of its patch to the v3 files.
- Drop the `@changesets/assemble-release-plan` patch: v3 bumps peer
  dependents by patch instead of major.
- Bump `changesets/action` to v2.1.2, which v3 requires, and move to its
  renamed inputs.
- Rename `prepublishOnly` to `prepublish`, the publish hook Yarn runs.
- Let Yarn perform the trusted-publishing exchange, with provenance and
  the npm registry set explicitly, instead of installing npm 11.
@claude claude Bot assigned indietyp Oct 8, 2026
@vercel

vercel Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

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

Project Deployment Actions Updated
hash Ready Ready Preview Oct 9, 2026 5:37pm UTC
hashdotdesign-tokens Ready Ready Preview Oct 9, 2026 5:37pm UTC
petrinaut Ready Ready Preview Oct 9, 2026 5:37pm UTC
petrinaut-docs Ready Ready Preview Oct 9, 2026 5:37pm UTC

Request Review

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team area/apps > hash.design Affects the `hash.design` design site (app) labels Oct 8, 2026
@codecov

codecov Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 0% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 66.58%. Comparing base (049a8c5) to head (be83bed).
⚠️ Report is 33 commits behind head on main.

Files with missing lines Patch % Lines
...ckprotocol/type-system/typescript/rollup.config.js 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9973      +/-   ##
==========================================
+ Coverage   66.53%   66.58%   +0.05%     
==========================================
  Files        1954     1965      +11     
  Lines      215400   216192     +792     
  Branches     8429     8469      +40     
==========================================
+ Hits       143313   143951     +638     
- Misses      70484    70625     +141     
- Partials     1603     1616      +13     
Flag Coverage Δ
apps.hash-ai-worker-ts 2.04% <ø> (ø)
apps.hash-api 15.35% <ø> (ø)
blockprotocol.type-system 41.37% <0.00%> (ø)
durable-kernel 86.65% <ø> (ø)
error-stack 90.55% <ø> (ø)
harpc-codec 84.61% <ø> (ø)
harpc-net 96.30% <ø> (+0.04%) ⬆️
harpc-tower 67.11% <ø> (ø)
harpc-types 0.00% <ø> (ø)
harpc-wire-protocol 93.85% <ø> (ø)
hash-codec 72.09% <ø> (ø)
hash-config 83.57% <ø> (ø)
hash-graph 14.11% <ø> (ø)
hash-graph-api 36.80% <ø> (ø)
hash-graph-atlas 80.00% <ø> (+<0.01%) ⬆️
hash-graph-authentication 97.63% <ø> (ø)
hash-graph-authorization 68.47% <ø> (ø)
hash-graph-embeddings 91.54% <ø> (ø)
hash-graph-postgres-store 31.96% <ø> (-0.01%) ⬇️
hash-graph-store 51.60% <ø> (ø)
hash-graph-temporal-versioning 50.53% <ø> (ø)
hash-graph-types 0.00% <ø> (ø)
hash-graph-validation 85.37% <ø> (ø)
hash-integrations-definition 89.38% <ø> (?)
hash-middleware 89.60% <ø> (ø)
hashql-ast 90.01% <ø> (ø)
hashql-compiletest 28.71% <ø> (ø)
hashql-core 81.41% <ø> (ø)
hashql-diagnostics 72.85% <ø> (ø)
hashql-eval 79.77% <ø> (ø)
hashql-hir 89.10% <ø> (ø)
hashql-mir 87.22% <ø> (ø)
hashql-syntax-jexpr 94.77% <ø> (ø)
local.claude-hooks 0.00% <ø> (ø)
local.harpc-client 51.49% <ø> (ø)
local.hash-backend-utils 3.27% <ø> (ø)
local.hash-graph-sdk 10.02% <ø> (ø)
local.hash-isomorphic-utils 12.22% <ø> (ø)
problematic 90.09% <ø> (ø)
railroad-plugin 45.28% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Nothing in the repository calls `changeset status`, so its exit code no
longer matters. The publish-concurrency hunk stays.
@codspeed

codspeed Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

⚠️ 6 benchmarks measured no execution time

Nothing ran under measurement, usually because the compiler removed the code under test. These results are not comparable, so they count as unchanged.

Preventing compiler optimizations

✅ 98 untouched benchmarks


Comparing claude/fe-1917-changesets-v3 (be83bed) with main (51755b6)

Open in CodSpeed

claude added 5 commits October 8, 2026 23:57
`yarn npm publish` never runs `postpublish`, so the Block Protocol
packages' `prepublish` edits to `package.json` and generated sources
stayed in the working tree. Their entry fields already point at `dist`,
so nothing needs rewriting: inline `Real` into the copied declarations
during the type-system build, and stop stripping `devDependencies`,
which Yarn now publishes with resolved ranges like the other packages.

The shared rewrite and restore scripts in `@local/repo-chores` only
served these packages and four private ones that never publish, so
remove them with their helpers and the hooks that called them.
Yarn resolves `workspace:` ranges when it packs a package.
Yarn packs a `publishConfig` override in place of the top-level field.
It repeats the pending `stable-composer-controls` changeset, which
writes the entry on the next release.
Publishing no longer runs npm, so it writes no npm debug logs.
claude added 2 commits October 9, 2026 00:03
Yarn reads its `.npmignore` allow-list differently from npm and packed
the package's config files alongside `dist`.
@github-actions github-actions Bot added the type/eng > backend Owned by the @backend team label Oct 9, 2026
indietyp
indietyp previously approved these changes Oct 9, 2026
@alex-e-leon

Copy link
Copy Markdown
Contributor

I'm not super familiar with the publishing steps of all the projects this touches, so @CiaranMn should probably take a look at this - but one thing that's jumped out is that prepublish is deprecated, so not sure why this PR is switching everything from prepublishOnly back to prepublish

@claude

claude Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@alex-e-leon prepublish is only deprecated in npm, where it also ran on npm install. With Changesets v3, Yarn does the publishing (yarn npm publish), and Yarn handles these hooks differently:

  • Yarn 4 never runs prepublishOnly. Its CLI source has no reference to that name, so the builds in those hooks would silently stop running.
  • Yarn runs prepublish only before yarn npm publish and never on install (lifecycle scripts). That's why I switched to it.

That page also says not to build in prepublish and to use prepack instead. All six packages already have a prepack (the payload check), so the alternative is to put the build in front of it, e.g. "prepack": "turbo run build && node …/check-package-payload.mjs", as @hashintel/ds-helpers already does with codegen. The only change in behaviour is that yarn pack and changeset pack would then build too. I'm happy to switch to that if the team prefers it.


Generated by Claude Code

@indietyp

indietyp commented Oct 9, 2026

Copy link
Copy Markdown
Member

I'm happy to switch to that if the team prefers it.

Yes do that. And thanks for the flag on the prepublish, I thought only prepublishOnly was dead.

Yarn recommends `prepack` for building a package and `prepublish` only
for side-effect-free checks, so run each build ahead of the payload
check there. `yarn pack` and `changeset pack` now build as well.
@claude

claude Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@indietyp Done in 0efa9be. Each package now builds in prepack, ahead of the payload check. This also means yarn pack and changeset pack build now.


Generated by Claude Code

@alex-e-leon

Copy link
Copy Markdown
Contributor

Yes do that. And thanks for the flag on the prepublish, I thought only prepublishOnly was dead.

Yes, although as claude flagged, it looks like this is not the case for yarn (whose lifecycle steps I'm less familiar with), and it looks like the changesets upgrade has switched the publish steps from npm back to yarn, so it could be fine to use prepublish now.

If there's anyone more familiar with our publish workflows across all the packages would be good to get their eyes on this, and might also be a good idea to get claude to mock a publish to double check that there aren't any issues, as a small misconfiguration might cause issues here, and we've had problems with publishing in the past (ds-components wasn't publishing a valid package for over 6 months)

Yarn matches an unanchored `files` entry at any depth, so `README.md`
also packed every nested `README.md` under `src`, `docs` and
`benchmarks`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4xQyzV5Mb61k3XbH9J8ZA
@claude

claude Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

@alex-e-leon I ran a mock release locally. I bumped all six public packages with a throwaway changeset and ran yarn changeset:version and yarn changeset:publish against a local Verdaccio registry. That ran the patched Changesets v3, yarn npm publish, each new prepack build and the payload check, from a clean turbo cache. All six published.

For each tarball: every main/types/exports/typesVersions target exists, no workspace: ranges are left, internal ranges point at the bumped versions, and the file list matches the current npm release apart from rebuilt chunks. The run did find one problem: petrinaut and petrinaut-core were packing nested README.md files, because Yarn matches an unanchored files entry at any depth. That's fixed in 142660b, and a repack confirms only the root README.md ships now.

All 34 export subpaths type-check under bundler and nodenext, and the Node-loadable entry points import. On ds-components: the root import fails with "luma.gl - multiple versions detected". It pins @luma.gl/core 9.3.6 while @deck.gl/core pulls 9.4.2. The published 0.3.1 fails identically, and with a single luma copy it imports fine. This predates the PR; I can fix it in a separate PR if you want.

The one thing only GitHub Actions can prove is the OIDC trusted-publishing exchange and provenance through Yarn.


Generated by Claude Code

Each published package's `prepack` is now `turbo run build:pack`, a task
that depends on the package's build (or, for `@hashintel/ds-helpers`, on
its codegen) and runs the payload check as its own script, uncached so
it reads the files on disk at pack time.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L4xQyzV5Mb61k3XbH9J8ZA
@github-actions

github-actions Bot commented Oct 9, 2026

Copy link
Copy Markdown
Contributor

Benchmark results

hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$20.3 \mathrm{ms} \pm 139 \mathrm{μs}\left({\color{gray}0.626 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.65 \mathrm{ms} \pm 18.1 \mathrm{μs}\left({\color{gray}0.388 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$10.3 \mathrm{ms} \pm 90.3 \mathrm{μs}\left({\color{gray}3.12 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$33.7 \mathrm{ms} \pm 258 \mathrm{μs}\left({\color{gray}-2.109 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$11.4 \mathrm{ms} \pm 144 \mathrm{μs}\left({\color{gray}0.155 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$18.7 \mathrm{ms} \pm 155 \mathrm{μs}\left({\color{lightgreen}-8.222 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$21.5 \mathrm{ms} \pm 197 \mathrm{μs}\left({\color{gray}1.48 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.97 \mathrm{ms} \pm 19.5 \mathrm{μs}\left({\color{gray}3.57 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$11.2 \mathrm{ms} \pm 110 \mathrm{μs}\left({\color{gray}4.72 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$2.88 \mathrm{ms} \pm 19.0 \mathrm{μs}\left({\color{gray}-1.476 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.31 \mathrm{ms} \pm 14.9 \mathrm{μs}\left({\color{gray}-0.566 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$2.58 \mathrm{ms} \pm 16.5 \mathrm{μs}\left({\color{gray}-0.829 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$3.97 \mathrm{ms} \pm 34.6 \mathrm{μs}\left({\color{gray}-2.955 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.77 \mathrm{ms} \pm 14.8 \mathrm{μs}\left({\color{gray}-1.199 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$3.21 \mathrm{ms} \pm 19.9 \mathrm{μs}\left({\color{gray}-1.226 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$3.43 \mathrm{ms} \pm 24.1 \mathrm{μs}\left({\color{gray}0.321 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.65 \mathrm{ms} \pm 16.1 \mathrm{μs}\left({\color{gray}-0.335 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$3.12 \mathrm{ms} \pm 17.0 \mathrm{μs}\left({\color{gray}-1.979 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.13 \mathrm{ms} \pm 12.6 \mathrm{μs}\left({\color{gray}-0.279 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.08 \mathrm{ms} \pm 12.7 \mathrm{μs}\left({\color{gray}-0.777 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$2.18 \mathrm{ms} \pm 13.6 \mathrm{μs}\left({\color{gray}-1.517 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.34 \mathrm{ms} \pm 15.1 \mathrm{μs}\left({\color{gray}-2.470 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.23 \mathrm{ms} \pm 15.4 \mathrm{μs}\left({\color{gray}-2.456 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.47 \mathrm{ms} \pm 16.3 \mathrm{μs}\left({\color{gray}0.051 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$2.39 \mathrm{ms} \pm 13.9 \mathrm{μs}\left({\color{gray}-1.179 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.16 \mathrm{ms} \pm 19.1 \mathrm{μs}\left({\color{gray}-1.943 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$2.29 \mathrm{ms} \pm 12.3 \mathrm{μs}\left({\color{gray}-1.564 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$2.70 \mathrm{ms} \pm 17.7 \mathrm{μs}\left({\color{gray}-3.097 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.38 \mathrm{ms} \pm 14.8 \mathrm{μs}\left({\color{gray}-1.317 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$2.58 \mathrm{ms} \pm 18.9 \mathrm{μs}\left({\color{gray}-3.185 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$2.64 \mathrm{ms} \pm 15.8 \mathrm{μs}\left({\color{gray}-1.625 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.38 \mathrm{ms} \pm 18.5 \mathrm{μs}\left({\color{gray}-0.462 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$2.60 \mathrm{ms} \pm 19.7 \mathrm{μs}\left({\color{gray}-0.981 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$24.5 \mathrm{ms} \pm 140 \mathrm{μs}\left({\color{gray}-1.333 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$53.4 \mathrm{ms} \pm 377 \mathrm{μs}\left({\color{gray}-3.467 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$27.6 \mathrm{ms} \pm 199 \mathrm{μs}\left({\color{gray}-2.685 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$29.5 \mathrm{ms} \pm 259 \mathrm{μs}\left({\color{gray}-2.935 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$34.2 \mathrm{ms} \pm 257 \mathrm{μs}\left({\color{gray}2.45 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$25.7 \mathrm{ms} \pm 156 \mathrm{μs}\left({\color{gray}0.437 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$317 \mathrm{ms} \pm 1.03 \mathrm{ms}\left({\color{gray}-0.641 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$70.7 \mathrm{ms} \pm 574 \mathrm{μs}\left({\color{gray}-3.887 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$54.9 \mathrm{ms} \pm 385 \mathrm{μs}\left({\color{gray}-1.082 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$212 \mathrm{ms} \pm 1.09 \mathrm{ms}\left({\color{gray}-1.362 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$7.98 \mathrm{ms} \pm 69.5 \mathrm{μs}\left({\color{gray}0.643 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$7.95 \mathrm{ms} \pm 42.1 \mathrm{μs}\left({\color{gray}-4.000 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$8.13 \mathrm{ms} \pm 55.9 \mathrm{μs}\left({\color{lightgreen}-5.910 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$8.05 \mathrm{ms} \pm 52.4 \mathrm{μs}\left({\color{lightgreen}-5.738 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$8.10 \mathrm{ms} \pm 54.4 \mathrm{μs}\left({\color{gray}-2.879 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$8.00 \mathrm{ms} \pm 57.4 \mathrm{μs}\left({\color{gray}-1.470 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$7.95 \mathrm{ms} \pm 55.0 \mathrm{μs}\left({\color{gray}-3.797 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$7.99 \mathrm{ms} \pm 59.0 \mathrm{μs}\left({\color{gray}-2.121 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$8.20 \mathrm{ms} \pm 66.4 \mathrm{μs}\left({\color{gray}1.61 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$8.38 \mathrm{ms} \pm 74.5 \mathrm{μs}\left({\color{gray}0.298 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity

Function Value Mean Flame graphs
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/block/v/1 $$8.29 \mathrm{ms} \pm 57.4 \mathrm{μs}\left({\color{gray}-3.002 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$8.25 \mathrm{ms} \pm 52.6 \mathrm{μs}\left({\color{gray}-0.793 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$8.27 \mathrm{ms} \pm 51.5 \mathrm{μs}\left({\color{gray}-2.070 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$8.27 \mathrm{ms} \pm 55.2 \mathrm{μs}\left({\color{gray}-1.496 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$8.30 \mathrm{ms} \pm 59.5 \mathrm{μs}\left({\color{gray}-2.498 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$8.31 \mathrm{ms} \pm 51.2 \mathrm{μs}\left({\color{lightgreen}-5.309 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$8.22 \mathrm{ms} \pm 52.9 \mathrm{μs}\left({\color{gray}-3.127 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$8.33 \mathrm{ms} \pm 56.9 \mathrm{μs}\left({\color{lightgreen}-6.010 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$8.25 \mathrm{ms} \pm 46.8 \mathrm{μs}\left({\color{gray}-2.245 \mathrm{\%}}\right) $$ Flame Graph

representative_read_entity_type

Function Value Mean Flame graphs
get_entity_type_by_id Account ID: bf5a9ef5-dc3b-43cf-a291-6210c0321eba $$6.05 \mathrm{ms} \pm 41.4 \mathrm{μs}\left({\color{gray}-2.237 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$45.1 \mathrm{ms} \pm 302 \mathrm{μs}\left({\color{lightgreen}-6.316 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$83.6 \mathrm{ms} \pm 417 \mathrm{μs}\left({\color{lightgreen}-9.946 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$50.4 \mathrm{ms} \pm 524 \mathrm{μs}\left({\color{lightgreen}-6.441 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$57.4 \mathrm{ms} \pm 409 \mathrm{μs}\left({\color{gray}-4.936 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$65.0 \mathrm{ms} \pm 591 \mathrm{μs}\left({\color{lightgreen}-5.379 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$69.0 \mathrm{ms} \pm 582 \mathrm{μs}\left({\color{lightgreen}-7.234 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$36.0 \mathrm{ms} \pm 301 \mathrm{μs}\left({\color{lightgreen}-7.011 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$58.1 \mathrm{ms} \pm 736 \mathrm{μs}\left({\color{gray}-4.326 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$40.4 \mathrm{ms} \pm 289 \mathrm{μs}\left({\color{lightgreen}-8.271 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$47.4 \mathrm{ms} \pm 339 \mathrm{μs}\left({\color{lightgreen}-7.129 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$48.6 \mathrm{ms} \pm 377 \mathrm{μs}\left({\color{lightgreen}-9.267 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$49.5 \mathrm{ms} \pm 351 \mathrm{μs}\left({\color{lightgreen}-6.063 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$89.9 \mathrm{ms} \pm 469 \mathrm{μs}\left({\color{gray}2.87 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$99.3 \mathrm{ms} \pm 478 \mathrm{μs}\left({\color{gray}2.29 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$19.9 \mathrm{ms} \pm 183 \mathrm{μs}\left({\color{red}11.8 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$401 \mathrm{ms} \pm 1.35 \mathrm{ms}\left({\color{gray}-2.854 \mathrm{\%}}\right) $$ Flame Graph

This branch was successfully deployed

5 active deployments
Preview – hash — be83bede Deployed Oct 9, 2026 by vercel[bot]
Preview – petrinaut-docs — be83bede Deployed Oct 9, 2026 by vercel[bot]
Preview – petrinaut — be83bede Deployed Oct 9, 2026 by vercel[bot]
Preview – hashdotdesign-tokens — be83bede Deployed Oct 9, 2026 by vercel[bot]
pull-request — be83bede Deployed Oct 9, 2026 by claude[bot] via Sourcemaps (@apps/hash-integration-worker) #39104
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash.design Affects the `hash.design` design site (app) area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

3 participants