Skip to content

BE-802: Load programmatic defaults in hash-config - #9437

Open
TimDiekmann wants to merge 5 commits into
mainfrom
t/be-802-load-programmatic-defaults-in-hash-config
Open

BE-802: Load programmatic defaults in hash-config#9437
TimDiekmann wants to merge 5 commits into
mainfrom
t/be-802-load-programmatic-defaults-in-hash-config

Conversation

@TimDiekmann

Copy link
Copy Markdown
Member

🌟 What is the purpose of this PR?

hash-config gets its first working slice. A binary builds its configuration type from programmatic defaults with Loader::new().with_defaults(…).load::<Config>(), which returns the deserialized configuration. Figment does the merging and appears in no public signature.

The error path is the substantive part of this change. Figment's own messages inline the value they rejected, so a bad store.port reads invalid type: found string "hunter2", expected u16. A configuration value can be a database password or an API key, which makes such an error unsafe to put in a log. Here the error names the key and the shape that was expected, and never the value.

🔗 Related links

🚫 Blocked by

Nothing. BE-801 is merged.

🔍 What does this change?

  • Loader::with_defaults accepts any impl Serialize that serializes to a map and merges it into the default layer. Repeated calls apply in order: later scalars and arrays replace earlier ones, and maps merge recursively. BE-802 calls this method defaults; it is with_defaults here to match the builder convention the rest of the workspace uses, including the layered builder in libs/@local/telemetry/src/lib.rs.
  • Loader::load deserializes the merged values into the caller's type and returns Report<LoadError> on failure.
  • Errors carry the key path. Figment supplies it on its error type and the diagnostic discarded it, so every failure read as "something is a string" with no way to tell which of a hundred settings was meant. A missing field joins with its parent, so it reads missing field \store.port`rather thanmissing field `port``.
  • Errors carry Serde's expected text. Visitor::expecting receives no value, so it cannot quote one.
  • Configuration keys count as schema and are reported, map keys and array indices included. Scalars, enum variant names, lengths and hand-written serde::de::Error::custom messages count as values and are dropped.
  • A private provider wraps Serialized so a diagnostic names the layer defaults instead of the Rust type it was handed, and so keys render dotted instead of prefixed with the profile they were found under.
  • Loader implements Debug by hand and lists the layer names. Figment's derived Debug renders the merged values, which would put configuration values into any log line that formats a loader.
  • The crate is split into lib.rs for the Loader, error.rs for the error type and the diagnostic translation, and defaults.rs for the provider. Each later source is a provider plus a Loader method and gets a module of its own.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • does not modify any publishable blocks or libraries, or modifications do not need publishing

📜 Does this require a change to the docs?

The changes in this PR:

  • are internal and do not require a docs change

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

The changes in this PR:

  • affected the execution graph, and the turbo.json's have been updated to reflect this

⚠️ Known issues

Serde stops at the first error within a single document, so a configuration with three mistakes reports them one run at a time. More than one diagnostic appears only when several sources each fail to produce data at all. This is Serde's behaviour rather than something the loader chooses, and reporting every mistake in one pass would mean writing a deserializer of our own.

LoadError has a single variant, so a caller can render a report but cannot branch on what went wrong; the categories live in a private type. That is enough while there is one failure mode. Adding variants is a breaking change for callers, and doing it now would mean guessing at the joints before the file, environment and override layers exist.

unknown field only fires for configuration types that set #[serde(deny_unknown_fields)]. Without it, Serde ignores an unrecognised key and the field takes its default, so a typo passes silently. Closing that properly needs the schema walk, which can compare a document against the schema whether or not the attribute is set.

🐾 Next steps

The remaining slices under H-4170: file sources with profiles and the directory cascade, the environment layer, -C overrides with the clap integration, the schema walk, and the config subcommand. set_default(key, value) for seeding a single subtree belongs to the defaults layer and is not in this PR.

🛡 What tests cover this?

  • libs/@local/config/tests/defaults.rs covers the merge contract and one case per diagnostic category, each asserting both halves of the contract: the key appears, the value does not.
  • libs/@local/config/examples/defaults.rs is the runnable example and carries two tests of its own. test = true on the [[example]] target is what makes them run, and doc-scrape-examples = true puts the example on the Loader::new, with_defaults and load doc pages.
  • The doctest on Loader.

❓ How to test this?

  1. Check out the branch.
  2. cargo nextest run --all-features --package hash-config
  3. cargo run --all-features --package hash-config --example defaults

📹 Demo

The example composes two default layers and then sets the port to a password:

localhost:6543 serving ["api", "health"]

the configuration could not be loaded
├╴at libs/@local/config/examples/defaults.rs:55:10
╰╴invalid type: found string, expected u16 at `store.port` in `defaults` (libs/@local/config/examples/defaults.rs:54:10)

