Skip to content

FE-1162: Add Petrinaut optimization UI#9051

Draft
kube wants to merge 1 commit into
mainfrom
codex/petrinaut-optimization-frontend
Draft

FE-1162: Add Petrinaut optimization UI#9051
kube wants to merge 1 commit into
mainfrom
codex/petrinaut-optimization-frontend

Conversation

@kube

@kube kube commented Jul 17, 2026

Copy link
Copy Markdown
Collaborator

🌟 What is the purpose of this PR?

Add the Petrinaut optimization UI and its HASH integration on top of the backend introduced in #9040.

🔍 What does this change?

  • Adds a separate capability-gated Optimizations view in Petrinaut.
  • Requires scenario selection before configuration and supports a flat set of fixed or optimized scenario parameters.
  • Supports one saved or run-local custom metric with maximize/minimize direction.
  • Streams trial progress and best-so-far results into dedicated views.
  • Adds the authenticated HASH host-to-iframe bridge and provider without exposing optimizer addresses to the embedded editor.
  • Adds a direct Petrinaut demo-site adapter and yarn dev:petrinaut-optimization for isolated development.
  • Adds a supply-chain example and user-facing optimization documentation.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

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

📜 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

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

The changes in this PR:

  • do not affect the execution graph

⚠️ Known issues

  • Optimization runs are tied to the browser request; closing or reloading the page cancels the run.
  • The initial interface supports one objective metric and a flat scenario-parameter search space only.

🛡 What tests cover this?

  • Petrinaut UI: 169 tests
  • HASH host/iframe optimization bridge: 11 focused tests
  • Petrinaut demo website adapter: 1 test
  • TypeScript and lint checks for Petrinaut, the demo website, and HASH frontend

❓ How to test this?

  1. Run yarn dev:petrinaut-optimization for the isolated demo integration, or start HASH with the backend from FE-1162: Add Petrinaut optimization backend #9040 configured.
  2. Open a model with a scenario and metric.
  3. Open Simulate → Optimizations, select the scenario, configure fixed and optimized parameters, and choose the objective direction.
  4. Start the optimization and verify progressive trials, best parameters, completion, and cancellation.

@vercel

vercel Bot commented Jul 17, 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, Comment Jul 19, 2026 12:19am
hashdotdesign-tokens Ready Ready Preview, Comment Jul 19, 2026 12:19am
petrinaut Ready Ready Preview, Comment Jul 19, 2026 12:19am

