Skip to content

Conversation

@lunelson
Copy link
Contributor

@lunelson lunelson commented Dec 17, 2025

WIP

This PR builds out the decomposition workflow as a Mastra workflow with "revision loop" control-flow

  • All 4 fixtures pass on first attempt (no revisions needed)
  • Revision loop infrastructure is ready if/when needed
  • 4/4 valid plans, ~42s total

What's working well:

  • Deterministic validation catches structural issues
  • Planner agent generates valid plans reliably
  • Revision feedback is ready for edge cases

Demo

asciicast

@github-actions github-actions bot added area/apps > hash* Affects HASH (a `hash-*` app) area/infra Relates to version control, CI, CD or IaC (area) area/apps labels Dec 17, 2025
@lunelson lunelson force-pushed the ln/h-5847-dynamic-workflows branch from 533d3ce to a969bf4 Compare December 19, 2025 10:36
@lunelson lunelson force-pushed the ln/h-5742-rd-revision-loop-mvp branch from 5800b9c to f7db198 Compare December 19, 2025 10:37
@vercel vercel bot temporarily deployed to Preview – petrinaut December 19, 2025 10:37 Inactive
@github-actions github-actions bot added the area/deps Relates to third-party dependencies (area) label Dec 19, 2025
@lunelson lunelson changed the title H-5742: Revision loop MVP H-5742: Dynamic Workflow Compiler + Demo Dec 19, 2025
@lunelson lunelson force-pushed the ln/h-5847-dynamic-workflows branch from a969bf4 to 4d73567 Compare December 19, 2025 13:01
@lunelson lunelson force-pushed the ln/h-5742-rd-revision-loop-mvp branch from f7db198 to 721982d Compare December 19, 2025 13:02
@vercel vercel bot temporarily deployed to Preview – petrinaut December 19, 2025 14:56 Inactive
@lunelson lunelson force-pushed the ln/h-5847-dynamic-workflows branch from 8aed145 to a458733 Compare December 22, 2025 10:29
@lunelson lunelson force-pushed the ln/h-5742-rd-revision-loop-mvp branch from 1633090 to 0e0fca3 Compare December 22, 2025 14:33
const prompt = buildPromptForStep(planStep, inputData, ctx);

// Execute via mock agent
const response = await agent.generate(prompt);

Check failure

Code scanning / Semgrep PRO

Semgrep Finding: javascript.express.security.express-wkhtml-injection.express-wkhtmltoimage-injection Error

If unverified user data can reach the phantom methods it can result in Server-Side Request Forgery vulnerabilities
@codecov
Copy link

codecov bot commented Dec 23, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 58.90%. Comparing base (b6338db) to head (0a31d8a).

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #8192   +/-   ##
=======================================
  Coverage   58.90%   58.90%           
=======================================
  Files        1193     1193           
  Lines      112723   112723           
  Branches     5013     5013           
=======================================
+ Hits        66394    66396    +2     
+ Misses      45571    45569    -2     
  Partials      758      758           
Flag Coverage Δ
local.claude-hooks 0.00% <ø> (ø)
rust.hash-graph-validation 83.45% <ø> (ø)
rust.hashql-core 82.36% <ø> (ø)
rust.hashql-hir 89.10% <ø> (ø)

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

☔ View full report in Codecov by Sentry.
📢 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.