`Loader::with_defaults` takes anything that serializes to a map and merges it
into the default layer; repeated calls replace scalars and arrays and merge maps
recursively. `Loader::load` deserializes the merged values.

Errors report the key and the expected shape and never the value, so a report is
safe to log in full: a mistyped `store.port` reads `invalid type: found string,
expected u16 at "store.port"`. Configuration keys count as schema and are
reported, including map keys and array indices; scalars, enum variant names,
lengths and hand-written Serde messages are values and are dropped. Figment's
`Debug` renders the merged values, so `Loader` implements it by listing the
layer names instead.
@TimDiekmann TimDiekmann self-assigned this Aug 29, 2026
@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview Aug 29, 2026 3:56pm
3 Skipped Deployments
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Aug 29, 2026 3:56pm
petrinaut Skipped Skipped Aug 29, 2026 3:56pm
petrinaut-docs Skipped Skipped Aug 29, 2026 3:56pm

Request Review

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team area/tests New or updated tests labels Aug 29, 2026
Comment thread libs/@local/config/src/error.rs Fixed
Signed-off-by: Tim Diekmann <21277928+TimDiekmann@users.noreply.github.com>
@vercel
vercel Bot temporarily deployed to Preview – petrinaut-docs August 29, 2026 03:17 Inactive
@vercel
vercel Bot temporarily deployed to Preview – petrinaut August 29, 2026 03:17 Inactive
@TimDiekmann
TimDiekmann deployed to pull-request August 29, 2026 03:18 — with GitHub Actions Active
@TimDiekmann
TimDiekmann deployed to pull-request August 29, 2026 03:18 — with GitHub Actions Active
@codspeed-hq

codspeed-hq Bot commented Aug 29, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 15.38%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

❌ 2 regressed benchmarks
✅ 96 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
bit_matrix/dense/iter_row[64] 140.8 ns 170 ns -17.16%
bit_matrix/dense/iter_row[200] 185.8 ns 215 ns -13.57%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing t/be-802-load-programmatic-defaults-in-hash-config (0968bae) with main (59468b1)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (56c4651) during the generation of this report, so 59468b1 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@codecov

codecov Bot commented Aug 29, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.61929% with 50 lines in your changes missing coverage. Please review.
✅ Project coverage is 61.01%. Comparing base (59468b1) to head (0968bae).
⚠️ Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
libs/@local/config/src/error.rs 76.39% 38 Missing ⚠️
libs/@local/config/src/lib.rs 52.00% 12 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9437      +/-   ##
==========================================
+ Coverage   60.66%   61.01%   +0.35%     
==========================================
  Files        1439     1448       +9     
  Lines      143119   144648    +1529     
  Branches     6654     6692      +38     
==========================================
+ Hits        86817    88263    +1446     
- Misses      55211    55281      +70     
- Partials     1091     1104      +13     
Flag Coverage Δ
rust.hash-config 74.74% <74.61%> (-25.26%) ⬇️

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.

Four doc comments described a mechanism or justified a choice instead of saying
what the item is: on `Defaults::new`, on `Debug for Loader`, on a test, and in
the provider's `metadata`. What `#[track_caller]` does needs no comment.

`Loader` is documented as building from layered sources rather than from
explicitly selected ones, and `with_defaults` says the error names the call
instead of saying that a call site is recorded.
@vercel
vercel Bot temporarily deployed to Preview – petrinaut-docs August 29, 2026 14:56 Inactive
@vercel
vercel Bot temporarily deployed to Preview – petrinaut August 29, 2026 14:56 Inactive
@TimDiekmann
TimDiekmann deployed to pull-request August 29, 2026 14:57 — with GitHub Actions Active
@TimDiekmann
TimDiekmann deployed to pull-request August 29, 2026 14:57 — with GitHub Actions Active
A key that came from a selected profile reports it, so `missing field `port``
becomes `missing field `port` under profile `production``. The default profile
is left unnamed: until a profile is selected every key sits under it.
@vercel
vercel Bot temporarily deployed to Preview – petrinaut-docs August 29, 2026 15:47 Inactive
@vercel
vercel Bot temporarily deployed to Preview – petrinaut August 29, 2026 15:47 Inactive
@TimDiekmann
TimDiekmann deployed to pull-request August 29, 2026 15:48 — with GitHub Actions Active
@TimDiekmann
TimDiekmann deployed to pull-request August 29, 2026 15:48 — with GitHub Actions Active
@TimDiekmann
TimDiekmann marked this pull request as ready for review August 29, 2026 16:52
@cursor

cursor Bot commented Aug 29, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
New internal library with no binary wiring yet; main concern is future misuse of error reports if redaction rules miss an edge case, but behavior is heavily tested.

Overview
hash-config gains its first usable API: Loader::new().with_defaults(…).load::<Config>() builds a typed config from one or more programmatic default layers (Figment merges internally; later layers override scalars/arrays and deep-merge maps).

