Skip to content

FE-1437: Move brunch-agent into hashintel/hash with its history - #9274

Merged
lunelson merged 65 commits into
mainfrom
ln/fe-1437-hash-monorepo-import
Aug 25, 2026
Merged

FE-1437: Move brunch-agent into hashintel/hash with its history#9274
lunelson merged 65 commits into
mainfrom
ln/fe-1437-hash-monorepo-import

Conversation

@lunelson

@lunelson lunelson commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

🌟 What is the purpose of this PR?

Brunch — the elicitation-agent harness developed to date in the standalone brunch-lite repository — moves into hashintel/hash, which becomes its sole writable home. This branch imports the standalone history, renames the package family to @hashintel/brunch-agent* under libs/@hashintel/brunch-agent/ (application at apps/brunch-agent), and adopts the HASH toolchain (Yarn/Turbo, Biome, Vitest) in place of Bun.

🔗 Related links

  • FE-1437: Move brunch-agent into hashintel/hash with its history (internal)
  • Execution plan: libs/@hashintel/brunch-agent/docs/planning/_shared/hash-monorepo-import-plan.md
  • Decision record: libs/@hashintel/brunch-agent/docs/adr/0004-in-petrinaut-staging-and-the-monorepo-import.md
  • Standalone repository frozen at 43a0022918861846344b96a32cb94f92e2ee96ae (read-only reference)

🚫 Blocked by

Nothing — the import gates (FE-1434/FE-1435 spike verdicts, standalone review stack) all landed before the cutover.

🔍 What does this change?

Adds the Brunch package family as five new workspaces: the substrate-independent harness (@hashintel/brunch-agent), the Flue binding, the AI SDK transport, the Gherkin target plugin, and the application at apps/brunch-agent. It also lands the first slice of the Petrinaut website integration — a generic interactive-tool extension point in @hashintel/petrinaut (with changeset) and an app-level Brunch ask tool in apps/petrinaut-website — which the trimmed FE-1440 builds on. Boundary rules survive as enforced tests: plugins depend only on the harness, transports never on a binding, @hashintel/petrinaut stays Brunch-agnostic, and applications are the only Brunch–Petrinaut meeting point.

🏗️ Agent notes

Final physical shape

hash/
├── apps/
│   └── brunch-agent/                 # runnable composition application
│
└── libs/@hashintel/brunch-agent/     # Brunch context root; not a workspace
    ├── CONTEXT.md
    ├── AGENTS.md / CLAUDE.md
    ├── docs/
    ├── scripts/
    └── packages/
        ├── core/
        ├── binding-flue/
        ├── transport-aisdk/
        └── plugin-gherkin/