@vercel vercel bot temporarily deployed to Preview – petrinaut December 23, 2025 12:06 Inactive
@github-actions
Copy link
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 $$26.0 \mathrm{ms} \pm 218 \mathrm{μs}\left({\color{lightgreen}-12.076 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.22 \mathrm{ms} \pm 14.3 \mathrm{μs}\left({\color{gray}0.754 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1001 $$12.3 \mathrm{ms} \pm 85.3 \mathrm{μs}\left({\color{red}5.86 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$42.8 \mathrm{ms} \pm 334 \mathrm{μs}\left({\color{gray}3.73 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$14.8 \mathrm{ms} \pm 93.2 \mathrm{μs}\left({\color{red}6.41 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1526 $$24.0 \mathrm{ms} \pm 154 \mathrm{μs}\left({\color{red}5.42 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$26.3 \mathrm{ms} \pm 184 \mathrm{μs}\left({\color{lightgreen}-37.775 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.62 \mathrm{ms} \pm 20.4 \mathrm{μs}\left({\color{lightgreen}-81.458 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$13.6 \mathrm{ms} \pm 109 \mathrm{μs}\left({\color{lightgreen}-50.214 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.59 \mathrm{ms} \pm 19.1 \mathrm{μs}\left({\color{gray}1.16 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.78 \mathrm{ms} \pm 11.5 \mathrm{μs}\left({\color{gray}0.709 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 51 $$3.13 \mathrm{ms} \pm 12.3 \mathrm{μs}\left({\color{gray}1.36 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$4.91 \mathrm{ms} \pm 27.1 \mathrm{μs}\left({\color{gray}0.791 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.42 \mathrm{ms} \pm 20.0 \mathrm{μs}\left({\color{gray}2.70 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 107 $$3.96 \mathrm{ms} \pm 19.1 \mathrm{μs}\left({\color{gray}2.51 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.17 \mathrm{ms} \pm 22.6 \mathrm{μs}\left({\color{red}5.67 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.23 \mathrm{ms} \pm 15.8 \mathrm{μs}\left({\color{gray}1.28 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$3.80 \mathrm{ms} \pm 20.3 \mathrm{μs}\left({\color{gray}0.877 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.59 \mathrm{ms} \pm 8.66 \mathrm{μs}\left({\color{red}10.8 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.52 \mathrm{ms} \pm 12.4 \mathrm{μs}\left({\color{red}9.98 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1 $$2.58 \mathrm{ms} \pm 10.7 \mathrm{μs}\left({\color{red}8.32 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$2.78 \mathrm{ms} \pm 11.8 \mathrm{μs}\left({\color{red}7.27 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.72 \mathrm{ms} \pm 12.9 \mathrm{μs}\left({\color{red}9.94 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$2.91 \mathrm{ms} \pm 11.8 \mathrm{μs}\left({\color{red}8.98 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$2.83 \mathrm{ms} \pm 14.3 \mathrm{μs}\left({\color{red}5.61 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.55 \mathrm{ms} \pm 10.6 \mathrm{μs}\left({\color{red}7.36 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 25 $$2.71 \mathrm{ms} \pm 10.9 \mathrm{μs}\left({\color{red}7.30 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.19 \mathrm{ms} \pm 16.3 \mathrm{μs}\left({\color{gray}4.71 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$2.75 \mathrm{ms} \pm 11.6 \mathrm{μs}\left({\color{gray}4.69 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 26 $$2.97 \mathrm{ms} \pm 11.7 \mathrm{μs}\left({\color{gray}3.92 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.09 \mathrm{ms} \pm 22.9 \mathrm{μs}\left({\color{gray}4.31 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.73 \mathrm{ms} \pm 13.5 \mathrm{μs}\left({\color{gray}4.84 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.02 \mathrm{ms} \pm 20.1 \mathrm{μs}\left({\color{red}6.64 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$38.5 \mathrm{ms} \pm 134 \mathrm{μs}\left({\color{gray}0.771 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$77.4 \mathrm{ms} \pm 344 \mathrm{μs}\left({\color{gray}3.83 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$44.9 \mathrm{ms} \pm 241 \mathrm{μs}\left({\color{red}5.17 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$47.1 \mathrm{ms} \pm 242 \mathrm{μs}\left({\color{gray}4.76 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$55.4 \mathrm{ms} \pm 304 \mathrm{μs}\left({\color{red}6.85 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$41.6 \mathrm{ms} \pm 189 \mathrm{μs}\left({\color{red}5.20 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$419 \mathrm{ms} \pm 815 \mathrm{μs}\left({\color{gray}2.34 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$95.0 \mathrm{ms} \pm 367 \mathrm{μs}\left({\color{gray}2.11 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$86.8 \mathrm{ms} \pm 337 \mathrm{μs}\left({\color{gray}4.58 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$312 \mathrm{ms} \pm 735 \mathrm{μs}\left({\color{red}13.0 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$15.0 \mathrm{ms} \pm 74.0 \mathrm{μs}\left({\color{gray}3.86 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$15.5 \mathrm{ms} \pm 82.5 \mathrm{μs}\left({\color{red}6.88 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$15.2 \mathrm{ms} \pm 76.1 \mathrm{μs}\left({\color{gray}3.39 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$15.2 \mathrm{ms} \pm 63.8 \mathrm{μs}\left({\color{gray}4.72 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$17.8 \mathrm{ms} \pm 75.8 \mathrm{μs}\left({\color{gray}2.47 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$14.8 \mathrm{ms} \pm 61.2 \mathrm{μs}\left({\color{gray}1.83 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$14.8 \mathrm{ms} \pm 80.0 \mathrm{μs}\left({\color{gray}3.20 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$14.7 \mathrm{ms} \pm 63.9 \mathrm{μs}\left({\color{gray}2.07 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$15.1 \mathrm{ms} \pm 63.7 \mathrm{μs}\left({\color{gray}1.94 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$22.6 \mathrm{ms} \pm 148 \mathrm{μs}\left({\color{gray}3.58 \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.0 \mathrm{ms} \pm 290 \mathrm{μs}\left({\color{gray}-0.355 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$28.7 \mathrm{ms} \pm 279 \mathrm{μs}\left({\color{gray}-1.550 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$30.2 \mathrm{ms} \pm 200 \mathrm{μs}\left({\color{gray}4.29 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$28.9 \mathrm{ms} \pm 238 \mathrm{μs}\left({\color{gray}0.234 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$29.8 \mathrm{ms} \pm 280 \mathrm{μs}\left({\color{gray}0.005 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$30.9 \mathrm{ms} \pm 280 \mathrm{μs}\left({\color{gray}2.87 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$30.5 \mathrm{ms} \pm 297 \mathrm{μs}\left({\color{gray}3.10 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$29.2 \mathrm{ms} \pm 290 \mathrm{μs}\left({\color{gray}0.124 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$29.6 \mathrm{ms} \pm 301 \mathrm{μs}\left({\color{gray}-0.049 \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 $$7.94 \mathrm{ms} \pm 30.3 \mathrm{μs}\left({\color{gray}1.02 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$46.8 \mathrm{ms} \pm 276 \mathrm{μs}\left({\color{gray}2.11 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$93.2 \mathrm{ms} \pm 309 \mathrm{μs}\left({\color{gray}1.15 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$52.2 \mathrm{ms} \pm 262 \mathrm{μs}\left({\color{gray}0.460 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$60.7 \mathrm{ms} \pm 349 \mathrm{μs}\left({\color{gray}1.97 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$68.5 \mathrm{ms} \pm 337 \mathrm{μs}\left({\color{gray}1.10 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:2;properties:2;links:1;link_dests:0;type:true $$74.4 \mathrm{ms} \pm 298 \mathrm{μs}\left({\color{gray}0.728 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$49.9 \mathrm{ms} \pm 263 \mathrm{μs}\left({\color{gray}1.76 \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 $$77.9 \mathrm{ms} \pm 396 \mathrm{μs}\left({\color{gray}3.67 \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 $$56.6 \mathrm{ms} \pm 278 \mathrm{μs}\left({\color{gray}-0.390 \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 $$65.0 \mathrm{ms} \pm 340 \mathrm{μs}\left({\color{gray}3.13 \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 $$66.2 \mathrm{ms} \pm 323 \mathrm{μs}\left({\color{gray}1.95 \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 $$66.4 \mathrm{ms} \pm 400 \mathrm{μs}\left({\color{gray}2.46 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$144 \mathrm{ms} \pm 476 \mathrm{μs}\left({\color{red}11.9 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$141 \mathrm{ms} \pm 436 \mathrm{μs}\left({\color{red}7.73 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$39.3 \mathrm{ms} \pm 175 \mathrm{μs}\left({\color{lightgreen}-61.552 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$599 \mathrm{ms} \pm 1.09 \mathrm{ms}\left({\color{gray}2.37 \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 > hash* Affects HASH (a `hash-*` app) area/apps area/deps Relates to third-party dependencies (area) area/infra Relates to version control, CI, CD or IaC (area)

Development

Successfully merging this pull request may close these issues.

2 participants