FE-1573: Deliver a substantial worked-scenario demo (Mission 7b) - #9649
FE-1573: Deliver a substantial worked-scenario demo (Mission 7b)#9649lunelson wants to merge 27 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
PR SummaryMedium Risk Overview Browser construction metadata is renamed Package changesets document Petrinaut host dynamic AI tools and error attribution, File → New Build with Brunch / Start blank, and petrinaut-core selected ordered mutation-batch admission. Brunch README and npm scripts add browser-tracer build notes and Reviewed by Cursor Bugbot for commit 681060c. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
🔵 Needs a closer look
It introduces new host-executed AI tool execution paths plus cross-cutting diagnostics/telemetry changes across multiple packages that warrant careful human validation.
Pull request overview
This PR extends the Petrinaut/Brunch integration surface to support host-defined dynamic tools that can execute automatically, adds structured error/diagnostic reporting across the stack, and introduces a selected ordered mutation batch contract (plus host tooling) to support batched construction flows.
Changes:
- Add
aiAssistant.automaticTools(validated input/output +execute({ input, instance, toolCallId })) and corresponding tests/documentation. - Enhance transport + transcript projection to mark host-defined client tools as dynamic, and report otherwise-hidden server-tool failures via a callback.
- Introduce mutation batching/recording improvements: selected mutation batch schema/executor,
mutate_petrinettool path, and consistent “mutationRecord” renames throughout fixtures/tests/docs. - Add structured runtime diagnostics + development-friendly telemetry collector reachability handling for the Brunch agent server.
File summaries
| File | Description |
|---|---|
| libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.test.tsx | Add ErrorTracker DI and tests for stream failure reporting + automatic tool execution. |
| libs/@hashintel/petrinaut/src/ui/types/ai-automatic-tool.ts | New public type defining host-owned automatic dynamic tool contract. |
| libs/@hashintel/petrinaut/src/ui/petrinaut.tsx | Extend PetrinautAiAssistant with automaticTools. |
| libs/@hashintel/petrinaut/src/ui/index.ts | Export PetrinautAiAutomaticTool. |
| libs/@hashintel/petrinaut/src/react/index.ts | Export expanded ErrorTracker types. |
| libs/@hashintel/petrinaut/src/react/error-tracker-context.ts | Add capture context (source, tags) to captureException. |
| libs/@hashintel/petrinaut/src/main.ts | Re-export ErrorTracker capture context types for host entrypoint. |
| libs/@hashintel/petrinaut/README.md | Document aiAssistant.automaticTools. |
| libs/@hashintel/petrinaut-core/src/selected-mutation-batch.ts | New selected mutation batch schema + ordered-stop executor. |
| libs/@hashintel/petrinaut-core/src/selected-mutation-batch.test.ts | Tests for schema constraints and ordered-stop semantics. |
| libs/@hashintel/petrinaut-core/src/index.ts | Export selected mutation batch APIs. |
| libs/@hashintel/brunch-agent/packages/transport-aisdk/test/ui-stream.test.ts | Tests for dynamic client-tool projection + tool-output error reporting. |
| libs/@hashintel/brunch-agent/packages/transport-aisdk/test/transcript.test.ts | Test rehydration of dynamic client tools. |
| libs/@hashintel/brunch-agent/packages/transport-aisdk/test/client-tool-result.test.ts | New tests for parse-issue reporting without leaking content. |
| libs/@hashintel/brunch-agent/packages/transport-aisdk/src/ui-stream.ts | Add dynamicClientToolNames + onToolOutputError and track toolName by callId. |
| libs/@hashintel/brunch-agent/packages/transport-aisdk/src/transcript.ts | Project dynamic tools as type: "dynamic-tool" parts when configured. |
| libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts | Export new types and thread options into stream submission. |
| libs/@hashintel/brunch-agent/packages/transport-aisdk/src/client-tool-result.ts | Add parse issue classification callback; keep bodies unlogged. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/root-state.test.ts | Update tests to mutation-record terminology/APIs. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/root-node.test.ts | Update tests to mutation-record terminology/APIs. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/reconciliation.test.ts | Update fixtures/types to mutationRecord. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/mutation-record.test.ts | Update tests + add explicit unknown-outcome reasoning coverage. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/mutate-petrinet.test.ts | New tests for mutate_petrinet admission and base-observation validation. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/fixtures/reconciliation/record.json | Fixture rename from transitionRecord → mutationRecord. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/fixtures.ts | Update helper to use mutation-effect derivation/outcome. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts | Add batched-construction mode validation tests. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts | Switch imports to mutation-record types. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/mutate-petrinet.ts | New Flue tool definition for ordered batch mutation admission. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/root-state.ts | Switch import to mutation-record type. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/root-node.ts | Switch import to mutation-record type. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/mutation-record.ts | Rename/refactor transition-record into mutation-record, add outcome reasoning. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/mutate-petrinet.ts | New zod schema for batched mutation input contract. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/index.ts | Export new mutation-record and mutate-petrinet APIs. |
| libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts | Add batched construction mode wiring + mutate_petrinet tool. |
| libs/@hashintel/brunch-agent/docs/mission-drafts/7-explainable-construction.md | Update Mission 7b links/wording. |
| libs/@hashintel/brunch-agent/docs/mission-drafts/11-optimisation-handoff.md | Update Mission 7b links + mutation-record terminology + optimization path ref. |
| libs/@hashintel/brunch-agent/docs/mission-drafts/10-bounded-reviewer-revision.md | Update Mission 7b links + mutation-record terminology. |
| libs/@hashintel/brunch-agent/docs/mission-archive/README.md | Add archive entry for Mission 7a closeout. |
| libs/@hashintel/brunch-agent/docs/evidence/design/core-plugin-ownership-audit-2026-09-09.md | Update status language around side-quest disposition. |
| libs/@hashintel/brunch-agent/AGENTS.md | Refine “Safeguards must earn their friction” guidance. |
| apps/petrinaut-website/src/sentry/sentry-error-tracker-provider.tsx | Implement environment-aware error tracking with redaction + tagging. |
| apps/petrinaut-website/src/sentry/sentry-error-tracker-provider.test.ts | Tests for environment behavior + message redaction invariants. |
| apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts | Thread dynamicClientToolNames into message projection. |
| apps/petrinaut-website/src/main/app/local-storage-demo/typed-state.test.ts | Update recorder naming to mutation recorder. |
| apps/petrinaut-website/src/main/app/local-storage-demo/mutation-record.ts | Rename/extend browser-side mutation recording + contained failure callback. |
| apps/petrinaut-website/src/main/app/local-storage-demo/mutation-record.test.ts | Update tests for mutation recorder; add contained-failure reporting test. |
| apps/petrinaut-website/src/main/app/local-storage-demo/mutate-petrinet-tool.ts | New host automatic tool implementing mutate_petrinet execution + output schema. |
| apps/petrinaut-website/src/main/app/local-storage-demo/mutate-petrinet-tool.test.ts | Tests for ordered-stop outcomes, suffix marking, and failure callback. |
| apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx | Wire batched construction mode, automatic tool, dynamic tools, and error reporting. |
| apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts | Thread dynamicClientToolNames + onToolOutputError into transport. |
| apps/petrinaut-website/README.md | Update wording from transition record → mutation record. |
| apps/brunch-agent/test/typed-state.integration.ts | Update integration expectations to mutationRecord + verifyMutationAttempt. |
| apps/brunch-agent/test/telemetry.test.ts | Add tests for collector reachability filtering/probing behavior. |
| apps/brunch-agent/test/root-creation.integration.ts | Update integration expectations to mutationRecord. |
| apps/brunch-agent/test/root-arc.test.ts | Update test fixture parsing to mutationRecord. |
| apps/brunch-agent/test/reopened-why.integration.ts | Update to verify mutation attempts/record naming. |
| apps/brunch-agent/test/reopened-why-retention-browser.ts | Update to mutation-record script naming and verification function. |
| apps/brunch-agent/test/reconciliation.test.ts | Update reconciliation fixture parsing to mutationRecord. |
| apps/brunch-agent/test/provider-registration.test.ts | Ensure mutate_petrinet classified as browser tool in admission rules. |
| apps/brunch-agent/test/postgres.test.ts | Route idle pool errors into diagnostics sink. |
| apps/brunch-agent/test/persona-request-accounting.test.ts | Ensure user Stop/abort doesn’t raise provider-accounting failure diagnostics. |
| apps/brunch-agent/test/persona-browser.integration.ts | Update metadata expectation to mutationRecord. |
| apps/brunch-agent/test/mutation-records.integration.ts | Rename/add prerequisites and update verification to mutation records. |
| apps/brunch-agent/test/integration/admission-controls.test.ts | Add assertion that failed submissions are attributable in dev output without leaking content. |
| apps/brunch-agent/test/history-retention-new-records.integration.ts | Update script dependency naming to mutation-records tracer output. |
| apps/brunch-agent/test/history-retention-diagnostics.sh | Update to run mutation-records integration script. |
| apps/brunch-agent/test/history-retention-audit.py | Update audit assertion to mutationRecord naming. |
| apps/brunch-agent/test/fixtures/root-arc/history.json | Update embedded fixture metadata to mutationRecord. |
| apps/brunch-agent/test/fixtures/reconciliation/history.json | Update embedded fixture metadata to mutationRecord. |
| apps/brunch-agent/test/fixtures/reconciliation/a5-history.json | Update embedded fixture metadata to mutationRecord. |
| apps/brunch-agent/test/construction-progression.integration.ts | Update records verification and fixture mutationRecord injections. |
| apps/brunch-agent/test/browser-result.ts | Update test typing: transitionRecord → mutationRecord. |
| apps/brunch-agent/test/aggregate-why.test.ts | Update type usage and metadata parsing for mutationRecord. |
| apps/brunch-agent/src/telemetry.ts | Add collector reachability probe + dev-only endpoint dropping before exporter registration. |
| apps/brunch-agent/src/telemetry-bootstrap.ts | Await telemetry install so env filtering happens before OTEL globals are read. |
| apps/brunch-agent/src/runtime-diagnostics.ts | New structured diagnostic sink for runtime failures with content-aware retention. |
| apps/brunch-agent/src/provider-accounting.ts | Report/note accounting failures into diagnostics; treat abort as non-failure note. |
| apps/brunch-agent/src/postgres.ts | Route idle pool errors into diagnostics + telemetry. |
| apps/brunch-agent/src/logger.ts | New shared structured logger instance + environment resolution. |
| apps/brunch-agent/src/http/ownership.ts | Report malformed admission-body parse failures to diagnostics. |
| apps/brunch-agent/src/db.ts | Report DB configuration failures to diagnostics before exit. |
| apps/brunch-agent/src/conversation/why.ts | Update record verification to mutation attempts and report refusal causes to diagnostics. |
| apps/brunch-agent/src/conversation/root-arc.ts | Update record verification to mutation attempts and enforce mutationRecord presence. |
| apps/brunch-agent/src/app.ts | Install diagnostics observer instrumentation; classify mutate_petrinet as browser tool. |
| apps/brunch-agent/src/agents/chat-agent/agent.ts | Report client-tool-result parse drops as diagnostics notes; update mutationRecord wording. |
| apps/brunch-agent/README.md | Document browser tracer build prerequisites for local integration scripts. |
| apps/brunch-agent/package.json | Update browser tracer scripts to mutation-records integration entrypoint. |
| .changeset/selected-mutation-batch.md | Changeset for petrinaut-core batch contract exposure. |
| .changeset/automatic-dynamic-tools.md | Changeset for petrinaut automatic tools + error tracker context. |
Review details
Suppressed comments (3)
apps/petrinaut-website/src/main/app/local-storage-demo/mutation-record.ts:81
- This error message still refers to a "transition" even though this module now records mutations; that makes failures harder to attribute when debugging host/browser binding mismatches.
libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/mutation-record.ts:666 - This error message still refers to a "transition" outcome, but this module (and the surrounding logic) is now about mutation attempts/outcomes. Updating the wording will make diagnostics clearer when a recorded outcome disagrees with recomputed observations.
libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/mutation-record.ts:647 - This error message still uses the old "arc transition" terminology even though the surrounding verification logic is now for mutation attempts. Aligning the wording will make it easier to interpret failures at the receiving boundary.
This issue also appears on line 664 of the same file.
- Files reviewed: 99/99 changed files
- Comments generated: 0
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
2fe1176 to
a58fcdc
Compare
| submissionId: observation.submissionId, | ||
| outcome: observation.outcome, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
Stops logged as submission failures
Low Severity
The new Flue observer reports every submission_settled event whose outcome is not completed through report, which logs an error. A user Stop also settles the submission with a non-completed outcome, so ordinary cancellation is recorded as [brunch] flue.submission failed. The same change set already treats stream abort as a note in provider accounting rather than an alarm.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit a58fcdc. Configure here.
f7e79d8 to
92b8e8b
Compare
92b8e8b to
94c929c
Compare
e4051a1 to
8ba994f
Compare
Co-authored-by: Cursor <cursoragent@cursor.com>
Add one Flue observer and a content-aware logger to the Brunch server so failed tools, turns, tasks, compaction, settlements and recoveries reach the terminal with their runtime IDs, keeping original errors and stacks in development and only type/code in production. Report the failures the server previously converted into ordinary values: dropped client-tool results, why refusals from internal exceptions, malformed admission bodies, and poisoned request accounting. Extend Petrinaut's ErrorTracker with source and tags so the AI assistant panel reports stream, tool, continuation and Stop failures at their source, add a transport callback for server tool-output errors (hidden tools included), and wire the Petrinaut website's contained mutation, transition record and history failures to a tracker that prints in development and classifies for Sentry in production. Co-authored-by: Cursor <cursoragent@cursor.com>
Flue's errorInfo for an argument-validation failure carries only type "_OTHER"; the reason lives in the tool event's error result, which the real mutate_petrinet attempt showed is the only server-side record of why the call was refused. Read it in development only. Co-authored-by: Cursor <cursoragent@cursor.com>
…tics side quest Co-authored-by: Cursor <cursoragent@cursor.com>
Outside production, probe HASH_OTLP_ENDPOINT once at startup and run without exporters when it is unreachable, so a dead local collector no longer floods the terminal with gRPC export stacks. Production keeps its requirement and never probes. Forward the original error to Sentry in production and redact only its message text through a scoped event processor, so stacks and grouping survive while conversation content still stays out. Prefer a Flue error record's message over its details, classify an aborted provider stream as a note rather than a failure, and use dotted stage names throughout. Co-authored-by: Cursor <cursoragent@cursor.com>
…tion cannot be derived The outcome classifier swallowed the derivation error, so the retained attempt said "unknown" with no cause. classifyTransitionOutcome returns the reason beside the outcome; observedArcOutcome remains its projection, and the browser recorder carries the reason into the thrown message that becomes the attempt's recorded error. Co-authored-by: Cursor <cursoragent@cursor.com>
…tion The recorder in plugin-sdcpn was born for one addArc tracer and now classifies, diffs, verifies and reconciles every observed construction mutation. Its symbols still said "Arc" and "Transition", and transition is a first-class Petri-net entity. Rename the module to `mutation-record`, the types to `ConstructionMutationAttempt`/`ConstructionMutationRecord` (and the arc-scoped `ArcMutation*` lane), the helpers to `deriveMutationEffects`, `observedMutationOutcome`, `verifyMutationAttempt` and `reconcileMutationAttempts`, the website recorder to `createBrowserMutationRecorder`, and the diagnostic source to `brunch.mutation-record`. Genuinely arc-scoped names (`ArcMutationRequest`, root-arc why) are unchanged. The persisted client-tool-result sidecar key `metadata.transitionRecord` is renamed to `metadata.mutationRecord` without dual-read: local `.data-wipe-me` histories written before this commit will not resolve their records. Fixtures, the Python retention audit, the model instruction and the tracer script (`test/mutation-records.integration.ts`) follow the rename; MISSION prose and live drafts now say "mutation record". Archive and evidence are untouched. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…ation contract. A rejected first attempt was becoming an executable browser part and stranding the accepted retry; the wrapped operation dialect is what the model could not follow.
The product path now lands a client-tool-result for a flat batch, so the next throughline step is the 25-operation comparison rather than another dispatch diagnosis.
…lls. The empty-net product path now matches definition hash at 5.8× settlement, so the remaining discriminator is a real-provider 25-operation generation rather than another dispatch repair.
The batch premise now has a real accepted 25-operation call, so the next strain is ordinary Brunch still gating construction behind tracer mode.
The tracer already settled construction; ordinary create/open should use that same catalogue instead of a docs-only host.
…patch. The batched catalogue was already mounted; the crew-reservation preparer still ran and poisoned start-from-scratch before the user spoke.
The receiving-dock accept/reject question was honest exclusive-choice, but the mechanical why pane stayed empty; the next discriminator is an ordinary correction on that net.
Add-only mutate_petrinet could not split InspectionDone without leaving a dead parallel net; root removePlace, removeTransition, and removeArc now sit on the selected batch.
Remove-capable mutate_petrinet rewired InspectionDone into Passed/Failed without rebuilding the upstream path; updated why on that branch is the next discriminator.
The AcceptGoods/Passed question distinguished the correction from the original shared InspectionDone; further ordinary-why turns will not conjure the mechanical pane.
The create-new flow now opens the assistant with interview-or-preview chips, or starts a blank net without the first-run prompt.
The mission's inventory-purchasing spelling is already a simulation-scenario location, and selected mutate_petrinet still refuses the definition classes Inventory construction needs.
Inventory-scale construction cannot start from a place/transition/arc catalogue; these root definition classes stay inside the 64 KiB selected schema.
c4bdddc to
e4490ae
Compare
e623489 to
681060c
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 681060c. Configure here.
| output, | ||
| } as never); | ||
| return; | ||
| } |
There was a problem hiding this comment.
Automatic tools skip read-only guard
High Severity
The new automatic dynamic-tool path runs mutate_petrinet without consulting readOnlyReason. Static mutations already refuse in simulate, actual, host-readonly, and active-simulation states. On ordinary Brunch that batch tool is the only construction writer, so those modes no longer block edits and a running simulation can be rewritten under the user.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 681060c. Configure here.


