Skip to content

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

Open
lunelson wants to merge 65 commits into
mainfrom
ln/fe-1437-hash-monorepo-import
Open

FE-1437: Move brunch-agent into hashintel/hash with its history#9274
lunelson wants to merge 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
lunelson and others added 17 commits August 24, 2026 18:02
Expose the long-running fixture through the task graph so local Petrinaut verification follows HASH tooling conventions.

Co-authored-by: Cursor <cursoragent@cursor.com>
Expose host interactive tools and align Brunch's AI SDK continuation protocol with real browser payloads. Remove the unrelated Actual-mode fixture wiring from this import.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep host extensibility at an opaque registry boundary while deriving Brunch wire types from their runtime schemas and separating Petrinaut decisions from persisted results.

Co-authored-by: Cursor <cursoragent@cursor.com>
Bring the context's control surfaces in line with the executed FE-1437
import:

- COORDINATION.md: rewrite the sequencing recommendation as of
  2026-08-21 (cutover executed on the import branch, hashintel/hash
  authoritative) and flip the handoff threshold to past tense.
- SPEC-LEDGER.md, topology.md, flue-architecture-cheatsheet.md: repair
  pre-import tense and vocabulary (apps/dev -> apps/brunch-agent,
  "For brunch-lite" -> "For Brunch", bun-era phrasing).
- issue-tracker.md: correct the elicitation-kernel archive path
  (docs/history/planning/) and name the ds-wayfind skill.
- domain.md: point at the ds-domain-modeling skill actually installed.
- AGENTS.md: drop the duplicated protocol list.
- apps/brunch-agent: remove a stray await on the synchronous
  agent.refresh() (the one eslint warning) and make CLAUDE.md a
  symlink to AGENTS.md, matching the context root.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
FE-1440 is trimmed to the remaining elicitor-mode wiring; the client
rendering contract travelled with the FE-1437 import branch, which is
submitted as-is.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The context's PR guidance previously prescribed a free-form two-layer
body, which conflicts with .github/pull_request_template.md. PRs now
fill the template: the purpose section carries the one-or-two-sentence
scan layer, and the what-does-this-change section carries a plain
description followed by the collapsed agent-notes record. Linear issue
guidance is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The imported agent docs mandated gh stack and prohibited gt — a late
standalone-repo convention wrongly generalized to hashintel/hash. HASH's
de facto convention is Graphite (the CI optimizer runs on it, and this
clone carries live gt metadata), and gh stack proved buggy in practice,
so the rule now points the other way: gt for stack operations, plain git
for local reads and commits, gh stack not used here. The historical
re-authoring instruction in the import plan is left as a record.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two disjoint fixes for the per-package CI jobs, which run in a
turbo-pruned tree:

- prune-repository now adds @apps/brunch-agent whenever any Brunch
  library is in scope, so the boundary suite can scan the whole package
  family the way it does in a full checkout.
- The three suites that read the Brunch context root (docs/, scripts/,
  AGENTS.md) skip when it is absent: turbo prune only copies workspace
  directories, and the context root belongs to no workspace. The
  linear-project-graph test now loads its module through a computed
  specifier so lint:tsc also passes in the pruned tree.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
data/linear-proposals-FE-1357.json tripped the preflight scan that
blocks merging any pull request whose title names a ticket still
referenced beside a task marker, for every ticket from FE-1437 through
FE-1441. The snapshot's bytes remain in git history; the validator now
carries the 29 removed proposals' identifiers and applied titles, so
subtree coverage and the GitHub PR title checks still hold, and its
expectations are recomputed for the 38 live proposals.

Also repins the two raw source snapshots' frozen hashes: the monorepo
formatter pretty-printed them during assimilation (parse-identical, and
verified against the capture-time bytes), which had silently broken the
validator. The frozen provenance manifest keeps the capture-time hashes
in its generatedFrom block.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adding @earendil-works/pi-ai (which pins @anthropic-ai/sdk@0.91.1) let
yarn fold @anthropic-ai/bedrock-sdk's >=0.50.3 <1 range onto 0.91.1,
splitting hash-ai-worker-ts across two incompatible SDK type trees and
breaking its build. The resolution keeps bedrock-sdk on the 0.74.0 the
worker already pins.

Follow-up filed to evaluate the cost of carrying this pin.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
turbo prune copies workspace directories only, so the Brunch context
root's docs/, scripts/, and agent contract files never reached the
pruned tree, and the architecture suites that read them (docs index,
baseline runner, Linear project graph) skipped in CI — leaving those
invariants a local-only gate. A new EXTRA_PATHS table in the
prune-repository action copies declared non-workspace paths into out/
after pruning, triggered by the same prefix matching as
EXTRA_DEPENDENCIES. The skipIf guards in the tests stay as a fallback
for a pruned tree where the copy rule is absent or has drifted.

Reviewers may reasonably push back on adding a copy-arbitrary-paths
mechanism to a shared CI action for one package family's benefit. If
so, reverting this commit alone is safe: the guards make the affected
suites skip in CI again rather than fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The docs tree under libs/@hashintel/brunch-agent/docs is an imported
record: it holds hash-pinned frozen data snapshots and prose whose
bytes are referenced by the migration validator, so the monorepo
formatter must not rewrite it. oxfmt's check was failing on one audit
doc's list indentation; rather than reformat the record, ignore the
tree in both oxfmt and markdownlint-cli2 and keep the imported bytes
as they are.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The license-in-workspaces check requires a LICENSE.md in every Yarn
workspace. The five imported Brunch workspaces declare AGPL-3.0 in
their manifests but shipped no license file; each now carries the
byte-identical AGPL-3.0 text the repo's other AGPL workspaces use.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@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

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