Skip to content

BE-565: Disallow zero ontology type versions - #9891

Open
montekki wants to merge 3 commits into
mainfrom
fs/be-565-disallow-version-0-in-type-system
Open

montekki wants to merge 3 commits into
mainfrom
fs/be-565-disallow-version-0-in-type-system

Conversation

@montekki

@montekki montekki commented Oct 2, 2026 •

Copy link
Copy Markdown
Member

🌟 What is the purpose of this PR?

Ontology type versions start at 1, but the Rust and TypeScript validators currently accept 0. This change rejects zero versions and updates the Graph and frontend callers to use valid versions.

🔗 Related links

🔍 What does this change?

  • Rust stores the major version as NonZero<u32> and rejects zero during parsing and PostgreSQL decoding. Graph version increments use checked_add, and updates without a valid predecessor retain the existing error type.
  • Snapshot restoration uses the schema's actual ID for temporary closed data and entity schemas.
  • TypeScript URL validation rejects zero, and makeOntologyTypeVersion accepts only integers from 1 through u32::MAX.
  • The frontend uses explicit draft state instead of version 0 and disables publishing updates at the maximum version.
  • Tests and fixtures use valid versions. Regression tests cover zero rejection, constructor bounds, draft creation, and editing at the maximum version.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

  • This PR modifies an npm-publishable library and I have added a changeset file.

📜 Does this require a change to the docs?

  • This PR enforces existing version rules and does not require a docs change.

🕸️ Does this require a change to the Turbo Graph?

  • The changes do not affect the execution graph.

🛡 What tests cover this?

  • Workspace compilation, strict Clippy with all features, Clippy across 45 feature configurations, and public/private rustdoc checks passed.
  • Rust unit tests passed across 45 feature configurations. The all-features runs passed 719 affected tests and 2,753 downstream tests. All 107 doctests passed.
  • All 130 Graph integration tests passed. All 402 PostgreSQL store tests passed across eight feature configurations, with two tests skipped in each configuration. Authorization integration tests passed.
  • All 135 Miri tests passed across Atlas, graph embeddings, and HashQL evaluation.
  • TypeScript checks, ESLint, and 2,188 source unit tests passed across dependent packages, including 64 type-system and 1,367 frontend tests.
  • Formatting, repository lint checks, generated OpenAPI and type declarations, and lockfile stability checks passed.

The broader integration run had 23 failures because Kratos, Temporal, and MinIO were unavailable locally. The TypeScript coverage run also discovered compiled AI-worker tests in dist, which require a Graph API and include paths to uncopied fixtures; the AI-worker source tests passed with coverage when dist was excluded.

❓ How to test this?

Run cargo check --all --all-features --all-targets and cargo clippy --workspace --all-features --all-targets --no-deps -- -D warnings.

Run yarn workspace @blockprotocol/type-system test:unit and yarn workspace @apps/hash-frontend test:unit after building their dependencies. With PostgreSQL running, run cargo nextest run -p hash-graph-integration --all-features.

@montekki montekki self-assigned this Oct 2, 2026
@vercel

vercel Bot commented Oct 2, 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 2, 2026 2:42pm UTC
3 Skipped Deployments
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Oct 2, 2026 2:42pm UTC
petrinaut Skipped Skipped Oct 2, 2026 2:42pm UTC
petrinaut-docs Skipped Skipped Oct 2, 2026 2:42pm UTC

Request Review

@github-actions github-actions Bot added area/apps > hash* Affects HASH (a `hash-*` app) 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 type/eng > backend Owned by the @backend team area/tests New or updated tests area/apps labels Oct 2, 2026
@montekki
montekki deployed to pull-request October 2, 2026 07:37 — with GitHub Actions Active
@montekki
montekki deployed to pull-request October 2, 2026 07:37 — with GitHub Actions Active
@codecov

codecov Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 31.89655% with 79 lines in your changes missing coverage. Please review.
✅ Project coverage is 66.21%. Comparing base (7c43342) to head (c2d12a1).
⚠️ Report is 12 commits behind head on main.

