Skip to content

FE-1270: Extract Python bindings for the Petrinaut CLI into @local/petrinaut-python - #9228

Merged
kube merged 3 commits into
mainfrom
cf/fe-1270-create-python-bindings-to-petrinaut-core
Aug 21, 2026
Merged

FE-1270: Extract Python bindings for the Petrinaut CLI into @local/petrinaut-python#9228
kube merged 3 commits into
mainfrom
cf/fe-1270-create-python-bindings-to-petrinaut-core

Conversation

@kube

@kube kube commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

🌟 What is the purpose of this PR?

apps/petrinaut-opt carried its own Petrinaut CLI client, private to that service and covering two of the CLI's five protocol methods. This PR extracts the client into a package any Python code can use, and removes the service's knowledge of the CLI.

Bottom of stack #9269; FE-1467 (#9261) sits above.

Most of the diff is a move: petrinaut_client.pysession.py.

🔗 Related links

🔍 What does this change?

New package libs/@local/petrinaut-python (import name petrinaut), internal to the monorepo:

  • PetrinautSession runs one model per CLI process and exposes healthz(), metadata(), run(), and request().
  • OptimizationSession drives a study over a manifest it treats as opaque JSON: describe(), evaluate(), objective().
  • Process handling is unchanged from the old client: scrubbed child environment, bounded reads with deadlines, process-group shutdown. Errors split into PetrinautRunError (recoverable) and PetrinautClientError/PetrinautProtocolError (session closes).

