hash icon indicating copy to clipboard operation
hash copied to clipboard

[H-5747] Set up dev harness for Agentic Workflows

Open lunelson opened this issue 1 month ago • 5 comments

🌟 What is the purpose of this PR?

Ports the entity extraction and claims extraction pipeline from hash-ai-worker-ts to hash-ai-agent using the Mastra agent framework. This is an experimental foundation for migrating AI inference capabilities to a more structured, testable architecture.

🔗 Related links

  • Source implementations: apps/hash-ai-worker-ts/src/activities/flow-activities/shared/infer-summaries-then-claims-from-text/

🔍 What does this change?

Agents:

  • entitySummaryAgent - extracts named entities from text with type/summary info
  • claimExtractionAgent - extracts subject-predicate-object claims about discovered entities

Tools:

  • registerEntitySummariesTool - schema for entity registration
  • submitClaimsTool - schema for claim submission

Scorers and Fixtures:

  • entitySummariesCompositeScorer - LLM-judged scorer comparing against gold/irrelevant/wrong-type reference lists
  • claimsStructureScorer - validates claim structure and entity ID references
  • Test fixtures ported from source test-data.ts and infer-summaries-then-claims-from-text.ai.test.ts

Utilities:

  • dereference-entity-type.ts - WIP type definitions for working with entity types

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

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

📜 Does this require a change to the docs?

  • [x] are internal and do not require a docs change

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

  • [x] do not affect the execution graph

⚠️ Known issues

  • Tools return mock { submitted: true } - no actual execution logic yet
  • No orchestration workflow chaining the two agents
  • No multi-turn validation/retry (source has max 3 retries with error feedback)
  • No graph persistence for claims
  • 3 of 4 claim extraction fixtures disabled pending HTML capture

🐾 Next steps

  1. Define core types (LocalEntitySummary, Claim) in shared types file
  2. Create Mastra workflow chaining entitySummaryAgentclaimExtractionAgent
  3. Implement tool execution logic (move from mock responses)
  4. Port validation/retry logic from source
  5. Wire up HASH graph persistence for claims
  6. Capture remaining HTML fixtures and enable disabled tests

🛡 What tests cover this?

  • entity-summary-agent.test.ts - single agent extraction with runEvals + composite scorer
  • claim-extraction-agent.test.ts - WIP two-stage pipeline test (entity → claims) — not yet working

❓ How to test this?

  1. Checkout the branch
  2. Set OPENROUTER_API_KEY environment variable
  3. Run: cd apps/hash-ai-agent && yarn test
  4. Verify agents extract entities and claims from test fixtures with scores > 0.5

[!NOTE] Introduces a new Mastra-based AI agent app implementing entity and claim extraction with supporting tools, scorers, fixtures, and tests, plus project configs and dependencies.

  • Apps / New module:
    • Add @apps/hash-ai-agent (Mastra-based) with dev/build scripts, TypeScript config, Turbo task, ESLint config, and README/license.
  • Agents:
    • entitySummaryAgent for NER and claimExtractionsAgent for subject–predicate–object claims (OpenRouter Gemini models).
  • Tools:
    • registerEntitySummariesTool and submitClaims for agent outputs.
  • Evals / Scorers:
    • entitySummariesCompositeScorer and claimsStructureScorer with runEvals integration.
  • Tests & Fixtures:
    • Add extensive fixtures and tests: entity-summary-agent.test.ts, claim-extraction-agent.test.ts.
  • Mastra setup:
    • Initialize src/mastra/index.ts with in-memory LibSQL storage and logger.
  • Configs & Infra:
    • Update repo configs (biome.jsonc, .markdownlint-cli2.jsonc, .cursor/mcp.json) and add ignore patterns; add dependency resolutions and lockfile updates.

Written by Cursor Bugbot for commit 5efd576aefe76cde2c7cefbf6f9cb7e699fc9a8a. This will update automatically on new commits. Configure here.

lunelson avatar Dec 05 '25 16:12 lunelson

@vilkinsons the semgrep stuff is coming through because I tried to capture the sources that the tests rely on as static fixtures… and now it's being parsed as if it's intentional HTML, rather than foreign. do you know if there's a good way of having semgrep ignore that stuff?

lunelson avatar Dec 10 '25 12:12 lunelson

@vilkinsons the semgrep stuff is coming through because I tried to capture the sources that the tests rely on as static fixtures… and now it's being parsed as if it's intentional HTML, rather than foreign. do you know if there's a good way of having semgrep ignore that stuff?

@lunelson Ignoring findings: Findings can be individually ignored (which are then remembered across subsequent reviews, etc so not having to do time and time again for the same reports). We do want to make sure that only valid non-issues are ignored, and we provide our reasons, as we need to explain static analysis results we ignore as part of compliance documentation.

On integrity attributes specifically: If I understand correctly, if this is a source that the test relies on, I don't see any harm in adding the integrity attributes... since any change in the associated returned value would imply that the source has changed since the test was set up, anyway. These ought never to change anyway given Cloudflare/jsdelivr are the CDNs referenced.

vilkinsons avatar Dec 10 '25 13:12 vilkinsons