Files with missing lines Patch % Lines
libs/@local/graph/api/src/rest/legacy/data_type.rs 0.00% 22 Missing ⚠️
...bs/@local/graph/api/src/rest/legacy/entity_type.rs 0.00% 22 Missing ⚠️
.../@local/graph/api/src/rest/legacy/property_type.rs 0.00% 22 Missing ⚠️
...horization/rust/src/policies/resource/data_type.rs 0.00% 3 Missing ⚠️
...rization/rust/src/policies/resource/entity_type.rs 0.00% 3 Missing ⚠️
...zation/rust/src/policies/resource/property_type.rs 0.00% 3 Missing ⚠️
...ization/rust/src/policies/cedar/expression_tree.rs 92.85% 1 Missing and 1 partial ⚠️
...s-store/src/snapshot/ontology/data_type/channel.rs 0.00% 1 Missing ⚠️
...store/src/snapshot/ontology/entity_type/channel.rs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9891      +/-   ##
==========================================
+ Coverage   66.07%   66.21%   +0.13%     
==========================================
  Files        1911     1913       +2     
  Lines      211128   211993     +865     
  Branches     8285     8349      +64     
==========================================
+ Hits       139496   140361     +865     
+ Misses      70070    70067       -3     
- Partials     1562     1565       +3     
Flag Coverage Δ
apps.hash-ai-worker-ts 2.04% <ø> (ø)
apps.hash-api 15.35% <ø> (ø)
blockprotocol.type-system 41.37% <100.00%> (+3.22%) ⬆️
hash-graph 14.11% <ø> (ø)
hash-graph-api 35.86% <1.49%> (-0.34%) ⬇️
hash-graph-atlas 80.00% <ø> (-0.01%) ⬇️
hash-graph-authentication 97.63% <ø> (+0.29%) ⬆️
hash-graph-authorization 68.47% <70.27%> (+0.79%) ⬆️
hash-graph-embeddings 91.54% <ø> (ø)
hash-graph-postgres-store 31.96% <0.00%> (+0.01%) ⬆️
hash-graph-store 51.60% <100.00%> (-0.12%) ⬇️
hash-graph-types 0.00% <ø> (ø)
hash-graph-validation 85.37% <ø> (ø)
hash-middleware 89.60% <ø> (ø)
hashql-compiletest 28.71% <ø> (ø)
hashql-eval 79.77% <ø> (ø)
local.hash-backend-utils 3.27% <ø> (ø)
local.hash-graph-sdk 10.02% <ø> (ø)
local.hash-isomorphic-utils 12.22% <ø> (ø)

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.

@codspeed

codspeed Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 18 untouched benchmarks
⏩ 80 skipped benchmarks1


Comparing fs/be-565-disallow-version-0-in-type-system (c2d12a1) with main (25dd9ca)2

Open in CodSpeed

Footnotes

  1. 80 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩

  2. No successful run was found on main (d6a31cd) during the generation of this report, so 25dd9ca was used instead as the comparison base. There might be some changes unrelated to this pull request in this report. ↩

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nothing you could have possibly known, but the goal is to migrate away from http-tests, mainly because they're very long to write and annoying to test locally.
I would keep the changes you added, but as a general flag I think it's worth pointing out.
In particular this file is already quite large, and the embedded embeddings make this even worse.