apps/petrinaut-opt depends on the bindings and nothing else. It no longer names the CLI in code, tests, docs, configuration, or the image:

  • The bindings declare @hashintel/petrinaut-cli as a runtime dependency, so the Docker image provisions the bindings' closure (turbo prune @local/petrinaut-python) and links the closure's petrinaut executable into /usr/local/bin. The image ships built output only.
  • uv sync --no-editable builds the bindings into the virtualenv, so the runner copies the virtualenv alone.
  • The Node-options passthrough is renamed PETRINAUT_CHILD_NODE_OPTIONS; the image's own NODE_OPTIONS never reached the child and is removed.
  • FE-1414 (FE-1414: Support Python packages in the architecture docs #9230) adds the architecture check that enforces this: optimizer → python-bindings with no edge to cli.

Review fixes. from_model_file and from_model are staticmethods rather than classmethods: they always build a base PetrinautSession, and a classmethod read as a subclass constructor on OptimizationSession while returning the base class. PetrinautRunError's docstring now also names the non-finite-objective case, and a doubled sentence in the README's development instructions is fixed.

Two follow-up commits address the remaining review threads:

  • describe_optimization() is renamed to describe(): the old name repeated the class name, its siblings evaluate()/objective() carry no prefix, and describe() maps 1:1 to the protocol's optimization.describe. The previous name remains as an alias.
  • Caller-input bugs no longer raise PetrinautClientError, whose contract says the session's process or transport is gone: params or a bootstrap payload that will not serialize to JSON raise TypeError, and a payload over the 8 MiB line cap raises ValueError — all before anything is written, leaving the session untouched (the request id is only consumed after a successful encode). Raised by Cursor and in review.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies a workspace but not a publishable library. @local/petrinaut-python is private.

📜 Does this require a change to the docs?

The changes in this PR:

  • require changes to docs which are made as part of this PR: the package README and both consumers' READMEs. In-app user-guide behaviour is unchanged.

🕸️ 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: the bindings' test:unit depends on the CLI's build, and petrinaut-opt's codegen inputs include the bindings' *.py sources.

🛡 What tests cover this?

  • Bindings: every test from the deleted test_petrinaut_client.py, plus end-to-end tests that spawn the built CLI for a run and an optimization study.
  • apps/petrinaut-opt: 75 tests pass against the package.
  • Build petrinaut-opt (arm64) in CI builds the rewired image.

❓ How to test this?

  1. turbo run test:unit --filter @local/petrinaut-python --filter @apps/petrinaut-opt
  2. uv run python -c "from petrinaut import OptimizationSession, PetrinautSession"

🤖 Generated with Claude Code

@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown

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

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

@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 type/eng > backend Owned by the @backend team area/tests New or updated tests area/apps type/legal Owned by the @legal team labels Aug 16, 2026
@kube kube self-assigned this Aug 16, 2026
@kube kube changed the title FE-1270: Extract Python bindings for the Petrinaut CLI FE-1270: Extract Python bindings for the Petrinaut CLI into @local/petrinaut-python Aug 16, 2026
@kube
kube deployed to pull-request August 16, 2026 18:06 — with GitHub Actions Active
@kube
kube deployed to pull-request August 16, 2026 18:06 — with GitHub Actions Active
@codspeed-hq

codspeed-hq Bot commented Aug 16, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 98 untouched benchmarks


Comparing cf/fe-1270-create-python-bindings-to-petrinaut-core (7f897d7) with main (73f48b3)1

Open in CodSpeed

Footnotes

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

@kube
kube force-pushed the cf/fe-1270-create-python-bindings-to-petrinaut-core branch from c1e9f74 to a2a4545 Compare August 17, 2026 23:51
@kube
kube deployed to pull-request August 17, 2026 23:52 — with GitHub Actions Active
@kube
kube deployed to pull-request August 17, 2026 23:52 — with GitHub Actions Active
@kube
kube force-pushed the cf/fe-1270-create-python-bindings-to-petrinaut-core branch from a2a4545 to cfbbb60 Compare August 17, 2026 23:56
@kube
kube marked this pull request as ready for review August 17, 2026 23:56
@kube
kube requested a review from a team as a code owner August 17, 2026 23:56
Copilot AI balanced review requested due to automatic review settings August 17, 2026 23:56
@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Rewires how the production optimizer image provisions and sandboxes the CLI child (prune graph, runtime path, Node permission flags). Process lifecycle is largely a move of existing code, but a packaging mistake would break study execution in stage.

Overview
Extracts the optimizer’s private CLI stdio client into a reusable @local/petrinaut-python package (petrinaut) so any Python code can run models and optimization studies without talking to the CLI itself.

PetrinautSession owns one petrinaut serve child (file or stdin model) and exposes healthz, metadata, run, and a generic request. OptimizationSession treats the manifest as opaque JSON and adds describe / evaluate / objective. Process handling is the same as before: scrubbed env, bounded reads, process-group shutdown. Unserializable caller input is now TypeError/ValueError before spawn, not a session-dead error.

petrinaut-opt now depends only on the bindings. The Docker image prunes @local/petrinaut-python (which pulls the CLI), installs the package non-editable into the venv, and links the closure’s petrinaut binary. Child Node options move to PETRINAUT_CHILD_NODE_OPTIONS; deploy change-detection also watches the new lib.

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

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 23 out of 26 changed files in this pull request and generated no new comments.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 28 out of 31 changed files in this pull request and generated no new comments.

Suppressed comments (1)

libs/@hashintel/petrinaut-cli/README.md:15

  • The architecture check described by this PR does not currently cover this new relationship. libs/@local/petrinaut-arch-docs/architecture.config.ts:34-57 registers only core, editor, and CLI; content/index.mdx:78-80 still says apps/petrinaut-opt is outside the generated model; and libs/@hashintel/petrinaut-cli/src/README.md:9-12 still says the optimizer directly spawns the CLI. Consequently the generated docs remain stale and no optimizer → python-bindings edge is enforced. Register the optimizer and bindings with layer declarations and update the stale architecture prose as part of this extraction.
The [`@local/petrinaut-python`](../../@local/petrinaut-python/README.md)
bindings drive this CLI from Python: sessions, run requests, and optimization
studies.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 28 out of 31 changed files in this pull request and generated no new comments.

Suppressed comments (1)

libs/@local/petrinaut-python/src/petrinaut/optimization.py:14

  • The stated architecture check cannot currently cover this new boundary: libs/@local/petrinaut-arch-docs/architecture.config.ts:35-57 registers only the core, editor, and CLI packages, while src/extract.ts:158-165 explicitly rejects Python packages because no extractor exists. As a result, the claimed optimizer → python-bindings edge is never generated or enforced, so a direct optimizer-to-CLI dependency would pass the architecture check. Add Python extraction/registration for both this package and apps/petrinaut-opt (with their layer declarations and graph wiring), or remove the claim and track that enforcement separately.
class OptimizationSession(PetrinautSession):

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 28 out of 31 changed files in this pull request and generated no new comments.

Suppressed comments (2)

libs/@local/petrinaut-python/src/petrinaut/session.py:328

  • PetrinautClientError means the process/transport is unusable (errors.py:6-7), and request() explicitly promises that this exception closes the session (lines 204-207). This branch deliberately leaves the session healthy, so callers cannot use the documented exception type to decide whether the session can be reused. Treat non-serializable params as caller input—consistent with the constructor’s ValueErrors—rather than as a transport failure.
    libs/@local/petrinaut-python/README.md:79
  • The uppercase constants are defaults, not constructor option names. A caller following this text and passing BOOTSTRAP_TIMEOUT_SECONDS= will get an unexpected-keyword TypeError; name bootstrap_timeout_seconds and request_timeout_seconds as the options and identify the constants as their defaults.
- Bootstrap (spawn to readiness) and each protocol response have deadlines,
  `BOOTSTRAP_TIMEOUT_SECONDS` and `PROTOCOL_READ_TIMEOUT_SECONDS`. Both are
  constructor options.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.63%. Comparing base (d8bfbe9) to head (42147aa).
⚠️ Report is 4 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #9228   +/-   ##
=======================================
  Coverage   59.63%   59.63%           
=======================================
  Files        1420     1420           
  Lines      138775   138775           
  Branches     6557     6557           
=======================================
  Hits        82753    82753           
  Misses      54958    54958           
  Partials     1064     1064           
Flag Coverage Δ
rust.hash-graph-api 7.36% <ø> (ø)
rust.hash-graph-store 46.78% <ø> (ø)
rust.hash-graph-temporal-versioning 47.95% <ø> (ø)
rust.hash-graph-validation 84.71% <ø> (ø)
rust.hashql-ast 89.63% <ø> (ø)
rust.hashql-syntax-jexpr 94.04% <ø> (ø)

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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@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 2009728. Configure here.

Comment thread libs/@local/petrinaut-python/src/petrinaut/session.py
YannisZa
YannisZa previously approved these changes Aug 21, 2026

@YannisZa YannisZa left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Many thanks @kube! Does this PR imply that the petrinaut_client.py is now obsolete?

Copy link
Copy Markdown
Contributor

I think its worth addressing the cursor issue here too. Sorry forgot to mention it earlier!

Adds libs/@local/petrinaut-python: a stdlib-only, POSIX-only package
wrapping the CLI's JSON-lines protocol. PetrinautSession serves a model
(from a file or over stdin) with healthz/metadata/run plus a generic
request method; OptimizationSession adds describe/evaluate/objective over
an opaque manifest, and evaluate returns per-seed replicates when the
manifest asks for more than one seed. The code comes from petrinaut-opt's
client: spawn scrubbing, bounded reads, and process-group shutdown are
unchanged.

petrinaut-opt consumes the package as an editable uv path dependency,
mirrored as a workspace:* edge so Turbo pruning and change detection see
it; its codegen inputs, the Docker python-deps/runner stages, and the
deploy path filter follow. The old src/petrinaut_client.py, the
PYTHON_INTEGRATION.md walkthrough, and examples/python_stdio.py are
retired, and MODEL_EXAMPLES.md now uses the bindings. Two end-to-end
pytests drive the real built CLI bundle, one per session type.
@kube

kube commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

@YannisZa

Does this PR imply that the petrinaut_client.py is now obsolete?

Yes, petrinaut_client.py is now called session.py and is part of the Python bindings package.

petrinaut-opt does not have to deal with petrinaut-cli anymore, only consume the Python library.

Copy link
Copy Markdown
Contributor

Yes, petrinaut_client.py is now called session.py and is part of the Python bindings package.

This naming is a bit confusing. optimization.py is also a session but for consuming optimisation manifests. My understanding is that these scripts are still clients/wrappers for petrinaut-cli, right?

To add to these, why do we need a petrinaut directory within @local/petrinaut-python/src ?

kube added 2 commits August 21, 2026 13:58
The method sat on a class already named OptimizationSession, while its
siblings evaluate() and objective() carry no prefix. describe() maps 1:1
to the protocol's optimization.describe. The previous name remains as a
class-level alias. Raised in review on #9228.
Encoding failures happen before anything is written: params or a
bootstrap payload that will not serialize to JSON raise TypeError, and a
payload over the line cap raises ValueError. Both previously raised
PetrinautClientError, whose contract says the process or transport is no
longer usable — a caller treating it as terminal would discard a healthy
session. The request id is now consumed only after a successful encode,
so a rejected request leaves the session exactly as it was. Raised by
Cursor and in review on #9228.
@kube

kube commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

To add to these, why do we need a petrinaut directory within @local/petrinaut-python/src ?

This seems to be a pretty established convention, and is what uv init does by default:

https://docs.astral.sh/uv/guides/projects/

@kube

kube commented Aug 21, 2026

Copy link
Copy Markdown
Collaborator Author

This naming is a bit confusing. optimization.py is also a session but for consuming optimisation manifests. My understanding is that these scripts are still clients/wrappers for petrinaut-cli, right?

Yes, I'm gonna rename that, and they are still binding/wrappers for petrinaut-cli calls, but the idea being that you do not have to care about it when using it.
It could in the future communicate with/use petrinaut-core differently.

@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 $$19.7 \mathrm{ms} \pm 160 \mathrm{μs}\left({\color{gray}-1.599 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.62 \mathrm{ms} \pm 14.0 \mathrm{μs}\left({\color{gray}-3.542 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$9.65 \mathrm{ms} \pm 77.4 \mathrm{μs}\left({\color{gray}-2.139 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$32.7 \mathrm{ms} \pm 254 \mathrm{μs}\left({\color{gray}-4.288 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$11.1 \mathrm{ms} \pm 83.6 \mathrm{μs}\left({\color{lightgreen}-7.321 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$18.3 \mathrm{ms} \pm 134 \mathrm{μs}\left({\color{gray}-4.689 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$20.7 \mathrm{ms} \pm 150 \mathrm{μs}\left({\color{gray}-1.818 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.89 \mathrm{ms} \pm 11.4 \mathrm{μs}\left({\color{gray}-3.184 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$10.4 \mathrm{ms} \pm 120 \mathrm{μs}\left({\color{gray}-2.942 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$2.87 \mathrm{ms} \pm 16.1 \mathrm{μs}\left({\color{gray}-0.612 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.30 \mathrm{ms} \pm 10.7 \mathrm{μs}\left({\color{gray}-0.805 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$2.58 \mathrm{ms} \pm 11.8 \mathrm{μs}\left({\color{gray}-0.665 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$3.92 \mathrm{ms} \pm 26.0 \mathrm{μs}\left({\color{gray}-2.920 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.72 \mathrm{ms} \pm 14.7 \mathrm{μs}\left({\color{gray}-2.874 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$3.18 \mathrm{ms} \pm 19.8 \mathrm{μs}\left({\color{gray}-4.660 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$3.32 \mathrm{ms} \pm 18.0 \mathrm{μs}\left({\color{gray}-1.130 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.66 \mathrm{ms} \pm 17.4 \mathrm{μs}\left({\color{gray}-1.006 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$3.14 \mathrm{ms} \pm 17.5 \mathrm{μs}\left({\color{gray}-0.814 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.05 \mathrm{ms} \pm 10.3 \mathrm{μs}\left({\color{gray}-1.265 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$1.93 \mathrm{ms} \pm 10.6 \mathrm{μs}\left({\color{gray}-0.294 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$2.04 \mathrm{ms} \pm 10.2 \mathrm{μs}\left({\color{gray}-0.090 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.25 \mathrm{ms} \pm 13.7 \mathrm{μs}\left({\color{gray}0.221 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.11 \mathrm{ms} \pm 11.7 \mathrm{μs}\left({\color{gray}-1.122 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.25 \mathrm{ms} \pm 12.2 \mathrm{μs}\left({\color{gray}0.290 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$2.33 \mathrm{ms} \pm 15.3 \mathrm{μs}\left({\color{gray}0.339 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.10 \mathrm{ms} \pm 9.52 \mathrm{μs}\left({\color{gray}-1.203 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$2.30 \mathrm{ms} \pm 9.96 \mathrm{μs}\left({\color{gray}0.488 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$2.60 \mathrm{ms} \pm 12.6 \mathrm{μs}\left({\color{gray}-0.880 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.29 \mathrm{ms} \pm 13.0 \mathrm{μs}\left({\color{gray}-1.233 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$2.52 \mathrm{ms} \pm 15.5 \mathrm{μs}\left({\color{gray}-0.872 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$2.56 \mathrm{ms} \pm 15.6 \mathrm{μs}\left({\color{gray}-0.380 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.27 \mathrm{ms} \pm 15.1 \mathrm{μs}\left({\color{gray}-1.817 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$2.52 \mathrm{ms} \pm 12.7 \mathrm{μs}\left({\color{gray}-0.531 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$32.4 \mathrm{ms} \pm 155 \mathrm{μs}\left({\color{lightgreen}-5.821 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$25.5 \mathrm{ms} \pm 176 \mathrm{μs}\left({\color{gray}-1.894 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$27.7 \mathrm{ms} \pm 116 \mathrm{μs}\left({\color{gray}-4.117 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$24.8 \mathrm{ms} \pm 128 \mathrm{μs}\left({\color{gray}-1.302 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$33.0 \mathrm{ms} \pm 216 \mathrm{μs}\left({\color{gray}-4.196 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$38.1 \mathrm{ms} \pm 194 \mathrm{μs}\left({\color{gray}-1.846 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$31.5 \mathrm{ms} \pm 245 \mathrm{μs}\left({\color{lightgreen}-6.241 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$69.5 \mathrm{ms} \pm 437 \mathrm{μs}\left({\color{lightgreen}-8.211 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$26.3 \mathrm{ms} \pm 100 \mathrm{μs}\left({\color{gray}-4.940 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$215 \mathrm{ms} \pm 1.01 \mathrm{ms}\left({\color{lightgreen}-12.115 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$8.42 \mathrm{ms} \pm 40.0 \mathrm{μs}\left({\color{gray}-1.150 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$8.59 \mathrm{ms} \pm 48.9 \mathrm{μs}\left({\color{gray}-1.057 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$8.54 \mathrm{ms} \pm 70.3 \mathrm{μs}\left({\color{gray}-3.318 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$8.51 \mathrm{ms} \pm 54.1 \mathrm{μs}\left({\color{gray}1.75 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$8.54 \mathrm{ms} \pm 40.3 \mathrm{μs}\left({\color{gray}-3.581 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$8.41 \mathrm{ms} \pm 42.0 \mathrm{μs}\left({\color{gray}-3.297 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$8.52 \mathrm{ms} \pm 47.0 \mathrm{μs}\left({\color{gray}-1.076 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$8.54 \mathrm{ms} \pm 68.3 \mathrm{μs}\left({\color{gray}-2.072 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$8.58 \mathrm{ms} \pm 45.1 \mathrm{μs}\left({\color{lightgreen}-6.470 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$8.96 \mathrm{ms} \pm 56.1 \mathrm{μs}\left({\color{gray}-4.091 \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.72 \mathrm{ms} \pm 38.2 \mathrm{μs}\left({\color{gray}-1.261 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$8.93 \mathrm{ms} \pm 79.3 \mathrm{μs}\left({\color{gray}1.38 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$8.74 \mathrm{ms} \pm 43.4 \mathrm{μs}\left({\color{gray}0.029 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$8.88 \mathrm{ms} \pm 46.7 \mathrm{μs}\left({\color{gray}0.736 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$8.83 \mathrm{ms} \pm 60.8 \mathrm{μs}\left({\color{gray}0.939 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$8.88 \mathrm{ms} \pm 51.7 \mathrm{μs}\left({\color{gray}-0.159 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$8.84 \mathrm{ms} \pm 49.4 \mathrm{μs}\left({\color{gray}0.724 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$8.72 \mathrm{ms} \pm 41.6 \mathrm{μs}\left({\color{gray}-0.436 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$8.75 \mathrm{ms} \pm 50.4 \mathrm{μs}\left({\color{gray}-0.773 \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.49 \mathrm{ms} \pm 35.5 \mathrm{μs}\left({\color{gray}0.718 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$46.2 \mathrm{ms} \pm 305 \mathrm{μs}\left({\color{gray}-2.163 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$84.8 \mathrm{ms} \pm 409 \mathrm{μs}\left({\color{gray}-3.364 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$52.6 \mathrm{ms} \pm 398 \mathrm{μs}\left({\color{gray}-1.082 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$58.6 \mathrm{ms} \pm 464 \mathrm{μs}\left({\color{gray}-4.395 \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.9 \mathrm{ms} \pm 447 \mathrm{μs}\left({\color{gray}-3.478 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$71.2 \mathrm{ms} \pm 397 \mathrm{μs}\left({\color{gray}1.03 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$33.3 \mathrm{ms} \pm 342 \mathrm{μs}\left({\color{gray}-1.708 \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 $$55.7 \mathrm{ms} \pm 318 \mathrm{μs}\left({\color{gray}-1.859 \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 $$38.4 \mathrm{ms} \pm 204 \mathrm{μs}\left({\color{gray}-2.215 \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 $$45.9 \mathrm{ms} \pm 257 \mathrm{μs}\left({\color{gray}-1.452 \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 $$47.6 \mathrm{ms} \pm 247 \mathrm{μs}\left({\color{gray}-0.643 \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 $$47.5 \mathrm{ms} \pm 263 \mathrm{μs}\left({\color{gray}-1.222 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$94.1 \mathrm{ms} \pm 423 \mathrm{μs}\left({\color{gray}-2.263 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$105 \mathrm{ms} \pm 430 \mathrm{μs}\left({\color{gray}-0.810 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$14.4 \mathrm{ms} \pm 70.2 \mathrm{μs}\left({\color{gray}-3.615 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$424 \mathrm{ms} \pm 767 \mathrm{μs}\left({\color{gray}-3.710 \mathrm{\%}}\right) $$ Flame Graph

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps 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) area/tests New or updated tests type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team type/legal Owned by the @legal team

Development

Successfully merging this pull request may close these issues.

4 participants