Codecov Report

:white_check_mark: All modified and coverable lines are covered by tests. :white_check_mark: Project coverage is 57.84%. Comparing base (37d1e0e) to head (5efd576). :warning: Report is 23 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8151   +/-   ##
=======================================
  Coverage   57.84%   57.84%           
=======================================
  Files        1167     1167           
  Lines      109264   109264           
  Branches     4976     4976           
=======================================
  Hits        63208    63208           
  Misses      45310    45310           
  Partials      746      746           
Flag Coverage Δ
rust.harpc-tower 66.80% <ø> (ø)
rust.hash-graph-authorization 62.47% <ø> (ø)
rust.hash-graph-store 30.59% <ø> (ø)
rust.hashql-compiletest 49.36% <ø> (ø)
rust.hashql-diagnostics 72.43% <ø> (ø)
rust.hashql-eval 68.54% <ø> (ø)
rust.hashql-syntax-jexpr 94.04% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

codecov[bot] avatar Dec 11 '25 10:12 codecov[bot]

@CiaranMn @TimDiekmann I'm happy to provide legal ✅ when this has been code-reviewed.

vilkinsons avatar Dec 11 '25 12:12 vilkinsons

Benchmark results

@rust/hash-graph-benches – Integrations

policy_resolution_large

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2002 $$28.1 \mathrm{ms} \pm 156 \mathrm{μs}\left({\color{gray}0.053 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.30 \mathrm{ms} \pm 14.1 \mathrm{μs}\left({\color{gray}-0.268 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1001 $$12.7 \mathrm{ms} \pm 110 \mathrm{μs}\left({\color{gray}1.87 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$42.3 \mathrm{ms} \pm 256 \mathrm{μs}\left({\color{gray}0.629 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$13.8 \mathrm{ms} \pm 79.8 \mathrm{μs}\left({\color{gray}-0.443 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1526 $$23.8 \mathrm{ms} \pm 158 \mathrm{μs}\left({\color{gray}0.818 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$31.8 \mathrm{ms} \pm 173 \mathrm{μs}\left({\color{lightgreen}-27.878 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.67 \mathrm{ms} \pm 19.2 \mathrm{μs}\left({\color{lightgreen}-81.882 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$13.9 \mathrm{ms} \pm 80.6 \mathrm{μs}\left({\color{lightgreen}-51.219 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.72 \mathrm{ms} \pm 20.2 \mathrm{μs}\left({\color{gray}0.299 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.83 \mathrm{ms} \pm 9.87 \mathrm{μs}\left({\color{gray}-1.823 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 51 $$3.22 \mathrm{ms} \pm 13.4 \mathrm{μs}\left({\color{gray}-1.344 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.13 \mathrm{ms} \pm 20.9 \mathrm{μs}\left({\color{gray}-0.325 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.46 \mathrm{ms} \pm 14.1 \mathrm{μs}\left({\color{gray}0.089 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 107 $$4.03 \mathrm{ms} \pm 23.5 \mathrm{μs}\left({\color{gray}-0.022 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.40 \mathrm{ms} \pm 22.0 \mathrm{μs}\left({\color{red}7.82 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.33 \mathrm{ms} \pm 15.2 \mathrm{μs}\left({\color{gray}-0.855 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$3.96 \mathrm{ms} \pm 23.3 \mathrm{μs}\left({\color{gray}0.200 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.51 \mathrm{ms} \pm 9.77 \mathrm{μs}\left({\color{red}5.97 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.48 \mathrm{ms} \pm 8.54 \mathrm{μs}\left({\color{red}6.52 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1 $$2.56 \mathrm{ms} \pm 9.37 \mathrm{μs}\left({\color{red}5.89 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.76 \mathrm{ms} \pm 14.4 \mathrm{μs}\left({\color{gray}4.31 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.64 \mathrm{ms} \pm 11.6 \mathrm{μs}\left({\color{red}5.08 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.81 \mathrm{ms} \pm 12.9 \mathrm{μs}\left({\color{gray}3.32 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$2.92 \mathrm{ms} \pm 10.5 \mathrm{μs}\left({\color{red}5.94 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.58 \mathrm{ms} \pm 10.6 \mathrm{μs}\left({\color{red}6.91 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 25 $$2.80 \mathrm{ms} \pm 11.8 \mathrm{μs}\left({\color{red}8.42 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.28 \mathrm{ms} \pm 15.9 \mathrm{μs}\left({\color{red}6.20 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.80 \mathrm{ms} \pm 10.7 \mathrm{μs}\left({\color{gray}4.84 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 26 $$3.08 \mathrm{ms} \pm 16.5 \mathrm{μs}\left({\color{red}7.25 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.27 \mathrm{ms} \pm 15.4 \mathrm{μs}\left({\color{red}8.26 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.77 \mathrm{ms} \pm 10.6 \mathrm{μs}\left({\color{gray}4.67 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.09 \mathrm{ms} \pm 14.8 \mathrm{μs}\left({\color{red}7.02 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$38.9 \mathrm{ms} \pm 138 \mathrm{μs}\left({\color{gray}2.74 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$85.7 \mathrm{ms} \pm 426 \mathrm{μs}\left({\color{red}5.35 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$42.8 \mathrm{ms} \pm 206 \mathrm{μs}\left({\color{gray}-0.591 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$45.4 \mathrm{ms} \pm 163 \mathrm{μs}\left({\color{gray}0.989 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$53.6 \mathrm{ms} \pm 378 \mathrm{μs}\left({\color{gray}-0.827 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$40.3 \mathrm{ms} \pm 167 \mathrm{μs}\left({\color{gray}0.724 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$497 \mathrm{ms} \pm 1.03 \mathrm{ms}\left({\color{gray}-0.158 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$97.8 \mathrm{ms} \pm 537 \mathrm{μs}\left({\color{gray}-0.794 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$83.4 \mathrm{ms} \pm 427 \mathrm{μs}\left({\color{gray}0.929 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$290 \mathrm{ms} \pm 737 \mathrm{μs}\left({\color{gray}-0.064 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$15.0 \mathrm{ms} \pm 59.4 \mathrm{μs}\left({\color{gray}4.77 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$15.2 \mathrm{ms} \pm 68.3 \mathrm{μs}\left({\color{gray}-0.453 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$15.4 \mathrm{ms} \pm 73.4 \mathrm{μs}\left({\color{gray}2.50 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$15.3 \mathrm{ms} \pm 63.6 \mathrm{μs}\left({\color{gray}3.82 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$18.5 \mathrm{ms} \pm 79.7 \mathrm{μs}\left({\color{gray}4.80 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$14.7 \mathrm{ms} \pm 66.0 \mathrm{μs}\left({\color{gray}1.56 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$14.8 \mathrm{ms} \pm 56.1 \mathrm{μs}\left({\color{gray}0.875 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$14.9 \mathrm{ms} \pm 62.9 \mathrm{μs}\left({\color{gray}0.035 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$15.6 \mathrm{ms} \pm 71.5 \mathrm{μs}\left({\color{gray}1.40 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$22.5 \mathrm{ms} \pm 133 \mathrm{μs}\left({\color{gray}0.100 \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 $$30.1 \mathrm{ms} \pm 252 \mathrm{μs}\left({\color{gray}-2.875 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$30.2 \mathrm{ms} \pm 305 \mathrm{μs}\left({\color{gray}-2.797 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$30.0 \mathrm{ms} \pm 331 \mathrm{μs}\left({\color{gray}0.650 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$30.9 \mathrm{ms} \pm 310 \mathrm{μs}\left({\color{gray}4.18 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$29.4 \mathrm{ms} \pm 277 \mathrm{μs}\left({\color{gray}-0.058 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$30.1 \mathrm{ms} \pm 320 \mathrm{μs}\left({\color{gray}0.385 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$29.4 \mathrm{ms} \pm 276 \mathrm{μs}\left({\color{gray}-4.197 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$30.0 \mathrm{ms} \pm 314 \mathrm{μs}\left({\color{gray}0.418 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$30.3 \mathrm{ms} \pm 267 \mathrm{μs}\left({\color{gray}1.03 \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 $$9.17 \mathrm{ms} \pm 43.3 \mathrm{μs}\left({\color{gray}0.868 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$57.6 \mathrm{ms} \pm 280 \mathrm{μs}\left({\color{gray}1.12 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$110 \mathrm{ms} \pm 408 \mathrm{μs}\left({\color{gray}-0.476 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$62.8 \mathrm{ms} \pm 307 \mathrm{μs}\left({\color{gray}-1.541 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$71.6 \mathrm{ms} \pm 338 \mathrm{μs}\left({\color{gray}-0.898 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$81.0 \mathrm{ms} \pm 317 \mathrm{μs}\left({\color{gray}-1.093 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$88.6 \mathrm{ms} \pm 450 \mathrm{μs}\left({\color{gray}-0.215 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$51.3 \mathrm{ms} \pm 301 \mathrm{μs}\left({\color{gray}-1.197 \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 $$81.4 \mathrm{ms} \pm 308 \mathrm{μs}\left({\color{gray}0.039 \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 $$58.1 \mathrm{ms} \pm 355 \mathrm{μs}\left({\color{gray}-0.780 \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 $$66.9 \mathrm{ms} \pm 362 \mathrm{μs}\left({\color{gray}-2.678 \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 $$69.5 \mathrm{ms} \pm 327 \mathrm{μs}\left({\color{gray}0.073 \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 $$69.6 \mathrm{ms} \pm 345 \mathrm{μs}\left({\color{gray}-0.420 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$143 \mathrm{ms} \pm 545 \mathrm{μs}\left({\color{red}5.25 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$139 \mathrm{ms} \pm 575 \mathrm{μs}\left({\color{gray}3.40 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$41.9 \mathrm{ms} \pm 190 \mathrm{μs}\left({\color{lightgreen}-59.633 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$580 \mathrm{ms} \pm 1.18 \mathrm{ms}\left({\color{gray}-2.585 \mathrm{\%}}\right) $$ Flame Graph

github-actions[bot] avatar Dec 11 '25 12:12 github-actions[bot]