Comment on lines +69 to +70
} else if (isVersionExhausted) {
label = "– this type has reached the maximum version and cannot be updated";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Good addition!

Comment on lines 83 to 87
closed_schema: Valid::new_unchecked(ClosedEntityType {
id: VersionedUrl {
base_url: schema.id.base_url.clone(),
version: OntologyTypeVersion {
major: 0,
pre_release: None,
},
},
id: schema.id.clone(),
title: String::new(),
title_plural: None,
description: String::new(),

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

My assumption here that the schema is filled with dummy values anyway and is properly UPDATE-ed in entity_type.rs, so just cloning the whole schema.id would work here as well as any other id value.

@montekki
montekki marked this pull request as ready for review October 2, 2026 13:51
@cursor

cursor Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

PR Summary

Medium Risk
Touches core ontology ID parsing, Graph type update APIs, and authorization policy version literals; invalid or max-version types may behave differently than before.

Overview
Ontology type versions are now 1 through u32::MAX only — zero is rejected end-to-end in Rust (NonZero<u32> for majors), TypeScript URL validation, and makeOntologyTypeVersion.

The Graph API uses checked version increments and returns 400 when publishing would exceed the max; bulk updates stay atomic. Store/authorization paths reject zero majors (including Postgres decode and Cedar policy parsing). Snapshot restore no longer seeds placeholder closed schemas at v/0.

HASH frontend stops using version 0 for drafts: isDraft drives the edit bar, invalid /v/... segments show NotFound (with query/fragment stripped from path parsing), and publishing is disabled at the maximum version. Tests and HTTP fixtures cover bounds, overflow, and route validation.

Reviewed by Cursor Bugbot for commit c2d12a1. Bugbot is set up for automated code reviews on this repo. Configure here.

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stale Bugbot comment from a previous run.

Comment thread libs/@blockprotocol/type-system/typescript/src/native/url.ts
@vercel
vercel Bot temporarily deployed to Preview – petrinaut-docs October 2, 2026 14:33 Inactive
@vercel
vercel Bot temporarily deployed to Preview – petrinaut October 2, 2026 14:33 Inactive
@montekki
montekki deployed to pull-request October 2, 2026 14:34 — with GitHub Actions Active
@montekki
montekki deployed to pull-request October 2, 2026 14:34 — with GitHub Actions Active

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit c2d12a1. Configure here.

validateVersionedUrl(`${dataTypeBaseUrl}v/${requestedVersionString}`)
.type === "Err"
) {
return <NotFound resourceLabel={{ label: "data type" }} />;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

NotFound copy drops the article

Low Severity

The new invalid-version NotFound calls pass only label, so authenticated users see “If you believe you should be able to see here”. Other type pages supply withArticle, and NotFound interpolates that field with no fallback. The same gap is on the external entity-type route.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit c2d12a1. Configure here.

)),
vec![],
))
})?;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

shouldn't this be an error enough (that we can then also e.g. reference), instead of directly being a stringly status? (I guess not as important in the sense that we're about to port to the public API)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It may make sense to create a newtype over NonZero<u32> to encode the major version (and similarly for the minor version). That way, we could encode the error that way and just call report_to_response, since we currently duplicate the same error in more than half a dozen places.

Comment on lines 956 to +961
.major
.get()
.checked_sub(1)
.ok_or(UpdateError)
.and_then(NonZero::new)
.ok_or(OntologyVersionDoesNotExist)
.change_context(UpdateError)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Having a dedicated type that enforces NonZero would also allow this to be: .previous().change_context() instead.

@github-actions