@github-actions github-actions Bot added area/deps Relates to third-party dependencies (area) area/apps > hash* Affects HASH (a `hash-*` app) 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/apps labels Jul 17, 2026
const postToHost = (message: IframeToHostMessage) => {
// The sandboxed iframe has an opaque origin. This still targets only its
// parent window; the host independently verifies `event.source`.
window.parent.postMessage(message, "*");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified an issue in your code:
The target origin of the window.postMessage() API is set to "*". This could allow for information disclosure due to the possibility of any origin allowed to receive the message.

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by wildcard-postmessage-configuration.

You can view more details about this finding in the Semgrep AppSec Platform.

Comment on lines +67 to +145
window.addEventListener("message", (event) => {
if (event.source !== window.parent) {
return;
}

const data = event.data as unknown;
if (
typeof data !== "object" ||
data === null ||
typeof (data as { kind?: unknown }).kind !== "string"
) {
return;
}

const message = data as HostToIframeMessage;
if (
message.kind !== "optimizationResponseStart" &&
message.kind !== "optimizationChunk" &&
message.kind !== "optimizationEnd" &&
message.kind !== "optimizationError"
) {
return;
}

const pending = pendingRequests.get(message.requestId);
if (!pending) {
return;
}

switch (message.kind) {
case "optimizationResponseStart": {
if (pending.responded) {
rejectPendingRequest(
message.requestId,
new Error("The optimizer sent more than one response header"),
);
return;
}
pending.responded = true;
pending.clearResponseStartTimeout();
pending.resolveResponse(
new Response(pending.stream, {
headers: { "content-type": "application/x-ndjson" },
status: message.status,
statusText: message.statusText,
}),
);
break;
}
case "optimizationChunk": {
try {
pending.controller.enqueue(message.bytes);
} catch {
// The consumer may already have cancelled the stream.
}
break;
}
case "optimizationEnd": {
if (!pending.responded) {
rejectPendingRequest(
message.requestId,
new Error("The optimizer ended before sending a response"),
);
return;
}
try {
pending.controller.close();
} catch {
// The stream is already settled.
}
pending.cleanup();
pendingRequests.delete(message.requestId);
break;
}
case "optimizationError":
rejectPendingRequest(message.requestId, new Error(message.message));
break;
}
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified an issue in your code:
No validation of origin is done by the addEventListener API. It may be possible to exploit this flaw to perform Cross Origin attacks such as Cross-Site Scripting(XSS).

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by insufficient-postmessage-origin-validation.

You can view more details about this finding in the Semgrep AppSec Platform.

const waitForOptimizer = async () => {
for (let attempt = 0; attempt < 60; attempt += 1) {
try {
const response = await fetch(`${optimizerOrigin}/status`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Semgrep identified an issue in your code:
Unencrypted request over HTTP detected.

To resolve this comment:

🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.

💬 Ignore this finding

Reply with Semgrep commands to ignore this finding.

  • /fp <comment> for false positive
  • /ar <comment> for acceptable risk
  • /other <comment> for all other reasons

Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by react-insecure-request.

You can view more details about this finding in the Semgrep AppSec Platform.

const waitForOptimizer = async () => {
for (let attempt = 0; attempt < 60; attempt += 1) {
try {
const response = await fetch(`${optimizerOrigin}/status`);
const postToHost = (message: IframeToHostMessage) => {
// The sandboxed iframe has an opaque origin. This still targets only its
// parent window; the host independently verifies `event.source`.
window.parent.postMessage(message, "*");
Comment on lines +67 to +145
window.addEventListener("message", (event) => {
if (event.source !== window.parent) {
return;
}

const data = event.data as unknown;
if (
typeof data !== "object" ||
data === null ||
typeof (data as { kind?: unknown }).kind !== "string"
) {
return;
}

const message = data as HostToIframeMessage;
if (
message.kind !== "optimizationResponseStart" &&
message.kind !== "optimizationChunk" &&
message.kind !== "optimizationEnd" &&
message.kind !== "optimizationError"
) {
return;
}

const pending = pendingRequests.get(message.requestId);
if (!pending) {
return;
}

switch (message.kind) {
case "optimizationResponseStart": {
if (pending.responded) {
rejectPendingRequest(
message.requestId,
new Error("The optimizer sent more than one response header"),
);
return;
}
pending.responded = true;
pending.clearResponseStartTimeout();
pending.resolveResponse(
new Response(pending.stream, {
headers: { "content-type": "application/x-ndjson" },
status: message.status,
statusText: message.statusText,
}),
);
break;
}
case "optimizationChunk": {
try {
pending.controller.enqueue(message.bytes);
} catch {
// The consumer may already have cancelled the stream.
}
break;
}
case "optimizationEnd": {
if (!pending.responded) {
rejectPendingRequest(
message.requestId,
new Error("The optimizer ended before sending a response"),
);
return;
}
try {
pending.controller.close();
} catch {
// The stream is already settled.
}
pending.cleanup();
pendingRequests.delete(message.requestId);
break;
}
case "optimizationError":
rejectPendingRequest(message.requestId, new Error(message.message));
break;
}
});
@codspeed-hq

codspeed-hq Bot commented Jul 17, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 98 untouched benchmarks


Comparing codex/petrinaut-optimization-frontend (bf55e30) with main (a1d86bd)1

Open in CodSpeed

Footnotes

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

@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 $$25.5 \mathrm{ms} \pm 204 \mathrm{μs}\left({\color{gray}0.339 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$3.37 \mathrm{ms} \pm 14.9 \mathrm{μs}\left({\color{gray}-1.461 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 1002 $$11.9 \mathrm{ms} \pm 77.5 \mathrm{μs}\left({\color{gray}-0.624 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 3314 $$41.8 \mathrm{ms} \pm 345 \mathrm{μs}\left({\color{gray}-0.267 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$14.4 \mathrm{ms} \pm 126 \mathrm{μs}\left({\color{gray}1.18 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 1527 $$23.4 \mathrm{ms} \pm 187 \mathrm{μs}\left({\color{gray}-0.278 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 2078 $$25.8 \mathrm{ms} \pm 163 \mathrm{μs}\left({\color{gray}-1.012 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.68 \mathrm{ms} \pm 16.5 \mathrm{μs}\left({\color{gray}-1.017 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 1033 $$13.0 \mathrm{ms} \pm 102 \mathrm{μs}\left({\color{gray}0.066 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_medium

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 102 $$3.69 \mathrm{ms} \pm 18.8 \mathrm{μs}\left({\color{gray}-0.582 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.96 \mathrm{ms} \pm 13.9 \mathrm{μs}\left({\color{gray}-1.284 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 52 $$3.30 \mathrm{ms} \pm 15.5 \mathrm{μs}\left({\color{gray}-1.993 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 269 $$5.06 \mathrm{ms} \pm 28.9 \mathrm{μs}\left({\color{gray}-0.323 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.58 \mathrm{ms} \pm 21.5 \mathrm{μs}\left({\color{gray}0.931 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 108 $$4.11 \mathrm{ms} \pm 27.4 \mathrm{μs}\left({\color{gray}0.143 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 133 $$4.37 \mathrm{ms} \pm 32.2 \mathrm{μs}\left({\color{gray}0.228 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.40 \mathrm{ms} \pm 14.9 \mathrm{μs}\left({\color{gray}-1.001 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 63 $$4.02 \mathrm{ms} \pm 24.9 \mathrm{μs}\left({\color{gray}-2.712 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_none

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 2 $$2.73 \mathrm{ms} \pm 22.7 \mathrm{μs}\left({\color{gray}0.257 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.66 \mathrm{ms} \pm 12.9 \mathrm{μs}\left({\color{gray}-0.167 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 2 $$2.77 \mathrm{ms} \pm 15.0 \mathrm{μs}\left({\color{gray}-0.977 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 8 $$3.03 \mathrm{ms} \pm 16.7 \mathrm{μs}\left({\color{gray}-0.989 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$2.85 \mathrm{ms} \pm 12.9 \mathrm{μs}\left({\color{gray}-0.431 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 3 $$3.13 \mathrm{ms} \pm 15.0 \mathrm{μs}\left({\color{gray}-0.770 \mathrm{\%}}\right) $$ Flame Graph

policy_resolution_small

Function Value Mean Flame graphs
resolve_policies_for_actor user: empty, selectivity: high, policies: 52 $$3.07 \mathrm{ms} \pm 19.9 \mathrm{μs}\left({\color{gray}0.479 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: low, policies: 1 $$2.82 \mathrm{ms} \pm 18.9 \mathrm{μs}\left({\color{gray}2.87 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: empty, selectivity: medium, policies: 26 $$2.94 \mathrm{ms} \pm 17.4 \mathrm{μs}\left({\color{gray}0.609 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: high, policies: 94 $$3.50 \mathrm{ms} \pm 25.7 \mathrm{μs}\left({\color{gray}1.83 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: low, policies: 1 $$3.09 \mathrm{ms} \pm 11.4 \mathrm{μs}\left({\color{gray}1.53 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: seeded, selectivity: medium, policies: 27 $$3.31 \mathrm{ms} \pm 19.6 \mathrm{μs}\left({\color{gray}1.39 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: high, policies: 66 $$3.41 \mathrm{ms} \pm 19.7 \mathrm{μs}\left({\color{gray}0.966 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: low, policies: 1 $$3.08 \mathrm{ms} \pm 17.0 \mathrm{μs}\left({\color{gray}1.61 \mathrm{\%}}\right) $$ Flame Graph
resolve_policies_for_actor user: system, selectivity: medium, policies: 29 $$3.33 \mathrm{ms} \pm 17.6 \mathrm{μs}\left({\color{gray}1.66 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_complete

Function Value Mean Flame graphs
entity_by_id;one_depth 1 entities $$31.6 \mathrm{ms} \pm 148 \mathrm{μs}\left({\color{gray}-0.148 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 10 entities $$67.8 \mathrm{ms} \pm 401 \mathrm{μs}\left({\color{gray}-2.841 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 25 entities $$35.4 \mathrm{ms} \pm 196 \mathrm{μs}\left({\color{gray}1.02 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 5 entities $$38.7 \mathrm{ms} \pm 259 \mathrm{μs}\left({\color{gray}2.27 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;one_depth 50 entities $$42.6 \mathrm{ms} \pm 241 \mathrm{μs}\left({\color{gray}3.34 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 1 entities $$33.2 \mathrm{ms} \pm 176 \mathrm{μs}\left({\color{gray}-0.160 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 10 entities $$392 \mathrm{ms} \pm 1.02 \mathrm{ms}\left({\color{lightgreen}-5.613 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 25 entities $$89.5 \mathrm{ms} \pm 515 \mathrm{μs}\left({\color{gray}0.850 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 5 entities $$70.6 \mathrm{ms} \pm 363 \mathrm{μs}\left({\color{gray}-0.096 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;two_depth 50 entities $$295 \mathrm{ms} \pm 1.24 \mathrm{ms}\left({\color{gray}-0.486 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 1 entities $$10.5 \mathrm{ms} \pm 36.7 \mathrm{μs}\left({\color{gray}-1.410 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 10 entities $$10.9 \mathrm{ms} \pm 59.6 \mathrm{μs}\left({\color{gray}-0.144 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 25 entities $$10.9 \mathrm{ms} \pm 58.1 \mathrm{μs}\left({\color{gray}0.226 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 5 entities $$10.9 \mathrm{ms} \pm 80.1 \mathrm{μs}\left({\color{gray}1.17 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id;zero_depth 50 entities $$10.8 \mathrm{ms} \pm 53.1 \mathrm{μs}\left({\color{gray}0.133 \mathrm{\%}}\right) $$ Flame Graph

read_scaling_linkless

Function Value Mean Flame graphs
entity_by_id 1 entities $$10.7 \mathrm{ms} \pm 45.3 \mathrm{μs}\left({\color{gray}-0.374 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10 entities $$10.8 \mathrm{ms} \pm 59.5 \mathrm{μs}\left({\color{gray}-0.469 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 100 entities $$10.8 \mathrm{ms} \pm 52.1 \mathrm{μs}\left({\color{gray}-0.317 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 1000 entities $$11.0 \mathrm{ms} \pm 64.6 \mathrm{μs}\left({\color{gray}0.437 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id 10000 entities $$10.9 \mathrm{ms} \pm 60.5 \mathrm{μs}\left({\color{gray}0.122 \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 $$11.3 \mathrm{ms} \pm 63.7 \mathrm{μs}\left({\color{gray}1.54 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/book/v/1 $$11.2 \mathrm{ms} \pm 80.5 \mathrm{μs}\left({\color{gray}-0.320 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/building/v/1 $$11.2 \mathrm{ms} \pm 54.0 \mathrm{μs}\left({\color{gray}-0.904 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/organization/v/1 $$11.2 \mathrm{ms} \pm 68.3 \mathrm{μs}\left({\color{gray}-0.265 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/page/v/2 $$11.2 \mathrm{ms} \pm 65.7 \mathrm{μs}\left({\color{gray}-0.687 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/person/v/1 $$11.2 \mathrm{ms} \pm 51.6 \mathrm{μs}\left({\color{gray}-0.132 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/playlist/v/1 $$11.2 \mathrm{ms} \pm 74.0 \mathrm{μs}\left({\color{gray}0.141 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/song/v/1 $$11.2 \mathrm{ms} \pm 62.8 \mathrm{μs}\left({\color{gray}-0.420 \mathrm{\%}}\right) $$ Flame Graph
entity_by_id entity type ID: https://blockprotocol.org/@alice/types/entity-type/uk-address/v/1 $$11.2 \mathrm{ms} \pm 61.8 \mathrm{μs}\left({\color{gray}-1.112 \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 $$8.18 \mathrm{ms} \pm 37.8 \mathrm{μs}\left({\color{gray}-0.771 \mathrm{\%}}\right) $$ Flame Graph

representative_read_multiple_entities

Function Value Mean Flame graphs
entity_by_property traversal_paths=0 0 $$58.3 \mathrm{ms} \pm 432 \mathrm{μs}\left({\color{gray}0.585 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=255 1,resolve_depths=inherit:1;values:255;properties:255;links:127;link_dests:126;type:true $$108 \mathrm{ms} \pm 535 \mathrm{μs}\left({\color{gray}0.120 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:0;link_dests:0;type:false $$65.3 \mathrm{ms} \pm 426 \mathrm{μs}\left({\color{gray}1.53 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:0;links:1;link_dests:0;type:true $$74.2 \mathrm{ms} \pm 511 \mathrm{μs}\left({\color{gray}1.33 \mathrm{\%}}\right) $$
entity_by_property traversal_paths=2 1,resolve_depths=inherit:0;values:0;properties:2;links:1;link_dests:0;type:true $$82.5 \mathrm{ms} \pm 517 \mathrm{μs}\left({\color{gray}-0.052 \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.4 \mathrm{ms} \pm 470 \mathrm{μs}\left({\color{gray}0.485 \mathrm{\%}}\right) $$
link_by_source_by_property traversal_paths=0 0 $$45.1 \mathrm{ms} \pm 219 \mathrm{μs}\left({\color{gray}-0.018 \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 $$71.4 \mathrm{ms} \pm 454 \mathrm{μs}\left({\color{gray}0.004 \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 $$50.9 \mathrm{ms} \pm 257 \mathrm{μs}\left({\color{gray}-0.381 \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 $$59.4 \mathrm{ms} \pm 283 \mathrm{μs}\left({\color{gray}-0.142 \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 $$61.8 \mathrm{ms} \pm 436 \mathrm{μs}\left({\color{gray}0.524 \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 $$61.8 \mathrm{ms} \pm 346 \mathrm{μs}\left({\color{gray}0.667 \mathrm{\%}}\right) $$

scenarios

Function Value Mean Flame graphs
full_test query-limited $$116 \mathrm{ms} \pm 426 \mathrm{μs}\left({\color{gray}-2.126 \mathrm{\%}}\right) $$ Flame Graph
full_test query-unlimited $$128 \mathrm{ms} \pm 477 \mathrm{μs}\left({\color{gray}-3.241 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-limited $$18.4 \mathrm{ms} \pm 132 \mathrm{μs}\left({\color{lightgreen}-20.304 \mathrm{\%}}\right) $$ Flame Graph
linked_queries query-unlimited $$541 \mathrm{ms} \pm 1.04 \mathrm{ms}\left({\color{gray}-0.637 \mathrm{\%}}\right) $$ Flame Graph

Base automatically changed from codex/petrinaut-optimization-ui to main July 18, 2026 20:09
@github-actions github-actions Bot added area/apps > hash-api Affects the HASH API (app) type/eng > backend Owned by the @backend team area/tests New or updated tests type/legal Owned by the @legal team labels Jul 18, 2026
@kube
kube force-pushed the codex/petrinaut-optimization-frontend branch from 444bc2d to bf55e30 Compare July 18, 2026 23:54
@github-actions github-actions Bot removed area/apps > hash-api Affects the HASH API (app) type/eng > backend Owned by the @backend team area/tests New or updated tests type/legal Owned by the @legal team labels Jul 18, 2026
@codecov

codecov Bot commented Jul 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 59.18%. Comparing base (b00c6bd) to head (bf55e30).

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #9051      +/-   ##
==========================================
- Coverage   59.22%   59.18%   -0.04%     
==========================================
  Files        1391     1393       +2     
  Lines      135140   135340     +200     
  Branches     6223     6268      +45     
==========================================
+ Hits        80032    80103      +71     
- Misses      54152    54266     +114     
- Partials      956      971      +15     
Flag Coverage Δ
apps.hash-ai-worker-ts 1.99% <ø> (+0.09%) ⬆️
apps.hash-api 9.42% <ø> (ø)
local.hash-backend-utils 2.55% <ø> (+0.67%) ⬆️
local.hash-isomorphic-utils 3.07% <ø> (+2.89%) ⬆️

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.

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) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

2 participants