The existing root workspace globs, apps/** and libs/**, already discover these nested packages. No new root workspace rule or context-root package.json was needed.

Package identities and dependency graph

The standalone names became HASH-native:

  • @brunch/core@hashintel/brunch-agent
  • @brunch/binding-flue@hashintel/brunch-agent-binding-flue
  • @brunch/transport-aisdk@hashintel/brunch-agent-transport-aisdk
  • @brunch/plugin-gherkin@hashintel/brunch-agent-plugin-gherkin
  • @brunch/dev@apps/brunch-agent
plugin-gherkin ───────┐
                      ▼
                 brunch-agent core
                    ▲       ▲
                    │       │
          binding-flue   transport-aisdk
              │               │
              ▼               ▼
         Flue substrate     AI SDK wire

apps/brunch-agent → composes all four

The planned invariants remain:

  • Core knows no Flue or other substrate.
  • Plugins depend only on core.
  • The binding joins core to Flue, but never owns plugins.
  • The transport joins core to the AI SDK wire format.
  • Only the app composes the full system.
  • apps/brunch-agent remains independent of Petrinaut packages; apps/petrinaut-website is the Brunch/Petrinaut meeting point.

All packages are private, use 0.0.0-private, carry the HASH license, use workspace:* internally, and have versions reconciled through the HASH lockfile and constraints.

Toolchain rewiring

The largest incidental adaptation was removing the standalone Bun toolchain.

  • Bun workspace discovery → root Yarn workspaces.
  • Bun task orchestration → Turbo package tasks.
  • bun:test → Vitest.
  • Bun.spawn → a shared Node child-process helper.
  • Bun.file → Node fs APIs.
  • Bun.spawnSync → Node child_process.
  • Bun script execution → Node's type-stripping mode where scripts remain TypeScript.
  • Standalone root TypeScript/Bun/Oxfmt/CI configuration was retired.

Each workspace now exposes HASH-shaped tasks:

  • build
  • lint:eslint
  • lint:tsc
  • test:unit
  • app-specific dev tasks where appropriate

TypeScript configuration was split per package, using strict bundler resolution, tsgo, explicit Node/DOM types, and explicit .ts extensions where Node executes source directly.

Build reshaping

Each library became an independently built Vite ESM library:

  • Core emits main, client-tools, storage, and testing entry points.
  • Binding, plugin, and transport each emit standalone ESM output.
  • The transport additionally emits its browser-safe client-tools entry point.
  • External dependencies remain external rather than being bundled.
  • Sourcemaps are emitted.
  • The app separately builds its server and browser client.

An attempted declaration-bundling setup exposed incompatibilities with Brunch's Valibot value/type same-name pattern. The resulting private-package contract is therefore deliberately:

types   → src/*.ts
runtime → dist/*.js

That preserved type ownership without forcing changes to the domain schemas merely to satisfy a declaration bundler.

The app also gained a dedicated vitest.config.ts: loading its full Vite/Flue configuration under Vitest caused the Flue build plugin to execute in an incompatible SSR context.

Test ownership reshaping

The old repository-level tests were distributed according to what they govern:

  • Package unit tests live with each package.
  • Family-wide architecture tests live under core/test/architecture/.
  • App integration, runtime, and built-artifact tests live under apps/brunch-agent/test/.
  • The transport's pure wire tests remain with the transport.
  • Its server composition test moved to the app because it exercises transport + binding + host.
  • Transport fixtures moved alongside the transport.
  • Baseline-runner and documentation-governance tests became architecture tests.

The architecture scanner was rewritten for the new topology. It discovers:

  • all children of libs/@hashintel/brunch-agent/packages/;
  • the separate apps/brunch-agent workspace.

Its dependency proof also changed. Bun's isolated installation allowed tests to assert that forbidden packages physically could not resolve. HASH's Yarn linker may hoist dependencies, so that would have become a false proof. The replacement checks:

  • declared runtime dependencies;
  • actual authored imports;
  • package-role naming;
  • source coverage;
  • absence of forbidden substrate imports.

Documentation and agent-context reshaping

The nested directory became a true domain context:

  • CONTEXT.md remains the canonical Brunch glossary.
  • AGENTS.md and CLAUDE.md were rewritten for operation inside HASH.
  • App-level guidance points back to the context root.
  • docs/spec.md remains authoritative.
  • Completed elicitation planning moved under docs/history/.
  • Living planning, ADRs, references, baseline material, and scripts stayed locally available.
  • The documentation index and boundary-test paths were updated.
  • Git workflow guidance was adapted to HASH.
  • Baseline and Linear scripts are exposed through package commands despite the context root having no manifest.

Import-process adaptations

The Git history was imported in four deliberately separate stages:

  1. Import the frozen standalone ancestry.
  2. Format files while they still occupied the import path.
  3. Mechanically move them to final HASH paths.
  4. Rewrite manifests, runtime APIs, tests, and lockfile for HASH.

That unusual order was discovered during execution:

  • Moving manifests too early caused Yarn's pre-commit validation to reject an intermediate workspace state.
  • Moving unformatted files caused HASH formatting hooks to obscure the mechanical rename.
  • Formatting before moving preserved a legible path-only move commit.

Post-review follow-ups

The review follow-ups:

  • add package-level turbo.json files so build outputs and dependency builds are explicit;
  • restore scoped ignores for .flue/, .data-wipe-me/, and documentation drafts;
  • repair relative links after documentation relocation;
  • add a test preventing future internal documentation-link rot;
  • keep core-owned boundary gates intact where migration tests proved them;
  • retain source-type/runtime-dist exports rather than adopting declaration bundling that breaks merged schema/type exports.

Petrinaut integration

The imported transport is wired into the Petrinaut demo without coupling the Brunch application to Petrinaut:

  • Petrinaut accepts host-owned interactive tools through an opaque registry capability.
  • The website supplies a typed inline brunch_ask widget.
  • Brunch and Petrinaut share the canonical ask input/output contracts.
  • AI SDK continuation accepts the real browser tool-brunch_ask payload shape.
  • Assistant message identity is preserved across ask/answer continuation.
  • The end-to-end chat path was verified in local development without duplicate questions or continuation errors.
  • The unrelated Brunch Actual-mode fixture remains outside this integration.

Type ownership

The host-tool extension preserves source-of-truth typing:

  • Brunch ask input/output types are inferred from canonical Valibot schemas.
  • The website imports those contracts and parsers instead of recreating them with local Zod schemas.
  • Petrinaut's built-in tool submissions retain their concrete types.
  • Auto-layout decisions are distinct from persisted results.
  • Heterogeneous host tools erase their private generics only inside an opaque capability.
  • Remaining unknown values are confined to genuine runtime boundaries such as raw AI SDK dynamic-tool data.

Post-import branch state

  • Import gates re-verified on the final tip: workspace constraints pass with no Brunch exemptions; build, lint, typecheck, and 173 unit tests green across the five workspaces (core 114, binding-flue 16, transport-aisdk 11, plugin-gherkin 2, app 30); boundary tests including a mutation proof (an injected illegal import fails exactly the intended gate); hermetic faux-provider runtime POST test; no Bun residue; git log --follow/blame continuity into pre-import commits.
  • The imported subtree is byte-identical to the frozen brunch-lite tree at the import commit.
  • Post-import commits on the branch: docs/tense settlement after the cutover, the FE-1440 trim record, the PR-template guidance integration, the Petrinaut changeset, and the switch of the Brunch stacking convention from gh stack to Graphite (matching HASH's repo-wide Graphite use).
  • Known environmental issue unrelated to this branch: tsx cannot create its IPC pipe on the dev machine (listen EPERM), breaking @hashintel/ds-components#codegen locally; no branch commit touches ds-components.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies an npm-publishable library and I have added a changeset file(s)

@hashintel/petrinaut gains the interactive-tool extension point (patch changeset); the imported Brunch packages are all 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

Brunch context, architecture, planning, and operating documentation were updated for HASH, and the Petrinaut AI assistant guide documents host-specific interactive widgets.

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

The changes in this PR:

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

⚠️ Known issues

  • Squash-merging (the repo convention) collapses the imported history into one commit on main; the full standalone history remains preserved on this branch and in the PR record, and the standalone repository stays available read-only at the frozen SHA.
  • Screenshots showing the Petrinaut AI chat flow should be refreshed to include the inline Brunch question widget.

🐾 Next steps

  • FE-1440 (trimmed): the elicitor mode in apps/petrinaut-website — mode switch, browser identifier bootstrap, remote transport swap
  • FE-1438 client-tool round-trip and FE-1439 private durable sessions, now advanced in this repository
  • FE-1441: deployment of the remote Brunch server
  • Add or refresh the Petrinaut chat-flow screenshot

🛡 What tests cover this?

  • Brunch package unit, architecture, runtime-entrypoint, and built-artifact tests.
  • Transport ask/reply continuation tests using the browser payload shape.
  • Petrinaut interactive registry and auto-layout widget tests.
  • TypeScript and ESLint checks across the Brunch packages, Petrinaut library, and Petrinaut website.
  • Vite builds for the application and affected libraries.
  • Petrinaut architecture-document lint.

The final focused verification completed 23/23 Turbo tasks. Brunch core completed 114/114 tests.

❓ How to test this?

  1. Run:

    turbo run build test:unit lint:tsc lint:eslint \
      --filter '@hashintel/brunch-agent' \
      --filter '@hashintel/brunch-agent-transport-aisdk' \
      --filter '@hashintel/petrinaut' \
      --filter '@apps/petrinaut-website'
  2. Run:

    yarn workspace @local/petrinaut-arch-docs lint:arch-docs
  3. Start the Brunch agent and Petrinaut website development servers.

  4. Open the Petrinaut local-storage demo and send an elicitation prompt.

  5. Confirm the inline Brunch question renders, accepts an answer, and continues the same assistant message without errors or duplication.

📹 Demo

The local browser flow has been manually verified. A refreshed screenshot should be added before merge.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Aug 21, 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 24, 2026 4:27pm
hashdotdesign-tokens Ready Ready Preview Aug 24, 2026 4:27pm
petrinaut Ready Ready Preview Aug 24, 2026 4:27pm
petrinaut-docs Ready Ready Preview Aug 24, 2026 4:27pm

@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/tests New or updated tests area/apps labels Aug 21, 2026

lunelson commented Aug 21, 2026

Copy link
Copy Markdown
Contributor Author

@lunelson lunelson changed the title Initialize repo: agent config, wayfinder map, elicitation-kernel planning state FE-1437: Import Brunch agent into the HASH monorepo Aug 21, 2026
@codecov

codecov Bot commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 60.10%. Comparing base (357589c) to head (27fa5c5).
⚠️ Report is 10 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9274      +/-   ##
==========================================
+ Coverage   59.71%   60.10%   +0.39%     
==========================================
  Files        1423     1314     -109     
  Lines      138862   132988    -5874     
  Branches     6572     6190     -382     
==========================================
- Hits        82915    79933    -2982     
+ Misses      54881    52034    -2847     
+ Partials     1066     1021      -45     
Flag Coverage Δ
apps.hash-ai-worker-py ?
apps.hash-ai-worker-ts 1.99% <ø> (ø)
apps.hash-api 14.66% <ø> (ø)
backend-integration-tests ?
blockprotocol.type-system 40.84% <ø> (ø)
deer ?
error-stack ?
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% <ø> (ø)
local.hash-subgraph ?
rust.antsi 2.36% <ø> (ø)
rust.deer ?
rust.error-stack 90.81% <ø> (ø)
rust.harpc-codec 84.70% <ø> (ø)
rust.harpc-net 96.23% <ø> (+0.01%) ⬆️
rust.harpc-tower 67.03% <ø> (ø)
rust.harpc-types 0.00% <ø> (ø)
rust.harpc-wire-protocol 92.23% <ø> (ø)
rust.hash-codec 72.76% <ø> (ø)
rust.hash-graph-api 11.00% <ø> (+3.50%) ⬆️
rust.hash-graph-authentication 91.78% <ø> (+7.81%) ⬆️
rust.hash-graph-authorization 62.59% <ø> (ø)
rust.hash-graph-embeddings 91.88% <ø> (ø)
rust.hash-graph-postgres-store 29.33% <ø> (ø)
rust.hash-graph-store 46.78% <ø> (ø)
rust.hash-graph-temporal-versioning 47.95% <ø> (ø)
rust.hash-graph-types 0.00% <ø> (ø)
rust.hash-graph-validation 84.71% <ø> (ø)
rust.hashql-ast 89.63% <ø> (ø)
rust.hashql-compiletest 28.39% <ø> (ø)
rust.hashql-core 78.98% <ø> (ø)
rust.hashql-diagnostics 72.51% <ø> (ø)
rust.hashql-eval 79.82% <ø> (ø)
rust.hashql-hir 89.09% <ø> (ø)
rust.hashql-mir 87.92% <ø> (ø)
rust.hashql-syntax-jexpr 94.04% <ø> (ø)
rust.sarif ?
sarif ?
tests.hash-backend-integration ?
unit-tests ?

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.

Comment thread libs/@hashintel/brunch-agent/packages/core/src/naming.ts
Comment thread libs/@hashintel/brunch-agent/packages/core/src/naming.ts Dismissed
@codspeed-hq

codspeed-hq Bot commented Aug 21, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 98 untouched benchmarks


Comparing ln/fe-1437-hash-monorepo-import (27fa5c5) with main (ab96828)1

Open in CodSpeed

Footnotes

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

@lunelson
lunelson force-pushed the ln/fe-1437-hash-monorepo-import branch from b898a9d to 65c318b Compare August 21, 2026 14:28
@lunelson
lunelson marked this pull request as ready for review August 21, 2026 14:28
@cursor

cursor Bot commented Aug 21, 2026

Copy link
Copy Markdown

PR Summary

High Risk
Adds a remote elicitation server, conversation storage, and a Petrinaut chat transport with CORS, request validation, and tool-reply admission. It also changes CI prune behavior for Brunch jobs.

Overview
Imports the Brunch elicitation harness into HASH as the native home: a context root under libs/@hashintel/brunch-agent, four private packages (core, Flue binding, AI SDK transport, Gherkin plugin), and apps/brunch-agent as the remote Flue server. The family is Yarn/Turbo/Vitest-shaped, with architecture tests that keep plugins on the harness only, transports binding-free, and Brunch–Petrinaut composition in applications.

The app mounts a Gherkin elicitor, durable SQLite conversations, a local capture store, and /api/chat that streams Petrinaut-compatible AI SDK events—including brunch_ask suspend/return with history-backed admission. petrinaut:dev proxies the real panel without editing HASH’s tracked website.

Petrinaut gains a host-owned interactive-tool registry (patch changeset). The local-storage demo registers an inline brunch_ask widget using the transport’s client-tool contracts. CI prune now copies Brunch context files and the app only when @hashintel/brunch-agent is the requested scope, so sibling jobs do not pull that fixture.

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

Comment thread apps/brunch-agent/package.json
@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 $$16.2 \mathrm{ms} \pm 90.8 \mathrm{μs}\left({\color{gray}-0.068 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.12 \mathrm{ms} \pm 12.7 \mathrm{μs}\left({\color{gray}-1.322 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$7.79 \mathrm{ms} \pm 67.3 \mathrm{μs}\left({\color{gray}1.74 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$26.7 \mathrm{ms} \pm 183 \mathrm{μs}\left({\color{gray}-1.103 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$9.54 \mathrm{ms} \pm 72.0 \mathrm{μs}\left({\color{gray}-4.083 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$15.8 \mathrm{ms} \pm 119 \mathrm{μs}\left({\color{gray}1.14 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$17.2 \mathrm{ms} \pm 123 \mathrm{μs}\left({\color{gray}1.11 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.32 \mathrm{ms} \pm 12.0 \mathrm{μs}\left({\color{gray}-2.502 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$8.29 \mathrm{ms} \pm 69.3 \mathrm{μs}\left({\color{gray}2.80 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$2.30 \mathrm{ms} \pm 15.3 \mathrm{μs}\left({\color{gray}0.727 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$1.89 \mathrm{ms} \pm 7.91 \mathrm{μs}\left({\color{gray}0.476 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$2.13 \mathrm{ms} \pm 15.1 \mathrm{μs}\left({\color{gray}0.362 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$3.18 \mathrm{ms} \pm 21.6 \mathrm{μs}\left({\color{gray}0.813 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.25 \mathrm{ms} \pm 18.4 \mathrm{μs}\left({\color{gray}0.522 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$2.53 \mathrm{ms} \pm 13.2 \mathrm{μs}\left({\color{gray}-0.064 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$2.65 \mathrm{ms} \pm 19.1 \mathrm{μs}\left({\color{gray}-0.192 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.18 \mathrm{ms} \pm 13.4 \mathrm{μs}\left({\color{gray}0.951 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$2.48 \mathrm{ms} \pm 15.2 \mathrm{μs}\left({\color{gray}-1.690 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$1.68 \mathrm{ms} \pm 7.27 \mathrm{μs}\left({\color{gray}-1.013 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$1.57 \mathrm{ms} \pm 6.84 \mathrm{μs}\left({\color{gray}0.394 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$1.68 \mathrm{ms} \pm 8.28 \mathrm{μs}\left({\color{gray}0.227 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$1.85 \mathrm{ms} \pm 8.55 \mathrm{μs}\left({\color{gray}-1.151 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$1.73 \mathrm{ms} \pm 7.50 \mathrm{μs}\left({\color{gray}-0.301 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$1.86 \mathrm{ms} \pm 11.6 \mathrm{μs}\left({\color{gray}0.894 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$1.89 \mathrm{ms} \pm 10.4 \mathrm{μs}\left({\color{gray}0.801 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$1.71 \mathrm{ms} \pm 7.55 \mathrm{μs}\left({\color{gray}-1.784 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$1.90 \mathrm{ms} \pm 11.9 \mathrm{μs}\left({\color{gray}0.728 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$2.10 \mathrm{ms} \pm 10.7 \mathrm{μs}\left({\color{gray}-0.047 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$1.89 \mathrm{ms} \pm 9.56 \mathrm{μs}\left({\color{gray}1.45 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$2.07 \mathrm{ms} \pm 10.4 \mathrm{μs}\left({\color{gray}0.989 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$2.06 \mathrm{ms} \pm 11.0 \mathrm{μs}\left({\color{gray}1.35 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$1.88 \mathrm{ms} \pm 9.83 \mathrm{μs}\left({\color{gray}0.316 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$2.04 \mathrm{ms} \pm 13.2 \mathrm{μs}\left({\color{gray}0.743 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$26.8 \mathrm{ms} \pm 157 \mathrm{μs}\left({\color{gray}0.864 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$22.0 \mathrm{ms} \pm 138 \mathrm{μs}\left({\color{gray}2.07 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$22.9 \mathrm{ms} \pm 113 \mathrm{μs}\left({\color{gray}0.144 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$21.0 \mathrm{ms} \pm 130 \mathrm{μs}\left({\color{gray}0.664 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$26.3 \mathrm{ms} \pm 147 \mathrm{μs}\left({\color{gray}-2.365 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$30.8 \mathrm{ms} \pm 172 \mathrm{μs}\left({\color{gray}1.24 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$25.6 \mathrm{ms} \pm 169 \mathrm{μs}\left({\color{gray}1.45 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$52.8 \mathrm{ms} \pm 326 \mathrm{μs}\left({\color{gray}2.96 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$22.1 \mathrm{ms} \pm 134 \mathrm{μs}\left({\color{gray}1.17 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$159 \mathrm{ms} \pm 612 \mathrm{μs}\left({\color{gray}0.407 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$7.24 \mathrm{ms} \pm 68.6 \mathrm{μs}\left({\color{gray}3.61 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$7.12 \mathrm{ms} \pm 38.0 \mathrm{μs}\left({\color{gray}0.499 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$7.15 \mathrm{ms} \pm 49.0 \mathrm{μs}\left({\color{gray}1.22 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$7.18 \mathrm{ms} \pm 50.8 \mathrm{μs}\left({\color{gray}2.10 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$7.32 \mathrm{ms} \pm 64.3 \mathrm{μs}\left({\color{gray}2.08 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$7.11 \mathrm{ms} \pm 42.2 \mathrm{μs}\left({\color{gray}1.13 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$7.21 \mathrm{ms} \pm 36.5 \mathrm{μs}\left({\color{gray}2.86 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$7.22 \mathrm{ms} \pm 43.3 \mathrm{μs}\left({\color{gray}2.59 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$7.30 \mathrm{ms} \pm 53.2 \mathrm{μs}\left({\color{gray}2.98 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$7.44 \mathrm{ms} \pm 45.0 \mathrm{μs}\left({\color{gray}-0.283 \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 $$7.37 \mathrm{ms} \pm 46.0 \mathrm{μs}\left({\color{gray}-1.584 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$7.40 \mathrm{ms} \pm 40.6 \mathrm{μs}\left({\color{gray}0.944 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$7.32 \mathrm{ms} \pm 39.7 \mathrm{μs}\left({\color{gray}-2.791 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$7.33 \mathrm{ms} \pm 34.5 \mathrm{μs}\left({\color{gray}0.189 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$7.37 \mathrm{ms} \pm 40.5 \mathrm{μs}\left({\color{gray}-1.282 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$7.36 \mathrm{ms} \pm 39.1 \mathrm{μs}\left({\color{gray}-1.215 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$7.33 \mathrm{ms} \pm 38.7 \mathrm{μs}\left({\color{gray}-0.214 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$7.42 \mathrm{ms} \pm 44.5 \mathrm{μs}\left({\color{gray}-1.213 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$7.40 \mathrm{ms} \pm 43.2 \mathrm{μs}\left({\color{gray}0.562 \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 $$5.51 \mathrm{ms} \pm 34.4 \mathrm{μs}\left({\color{gray}1.20 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$38.8 \mathrm{ms} \pm 242 \mathrm{μs}\left({\color{gray}4.25 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$71.5 \mathrm{ms} \pm 366 \mathrm{μs}\left({\color{gray}1.11 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$43.9 \mathrm{ms} \pm 240 \mathrm{μs}\left({\color{gray}0.492 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$50.4 \mathrm{ms} \pm 315 \mathrm{μs}\left({\color{gray}3.91 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$55.9 \mathrm{ms} \pm 534 \mathrm{μs}\left({\color{gray}2.41 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$59.3 \mathrm{ms} \pm 392 \mathrm{μs}\left({\color{gray}1.01 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$27.3 \mathrm{ms} \pm 210 \mathrm{μs}\left({\color{gray}1.84 \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 $$45.5 \mathrm{ms} \pm 241 \mathrm{μs}\left({\color{gray}1.56 \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 $$31.1 \mathrm{ms} \pm 184 \mathrm{μs}\left({\color{gray}2.25 \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 $$37.6 \mathrm{ms} \pm 227 \mathrm{μs}\left({\color{gray}2.37 \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 $$38.7 \mathrm{ms} \pm 183 \mathrm{μs}\left({\color{gray}2.31 \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 $$39.4 \mathrm{ms} \pm 215 \mathrm{μs}\left({\color{gray}2.96 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$73.2 \mathrm{ms} \pm 289 \mathrm{μs}\left({\color{lightgreen}-8.023 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$80.2 \mathrm{ms} \pm 328 \mathrm{μs}\left({\color{lightgreen}-7.152 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$11.7 \mathrm{ms} \pm 77.4 \mathrm{μs}\left({\color{gray}-0.811 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$335 \mathrm{ms} \pm 615 \mathrm{μs}\left({\color{gray}1.54 \mathrm{\%}}\right) $$ Flame Graph

@lunelson
lunelson added this pull request to the merge queue Aug 25, 2026
Merged via the queue into main with commit 40811ae Aug 25, 2026
212 checks passed
@lunelson
lunelson deleted the ln/fe-1437-hash-monorepo-import branch August 25, 2026 09:07
@hash-release hash-release Bot mentioned this pull request Aug 25, 2026
@hash-release hash-release Bot mentioned this pull request Aug 25, 2026
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 > 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