Failures return Report<LoadError> with Figment/Serde errors translated into LoadDiagnostic attachments that name keys, expected shapes, provider/layer, and call sites while never echoing secret values (passwords, API keys, mistyped strings). A custom defaults Figment provider labels the layer and uses dotted key paths; Loader’s Debug lists layer names only so logs do not dump merged config.

Adds figment / error-stack wiring, an example, integration tests for merge + redaction, and replaces the prior scaffold-only crate layout (defaults, error, lib modules).

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

@github-actions

Copy link
Copy Markdown
Contributor

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$28.5 \mathrm{ms} \pm 257 \mathrm{μs}\left({\color{gray}-2.309 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.66 \mathrm{ms} \pm 36.6 \mathrm{μs}\left({\color{gray}0.560 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$13.8 \mathrm{ms} \pm 115 \mathrm{μs}\left({\color{gray}1.45 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$45.0 \mathrm{ms} \pm 449 \mathrm{μs}\left({\color{gray}1.09 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$16.3 \mathrm{ms} \pm 190 \mathrm{μs}\left({\color{gray}1.14 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$26.1 \mathrm{ms} \pm 446 \mathrm{μs}\left({\color{gray}1.92 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$29.7 \mathrm{ms} \pm 286 \mathrm{μs}\left({\color{gray}-0.803 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.97 \mathrm{ms} \pm 22.2 \mathrm{μs}\left({\color{gray}-0.764 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$14.9 \mathrm{ms} \pm 123 \mathrm{μs}\left({\color{gray}2.50 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.91 \mathrm{ms} \pm 29.4 \mathrm{μs}\left({\color{gray}-2.239 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.09 \mathrm{ms} \pm 22.6 \mathrm{μs}\left({\color{gray}-0.564 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$3.47 \mathrm{ms} \pm 28.1 \mathrm{μs}\left({\color{gray}-0.087 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.42 \mathrm{ms} \pm 47.4 \mathrm{μs}\left({\color{gray}-1.456 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.69 \mathrm{ms} \pm 36.6 \mathrm{μs}\left({\color{gray}-0.073 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$4.36 \mathrm{ms} \pm 38.0 \mathrm{μs}\left({\color{gray}-0.900 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.65 \mathrm{ms} \pm 49.6 \mathrm{μs}\left({\color{gray}0.063 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.62 \mathrm{ms} \pm 27.3 \mathrm{μs}\left({\color{gray}-0.774 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.21 \mathrm{ms} \pm 37.5 \mathrm{μs}\left({\color{gray}-2.012 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.79 \mathrm{ms} \pm 22.4 \mathrm{μs}\left({\color{gray}1.79 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.62 \mathrm{ms} \pm 16.9 \mathrm{μs}\left({\color{gray}1.66 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$2.75 \mathrm{ms} \pm 19.2 \mathrm{μs}\left({\color{gray}-0.161 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$3.07 \mathrm{ms} \pm 26.5 \mathrm{μs}\left({\color{gray}2.75 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.83 \mathrm{ms} \pm 19.8 \mathrm{μs}\left({\color{gray}-0.139 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$3.02 \mathrm{ms} \pm 22.7 \mathrm{μs}\left({\color{gray}1.13 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.19 \mathrm{ms} \pm 24.6 \mathrm{μs}\left({\color{gray}1.90 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.87 \mathrm{ms} \pm 22.1 \mathrm{μs}\left({\color{gray}0.958 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$3.15 \mathrm{ms} \pm 27.2 \mathrm{μs}\left({\color{gray}4.19 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.58 \mathrm{ms} \pm 25.6 \mathrm{μs}\left({\color{gray}0.003 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.09 \mathrm{ms} \pm 19.9 \mathrm{μs}\left({\color{gray}2.31 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$3.46 \mathrm{ms} \pm 27.0 \mathrm{μs}\left({\color{gray}3.89 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.50 \mathrm{ms} \pm 21.6 \mathrm{μs}\left({\color{gray}-1.514 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.10 \mathrm{ms} \pm 36.2 \mathrm{μs}\left({\color{gray}1.65 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.51 \mathrm{ms} \pm 29.5 \mathrm{μs}\left({\color{gray}3.45 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$43.9 \mathrm{ms} \pm 284 \mathrm{μs}\left({\color{gray}2.06 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$33.9 \mathrm{ms} \pm 240 \mathrm{μs}\left({\color{gray}1.54 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$37.4 \mathrm{ms} \pm 296 \mathrm{μs}\left({\color{gray}-0.144 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$32.7 \mathrm{ms} \pm 219 \mathrm{μs}\left({\color{gray}1.70 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$43.5 \mathrm{ms} \pm 290 \mathrm{μs}\left({\color{gray}-1.188 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$51.0 \mathrm{ms} \pm 402 \mathrm{μs}\left({\color{gray}-1.377 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$41.6 \mathrm{ms} \pm 304 \mathrm{μs}\left({\color{gray}-0.497 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$88.1 \mathrm{ms} \pm 767 \mathrm{μs}\left({\color{lightgreen}-7.726 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$34.9 \mathrm{ms} \pm 237 \mathrm{μs}\left({\color{gray}-0.229 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$280 \mathrm{ms} \pm 1.19 \mathrm{ms}\left({\color{gray}-2.515 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$10.9 \mathrm{ms} \pm 82.5 \mathrm{μs}\left({\color{gray}-0.058 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$10.9 \mathrm{ms} \pm 85.9 \mathrm{μs}\left({\color{gray}-2.319 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$11.0 \mathrm{ms} \pm 76.2 \mathrm{μs}\left({\color{gray}-0.111 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$10.7 \mathrm{ms} \pm 93.6 \mathrm{μs}\left({\color{gray}-2.740 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$10.8 \mathrm{ms} \pm 82.3 \mathrm{μs}\left({\color{gray}-0.884 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$10.8 \mathrm{ms} \pm 79.6 \mathrm{μs}\left({\color{gray}-0.161 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$10.7 \mathrm{ms} \pm 66.0 \mathrm{μs}\left({\color{gray}-2.671 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$11.0 \mathrm{ms} \pm 99.2 \mathrm{μs}\left({\color{gray}1.30 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$10.9 \mathrm{ms} \pm 102 \mathrm{μs}\left({\color{gray}0.518 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$11.2 \mathrm{ms} \pm 81.1 \mathrm{μs}\left({\color{gray}-0.122 \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.1 \mathrm{ms} \pm 62.4 \mathrm{μs}\left({\color{gray}-1.492 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$11.1 \mathrm{ms} \pm 77.5 \mathrm{μs}\left({\color{gray}-1.217 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$11.5 \mathrm{ms} \pm 92.0 \mathrm{μs}\left({\color{gray}2.80 \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 88.7 \mathrm{μs}\left({\color{gray}-3.386 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$11.2 \mathrm{ms} \pm 84.9 \mathrm{μs}\left({\color{lightgreen}-5.514 \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 72.5 \mathrm{μs}\left({\color{gray}0.673 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$11.1 \mathrm{ms} \pm 77.7 \mathrm{μs}\left({\color{gray}-2.562 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$11.2 \mathrm{ms} \pm 81.5 \mathrm{μs}\left({\color{gray}-3.286 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$11.2 \mathrm{ms} \pm 94.6 \mathrm{μs}\left({\color{gray}-0.802 \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.37 \mathrm{ms} \pm 59.6 \mathrm{μs}\left({\color{gray}-0.449 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$58.1 \mathrm{ms} \pm 464 \mathrm{μs}\left({\color{gray}-4.759 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$111 \mathrm{ms} \pm 681 \mathrm{μs}\left({\color{gray}-4.051 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$65.1 \mathrm{ms} \pm 554 \mathrm{μs}\left({\color{gray}-4.468 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$75.2 \mathrm{ms} \pm 780 \mathrm{μs}\left({\color{gray}-1.482 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$83.3 \mathrm{ms} \pm 655 \mathrm{μs}\left({\color{gray}-2.898 \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.7 \mathrm{ms} \pm 655 \mathrm{μs}\left({\color{gray}-4.047 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$44.3 \mathrm{ms} \pm 311 \mathrm{μs}\left({\color{gray}-2.547 \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 $$73.9 \mathrm{ms} \pm 608 \mathrm{μs}\left({\color{gray}-2.107 \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 $$50.0 \mathrm{ms} \pm 552 \mathrm{μs}\left({\color{gray}-4.035 \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 $$60.2 \mathrm{ms} \pm 462 \mathrm{μs}\left({\color{gray}-2.618 \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 $$63.1 \mathrm{ms} \pm 562 \mathrm{μs}\left({\color{gray}-2.392 \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 $$63.4 \mathrm{ms} \pm 536 \mathrm{μs}\left({\color{gray}-1.062 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$119 \mathrm{ms} \pm 796 \mathrm{μs}\left({\color{red}5.23 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$132 \mathrm{ms} \pm 831 \mathrm{μs}\left({\color{gray}3.84 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$23.6 \mathrm{ms} \pm 214 \mathrm{μs}\left({\color{red}25.3 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$538 \mathrm{ms} \pm 1.81 \mathrm{ms}\left({\color{gray}-1.347 \mathrm{\%}}\right) $$ Flame Graph

@TimDiekmann
TimDiekmann requested a review from indietyp August 29, 2026 17:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/deps Relates to third-party dependencies (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

Development

Successfully merging this pull request may close these issues.

2 participants