github-actions Bot commented Oct 2, 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 $$28.3 \mathrm{ms} \pm 328 \mathrm{μs}\left({\color{gray}-4.632 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.40 \mathrm{ms} \pm 25.3 \mathrm{μs}\left({\color{lightgreen}-11.153 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$13.5 \mathrm{ms} \pm 144 \mathrm{μs}\left({\color{lightgreen}-6.703 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$44.7 \mathrm{ms} \pm 522 \mathrm{μs}\left({\color{gray}-3.040 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$15.0 \mathrm{ms} \pm 224 \mathrm{μs}\left({\color{gray}-4.039 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$25.2 \mathrm{ms} \pm 320 \mathrm{μs}\left({\color{gray}-3.853 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$29.3 \mathrm{ms} \pm 232 \mathrm{μs}\left({\color{gray}-2.720 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.77 \mathrm{ms} \pm 38.7 \mathrm{μs}\left({\color{lightgreen}-9.308 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$14.7 \mathrm{ms} \pm 129 \mathrm{μs}\left({\color{lightgreen}-6.787 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.85 \mathrm{ms} \pm 34.7 \mathrm{μs}\left({\color{gray}-0.035 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.05 \mathrm{ms} \pm 25.6 \mathrm{μs}\left({\color{gray}1.30 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$3.42 \mathrm{ms} \pm 29.8 \mathrm{μs}\left({\color{gray}1.67 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.37 \mathrm{ms} \pm 57.1 \mathrm{μs}\left({\color{gray}3.24 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.60 \mathrm{ms} \pm 30.4 \mathrm{μs}\left({\color{gray}2.33 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$4.23 \mathrm{ms} \pm 40.5 \mathrm{μs}\left({\color{gray}0.727 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.55 \mathrm{ms} \pm 70.1 \mathrm{μs}\left({\color{gray}-0.206 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.42 \mathrm{ms} \pm 24.2 \mathrm{μs}\left({\color{gray}-2.760 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.25 \mathrm{ms} \pm 37.8 \mathrm{μs}\left({\color{gray}-1.802 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.76 \mathrm{ms} \pm 20.9 \mathrm{μs}\left({\color{gray}-2.788 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.68 \mathrm{ms} \pm 22.4 \mathrm{μs}\left({\color{gray}-3.619 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$2.85 \mathrm{ms} \pm 25.8 \mathrm{μs}\left({\color{gray}-2.640 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$3.06 \mathrm{ms} \pm 23.8 \mathrm{μs}\left({\color{gray}-0.163 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.86 \mathrm{ms} \pm 25.4 \mathrm{μs}\left({\color{gray}-3.068 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$3.22 \mathrm{ms} \pm 34.9 \mathrm{μs}\left({\color{gray}0.024 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.18 \mathrm{ms} \pm 29.4 \mathrm{μs}\left({\color{gray}-2.143 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.84 \mathrm{ms} \pm 27.3 \mathrm{μs}\left({\color{gray}0.240 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$2.96 \mathrm{ms} \pm 20.9 \mathrm{μs}\left({\color{gray}-2.122 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.61 \mathrm{ms} \pm 34.8 \mathrm{μs}\left({\color{gray}-1.171 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.05 \mathrm{ms} \pm 20.5 \mathrm{μs}\left({\color{gray}-3.747 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$3.37 \mathrm{ms} \pm 27.7 \mathrm{μs}\left({\color{gray}-1.714 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.45 \mathrm{ms} \pm 26.1 \mathrm{μs}\left({\color{gray}-1.493 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.10 \mathrm{ms} \pm 23.6 \mathrm{μs}\left({\color{gray}0.439 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.36 \mathrm{ms} \pm 24.8 \mathrm{μs}\left({\color{gray}-2.209 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$32.1 \mathrm{ms} \pm 230 \mathrm{μs}\left({\color{lightgreen}-6.819 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$72.7 \mathrm{ms} \pm 848 \mathrm{μs}\left({\color{gray}-1.665 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$35.5 \mathrm{ms} \pm 320 \mathrm{μs}\left({\color{gray}-1.587 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$39.9 \mathrm{ms} \pm 293 \mathrm{μs}\left({\color{gray}-3.182 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$41.6 \mathrm{ms} \pm 288 \mathrm{μs}\left({\color{gray}-4.761 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$34.1 \mathrm{ms} \pm 248 \mathrm{μs}\left({\color{gray}-1.184 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$420 \mathrm{ms} \pm 1.65 \mathrm{ms}\left({\color{gray}-2.178 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$92.2 \mathrm{ms} \pm 786 \mathrm{μs}\left({\color{gray}0.492 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$80.6 \mathrm{ms} \pm 502 \mathrm{μs}\left({\color{gray}-1.294 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$306 \mathrm{ms} \pm 1.25 \mathrm{ms}\left({\color{lightgreen}-5.142 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$10.3 \mathrm{ms} \pm 84.0 \mathrm{μs}\left({\color{lightgreen}-5.673 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$10.5 \mathrm{ms} \pm 82.0 \mathrm{μs}\left({\color{lightgreen}-5.566 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$10.6 \mathrm{ms} \pm 78.2 \mathrm{μs}\left({\color{lightgreen}-6.639 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$10.4 \mathrm{ms} \pm 92.7 \mathrm{μs}\left({\color{gray}-4.351 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$10.7 \mathrm{ms} \pm 94.6 \mathrm{μs}\left({\color{gray}-2.574 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$10.5 \mathrm{ms} \pm 71.8 \mathrm{μs}\left({\color{gray}-3.303 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$10.5 \mathrm{ms} \pm 88.9 \mathrm{μs}\left({\color{gray}-1.465 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$10.4 \mathrm{ms} \pm 114 \mathrm{μs}\left({\color{gray}-3.196 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$10.4 \mathrm{ms} \pm 70.1 \mathrm{μs}\left({\color{gray}-3.652 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$10.7 \mathrm{ms} \pm 76.9 \mathrm{μs}\left({\color{gray}-2.542 \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 $$11.0 \mathrm{ms} \pm 109 \mathrm{μs}\left({\color{gray}0.162 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$11.0 \mathrm{ms} \pm 82.2 \mathrm{μs}\left({\color{gray}-0.284 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$10.9 \mathrm{ms} \pm 88.2 \mathrm{μs}\left({\color{gray}-1.832 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$11.1 \mathrm{ms} \pm 99.1 \mathrm{μs}\left({\color{gray}-0.919 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$11.0 \mathrm{ms} \pm 81.3 \mathrm{μs}\left({\color{gray}0.342 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$11.2 \mathrm{ms} \pm 91.9 \mathrm{μs}\left({\color{gray}-0.990 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$11.0 \mathrm{ms} \pm 114 \mathrm{μs}\left({\color{gray}-1.455 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$11.0 \mathrm{ms} \pm 96.1 \mathrm{μs}\left({\color{gray}-3.399 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$11.0 \mathrm{ms} \pm 85.7 \mathrm{μs}\left({\color{gray}-0.954 \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 $$8.05 \mathrm{ms} \pm 67.8 \mathrm{μs}\left({\color{gray}0.347 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$57.0 \mathrm{ms} \pm 567 \mathrm{μs}\left({\color{gray}-3.335 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$109 \mathrm{ms} \pm 804 \mathrm{μs}\left({\color{gray}-1.630 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$63.1 \mathrm{ms} \pm 486 \mathrm{μs}\left({\color{gray}-3.752 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$72.6 \mathrm{ms} \pm 605 \mathrm{μs}\left({\color{gray}-4.738 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$81.8 \mathrm{ms} \pm 932 \mathrm{μs}\left({\color{gray}-1.698 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$88.3 \mathrm{ms} \pm 711 \mathrm{μs}\left({\color{gray}-0.864 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$46.5 \mathrm{ms} \pm 349 \mathrm{μs}\left({\color{gray}-1.746 \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 $$75.0 \mathrm{ms} \pm 707 \mathrm{μs}\left({\color{gray}0.963 \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 $$53.0 \mathrm{ms} \pm 459 \mathrm{μs}\left({\color{gray}-2.074 \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 $$61.0 \mathrm{ms} \pm 566 \mathrm{μs}\left({\color{gray}-3.409 \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 $$64.7 \mathrm{ms} \pm 530 \mathrm{μs}\left({\color{gray}0.245 \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 $$64.3 \mathrm{ms} \pm 689 \mathrm{μs}\left({\color{gray}0.000 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$114 \mathrm{ms} \pm 780 \mathrm{μs}\left({\color{gray}-1.119 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$126 \mathrm{ms} \pm 750 \mathrm{μs}\left({\color{gray}-0.487 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$23.2 \mathrm{ms} \pm 206 \mathrm{μs}\left({\color{lightgreen}-5.943 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$508 \mathrm{ms} \pm 1.72 \mathrm{ms}\left({\color{gray}0.593 \mathrm{\%}}\right) $$ Flame Graph

This branch was successfully deployed

2 active and 2 inactive deployments
Preview – hash — c2d12a1a Deployed Oct 2, 2026 by vercel[bot]
pull-request — c2d12a1a Deployed Oct 2, 2026 by montekki via Sourcemaps (@apps/hash-ai-worker-ts) #38029
Preview – petrinaut-docs — c2d12a1a Deployed Oct 2, 2026 by vercel[bot]
Preview – petrinaut — c2d12a1a Deployed Oct 2, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash* Affects HASH (a `hash-*` app) area/apps area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) area/tests New or updated tests 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