🌟 What is the purpose of this PR?
Deliver Mission 7b's product-manager path around substantial worked process models rather than diagnostic fixtures. Ordinary configured Petrinaut can now open a construction conversation, save a workpiece, apply a bounded
mutate_petrinetbatch, answer why in ordinary language, correct the net, and reopen the same session.This PR establishes that the batched construction carrier works on the real product, and that one ordinary start-from-scratch net can be constructed, fluently explained, corrected, re-explained, and reopened. It does not establish an Inventory-comparable flagship, a seeded scenario catalogue, mechanical
brunch_whycoverage, or the complete September demo.This is the child half of Lu's explicit FE-1573 two-PR exception. It stacks on Mission 7a. Landing 7a is not acceptance of this demo, and this branch is not closed.
🔗 Related links
ln/fe-1573-construct-and-explain.🚫 Blocked by
🔍 What does this change?
mutate_petrinetuntil server validation, flattens each operation to{operationId, basisId, type, input}, and proves a wrapped-dialect rejection plus a live accepted retry.mutate_petrinetwith 25 one-operation calls on the empty-net product path (same final hash, about 5.8× settlement) and records a live Sonnet turn that applied all 25 in one batch.?scenario=inventory-purchasingspelling is absorbed by existing shared-example document search, so it cannot seed a worked-scenario catalogue.addType,addParameter, andaddDifferentialEquationon selectedmutate_petrinet.addScenarioandaddMetricremain refused.🏗️ Agent notes
The current six-section mission contract follows. Code, tests, and native local records carry implementation evidence; no new repository run packet is introduced. The live ordinary receiving-dock conversation is local to this worktree and is not a portable fixture.
Mission 7b — Substantial worked-scenario demo
Status
Live on
ln/fe-1573-mission-7b, cut from Mission 7a tip2408b90bacunder Lu's explicit FE-1573 two-PR exception. Mission 7a remains in draft PR #9562; its pending CI/review/merge do not become acceptance through this cut. The archived Part A contract is Mission 7a — workpiece, construction and explanation groundwork.This mission replaces the former narrow interpretation of one scripted why/correction path. It requires substantial PM-explorable scenarios and evidence that Brunch produced the flagship through the real product. The current implementation supplies bounded workpiece, mutation and why groundwork; ordinary configured Brunch now constructs from a start-from-scratch composer without
?brunchTracer=, the retained persona run is not a connected model, and no production scenario catalogue exists.Current throughline: the candidate-mode
mutate_petrinettracer now crosses the real product and the same 25-operation empty-net target matches through one batch versus 25 one-operation calls. One directanthropic/claude-sonnet-4-6call passed the selected-schema carrier on its first attempt: one valid 25-operation tool call in 28.3 seconds, 5,287 input / 3,041 output tokens, with unique IDs and every arc referencing earlier created nodes. Missing browser-tool classification and AI SDK dynamic-tool projection now have deterministic coverage; mixedgetLatestNetDefinitionplus construction-resource reads in one proposal remain refused. Product diagnostics now exist (286e5780c2,b475155f53,638a0c2d02). Gate-then-flatten is in. A live?brunchTracer=root-creationSonnet turn accepted a flat three-operationmutate_petrineton the first attempt (toolu_011ci1Ja56WvDmo8hBLeXxr9) and landed oneclient-tool-result; that turn used 11 completions and about $0.071. A faux reject-then-accept witness proved the wrapped dialect never executes. The product-path comparison then built the spike's 10-place / 7-transition / 8-arc target twice on the empty-net tracer: onemutate_petrinet(25 applied, 412 ms) versus 25 one-operation calls (25 applied, 2,373 ms), samepostHash92b27202eea09f4eb637af7465f098d1f7eedc9e9beb1850973f36d60bda733a, about 5.8× settlement. That individual route is 25 one-operationmutate_petrinetcalls, not theaddPlacecatalogue;?brunchTracer=constructionstill opens the prepared crew-reservation substrate.root-creation.integration.tsstill assertsconversationConstructionModeagainst the batched URL. A live Sonnet turn then emitted one flat 25-operationmutate_petrineton that tracer (toolu_01Arft1KQ4xpiWusbjmWFPAN: 10addPlace, 7addTransition, 8addArc), the server accepted it, and the browser applied all 25 (postHashe0dc514b6bec893063e43f9f75f24d7fe8071d61dafcc3dc472c037468463868). That turn used 7 completions and about $0.089. The batch premise survives the product-path comparison. Ordinary configured Brunch now opens an incarnation-scopedbrunch-construction-v1conversation with the same batched catalogue. The first live ordinary start-from-scratch turn was poisoned:usePrepareCrewReservationConversationstill ran because the gate only excluded tracer construction, and first contact injected the Mission 6 crew-reservationbrunch.fixture.preparedsignal. After closing that gate, a fresh ordinary conversation (12e11c419a8ffcddfff0e3e3e5564492a0ba4bcbfe1640d9c76423f8a39532db) began on the user message, settled a goods-receiving workpiece, observed the empty net, and applied one 11-operationmutate_petrinet(toolu_01RPWSJZGDK5Lea566FuFBsZ: 6addPlace, 5addTransition, all applied,postHash607f9596e9e26ffa7997f931f4cede6429b341c09ccb4361d6d59c259f9d2a46). The live net has TruckArrived → Rejected (6 places, 5 transitions, 10 arcs). That turn used about $0.126. A follow-up why on the accept/reject branch (Why do both AcceptGoods and RejectGoods take from InspectionDone?) settled in one completion withoutbrunch_whyor a fresh net read (catalogue estimate about $0.013). The answer named exclusive-choice competition for the InspectionDone token and the unencoded inspection decision, and offered to revise; the workpiece pane stayed at revision 2 with no why record. An ordinary correction asking for a distinct accept/reject outcome then read the live net and stopped (catalogue estimate about $0.033): the model correctly refused to add a parallel dead structure because candidatemutate_petrinetonly admitted addPlace, addTransition, and addArc. The selected batch and ordinary catalogue now also admit root removePlace, removeTransition, and removeArc. A first retry after that widening emitted a valid 11-operation remove/add batch (toolu_01CyoNc7b51X5yr4etwYAKT9, about $0.059) but the browser refused a stale construction-era base after a core rebuild remount. A follow-up that re-read the live net then applied (toolu_01QXhYkr9psBopd9G62aKkhZ→ mutate, preHash02558ae6…0929c5, postHash1615cc3d…8d7d37): 9 applied, 2 no-op (cascaded arcs), workpiece revision 3. InspectionDone and InspectGoods are gone; AcceptGoods takes from Passed and RejectGoods from Failed; TruckArrived → ReadyForInspection is untouched. Exclusive choice moved to InspectPass/InspectFail on ReadyForInspection. That follow-up cost about $0.065. An updated why (Why does AcceptGoods take from Passed now instead of InspectionDone?) distinguished the original shared InspectionDone from the correction in one completion withoutbrunch_whyor a fresh read (about $0.014); the why pane stayed empty. The poisoned first attempt cost about $0.047 and died on the known one-browser-call refusal. Session inference spend is about $0.36 against Lu's $100 cap. Petrinaut File → New now offers Build with Brunch or Start blank when an assistant is mounted; Build with Brunch opens the assistant on a fresh empty net and offers Interview first versus Quick preview chips. File → New now offers Build with Brunch or Start blank when an assistant is mounted; Build with Brunch opens Interview first versus Quick preview chips. Closing and reopening the assistant on the receiving-dock net restored revision 3 and the corrected topology without a new turn.?scenario=inventory-purchasingis absorbed by the existing shared-example simulation-scenario location and stays on the ordinary route; it is not a catalogue bundle. Selectedmutate_petrinetnow admits root addType, addParameter, and addDifferentialEquation; addScenario and addMetric remain refused. This is not a seeded scenario catalogue. Lu authorizes Mission 7b development inference under that $100 cap and directs sapper-like execution: record usage, stop on material failure, but do not turn each bounded reversible step into another ceremony gate. Scenario seeding, remote write, release and Linear write remain separate.Imperative
Deliver a product manager–usable Brunch experience around substantial worked process models rather than diagnostic fixtures: begin from scratch or open an independently owned seeded scenario containing its real conversation, evolving workpiece, evidence and connected Petrinaut model; explore why consequential model content exists; correct the account in ordinary language; observe bounded workpiece/net change and updated explanation; and reopen/continue. Retain a recording proving that Brunch carried a realistic isolated persona from elicitation through visible native construction of the flagship.
Match the Inventory purchasing baseline's subsystem and decision complexity without treating its exact node topology or counts as an answer key. Keep the chat as the interaction basis until the simultaneous chat/workpiece presentation is solved; do not expand into a generic question-card framework. Establish the fundamental conversation → workpiece → substantial model → provenance → correction path before the lower-priority constraint/experiment slice.
Throughline
Product entrypoints
?user=value is not authorization./agents/chat/:instanceIdrouting remains through the demo. Future aliases/routes are deferred on any risk or doubt.Scenario catalogue and working copies
The PM-facing database-backed catalogue uses stable URLs such as:
The baseline set contains two substantial bundles. Inventory purchasing is the flagship and common capability baseline. Choose the contrasting second scenario only after the Inventory path reveals whether the dominant strain is replenishment/safety, continuous dynamics, or quality/recovery.
A scenario template is a coherent bundle, not only a Petrinaut document:
After migrations and before readiness, startup idempotently updates approved templates in Postgres under stable IDs. New definitions affect new opens without duplicating visible catalogue entries or changing existing sessions. Opening a scenario creates or resumes an independently owned working copy; template and other copies remain unchanged. Preserve coherent conversation, workpiece, evidence, transition and document identities through an inspected native contract—not blind string replacement, diagnostic-export import or model replay. Provide reliable resume and a safe clean-copy/rehearsal route; decide the smallest UX after inspecting native copy identity.
The existing
brunchDemoModetoggle and?brunch-fixture=crew-reservation-v1route remain developer/test mechanisms. The crew-reservation fixture and retained inert Vestera probe are not demo content.Workpiece and projection cadence
Quick preview
When time is tight or a user wants a preview, Brunch offers to fill gaps and proceeds only after assent. It may update the working workpiece and net immediately, but every model-supplied assumption remains visibly provisional, editable and attributed to the model rather than the interviewee. It may propose candidate safety thresholds, objectives and consequential policy choices, but those remain unresolved until the user adopts them. Preview usefulness depends on the same construction/provenance path working quickly and honestly; it is not a bypass around broken construction.
Current throughline — bounded mutation probe
The proposed
mutate_petrinetclient tool carries bounded coherent chunks of approximately 20–30 operations or 64 KiB of arguments, subject to provider evidence. Inventory topology arithmetic now suggests about 403 operations including metrics, or roughly 14–17 initial chunks, rather than hundreds of provider/browser settlement cycles. This remains an estimate, not a performance claim.Accepted candidate semantics for the probe:
unattempted.basisId.The completed local probe exercised a 26-operation canonical loop and a 25-operation generated carrier. Ordered and individual callbacks produced the same final hash; intra-chunk IDs resolved; a deterministic no-op, readonly no-ops, extension sanitization, exact committed prefix and explicit unattempted suffix were observed. Local outcome accounting averaged 2.240 ms versus 2.068 ms for individual callbacks, so the mechanism itself was 8.3% slower and the expected settlement-latency saving remains unproved. The 25-operation payload was 5,330 bytes / about 1,545 tokens, while the full 41-operation schema was 69,897 compact bytes / about 16,581 tokens and exceeded the provisional 64 KiB threshold. Transport correlation accepted one outer result and rejected changed replay content, but this probe did not independently prove a universal two-browser-call refusal. Native artifacts remain under
/tmp/m7b-batch-spike-{mechanics,carrier}and are disposable.The combined no-edit browser/provider probe stopped honestly because the shipped ChatAgent and website recognize static tool catalogues. The direct selected-schema Sonnet discriminator then passed on the first and only generation request (
req_011CeunumYCAx5eiRweqnDyf): the 15,449-byte / approximately 3,584-token schema produced exactly 10 places, 7 transitions and 8 arcs with valid canonical inputs, no repair and correct intra-call references. The candidate-mode tracer now crosses Flue deferred-tool correlation and browser canonical execution. A faux product-path comparison of that same 25-operation target recorded one batch versus 25 one-operationmutate_petrinetcalls: 1 versus 25 client-tool-results, 412 ms versus 2,373 ms, identical final hash, every operation applied. A live Sonnet generation then produced one flat 25-operation call on the same tracer and the browser applied all 25. A provisional 5× improvement is a strain detector, not a sacred benchmark; the observed 5.8× is settlement only (faux provider, no generation). Retain the tracer. The next strain is Inventory-scale admission (types, dynamics, parameters, metrics, scenarios) and a catalogue key that does not collide with document?scenario=, not another ordinary-path dispatch diagnosis. Ordinary start-from-scratch now has a live workpiece-then-mutate_petrinetproof; File → New now offers Build with Brunch or Start blank; reopen after the accept/reject correction restored revision 3.Proof
Visible completion
A representative live exploration adds approximately 5–10 ordinary chat turns; the presenter may rehearse one route, but those turns sample a broadly usable artifact rather than define its only supported path.
A PM who did not watch development can:
Shape and quality heuristics
The ranges below expose undersized work; counts alone cannot pass, and a smaller artifact may pass only when it preserves comparable subsystem and decision complexity.
Explanation readiness
Every consequential visible flagship element has an inspectable recorded basis or explicitly reports absent/incomplete basis:
Inventory the consequential visible elements and mechanically traverse each path. Human usefulness review samples main flow, resource constraint, branch/decision, timing/dynamics, exception, assumption/unsupported default, and the corrected element before/after correction. Answers must be understandable and credible, not merely return records. Broader cross-scenario reliability and the former passage/lifecycle/adversarial campaign remain deferred; that deferral cannot excuse a thin flagship.
Oracle table
mutate_petrinetnow hold. Failure of later Inventory-scale chunks still returns to the construction design discussion.Constraints
Scope posture: primary obligations and strains
The mission is bounded by visible product utility, not by pretending the route is equally secure everywhere. “Primary” means required for the product claim; “strain” names a current weak premise or expensive join whose next discriminator is explicit.
brunch_why, so the mechanical record/basis/passage pane stays empty.?scenario=inventory-purchasingspelling collides with the shared-example simulation-scenario location already owned byexample-search.ts; do not overload that key. Second scenario waits on Inventory's dominant observed strain.brunch_why. Mechanical completeness still requires the tool or an honest absence.mutate_petrinetnow also admits root addType, addParameter, and addDifferentialEquation. addScenario and addMetric remain refused.Earned data and execution contracts
Ownership
Owner decisions
mutate_petrinet. The throughline defect is premature browser dispatch plus an under-described wrapped operation dialect, not server/browser schema drift. Withholdmutate_petrinetuntil server validation, mark gated starts dynamic, flatten operations to{operationId, basisId, type, input}with envelope descriptions, and make root-only exclusions structural. Do not add a FlueprepareArgumentsnormalizer. Keep the panel's terminate-on-executor-throw rule.mutate_petrinetobserved. A live root-creation tracer turn accepted a flat three-operation batch on the first attempt and landed oneclient-tool-result; a faux reject-then-accept witness proved the wrapped dialect never executes.mutate_petrinetand through 25 one-operation calls on?brunchTracer=root-creation(412 ms versus 2,373 ms, 5.8× settlement, all 25 applied). Compare chunk size on the empty-net batched tracer; do not treat?brunchTracer=constructionor the stale root-creation individual-tool suite as that baseline.mutate_petrineton the empty-net tracer; the server accepted it and the browser applied every operation. Retain the tracer. Next is the first ordinary create/open path that does not depend on?brunchTracer=.brunch-construction-v1:${incarnationId}withbatched-constructioninitial data, the three-tool catalogue, workpiece pane andmutate_petrinet. Old UUID chats stay unused. Next is Inventory-scale construction and create-new UX, not another dispatch diagnosis.requestedBaseHash. Ordinary batched construction inherited that preparer and injected Mission 6 revision zero before the user's first message.mutate_petrinet(6 places, 5 transitions, all applied). Next is why/correction on that net or Inventory-scale chunks, not another catalogue-mount diagnosis.brunch_why. The receiving-dock accept/reject question was answered as exclusive-choice plus an unencoded decision. The model did not callbrunch_whyorgetLatestNetDefinition; the why pane stayed empty. Do not name the why tool in a follow-up.mutate_petrinetcannot rewire InspectionDone without leaving a dead parallel net. Admit root removePlace, removeTransition, and removeArc on the selected batch rather than asking the user to delete nodes or rebuild from scratch. Do not name those operations in the user prompt.brunch_why. After the correction, the AcceptGoods/Passed question distinguished original shared InspectionDone from the new routing. The model did not callbrunch_whyor re-read; the pane stayed at revision 3 with no why record. Do not spend further ordinary-why turns hoping the tool appears.?scenario=collides with document location.validateLocalStorageDemoSearch({ scenario: "inventory-purchasing" })keeps that value as the shared-example simulation-scenario id and stays on the ordinary route. Do not treat that key as a worked-scenario bundle until the location contract is recut.mutate_petrinetnow includes root addType, addParameter, and addDifferentialEquation. addScenario and addMetric stay refused until simulation-catalogue admission is a separate slice. Do not start a live Inventory construction until those remaining classes and a non-colliding catalogue key are decided.Fog-line
mutate_petrinet, and an ordinary correction then rewired that net with remove+add. Ordinary and updated why were fluent without abrunch_whyrecord. File → New now splits Build with Brunch and Start blank. Selectedmutate_petrinetnow admits types, parameters and differential equations. Do not deepen past addScenario/addMetric admission, a non-colliding catalogue key, or a later why-tool strain that is not another ordinary-language follow-up.Stop or reorient
Deferred
Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
Changesets cover selected mutation-batch admission, File → New create-new labels, and host-registered dynamic AI tools / assistant error attribution.
📜 Does this require a change to the docs?
The changes in this PR:
Petrinaut's drawing and AI-assistant docs describe File → New → Build with Brunch / Start blank. Maintainer screenshots of the submenu and chips are still pending.
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
apps/brunch-agentgains directtest:mutate-petrinet-comparisonandtest:mutate-petrinet-retryscripts. They are not new Turbo pipeline tasks.?scenario=inventory-purchasingstays on the ordinary shared-example route; do not overload that key.brunch_whyand a fresh net read. The why pane stayed empty.mutate_petrinetstill refusesaddScenarioandaddMetric. Full-registry schema remains above the provisional 64 KiB threshold.🐾 Next steps
brunch_whyappears; treat mechanical why as its own strain.🛡 What tests cover this?
mutate_petrinettests for the flattened{operationId, basisId, type, input}dialect, withheld invalid batches, and selected operation classes.test:mutate-petrinet-comparison(batch versus 25 one-operation calls) andtest:mutate-petrinet-retry(withheld wrapped dialect, then accepted flat retry).❓ How to test this?
ln/fe-1573-construct-and-explain. Do not review it as if it were based onmainalone.VITE_BRUNCH_CHAT_ENDPOINT=/agents/chat turbo run build test:unit lint:tsc lint:eslint --filter @hashintel/petrinaut-core --filter @hashintel/petrinaut --filter @hashintel/brunch-agent --filter @apps/brunch-agent --filter @apps/petrinaut-website.apps/brunch-agent, runyarn test:mutate-petrinet-comparisonandyarn test:mutate-petrinet-retryafter the documented website build variable is set. These use a local faux provider on the tracer routes; they are not persona-quality results.yarn dev:brunch). Open configured Petrinaut without?brunchTracer=or?brunch-fixture=. Confirm first contact does not inject the crew-reservation prepared fixture, then construct from the composer.?scenario=inventory-purchasingas a catalogue bundle.📹 Demo
The current live witness is the ordinary receiving-dock net: workpiece revisions 2 then 3, an 11-operation add batch, then a remove/add correction that left TruckArrived → ReadyForInspection untouched and moved exclusive choice to InspectPass/InspectFail. Closing and reopening the assistant restored that conversation without a new turn. Maintainer upload of the File → New submenu is pending. There is no Inventory-scale recording, seeded-catalogue walkthrough, or persona-carried construction video.
Stack generated by Git Town