From 9c0c82ecb5940d4064ef11473d1d007a4ddd1de1 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Thu, 3 Sep 2026 14:48:15 +0200 Subject: [PATCH 01/31] Cut Mission 6 resumable fixture authority --- libs/@hashintel/brunch-agent/MISSION.md | 228 +++++++++--------- libs/@hashintel/brunch-agent/MISSION.next.md | 25 +- ...6-resumable-workpiece-petrinaut-fixture.md | 165 ------------- .../mission-drafts/7-capture-backed-review.md | 4 +- .../mission-drafts/9-traceable-projection.md | 2 +- 5 files changed, 122 insertions(+), 302 deletions(-) delete mode 100644 libs/@hashintel/brunch-agent/docs/mission-drafts/6-resumable-workpiece-petrinaut-fixture.md diff --git a/libs/@hashintel/brunch-agent/MISSION.md b/libs/@hashintel/brunch-agent/MISSION.md index 80ffa308dc6..2bfbac0e175 100644 --- a/libs/@hashintel/brunch-agent/MISSION.md +++ b/libs/@hashintel/brunch-agent/MISSION.md @@ -1,164 +1,154 @@ -# Mission 5 — one Flue conversation route for Voice and the typed panel +# Mission 6 — resume one prepared workpiece and Petrinaut document ## Status -**Live as of 2026-09-04** for [FE-1574](https://linear.app/hash/issue/FE-1574/let-voice-speak-through-canonical-brunch-conversations) on `ln/fe-1574-direct-voice-flue`, stacked directly on the closed Mission 4 branch. This is the sole execution authority for the branch. The builder implementation now routes typed panel and finalized Voice turns through one browser `FlueClient` at `/agents/chat/:instanceId`, projects canonical replies into Petrinaut and TTS, uses durable Flue abort for explicit Stop, and rehydrates canonical conversation state through SDK observation. The former Brunch `/api/chat` handler and projector are deleted. A human witness passed typed and Voice admission, spoken playback, barge-in, and explicit durable Stop, but failed faithful reopen: per-message typed/Voice provenance disappeared and the stopped assistant entry returned as ordinary truncated content rather than a stopped turn. The owner deferred remediation to Mission 6 rather than expanding this branch. Mission acceptance remains open; proof leaf 8 is not complete. +**Live on `ln/fe-1575-resumable-workpiece-petrinaut` from 2026-09-03.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) is in progress. This authority cut is committed separately before product or evaluation implementation begins. It was recut on restack the same day to carry the product-manager litmus adopted in [`MISSION.next.md`](MISSION.next.md#current-authority-and-accepted-spine) after the first cut: completion is the readiness gate below, not the first green two-tab pass. The 2026-09-04 Mission 5 human witness also made faithful transcript resume load-bearing here: per-message typed/Voice provenance disappeared after reload, and a stopped assistant entry returned as ordinary truncated content. The owner deferred both defects to this mission rather than expanding Mission 5. -The accepted departure base remains Mission 4's package-composed `ChatAgent`: `useBrunchAgent()` mounts core's independent `elicitation` capability and `useSdcpnPlugin()` mounts the SDCPN job contribution. `@hashintel/brunch-agent-transport-aisdk` is now the browser adapter over public `@flue/sdk`, not a server handler. The current external Voice evidence remains PR [#9496](https://github.com/hashintel/hash/pull/9496) at `c7fe8a2e68e8fdc37018b21ec2e9daf4e9ef7c82`, PR [#9507](https://github.com/hashintel/hash/pull/9507) at `252b9dbb0c77fae8cee45a506f09cac3e20c381c`, and PR [#9512](https://github.com/hashintel/hash/pull/9512) at `d13535d1077b3a78d6a1411031b7d0a0a78e3144`. They are read-only source evidence, not branches to rewrite or wholesale architecture to restore. +## Imperative -Cold-start reads are [`docs/evidence/implementations/mission-4-voice-integration-handoff.md`](docs/evidence/implementations/mission-4-voice-integration-handoff.md), [`packages/transport-aisdk/src/index.ts`](packages/transport-aisdk/src/index.ts), [`packages/transport-aisdk/src/ui-stream.ts`](packages/transport-aisdk/src/ui-stream.ts), [`packages/transport-aisdk/src/transcript.ts`](packages/transport-aisdk/src/transcript.ts), [`apps/brunch-agent/src/app.ts`](../../../apps/brunch-agent/src/app.ts), [`apps/brunch-agent/src/http/ownership.ts`](../../../apps/brunch-agent/src/http/ownership.ts), [`apps/brunch-agent/test/petrinaut-chat.integration.ts`](../../../apps/brunch-agent/test/petrinaut-chat.integration.ts), [`apps/brunch-agent/test/architecture/boundaries.integration.ts`](../../../apps/brunch-agent/test/architecture/boundaries.integration.ts), [`apps/petrinaut-website/src/main/app/local-storage-demo/`](../../../apps/petrinaut-website/src/main/app/local-storage-demo/), [`apps/petrinaut-website/src/main/app/voice-interview/`](../../../apps/petrinaut-website/src/main/app/voice-interview/), and the installed Flue 2.0.3 documentation at `node_modules/@flue/sdk/docs/sdk/flue-client.md`, `node_modules/@flue/sdk/docs/reference/streaming-protocol.md`, and `node_modules/@flue/sdk/docs/guide/react.md`. +Determine whether one canonical Brunch conversation can maintain a useful Markdown workpiece and drive a meaningful change to a real Petrinaut document through the browser without reviving a comprehensive typed domain IR. -## Imperative +Mission 3 separately showed a recoverable Markdown workpiece and hermetic canonical Petrinaut callbacks, but its paid model could not carry a nested construction schema and no product path joined the two results. Mission 4 accepted the independent core `elicitation` capability and SDCPN job-skill composition but produced no full-run candidate. This mission must retire the join and resume uncertainty honestly with one deliberately prepared fixture rather than treating either historical result as an integrated product. + +### Visible product advance -Make the mounted Flue conversation route the only product door into a Brunch conversation, and make Voice a faithful audio projection of that one canonical conversation. One finalized spoken answer and one typed panel message must both enter the owning Flue conversation through `@flue/sdk` against `/agents/chat/:instanceId`, and the corresponding canonical Brunch response must reach visible text and TTS without another model rewriting the text. Do this now because Mission 4 established the canonical agent composition while two transports still exist to the same conversation: the Voice preview's AI SDK composer path and the server-side `/api/chat` adapter, which admits through a different code path than the SDK does. Routing Voice onto Flue while keeping `/api/chat` for typed text would harden the split into two routes, two ownership rules, and two protocols; the least mechanism is one route, with the AI SDK reduced to the panel's rendering contract behind a host-supplied browser `ChatTransport`. +**Release note:** Brunch edits the Petrinaut net you are looking at from the conversation, and your work survives closing the tab. -### Product-manager litmus +**Demo script (no engineer present):** with the local Brunch/Petrinaut development stack running, open the stable demo fixture selector for the labelled prepared crew-reservation case. Its canonical Brunch conversation, current Markdown workpiece, and non-empty Petrinaut net come back together. Tell Brunch the one new realistic fact the fixture is prepared for: final inspection uses the single dispatch crew, and sign-off releases it. Watch the workpiece update and a new arc appear in the live net from `Dispatch crew available` to `Start final inspection`. Save. Open the same fixture in a second tab and continue the conversation from the saved state. Confirm that messages retain their typed/Voice provenance and that an aborted assistant entry still presents as stopped rather than as an ordinary truncated answer. The fixture announces out loud that it is test-authored and prepared, and what it does not claim. -Adopted on restack onto the parent spine's 2026-09-03 litmus reframing. A product manager who did not watch the work must be able to notice the advance; the single-route consolidation, the browser `ChatTransport`, the deleted `/api/chat` door, and the repurposed transport package are internal sequencing and must not be presented as the advance. +**Previously impossible:** Brunch only produced off-canvas net JSON for manual load; nothing it did touched the live document or survived a reload. -**Release note:** in the Petrinaut Brunch panel you can type or speak to Brunch in one conversation; what you hear is exactly what Brunch wrote; **Stop** really stops Brunch rather than just hiding its answer; and reopening the panel shows the same conversation you left, without re-sending or replaying anything. +**Deployment posture:** the demo runs against the locally run Petrinaut website and Brunch agent (`yarn dev:brunch`). Mission 8 stopped before remote deployment, so no product-manager-noticeable claim here depends on remote infrastructure; remote durability stays with Mission 8. -**Demo script (no engineer present), on the deployment posture available at cut time — the local `yarn dev:brunch` pair with the Brunch preview selected:** open the panel and type one message; read the reply. Start Voice mode and speak one answer; see exactly one new user message appear, then see Brunch's reply appear as text and hear the same words read aloud. Speak over it once; playback stops and the text stays. Ask a second question and press **Stop** while Brunch is still working; the conversation shows that turn as stopped, not as an answer. Close the panel and reopen the same conversation: the typed turn, the spoken turn, and the stopped turn are all there exactly as you saw them, nothing replays, and nothing is sent again. +**Completion:** the mission is done when a product manager can run that demo script end to end for this fixture and every readiness-gate obligation in [Proof](#proof) is closed. The first green pass through the two-tab path is an internal milestone inside the mission, not its completion. -**Previously impossible:** Stop only cancelled the browser request while Brunch kept working, so reopening the panel showed a full answer you had stopped; typed and spoken turns entered Brunch through different doors, so a spoken turn could be held or ordered differently from a typed one. +## Throughline -**Completion:** the mission is complete at the contract stratum below — when a product manager can run this demo script end to end and proof leaf 8's witness bundle records it — not when the first typed or spoken turn crosses the route. The first green typed-panel tracer and the first green Voice tracer are internal milestones. +### Observed departure point and first unproved boundary -### Recut rationale +The production browser already has most local pieces: -Inspected at the real boundary on 2026-09-03 (`node_modules/@flue/sdk/docs/reference/streaming-protocol.md`, `packages/transport-aisdk/src/index.ts`, `packages/transport-aisdk/src/ui-stream.ts`, `apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts`, `node_modules/ai/dist/index.d.ts` `ChatTransport`): +- `apps/petrinaut-website`'s local-storage demo owns an editable `PetrinautDocHandle`, writes handle changes to `petrinaut-sdcpn`, maps each net to a persistent Brunch conversation id, and hydrates panel messages from the Brunch history door; +- Petrinaut's stock AI panel already validates and executes canonical read, mutation, and command tools against the active browser document and returns the original tool-call id; +- `apps/brunch-agent` already maps the principal plus conversation id to one Flue conversation, exposes `GET /api/chat?id=…` history, resumes client-tool results as correlated Flue signals, and projects the resulting stream back to the panel; and +- the SDCPN skill already emits a full recoverable `runbook-ir` block and requires construction to consume that workpiece rather than transcript archaeology. -- Flue's SSE does not remove the need for translation while the panel speaks `useChat`: Flue admits one `DeliveredMessage` with a 202 and streams `ConversationStreamChunk` batches on a separate, never-ending offset-resumed read; the AI SDK posts the whole `messages` array and expects one finite `UIMessageChunk` stream per turn. Request shape, vocabulary, and lifecycle all differ, and `@flue/*` ships no AI SDK adapter. -- At the recut, the adapter was one translation cut across two homes by the transport topology gate: AI SDK request framing, CORS, and principal parsing in `transport-aisdk` (then Flue-free), and the load-bearing `ConversationStreamChunk → UIMessageChunk` projection plus snapshot → UI messages in `apps/brunch-agent/src/conversation/`. -- A Hono-level relocation would have re-expressed the same admit → follow → project → terminate join as a server handler; it would have removed nothing and kept two routes. It was rejected. -- AI SDK `ChatTransport` is a client-side interface, and Petrinaut already accepts and wraps host-supplied transports. The landed browser transport over the same `createFlueClient()` that Voice uses owns the projector, removes `/api/chat` and its handler, and makes typed and spoken turns share one admission path, one ownership guard, and one protocol. +The first unproved boundary is ordinary Brunch conversation → mounted canonical document read / least mutation → browser execution → correlated continuation. Today ordinary SDCPN conversations mount only the Petrinaut documentation reader as a browser tool; the validated construction subset is headless-only, and no stable fixture selector or coherent cross-tab witness joins the conversation, workpiece, and document lifecycles. -## Throughline +### Accepted fixture and boundary crossings + +Prepare the existing final-inspection / dispatch-crew case as an explicitly test-authored fixture. Its starting workpiece and non-empty net preserve this narrow account: one crew is reserved during final inspection, sign-off releases it, the batch then becomes dispatch-ready, and timing plus failure/recovery remain unresolved. Its prepared material must identify its authorship and must not be presented as a Mission 4 candidate or model-produced evidence. -The real boundary is the local Petrinaut surface driven by `yarn dev:brunch` — both its typed panel and its Voice control — through one same-origin-proxied Flue route into the mounted production `ChatAgent`, back to visible Petrinaut text and, for Voice, audible playback: +Prepare the net with `Batch ready`, `Under final inspection`, `Ready for dispatch`, and `Dispatch crew available` places plus `Start final inspection` and `Sign-off` transitions. Preserve the batch-flow arcs and the return of the crew from sign-off, but deliberately omit the standard input arc that reserves the sole crew when final inspection starts. Use one realistic confirming answer: final inspection consumes the sole available dispatch crew, sign-off returns it, and timing plus recovery remain unknown. The least candidate mutation is one canonical weight-1 standard input arc from `Dispatch crew available` to `Start final inspection`. The exact before/after edge makes the semantic oracle discriminating while avoiding Mission 3's deeply nested schema failure. If that shallow mutation still cannot cross Flue faithfully, stop with the carrier blocker rather than weakening the claim. ```text - Petrinaut typed panel (`useChat`) Petrinaut microphone - → host-supplied browser `ChatTransport` → OpenAI Realtime provisional STT + turn detection - (`sendMessages` → one user text or → one validated finalized `continue_interview` answer - one client-tool-result signal) - └──────────────┬────────────────────────────┘ -→ one browser `createFlueClient()` per selected principal + logical conversation id -→ one supported `send()` admission at the same-origin proxied `/agents/chat/:instanceId` route - (Voice may enter via the panel's transport — preferred, one visible store — or call `send()` directly; see fog-line) -→ `agentOwnershipGuard` (the only ownership check) → `createAgentRouter(ChatAgent)` -→ current `ChatAgent` with `useBrunchAgent()` + `useSdcpnPlugin()` -→ SDK reads: `wait(admission, { onEvent })` for the panel's finite per-turn stream, - `observe({ live: "sse" })` for canonical state and reopen -→ response parts correlated by server-issued `submissionId` -→ panel: existing `ConversationStreamChunk → UIMessageChunk` projector, terminated on `submission-settled` -→ Voice: canonical completed Brunch text displayed and passed unchanged as TTS input -→ local playback/observation cancellation or explicit conversation-wide `abort()` -→ observation rehydration after reopening the same logical conversation +stable prepared-fixture selector +→ resolve distinct fixture, Petrinaut document, and Flue conversation identities +→ open the prepared non-empty browser document and hydrate canonical Flue history +→ recover the latest Markdown workpiece revision by source message id plus content hash +→ submit the realistic crew-reservation confirmation through the production panel door +→ Brunch emits an inspectable full workpiece revision without erasing prior meaning or the remaining unknown +→ SDCPN construction reads that current workpiece and the live browser document +→ Brunch requests the least canonical meaningful mutation +→ Petrinaut validates and executes it against the bound document +→ the original tool-call id and result resume the same Flue conversation +→ inspect the canonical non-empty document and record a settled fixture witness only after conversation/workpiece/document state is observable +→ a second tab opens the same fixture selector, resolves the same identities and settled hashes, and can continue ``` -The `/api/chat` route, `createPetrinautChatHandler`, the in-process `init().dispatch()/read()` admission path, the `GET ?id=` history door, and the `/api/chat` Vite proxy are removed from the Brunch app; the local launcher proxies `/agents/chat/*` instead. `@hashintel/brunch-agent-transport-aisdk` is repurposed as the browser-side adapter: it exports the projector, the snapshot → UI-message projection, the header names, and a `ChatTransport` factory over a caller-supplied `FlueClient`, and depends on `ai` and the public `@flue/sdk` client only. The Petrinaut panel itself stays on `useChat`; it is not rewritten onto `@flue/react`. +The fixture witness is a small local viability manifest, not a new event log, independent workpiece store, or distributed transaction. It records distinct ids, prepared inputs, latest settled workpiece source/hash, document hash or local revision token, and limitations. A failed history load, workpiece recovery, rejected/no-op mutation, or missing result correlation must not advance that witness; the partial state remains visible for diagnosis. The existing automatic localStorage mirror is the only document-save mechanism unless a real failure proves it insufficient. -`conversationId` is the stable logical reference selected by the Petrinaut host. The current principal plus that id mechanically derives the Flue instance path and ownership headers. `submissionId` correlates one admitted answer and its settlement. Flue offsets remain opaque. `uid` identifies one current incarnation and may guard a known continuation, but it must not replace the logical conversation id or be presented as durable user identity. +### Expected touched paths -For maintained Voice state beyond what the panel already holds, use the SDK's materialized `observe()` surface, or `useFlueAgent()` over the same memoized client if the React seam earns it. Use `readSubmissionReply()`, `read()`, or `wait({ onEvent })` only for submission-scoped extraction, not as a parallel transcript reducer; the panel transport's per-submission projection into `useChat`'s own store is that submission-scoped use, not a second transcript. Do not parse SSE, calculate offsets, retry stream chunks, or hand-pick the latest message. The tracer may stream canonical text visibly through the observation, but TTS begins only from completed speakable segments and may remain settlement-gated; token-by-token speech is not part of this claim. +This manifest is provisional and may shrink or move when the first real probe exposes the deeper existing boundary: -The first tracer is text-turn-only at the Brunch boundary. It does not require the temporary `brunch_ask` client-tool shim: a finalized spoken answer is a direct Flue user message, and canonical plain assistant text is sufficient to prove the transport. If the real tracer cannot preserve answer correlation without structured questions, stop and present that observed strain before mounting the suspended capability. +```text +libs/@hashintel/brunch-agent/ +├── MISSION.md ~ live authority and eventual close evidence +├── MISSION.next.md ~ future joins and carried flags only +├── packages/plugin-sdcpn/ ~ mount only the read/mutation capability earned by this tracer +└── docs/evidence/ + prepared fixture manifest and browser witness +apps/brunch-agent/ +├── src/agents/chat-agent/ and src/conversation/ ? only if normal client-tool mounting/correlation requires it +└── test/ + real Flue/client-tool fixture integration +apps/petrinaut-website/ +└── src/main/app/local-storage-demo/ ~ fixture selection, prepared seed, settled witness, and cross-tab resume +libs/@hashintel/petrinaut-core/ or libs/@hashintel/petrinaut/ ? only for an observed canonical contract or browser-host defect +``` -### Contract stratum and readiness gate +## Proof -Close the **one-route conversation transport stratum**: one typed turn and one finalized Voice turn each admitted once through `@flue/sdk` at the mounted route, canonical output, client-tool follow-up as a signal, local playback cancellation, durable abort, visible failure, and same-conversation reopen — with no second server-side door remaining. +The visible advance is the demo script in the imperative, run by a product manager against the named local posture. The evidence that backs the claim is one stable local demo URL or fixture selector plus its labelled prepared manifest, exact before/after Flue snapshots, recovered Markdown workpiece revisions, canonical Petrinaut document states, and two-tab witness; those are oracles for the builder and adjudicator, not the advance itself. Together they establish single-fixture browser-backed viability. They do **not** establish automatic full-net projection, capture-backed or selected-pair provenance, behavioral execution, broad scenario coverage, remote replacement durability, concurrent editing, Mission 3/4 quality superiority, or a promoted reusable product seed. -Order the tracers so the cheaper one proves the route first: the typed panel over the browser transport (it reuses the existing projector and has an existing integration scenario to re-express), then Voice. After each end-to-end turn works, enumerate the lateral obligations it exposes and close those required to make the visible claim true: duplicate finalization, ambiguous admission, submission/reply correlation, client-tool resume correlation, reconnect and replay, local cancellation versus durable abort races, fatal ownership errors, and canonical text/TTS-input correspondence. Carry broader speech ergonomics, multi-turn barge-in tuning, structured questions, and remote identity and exposure only to the named deferred owners below. +### Internal milestone: first green throughline -## Proof +The first internal milestone is one pass through the throughline for the prepared fixture: a cold reader can reconstruct the spine and distinguish supplied evidence, inference, and the explicit unknown in the workpiece; one realistic turn produces an inspectable workpiece revision without erasing the unknown; Brunch reads the live document and applies the one supported arc through the real browser client-tool boundary; the canonical net is non-empty and visibly corresponds to the confirmed meaning; and a second tab observes the same settled conversation, workpiece, and document revision and continues without duplicate submission or identity drift. Reaching this milestone authorizes the readiness work below; it does not close the mission. -This proof establishes that one real local typed turn and one real local Voice turn each cross the supported Flue conversation protocol at the single mounted route into the current canonical Brunch agent, that the typed turn returns as one finite AI SDK stream and the Voice turn as one visible and spoken canonical response, both with bounded cancellation and recovery semantics, and that no server-side AI SDK door remains. It does **not** establish trusted production authentication, remote deployment, broad Voice UX, structured-question transport, Petrinaut client-tool mutation, workpiece viability, or that the `useChat` panel itself is removable. +### Readiness gate: completion bar -1. **Typed panel over the browser Flue transport.** A typed panel submission calls `send()` exactly once with one `kind: "user"` message; a completed client-tool follow-up calls `send()` exactly once with one `kind: "signal"` `client-tool-result` message and resumes the same assistant message id; the returned `UIMessageChunk` stream carries the same start/step/part/finish sequence the former `/api/chat` integration asserted, and terminates on that submission's `submission-settled`. Reopen hydration comes from `observe({ live: "sse" })` through `snapshotToUiMessages`. Oracle: the current `apps/brunch-agent/test/petrinaut-chat.integration.ts` scenario re-expressed through the browser transport against the in-process `app.fetch` of the real `app.ts` (Flue route, ownership guard, faux provider), preserving its text, reasoning, server-tool, and client-tool-resume assertions; the relocated projector and transcript unit tests; and the outer witness typing one message in the real panel with the network ledger showing only `/agents/chat/:instanceId` traffic. -2. **Direct finalized admission.** A completed Realtime `continue_interview` call invokes Flue `send()` exactly once with one `kind: "user"` message; provisional transcript events, duplicated provider terminal events, stale epochs, and repeated tool-call delivery never enter history. The admitted server `submissionId` becomes the turn correlation key. A lost or ambiguous admission is surfaced and never blindly resent. Oracle: named cases in `apps/petrinaut-website/src/main/app/voice-interview/realtime-brunch-bridge.test.ts`, including `admits one finalized Realtime answer through Flue once`, plus canonical snapshot inspection showing exactly one matching visible user message. -3. **No server-side AI SDK door.** The Brunch app no longer mounts `/api/chat`; `createPetrinautChatHandler`, `PETRINAUT_CHAT_ROUTE`, the in-process `init()` admission path, and the `/api/chat` proxy are deleted; the repurposed transport package contains no `Request`/`Response` handler. The real Voice turn reaches the mounted route through `@flue/sdk` — either through the panel's Flue transport or by a direct `send()` — and makes no submission over any non-Flue protocol. Oracle: `apps/brunch-agent/test/build-artifact.test.ts` asserting the built server answers `/api/chat` with Hono's 404 and still serves the Flue route; the retained browser network ledger from the outer witness; and a focused integration case in `apps/petrinaut-website/src/main/app/voice-interview/voice-preview.integration.test.ts` named `admits a Voice turn only through the Flue route`. -4. **Canonical visible and TTS output.** The materialized response selected for the admitted `submissionId` is the source for visible text and TTS input. Completed visible assistant text is preserved in part order; reasoning and non-speech parts are not promoted to spoken text. The exact string array sent for canonical speech equals the selected Brunch text, and no response-preparation or simplification generation call occurs. Oracle: `apps/petrinaut-website/src/main/app/voice-interview/canonical-speech.test.ts`, `openai-realtime-session.test.ts`, and the outer artifact comparison of canonical snapshot text to the recorded TTS request payload; the human witness confirms that playback begins but does not claim synthesized audio is a verbatim recording. -5. **Cancellation and abort stay distinct.** Barge-in, pause, or panel closure stops local playback/observation according to the existing Voice contract without rewriting or deleting canonical history. An explicit durable Stop action uses Flue's conversation-wide `abort()` when work is unsettled, and history/observation exposes an `aborted` settlement; an abort that loses the race to completion remains completed. Oracle: named local-versus-durable cancellation cases in `voice-turn-controller.test.ts` and `voice-preview.integration.test.ts`, plus the retained Voice event ledger and Flue settlement. -6. **Reopen resumes without replay.** Reopening the same selected conversation rehydrates its canonical messages and settlements from Flue, does not submit another user message, and does not automatically replay settled audio. An absent conversation, fatal 401/403, reconnecting stream, and settled conversation are visibly distinguishable. Oracle: a named `rehydrates the settled Voice turn without resubmission or playback` case over the SDK observation in `realtime-brunch-bridge.test.ts`, followed by the outer witness reopening the panel and comparing the second view with the same snapshot. -7. **Architecture and boundary integrity.** The built app still mounts `useBrunchAgent()` plus `useSdcpnPlugin()`, excludes the obsolete app-local stub agent, derives ownership from principal plus logical conversation id in exactly one guard, and reaches Flue locally through a same-origin protocol-preserving proxy rather than a newly public route. The transport package's runtime dependencies are exactly `ai` and `@flue/sdk`; it imports no `@flue/runtime`, core, plugin, or binding module. Oracle: `apps/brunch-agent/test/build-artifact.test.ts`, `apps/brunch-agent/test/agent-ownership.test.ts`, the transport case in `apps/brunch-agent/test/architecture/boundaries.integration.ts` (`transports consume their wire encoder and the public Flue client only — never core, a binding, or the runtime`), SDCPN packaging tests, and browser inspection of the claimed local route and headers. -8. **Real Voice witness and retained proof bundle.** With `yarn dev:brunch`, a human speaks one answer, sees exactly one matching user message, sees and hears the canonical Brunch response begin, interrupts playback once, exercises Stop on one unsettled turn, and reopens the original settled turn. Retain under `docs/evidence/implementations/mission-5-direct-voice-flue/` the witness record, sanitized Voice event ledger, network route summary, canonical Flue snapshot, settlement outcomes, source/build commit, and hashes. Oracle: human adjudication against that bundle; mocked browser or server-only evidence cannot satisfy this leaf. -9. **Focused repository verification and truthful docs.** Brunch app, website, core/plugin, transport, and Petrinaut checks pass; end-user and operator prose describes the single route that actually shipped and preserves the distinction between canonical text and generated audio; no surviving prose or comment names `/api/chat` as a Brunch door. Oracle: `yarn exec turbo run lint:tsc lint:eslint test:unit build --filter @apps/brunch-agent --filter @apps/petrinaut-website --filter @hashintel/petrinaut --filter @hashintel/brunch-agent --filter @hashintel/brunch-agent-plugin-sdcpn --filter @hashintel/brunch-agent-transport-aisdk`, `yarn workspace @local/petrinaut-arch-docs lint:arch-docs` if a Petrinaut architectural boundary changes, `rg -n "api/chat" apps/brunch-agent libs/@hashintel/brunch-agent/packages apps/petrinaut-website/src/main/app/local-storage-demo` returning only the stock Petrinaut route and frozen Mission 4 evidence, inspection of `apps/petrinaut-website/README.md` and `libs/@hashintel/petrinaut/docs/ai-assistant.md`, and a patch changeset if the published Petrinaut package changes. +The mission completes only when the demo script works for this fixture and these obligations are closed: stale fixture/workpiece/document revision refusal, duplicate tool delivery, read/write failure visibility, unsupported meaning, no-op mutation honesty, partial-save behavior, second-tab rehydration, separate identity integrity, and one negative mutation case. Do not close every consequential-element provenance link, remote task replacement, broad scenario coverage, or repeated automatic projection here; those become Mission 7 or Mission 9 obligations only after this tracer exposes a finite peer set and load-bearing seams. -## Constraints +Every final leaf has a discriminating oracle: -- Preserve Mission 4's current core/plugin/app composition and authored skill packaging. Voice reconciliation must never restore the deleted app-local `ChatAgent`, concise stub prompt, YAML plugin machinery, or a second model-facing agent. -- Flue history is the sole canonical conversation record. Voice owns media capture, provisional display, turn finalization, TTS, playback, and local interaction state; it owns no durable transcript and may not splice into stock-assistant history. -- Use `@flue/sdk`/`@flue/react` directly for shell-facing conversation transport. No adapter may re-specify Flue offsets, retries, materialization, settlement, or recovery. The browser `ChatTransport` is a projection over the public `FlueClient` (`send()`, `wait()`/`observe()`, `history()`), never a second HTTP client; it reads chunks only through the SDK's `onEvent`/observation surfaces. -- One product route. `/agents/chat/:instanceId` behind `agentOwnershipGuard` is the sole door for typed, Voice, diagnostic, and evaluation traffic; no route, handler, or package may accept a conversation turn over another protocol. The stock Petrinaut `/api/chat` (the website's own OpenAI function) is untouched and must not be borrowed. -- The Petrinaut panel remains on `useChat`; the AI SDK is its rendering contract, supplied a transport by the host. Do not rewrite the panel onto `@flue/react`, and do not add a second transcript store beside `useChat`'s messages for the typed panel. -- Submit only the validated finalized answer. Provisional transcription and audio remain ephemeral. One Voice finalization causes at most one `send()` call; because Flue 2.0.3 does not accept a caller idempotency key on `send()`, ambiguous admission must remain visible and must not trigger an automatic retry. -- Brunch owns canonical response content. TTS may synthesize audio from exact selected text, but no second model may summarize, shorten, paraphrase, or select replacement wording for the tracer. -- Local playback cancellation, local observation cancellation, HTTP request cancellation, and Flue's conversation-wide durable abort are distinct operations and must remain distinguishable in code, UI state, evidence, and tests. -- The current browser-minted local principal is an ownership discriminator, not trusted authentication. The outer proof is local and same-origin; it must not expose `/agents/chat/:id` publicly or claim production identity, authorization, CORS, deployment, or recovery. -- `@hashintel/brunch-agent-transport-aisdk` survives only as the browser-side adapter and the home of the projector, snapshot projection, and header names. Its runtime dependencies are `ai` and `@flue/sdk`; it never imports `@flue/runtime`, core, a plugin, or a binding, and client-tool names reach it as caller-supplied options. The boundary test's transport gate is amended to say exactly that — this is the one accepted topology-gate change of the recut. -- Do not mount the suspended `brunch_ask` capability merely to preserve the divergent preview stack. Re-entry requires observed plain-turn correlation strain and an owner decision consistent with the structured-question planning contract. -- External Voice branches and their issues/PRs remain read-only evidence. Port only behavior that serves this mission, preserve relevant provenance in commits, and do not rewrite, close, or represent those records as accepted wholesale. -- Record admission, first canonical text, first TTS request/audio, and settlement latency without transcript, prompt, tool, SDP, audio, credential, or response-body content in ordinary telemetry. -- No implementation begins until this authority cut is committed separately. Material changes to this contract require owner review and another focused authority commit before dependent implementation. +1. **The prepared fixture is honest and sufficient for this narrow test.** The committed fixture manifest and a cold-reader adjudication identify its test-authored source, process spine, constrained crew, release policy, quantity context, explicit unknown, prepared net meaning, and non-claims. The reader must do this without transcript archaeology. +2. **One evidence turn maintains the Markdown workpiece.** A production-agent fixture integration retains the exact Flue snapshot and mechanically recovers the latest `runbook-ir` block with source message id and SHA-256. Before/after adjudication must find the supplied contextual quantity, retained crew/release meaning, retained unsupported context, and no invented fact or hardened unknown. +3. **The real browser executes a correlated Petrinaut read and write.** Focused plugin/transport tests prove that `getLatestNetDefinition` and the selected `addArc` schema come mechanically from Petrinaut's canonical contracts, fixture mode advertises only the selected operations, duplicate result delivery does not apply the mutation twice, rejected input remains visible, and a mutation that would change nothing is reported as a no-op rather than as a change. The browser witness must retain tool name, call id, parsed input, execution output, resumed signal, and resulting canonical definition; a headless callback alone does not pass. +4. **The document change is meaningful rather than merely accepted.** A structural comparison proves there was no standard input arc from `Dispatch crew available` to `Start final inspection` before the turn and exactly one weight-1 arc afterward, while `Sign-off` still returns the crew and the prepared net remains non-empty. The changed workpiece retains the reservation/release meaning and unresolved timing/recovery. Parser/schema acceptance or a disconnected convenience element fails. +5. **The settled witness cannot bless partial state.** A focused failure test injects history/workpiece-recovery failure, rejected `addArc`, or missing/duplicate result correlation and shows that the prior settled manifest remains selected while the failure and any partial state are inspectable. Do not invent a localStorage failure interface solely to satisfy this leaf. +6. **A second tab resumes the same fixture.** With `yarn dev:brunch` running, the recorded browser protocol opens the stable selector in Tab A, performs and settles the turn, then opens it in Tab B. The witness compares fixture id, document id and canonical definition hash, Flue conversation id and history, latest workpiece source/hash, per-message typed/Voice provenance, stopped-turn presentation, and absence of duplicate submission before one read or continuation succeeds in Tab B. An aborted entry rendered as ordinary truncated content fails this check even if a global latest-settlement banner still says stopped. Tab B opened against a stale or mismatched revision must refuse visibly rather than silently select older artifacts. +7. **The cut has not smuggled in the later architecture.** Public-schema and dependency inspection finds only fixture identity/revision links, Markdown recovery metadata, and canonical Petrinaut payloads—no closed process ontology, typed capture-to-workpiece reducer, graph database, second conversation log, or general projection engine. -### Expected touched paths +Verification proceeds inside-out but closure requires the outer boundary: -```text -~ libs/@hashintel/brunch-agent/packages/transport-aisdk/src/ delete the HTTP handler; add ChatTransport factory over FlueClient; receive ui-stream + snapshotToUiMessages + headers -~ libs/@hashintel/brunch-agent/packages/transport-aisdk/package.json deps become ai + @flue/sdk; drop valibot if unused -~ libs/@hashintel/brunch-agent/packages/transport-aisdk/test/ replace chat-handler/golden with transport + projector + snapshot tests -~ apps/brunch-agent/test/architecture/boundaries.integration.ts amend the transport gate -- apps/brunch-agent/src/http/petrinaut-chat.ts server-side door removed -- apps/brunch-agent/src/conversation/ui-stream.ts moves into the transport package -~ apps/brunch-agent/src/conversation/transcript.ts snapshotToUiMessages moves out; formatFlueTranscript stays for the CLI -~ apps/brunch-agent/src/http/routes.ts, local-origins.ts drop PETRINAUT_CHAT_ROUTE and the /api/chat proxy; proxy /agents/chat/* -~ apps/brunch-agent/src/app.ts remove the /api/chat mount and app-transport closure -~ apps/brunch-agent/package.json drop the `ai` devDependency if nothing else uses it -- apps/brunch-agent/test/petrinaut-chat.test.ts, petrinaut-chat.integration.ts, petrinaut-chat-result.ts, flue-ui-stream.test.ts re-expressed against the browser transport / relocated -~ apps/brunch-agent/test/build-artifact.test.ts, local-dev-origins.test.ts single-route assertions -~ apps/brunch-agent/petrinaut-local.vite.config.ts same-origin Flue-route proxy for the local real surface -~ apps/petrinaut-website/src/main/app/local-storage-demo/ createFlueClient composition, browser transport, delete use-flue-chat-history -~ apps/petrinaut-website/src/main/app/voice-interview/ direct Flue admission, materialized response, cancellation, reopen -~ apps/petrinaut-website/package.json add @flue/sdk -~ yarn.lock workspace dependency update -? apps/brunch-agent/src/http/ownership.ts, src/conversation/identity*.ts only if the identity-contract home (fog-line) moves -? libs/@hashintel/petrinaut/src/ui/ smallest public panel seam only if host composition cannot remain local -~ apps/petrinaut-website/README.md operator-facing route and preview behavior -~ libs/@hashintel/petrinaut/docs/ai-assistant.md user-visible Voice behavior -~ libs/@hashintel/brunch-agent/MISSION.next.md reconcile the production-door, restricted-ingress, and adapter-removal statements -+ libs/@hashintel/brunch-agent/docs/evidence/implementations/mission-5-direct-voice-flue/ retained proof bundle -? .changeset/ one patch changeset only if the published Petrinaut package changes -``` +- **Inner:** fixture parsing and prepared-label checks; identity separation; workpiece recovery/hash; canonical `addArc` schema and exact before/after edge assertion; idempotent client-tool result handling; settled-witness refusal. +- **Middle:** the built production `ChatAgent` and `/api/chat` path hydrate the prepared Flue conversation, accept the evidence turn, recover the revised workpiece, and carry actual browser-tool calls/results. Run the focused workspaces through root Turbo (`test:unit`, `lint:tsc`, `lint:eslint`, and `build` where changed). +- **Outer:** the two-tab `yarn dev:brunch` witness above, with retained before/after artifacts, one Voice-origin message, and one durably stopped assistant turn. A content-only transcript match does not establish faithful resume. +- **Semantic:** a cold human accepts fixture/workpiece honesty and the workpiece-to-document correspondence. The oracle may falsify those claims; it may not rewrite the interaction or architecture policy. +- **Product:** a product manager who did not watch the work runs the demo script from the imperative without an engineer and notices the advance. This is the last check before close, after the readiness gate; it is not a substitute for the oracles above. -## Fog-line +## Constraints -- How a finalized Voice answer enters Flue. Two shapes are admissible: **(B, preferred)** Voice submits through the panel's own Flue `ChatTransport` (`useChat.sendMessage` → `send()`), so the panel's `useChat` messages remain the single visible store and Voice's `observe()` shrinks to selecting completed canonical text for TTS — or reads the panel's completed assistant message and drops `observe()` entirely; **(A)** Voice calls `send()` directly and keeps its own `observe()` state, with the panel rehydrating. Start with B; fall back to A only if the existing hold-while-streaming, epoch, or TTS-correlation semantics demonstrably strain under the panel's transport, and record the observed strain. Either way, one finalization is one `send()`, and if the chosen shape would create two mutable transcript stores or a second custom reducer, stop and reorient at the panel boundary. -- The smallest honest home for the browser-safe principal + logical-conversation-id → Flue-instance-id contract and the two ownership header names. `apps/brunch-agent/src/conversation/identity-web.ts` proves the algorithm; the website must not gain an app-to-app source import, and core must not own HTTP header names. The leading candidate is the repurposed transport package, which already exports the principal header; a website-local copy pinned by an equality test against the app is the fallback. Do not create a new package to hold two strings and a hash. -- Whether `wait(admission, { onEvent })` alone gives the browser transport a clean finite per-turn stream, or whether the panel needs `observe()` for reconnect during a turn. `wait()` rejects on failed/aborted settlement and on `terminal_event_missing`; the transport must map those to `error`/`abort` chunks rather than throwing past `useChat`. The first real disconnect mid-turn decides; do not pre-build reconnect machinery. -- Whether `reconnectToStream` should return `null` (observation-only rehydration, the current behavior) or resume an unsettled submission after reload. Start with `null` plus SDK observation; re-enter only if the witness observes a lost in-flight turn. -- The exact subset of PRs #9496, #9507, and #9512 to port after semantic comparison with the current branch. Their useful Voice state-machine behavior is evidence; their app-local agent topology, temporary ask shim, and generative preparation are not presumed requirements. -- The bounded speech-selection policy if the exercised Brunch response contains multiple completed text blocks or an interactive part. Begin with canonical completed visible text in order; if this produces duplicate, misleading, or unspeakable output, retain the mismatch and seek a Brunch-owned deterministic presentation rule rather than another generator. -- Whether the existing Stop affordance can express both local Voice interruption and explicit conversation-wide durable abort without misleading the user. The first real race decides the smallest UI distinction. -- Whether a same-origin local proxy can carry every SDK history/SSE/send/abort route unchanged. A crisp protocol or middleware blocker permits the thinnest route correction; it does not permit rebuilding the AI SDK adapter under another name. +- Keep fixture id, Flue conversation id, latest workpiece source/revision, and Petrinaut document id/revision distinct and explicitly linked. One id must not impersonate all lifecycles. +- Flue history remains the canonical conversation log. Browser message caches and fixture artifacts are projections or evidence, never a second authority. +- Markdown remains the semantic workpiece. Recover its full latest version; do not introduce a comprehensive typed domain IR to make fixture lookup convenient. +- Projection consumes the current workpiece. The transcript may establish provenance and help recover that artifact but may not become the primary construction IR. +- Petrinaut owns canonical schemas, browser validation, mutations, and document state. Brunch imports or mechanically derives those contracts and does not hand-copy their field shapes. +- Client tools execute against the active bound browser document and return the original tool-call id. Stale, duplicate, cross-document, malformed, failed, and no-op outcomes fail visibly. +- Publish a new settled fixture witness only after the claimed Flue snapshot, workpiece revision, and document state can all be inspected. The witness does not make the browser and Flue stores transactional. Do not invent explicit save or cross-store transaction machinery without an observed recovery failure requiring it. +- Preserve the accepted Mission 4 `useBrunchAgent()` plus `useSdcpnPlugin()` architecture. The app composes; the plugin owns SDCPN operation semantics; the transport carries results; the UI executes them. +- Keep construction tools unavailable to unrelated ordinary conversations unless the real path proves the smallest safe selection can be scoped to this fixture/mode. Stock-assistant behavior must remain unchanged when Brunch is absent or unselected. +- The fixture is local and deliberately prepared. Make no remote durability, capture provenance, automatic projection, behavioral execution, or concurrent collaboration claim. +- No HASH Graph, Temporal, Redis, new database, observer, workflow engine, second agent, second event log, or closed workpiece schema. +- Update the affected Petrinaut user guide in the same change if the selector, save/resume behavior, or panel behavior becomes user-facing; add one Petrinaut changeset only if a published Petrinaut package changes. +- Repair typed/Voice provenance and stopped-turn presentation at the canonical history-to-Petrinaut projection boundary; do not add a second transcript store. Account for the observed discoverability strain around **Show transcript**, **Exit voice mode**, and the chat composer's durable **Stop** without conflating local Voice exit with Flue abort. -## Stop or reorient +## Fog-line -Stop and surface the evidence if the implementation creates a second conversation authority, keeps or re-adds any server-side route that accepts a conversation turn over a non-Flue protocol, submits provisional STT, automatically retries an ambiguous admission, rewrites canonical text through another model, hand-rolls stream recovery, computes offsets, restores the old stub agent, or activates `brunch_ask` without observed need and owner approval. +- Whether the selected shallow `addArc` schema survives the provider-visible Flue carrier and results in exactly one browser mutation without reopening the broader nested-schema problem. +- The least safe way to expose canonical `getLatestNetDefinition` plus `addArc` in a fixture conversation while retaining the headless-only guard for broader construction. +- How to prepare canonical Flue history reproducibly without pretending test-authored assistant content was model-produced; the preparation route and authorship must survive in the manifest. +- Whether the latest `runbook-ir` message id and hash are sufficient workpiece revision identity or the two-tab consumer exposes a need for a separate persisted workpiece artifact. +- Whether Mantine/localStorage synchronization plus the active `PetrinautDocHandle` is sufficient for the same-browser two-tab witness, and which document hash/revision signal best distinguishes settled from stale state. +- Whether the known provider-visible nested-schema failure is absent for the selected flat mutation. Do not generalize one success to nested construction classes. +- Which of history recovery, invalid `addArc`, or duplicate result delivery is the cheapest discriminating failure for the settled-witness rule after the first real path reveals the ordering. -Stop if the browser transport cannot preserve the current client-tool resume semantics (completed client-tool parts on the referenced assistant message → one signal send → continuation of the same assistant message id) without a server-side helper; that is evidence the resume contract needs redesign, not permission to reintroduce `/api/chat`. +Resolve these at the named production/browser boundaries. Clarifying prose alone does not clear them. If a choice changes the accepted interaction policy, architectural ownership, or proof claim, return it to the owner and amend this authority before implementation continues. + +## Stop or reorient -Stop at the boundary if direct Flue state cannot reach the existing visible panel without duplicated mutable history; decide the UI ownership seam before adding synchronization machinery. Stop if local cancellation accidentally aborts durable work, explicit Stop only cancels a browser request while the provider keeps spending, a stale response is spoken after conversation/epoch change, or reopen resubmits or replays a settled turn. +Stop and surface evidence if: -Stop rather than widen if the real route requires public unauthenticated exposure, production identity work, remote deployment, Petrinaut mutation tools, workpiece/projection state, or a whole assistant rewrite. Those are not hidden prerequisites to this transport tracer. +- fixture preparation requires pretending a Mission 4 candidate exists or hides test-authored/model-authored boundaries; +- the path conflates fixture, conversation, workpiece, and document identities or creates a second canonical conversation history; +- the agent rereads transcript prose as its primary projection input because the current Markdown workpiece cannot carry the needed meaning; +- parser/schema acceptance, document non-emptiness, or a disconnected convenience element is offered as semantic correspondence; +- client-tool results lose their original call id, can target the wrong document, or duplicate execution on retry/reload; +- a partial or failed write advances the settled witness, or second-tab reopening silently selects stale/mismatched artifacts; +- exposing one browser mutation requires mounting an unrestricted construction surface for every ordinary conversation; +- the selected provider/Flue schema cannot faithfully carry the least meaningful mutation—record the crisp blocker rather than hand-copying Petrinaut schemas or widening into Mission 9; +- the tracer needs a closed ontology, typed claim ledger, general projection engine, distributed transaction, or new durable service before a concrete failure demonstrates that need; or +- work widens into capture-backed why/provenance, automatic projection breadth, remote deployment durability, concurrent collaboration, or broad scenario readiness. ## Deferred -- **Faithful transcript projection on resume:** the 2026-09-04 human witness found that canonical messages returned after reload without audio replay, but typed/Voice provenance disappeared and a stopped assistant entry rehydrated as ordinary truncated content even though the global stopped settlement remained visible. Mission 6 owns preserving those two distinctions across its second-tab conversation resume and proving them at that real boundary. The same witness also found the small **Show transcript** control and the separation between **Exit voice mode** and the chat composer's durable **Stop** easy to miss; treat those as observed discoverability strain when shaping the resumed surface, without conflating local Voice exit with Flue abort. -- **`useChat` panel removal:** with the server-side door gone, the AI SDK survives only as the Petrinaut panel's rendering contract behind a host-supplied transport. Whether Petrinaut ever drops `useChat` is a Petrinaut product decision, not a Brunch transport question; Brunch carries no further obligation here. -- **Restricted-ingress rule for the Flue route:** Mission 8's landed contract denied `/agents/chat/:id` publicly and routed restricted traffic through `/api/chat`. This recut makes the Flue route the only product route, so that rule must be re-expressed as the FE-1423 gates applying directly to `/agents/chat/:id`. Record the re-expression in `MISSION.next.md`; the release/deployment gate owns its enforcement. -- **Structured questions:** core-owned question semantics, binding, rendering, correlated reply, and resumed tool execution remain in the shared future-planning record. Re-enter when plain Voice turns demonstrably cannot preserve a required interaction. -- **Broader Voice quality:** multi-turn barge-in tuning, long-response ergonomics, optional deterministic spoken presentation, accessibility breadth, and response optimisation re-enter after measured strain on the direct canonical route. -- **Remote/public operation:** trusted identity and authorization, origin policy, hosted Flue reachability, rate/spend controls, replacement recovery, and remote observability remain with the Mission 8 release/deployment gate or a separately cut successor. -- **Product-data work:** prepared workpiece/Petrinaut viability remains Mission 6; capture-backed review remains Mission 7; automatic traceable projection remains Mission 9. This mission carries no document mutation or provenance claim beyond canonical conversation history. -- **Host breadth:** stock/Brunch picker behavior, session switching beyond the selected local Brunch conversation, and HASH embed parity wait for the first visible consumer that makes them load-bearing. +Mission 7 still owns capture-backed visible why/provenance and broken-link refusal after this fixture is viable. Mission 9 still owns repeatable automatic projection, broader nested provider-schema classes, stable generated-element derivations, repeated/changed-input behavior, and the breadth of semantic correspondence. Remote replacement durability and release infrastructure remain in the historical Mission 8 handoff. Multi-tab concurrent editing, a durable cross-store commit protocol, explicit localStorage failure injection and refusal of a concurrent write from a tab holding an older revision (distinct from the readiness-gate refusal to reopen onto stale or mismatched artifacts), and promotion of this prepared fixture into a reusable product seed re-enter only if the automatic mirror loses or overwrites state, a later consumer requires atomic bundle identity, or this mission otherwise exposes concrete strain; their current planning home and re-entry conditions remain in [`MISSION.next.md`](MISSION.next.md) and the linked Mission 7/9 drafts. diff --git a/libs/@hashintel/brunch-agent/MISSION.next.md b/libs/@hashintel/brunch-agent/MISSION.next.md index c336cd4ebaf..637512ab406 100644 --- a/libs/@hashintel/brunch-agent/MISSION.next.md +++ b/libs/@hashintel/brunch-agent/MISSION.next.md @@ -1,8 +1,8 @@ # Brunch future mission spine -> Canonical future-planning spine, shared frame, and backlog index only. This file is not execution authority and authorizes no implementation. [`MISSION.md`](MISSION.md) is the live Mission 5 authority on this branch. Detailed provisional clusters are context repositories, not missions; re-evaluate and convert one into `MISSION.md` on its own branch before acting. +> Canonical future-planning spine, shared frame, and backlog index only. This file is not execution authority and authorizes no implementation. [`MISSION.md`](MISSION.md) is the sole live Mission 6 authority on this branch, which is stacked on the live Mission 5 authority of the FE-1574 branch. Detailed provisional clusters are context repositories, not missions; re-evaluate and convert one into `MISSION.md` on its own branch before acting. -This spine and its five linked drafts form one future-planning record. Keep each consequential meaning in one authoritative planning home: shared contracts and unallocated concerns live here; mission-specific detail lives in its draft. A spine pointer is not a second contract. Material omitted from a future cut returns to this record at full fidelity, and the consumed draft is removed. +This spine and its four linked drafts form one future-planning record. Keep each consequential meaning in one authoritative planning home: shared contracts and unallocated concerns live here; mission-specific detail lives in its draft. A spine pointer is not a second contract. Material omitted from a future cut returns to this record at full fidelity, and the consumed draft is removed. ## Current authority and accepted spine @@ -10,15 +10,15 @@ Mission 4 closed on this branch by owner adjudication on 2026-09-03. The accepte A future Mission 4 close-out addendum requires its own issue, branch, PR, and mission authority. It may stack on this closed branch and own broader reliability/hardening if warranted, browser parity, fixture/seed promotion contracts, topology-neutral case allocation, contract/readiness sweeps, archive subtraction, and Mission 8 preparation. It also owns the observed S4 report-versus-immediate-ask decision unless a later numbered mission first makes it load-bearing: re-enter only when a real review must continue immediately or repeated gap-only reports create visible friction; preserve S3 restraint while testing S4 activation and asking under a fresh instrument. Its exact issue/name and minimum scope remain owner decisions; do not create another Mission 4 draft. -Mission 5 is now live on this branch under FE-1574 and owns the direct Voice/Flue transport cut; its full contract lives only in [`MISSION.md`](MISSION.md). Mission 6 remains independently cuttable from Mission 4 under its own issue, branch, PR, worktree, and mission authority: one deliberately prepared, honestly labelled fixture joins canonical conversation, session history, Markdown workpiece, and Petrinaut document; one browser-backed read/write change saves and resumes across tabs. Neither mission requires a Mission 4 full-run candidate, and neither is the other's prerequisite. +Mission 6 is now live on the FE-1575 branch under root [`MISSION.md`](MISSION.md): one deliberately prepared, honestly labelled fixture must join canonical conversation, session history, Markdown workpiece, and Petrinaut document through a browser-backed read/write change and cross-tab resume. Its consumed draft has been removed; its product-manager litmus, demo script, and readiness-gate completion bar live only in that authority. Mission 5 is live on the FE-1574 branch directly beneath this one and owns the direct Voice/Flue transport cut; its full contract lives only in that branch's root `MISSION.md`. Neither tracer requires a Mission 4 full-run candidate. The two were cut as independent siblings, but Mission 5's recut made the browser Flue `ChatTransport` the only door into a Brunch conversation and removed the `/api/chat` path Mission 6 had named as its departure point; the owner therefore corrected Mission 6 to consume Mission 5's landed transport, and this branch now stacks on Mission 5's committed typed-panel transport tracer. The earlier capture-backed provenance, automatic-projection, revision, and optimisation drafts remain later readiness/product advances. They are renumbered around the historical Mission 8 deployment track rather than forcing the two uncertainty-retiring tracers to inherit its unproved remote boundary. ```text M4 closed — core/plugin elicitation pattern accepted; S4 transition and full-run candidate deferred M4+ optional successor — broader hardening or source promotion only under separate authority -M5 live on this branch — direct Voice/Flue turn, canonical streamed reply, cancellation, and reopen -M6 resumable fixture tracer — conversation → Markdown workpiece → Petrinaut read/write → cross-tab resume +M5 live on FE-1574, beneath this branch — direct Voice/Flue turn, canonical streamed reply, cancellation, and reopen +M6 live on FE-1575 — conversation → Markdown workpiece → Petrinaut read/write → cross-tab resume over Mission 5's transport M7 capture-backed review — close selected-pair provenance breadth and visible why/refusal M8 deployment handoff — historical branch stopped after local application proof, before infrastructure deployment M9 automatic projection — broaden the proved fixture seam to repeatable traceable projection of one meaningful region @@ -26,16 +26,10 @@ M10 revision — ship bounded authorized reviewer revision and a scoped patch M11 optimisation — ship an accepted optimisation handoff after its consumer contract exists ``` -Every numbered product mission after the proof-of-life exception must pass the **product-manager litmus**: a product manager who did not watch the work must be able to notice that the product materially moved forward. Each mission therefore states, in its draft's visible-product-advance section, a release-note sentence, a demo script a product manager can run without an engineer, and the thing that was impossible before. Snapshots, manifests, event ledgers, and negative controls are oracles that belong in the evidence sections; they are not the visible advance. A mission is complete at its readiness gate, when the demo script works for the named scenario, not at the first green throughline tracer, which is an internal milestone inside the mission. Mission 5 names the Petrinaut Brunch panel's typed and Voice surface over one Flue route, with its litmus stated in the live [`MISSION.md`](MISSION.md#product-manager-litmus); Mission 6 names the stable fixture and browser Petrinaut document; Missions 7, 9, and 10 name the Petrinaut Brunch panel. Because Mission 8 stopped before remote deployment, those panel missions must name the deployment posture available at cut time, and a locally run panel is acceptable for the demo; a product-manager-noticeable claim must never depend on infrastructure that does not exist, while remote durability obligations stay in their readiness gates. Architecture, schema repair, fixtures, evaluation, rehearsal, and spikes may support the advance but cannot be the sole outcome. Parallel work means separate issue, branch, PR, worktree, and mission authority; it never means multiple live missions here. +Every numbered product mission after the proof-of-life exception must pass the **product-manager litmus**: a product manager who did not watch the work must be able to notice that the product materially moved forward. Each mission therefore states, in its draft's visible-product-advance section and then in its cut `MISSION.md` imperative, a release-note sentence, a demo script a product manager can run without an engineer, and the thing that was impossible before. Snapshots, manifests, event ledgers, and negative controls are oracles that belong in the evidence sections; they are not the visible advance. A mission is complete at its readiness gate, when the demo script works for the named scenario, not at the first green throughline tracer, which is an internal milestone inside the mission. Live Mission 5 names the Petrinaut Brunch panel's typed and Voice surface over one Flue route, with its litmus stated in the FE-1574 branch's live `MISSION.md`; live Mission 6 names the stable fixture and browser Petrinaut document, with its litmus stated in this branch's [`MISSION.md`](MISSION.md#visible-product-advance); Missions 7, 9, and 10 name the Petrinaut Brunch panel. Because Mission 8 stopped before remote deployment, those panel missions must name the deployment posture available at cut time, and a locally run panel is acceptable for the demo; a product-manager-noticeable claim must never depend on infrastructure that does not exist, while remote durability obligations stay in their readiness gates. Architecture, schema repair, fixtures, evaluation, rehearsal, and spikes may support the advance but cannot be the sole outcome. Parallel work means separate issue, branch, PR, worktree, and mission authority; it never means multiple live missions here. ## Successor mission précis -### M6 — Prove the Markdown/workpiece/Petrinaut loop - -Tracker projection: [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs). - -One honestly prepared fixture links a canonical conversation, session history, Markdown workpiece, and Petrinaut document; Brunch updates the workpiece, performs one meaningful browser-backed document change, saves, and resumes from a second tab. The 2026-09-04 Mission 5 witness adds one bounded resume obligation: preserve each message's typed/Voice provenance and render an aborted assistant entry as stopped rather than ordinary truncated content. This can otherwise be cut immediately and independently of Voice input. **Product-manager litmus:** Brunch edits the net you are looking at from the conversation, and the work survives closing the tab. Demo: open the demo fixture, say one new thing about the process, watch the net change, save, reopen in a second tab and continue. Previously impossible: Brunch only produced off-canvas net JSON for manual load. Complete at the [readiness gate](docs/mission-drafts/6-resumable-workpiece-petrinaut-fixture.md#readiness-gate-after-the-new-throughline), not at the first green mutation; see the [visible product advance](docs/mission-drafts/6-resumable-workpiece-petrinaut-fixture.md#visible-product-advance). - ### M7 — Make the demo net genuinely explainable Tracker projection: [FE-1573](https://linear.app/hash/issue/FE-1573/explain-one-prepared-petrinaut-net-from-exact-conversation-evidence), advancing stakeholder outcome [FE-1478](https://linear.app/hash/issue/FE-1478/provide-provenance-from-a-generated-net-back-to-the-requirements-graph). @@ -239,15 +233,14 @@ The deliberately provisional shared-interface names remain `EvidenceBackedWorkpi ## Detailed provisional clusters -Detailed mission-specific boundaries, tracer floors, readiness ratchets, risks, oracles, and stop conditions live only in these five context repositories: +Detailed mission-specific boundaries, tracer floors, readiness ratchets, risks, oracles, and stop conditions live only in these four context repositories: -- [Draft Mission 6 — resumable workpiece-to-Petrinaut fixture tracer](docs/mission-drafts/6-resumable-workpiece-petrinaut-fixture.md) - [Draft Mission 7 — capture-backed review](docs/mission-drafts/7-capture-backed-review.md) - [Draft Mission 9 — automatic traceable projection](docs/mission-drafts/9-traceable-projection.md) - [Draft Mission 10 — bounded reviewer revision](docs/mission-drafts/10-bounded-reviewer-revision.md) - [Draft Mission 11 — optimisation handoff](docs/mission-drafts/11-optimisation-handoff.md) -Do not create Mission 4 or Mission 8 drafts. Mission 5 is live here; Mission 6 remains an independent next cut that must become the sole live root `MISSION.md` in its own worktree. Mission 11 stays deliberately shallow until Chris and Yannis accept input artifacts, one optimisation question, scenario/parameter representation, execution boundary, expected result, and minimum credibility checks. +Do not create Mission 4 or Mission 8 drafts. Mission 5 is live on the FE-1574 branch beneath this one and is Mission 6's transport prerequisite; Mission 6 is live here and its authority exists only in root `MISSION.md`. Mission 11 stays deliberately shallow until Chris and Yannis accept input artifacts, one optimisation question, scenario/parameter representation, execution boundary, expected result, and minimum credibility checks. ## Unallocated backlog @@ -487,3 +480,5 @@ The owner subsequently changed the integration premise: Voice should use canonic ## 2026-09-03 product-manager litmus reframing Later on 2026-09-03 the owner replaced the "visible/usable proof" completion criterion with the product-manager litmus defined in the accepted spine above. The observed problem was that each précis pinned completion to an evidence bundle at the first green throughline tracer, which convinces a builder but is invisible to a product manager, and that Draft Mission 9 carried engineering internals in its visible-advance section. The change re-pins completion to each mission's readiness gate for the named demo scenario, moves oracles out of the visible-advance sections, expands Mission 7 from one element to every consequential element of the demo net, and names the deployment posture problem for Missions 7, 9, and 10. Mission 5 was live on its own branch and was not touched by that commit; on restack, the live branch adopted the litmus in [`MISSION.md`](MISSION.md#product-manager-litmus), naming Stop-that-really-stops and one shared typed/spoken conversation as its product-manager-noticeable advance and its single-route consolidation as internal sequencing. Mission-specific detail lives in the affected drafts' `Visible product advance` and `Throughline proof floor` sections and in the [draft README](docs/mission-drafts/README.md). + +Mission 6 had been cut into root [`MISSION.md`](MISSION.md) on the FE-1575 branch from the pre-litmus draft earlier the same day. That cut was recut on restack rather than left as it stood: its proof section had named the evidence bundle (selector, manifest, snapshots, revisions) as the visible proof artifact and read as if the first green two-tab pass were completion. The recut moves the release note, demo script, and previously-impossible statement into the imperative, names the readiness gate as the completion bar, keeps the seven discriminating oracles as builder evidence, and records the local-only demo posture explicitly. No Mission 6 draft remains here. diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/6-resumable-workpiece-petrinaut-fixture.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/6-resumable-workpiece-petrinaut-fixture.md deleted file mode 100644 index a52ba6c346e..00000000000 --- a/libs/@hashintel/brunch-agent/docs/mission-drafts/6-resumable-workpiece-petrinaut-fixture.md +++ /dev/null @@ -1,165 +0,0 @@ -# Draft Mission 6 — Resumable workpiece-to-Petrinaut fixture tracer - -> Draft cluster only. Not execution authority. Do not implement until this cluster is re-evaluated and cut into `MISSION.md`. - -## Cold-start reads - -- [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) — tracker projection for this future branch mission; the eventual branch `MISSION.md` remains execution authority. -- [`../../MISSION.md`](../../MISSION.md) — live Mission 5 Voice authority on this branch; it supplies no Mission 6 execution authority and does not change Mission 4's explicit absence of a full-run candidate. -- [`../../MISSION.next.md`](../../MISSION.next.md) — shared workpiece, projection, evidence, and product constraints. -- [`../mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) and [`../evidence/implementations/fe-1525-headless-runbook-pn.md`](../evidence/implementations/fe-1525-headless-runbook-pn.md) — accepted workpiece viability, hermetic callback route, and failed real-model nested-schema carrier. -- [`../mission-archive/4-core-plugin-elicitation-proof-of-life.md`](../mission-archive/4-core-plugin-elicitation-proof-of-life.md) — accepted core/plugin architecture and exact proof exclusions. -- [`../../packages/plugin-sdcpn/src/flue.ts`](../../packages/plugin-sdcpn/src/flue.ts), [`../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts`](../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts), and Petrinaut's canonical AI/action schemas — current read and bounded construction capabilities. -- [`../../../../../apps/brunch-agent/src/conversation/client-tools.ts`](../../../../../apps/brunch-agent/src/conversation/client-tools.ts), [`../../../../../apps/brunch-agent/src/conversation/ui-stream.ts`](../../../../../apps/brunch-agent/src/conversation/ui-stream.ts), and the current browser host — existing client-tool carriage and result correlation; reuse semantics without requiring the old chat UI. -- Flue `FlueClient` documentation for stable conversation history, observation, submission reattachment, and tool-part materialization. - -## Visible product advance - -**Release note:** Brunch edits the Petrinaut net you are looking at from the conversation, and your work survives closing the tab. - -**Demo script (no engineer present):** open the stable demo fixture; the canonical Brunch conversation, current Markdown workpiece, and associated Petrinaut document come back together. Tell Brunch one new realistic thing about the process. Watch the workpiece update and a meaningful change appear in the live net. Save. Open the same fixture in a second tab and continue the conversation from the saved state. Confirm that messages retain their typed/Voice provenance and that an aborted assistant entry still presents as stopped rather than as an ordinary truncated answer. - -**Previously impossible:** Brunch only produced off-canvas net JSON for manual load; nothing it did touched the live document or survived a reload. - -The fixture may be deliberately prepared. It need not be a complete persona-produced Mission 4 artifact, a promoted quality baseline, or proof of comprehensive provenance. Prepared status, authored material, limitations, and any model-produced updates remain explicit, and the demo script says so out loud. - -**Completion:** the mission is done when a product manager can run the demo script end to end at the readiness gate below, not when the first browser mutation lands. - -## Contract stratum - -Close the **single-fixture viability stratum** for these two transformations and their resumable product boundary: - -```text -canonical conversation evidence → maintained Markdown workpiece -maintained Markdown workpiece → meaningful Petrinaut read/write change -``` - -The fixture has separate stable identities for the demo case, conversation, current workpiece revision, and Petrinaut document revision. One id must not impersonate all four lifecycles. A small manifest records their relationships, exact prepared inputs, current coherent bundle revision, and hashes or revision tokens needed to detect stale state. - -The minimum fixture contains one process spine, one shared or constrained resource, one decision/policy, one contextual quantity, one explicit unknown, and enough meaning to change a small non-empty net region. It does not require a comprehensive typed domain IR, assertion-card ontology, graph database, or full provenance ledger. - -## Boundary crossings and current throughline hypothesis - -```text -stable demo fixture id -→ resolve conversation id + workpiece revision + Petrinaut document id/revision -→ hydrate canonical Flue history and current Markdown workpiece -→ one realistic evidence turn updates the workpiece at an explicit phase boundary -→ Brunch reads current Petrinaut state through a browser-owned client tool -→ SDCPN skill interprets the current workpiece, not the transcript as projection IR -→ Brunch requests the least canonical Petrinaut mutation(s) -→ browser validates and executes against the bound document -→ correlated client-tool result resumes the same Flue conversation -→ verify meaningful non-empty state -→ publish a new coherent fixture revision only after workpiece and document saves succeed -→ second tab resolves and resumes that revision -``` - -A partial save remains visible and does not advance the fixture's current coherent revision. The first tracer does not require simultaneous multi-tab collaboration or a distributed transaction service. - -## Throughline proof floor - -For one deliberately prepared fixture: - -1. a cold reader can reconstruct the selected operational spine and distinguish supplied evidence, agent inference/assumption, and the explicit unknown in the current Markdown workpiece; -2. one new realistic conversation turn produces an inspectable workpiece revision without erasing the unknown or unsupported meaning; -3. through the real browser client-tool boundary, Brunch reads the associated Petrinaut document and applies one meaningful supported change derived from the current workpiece; -4. canonical Petrinaut state is non-empty and visibly corresponds to the selected meaning; and -5. after save, a second tab opens the same fixture id, observes the same settled conversation/workpiece/document revision, preserves per-message typed/Voice provenance and stopped-turn presentation, and successfully continues or reads it without duplicate submission or identity drift. - -One pass through those five steps is the first internal milestone, not mission completion. The retained oracles are the stable demo URL or fixture selector plus the before/after fixture manifest, exact Flue snapshot, Markdown workpiece revisions, and canonical Petrinaut document revisions; they are evidence for the builder, not the visible advance. This proves viability, not automatic full-net projection, selected-pair provenance breadth, remote replacement durability, concurrent editing, or Mission 3/4 quality superiority. - -## Readiness ratchet - -### Inherited stratum closure - -- Consume Mission 4's accepted `useBrunchAgent()` + `useSdcpnPlugin()` architecture and no broader quality claim. -- Consume Petrinaut-owned schemas/mutations mechanically; parser acceptance alone remains vacuous. -- Treat Flue history as canonical and client-tool results as correlated execution evidence. -- Preserve the Mission 3 failure: provider-visible nested mutation shapes are unproved and may force a smaller first mutation or a crisp upstream blocker. - -### Readiness gate after the new throughline - -This gate is the mission's completion bar: the demo script above must work for the named fixture. Before accepting this single-fixture capability, close stale fixture/workpiece/document revision refusal, duplicate tool delivery, read/write failure visibility, unsupported meaning, no-op mutation honesty, partial-save behavior, second-tab rehydration, separate identity integrity, and one negative mutation case. Do not close every consequential-element provenance link, remote task replacement, broad scenario coverage, or repeated automatic projection here; those become Mission 7 or Mission 9 obligations only after this tracer exposes a finite peer set and load-bearing seams. - -## Candidate evidence and oracles - -| Claim leaf | Candidate oracle | -| --- | --- | -| Prepared fixture is honest and minimally sufficient | Frozen manifest plus cold-reader adjudication identifies the spine, resource, policy, quantity, unknown, authorship, and preparation route. | -| Conversation evidence can maintain Markdown | Before/after workpiece inspection against the exact Flue snapshot detects invention, hardening, lost prior meaning, and lost unknowns. | -| Browser executes real Petrinaut read/write tools | Production-boundary integration records tool call ids, canonical parsed inputs, execution outcomes, correlated result signals, and current document state. | -| Change is meaningful | Human comparison binds one workpiece meaning to a visible canonical type/parameter/place/transition/arc change appropriate to the fixture; non-empty/parser-valid alone fails. | -| Save is coherent | Injected workpiece-save or document-save failure leaves the prior current bundle revision selected and exposes the partial result for recovery. | -| Second tab resumes stable state | Open the same stable fixture selector after save and compare conversation id/history, per-message typed/Voice provenance, stopped-turn presentation, workpiece revision/hash, document id/revision, and canonical definition before continuing. An aborted entry rendered as ordinary truncated content fails this check even if a global latest-settlement banner still says stopped. | -| No typed domain IR was smuggled in | Public-schema and dependency inspection finds only fixture identity/revision links and canonical Petrinaut payloads, not a closed process ontology or typed capture-to-workpiece model. | - -## Verification approach - -- **Inner:** fixture-manifest parse/version/stale checks, explicit identity separation, coherent-revision publication, idempotent client-tool result handling, and canonical Petrinaut mutation tests. -- **Middle:** drive the production Brunch agent through Flue, update the Markdown artifact, execute actual browser callbacks against the fixture-bound Petrinaut instance, and retain before/after artifacts plus one injected failure. -- **Outer:** from the real demo route or equivalent product selector, perform the update/save in Tab A and reopen/continue from the same fixture in Tab B. Include one Voice-origin message and one durably stopped assistant turn in the comparison; a headless callback or content-only transcript match does not establish this mission. -- **Semantic:** a cold human judges whether the workpiece remained honest and the changed net region corresponds to it. - -## Inputs and joins - -- This mission may cut directly from Mission 4 and run independently of the direct Voice mission. Typed text is sufficient for its first tracer; Voice can later become another input modality to the same canonical conversation. -- An owner selects one deliberately prepared fixture and records its non-claims. No full Mission 4 candidate or new persona campaign is prerequisite. -- Mission 7 inherits this fixture only if it needs to close capture-backed why/provenance breadth. Mission 9 inherits the browser mutation and semantic-projection seam only if the tracer proves them viable. -- Mission 8's local deployment artifact is terrain, not a prerequisite for a local two-tab viability proof and not evidence of remote durability. - -## Risks and assumptions - -- If a realistic prepared conversation/workpiece cannot support one meaningful mutation without richer typed structure, record the exact lookup, identity, or ambiguity strain before adding any schema. -- If existing per-action provider schemas cannot carry the required nested mutation, reduce to the smallest meaningful supported action only if semantic correspondence survives; otherwise stop with the crisp provider/Flue schema blocker. -- If coherent save cannot span existing workpiece/document stores, the least fixture-scoped commit marker may publish only after both writes; do not invent distributed transactions before a failure demonstrates the need. -- If direct browser tool servicing needs a transport abstraction, extract only tool-call/result correlation from the browser `ChatTransport` in `transport-aisdk` (recut Mission 5); do not require the chat UI or duplicate Flue observation. -- The 2026-09-04 Mission 5 witness established that message content and the global stopped settlement can survive while the UI loses message-source metadata and renders the stopped assistant entry as ordinary truncated content. Repair the projection at the canonical history-to-Petrinaut boundary; do not create a second transcript store. The small **Show transcript** control and the separation between local **Exit voice mode** and durable composer **Stop** are additional discoverability observations to account for in the resumed surface. - -## Accepted constraints and guarded invariants - -- Separate demo, conversation, workpiece, and document identities with explicit links. -- One canonical Flue history; fixture log projections do not become another authority. -- Markdown is the semantic workpiece; no comprehensive typed domain IR. -- Projection consumes the current workpiece, not the transcript as primary IR. -- Petrinaut owns canonical schemas and mutation execution. -- Client tools execute in the browser against the bound document and return the original tool call id. -- Current coherent revision advances only after all required saves succeed. -- Prepared fixture status and unsupported meaning remain visible. -- No claim of remote replacement durability, automatic full projection, provenance breadth, or concurrent collaboration. - -## Cross-cutting obligations - -Preserve exact evidence attribution, visible failure, stable identity, workpiece sufficiency, semantic correspondence, stock-assistant isolation if it remains present, and same-change user documentation for the demo selector/save/resume behavior. - -## Expected touched paths - -```text -libs/@hashintel/brunch-agent/ -├── evaluations or docs/evidence fixture area + one prepared fixture and adjudication -├── packages/core/ ? only minimal workpiece/fixture contracts with a real second consumer -└── packages/plugin-sdcpn/ ~ least read/write capability and guidance needed by the tracer -apps/brunch-agent/ -├── src/agents/chat-agent/ ~ mount accepted fixture read/write path -├── src/conversation/ ~ client-tool correlation without UI-message authority -└── test/ + real Flue/browser-tool integration -libs/@hashintel/petrinaut-core/ ~ canonical contracts only if a source defect is found -libs/@hashintel/petrinaut/src/ ~ stable fixture resolution, save/resume, browser tool execution -``` - -## Fog-line - -- The exact prepared scenario and smallest meaningful document mutation. -- Where the fixture manifest and current coherent-revision marker belong. -- The current Petrinaut document persistence/revision API and whether the demo route already has a stable selector. -- Whether workpiece Markdown is a file, Flue data part, or product document for this tracer; choose the least real persistence boundary that supports two-tab reopen. -- The least browser host for direct Flue client-tool servicing after removal or bypass of the old assistant UI. -- The exact negative save/mutation case and acceptable local-only durability claim. - -## Stop or reorient - -Stop if the tracer requires pretending a Mission 4 candidate exists, makes a prepared fixture look model-produced, conflates all ids, treats parser validity as meaning, submits client-tool results without original correlation, advances the current bundle after a partial save, uses transcript text as the projection IR, or introduces a closed domain ontology before observed strain. Stop at provider-schema or host-persistence blockers rather than widening into Mission 7/9 readiness work. - -## Carried evidence and rejected alternatives - -Mission 3 showed that a Markdown workpiece can be useful and that a hermetic callback can build canonical non-empty state, while falsifying the exercised real-model nested-schema carrier. Mission 4 established capability composition but produced no full-run candidate. This mission intentionally joins those facts with a prepared fixture to test viability before requiring promoted-source quality, complete provenance, or a generalized semantic model. diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/7-capture-backed-review.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/7-capture-backed-review.md index 11a1e320719..07ab3f6ca0c 100644 --- a/libs/@hashintel/brunch-agent/docs/mission-drafts/7-capture-backed-review.md +++ b/libs/@hashintel/brunch-agent/docs/mission-drafts/7-capture-backed-review.md @@ -8,8 +8,8 @@ A fresh builder must resolve the current repository and the deployment handoff rather than treating this draft as a specification: -- [`../../MISSION.md`](../../MISSION.md) — live Mission 5 Voice authority on this branch; it supplies no Mission 7 execution authority or conversation/workpiece candidate, and Mission 4 produced no full-run candidate. -- [`6-resumable-workpiece-petrinaut-fixture.md`](6-resumable-workpiece-petrinaut-fixture.md) — independent viability predecessor. If accepted, its deliberately prepared and honestly labelled fixture may become this mission's selected pair after a separate provenance-suitability decision; a complete persona workpiece is not intrinsically required. +- [`../../MISSION.md`](../../MISSION.md) — live Mission 6 viability authority on this branch, stacked on the live Mission 5 transport authority of [FE-1574](https://linear.app/hash/issue/FE-1574/let-voice-speak-through-canonical-brunch-conversations); neither supplies Mission 7 execution authority or a conversation/workpiece candidate, and Mission 4 produced no full-run candidate. +- [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) — live Mission 6 viability predecessor. If accepted, its deliberately prepared and honestly labelled fixture may become this mission's selected pair after a separate provenance-suitability decision; at cut time replace this live pointer with the accepted archive/evidence. A complete persona workpiece is not intrinsically required. - [`../../MISSION.next.md`](../../MISSION.next.md) — compact future spine, FE-1476 product frame, shared proof obligations, standing locks, and any later evidence admitted after this draft was written. - [`../mission-archive/2-mechanical-capture-sweep.md`](../mission-archive/2-mechanical-capture-sweep.md) — accepted mechanical capture throughline, exact close evidence, empty-payload boundary, conversation identity, and carried flags. - [`../mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) and [`../evidence/implementations/fe-1525-headless-runbook-pn.md`](../evidence/implementations/fe-1525-headless-runbook-pn.md) — accepted runbook/workpiece leg, falsified real-model construction leg, and the distinction between a hermetic non-empty fixture and vacuous empty-net parser success. diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/9-traceable-projection.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/9-traceable-projection.md index 82b84336fc9..8412c4b41dd 100644 --- a/libs/@hashintel/brunch-agent/docs/mission-drafts/9-traceable-projection.md +++ b/libs/@hashintel/brunch-agent/docs/mission-drafts/9-traceable-projection.md @@ -10,7 +10,7 @@ A fresh builder must resolve these authorities and evidence before choosing a me - [`../../MISSION.md`](../../MISSION.md) — live Mission 5 Voice authority on this branch. Mission 9 may be cut only after Mission 7 validly closes its accepted join and a new owner-authorized mission replaces the then-current branch authority. - [`../../MISSION.next.md`](../../MISSION.next.md) — compact future spine, FE-1476 floor, cross-mission obligations, standing locks, and current Mission 10 handoff. -- [`6-resumable-workpiece-petrinaut-fixture.md`](6-resumable-workpiece-petrinaut-fixture.md) and [`7-capture-backed-review.md`](7-capture-backed-review.md) — provisional viability and provenance predecessors. At cut time replace assumptions with their accepted evidence, exact current workpiece/derivation seam, and real browser mutation behavior. +- [`../../MISSION.md`](../../MISSION.md), [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs), and [`7-capture-backed-review.md`](7-capture-backed-review.md) — live Mission 6 viability authority plus the provisional provenance predecessor. At cut time replace the live pointer and assumptions with accepted evidence, the exact current workpiece/derivation seam, and observed browser mutation behavior. - [`../mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) and [`../evidence/implementations/fe-1525-headless-runbook-pn.md`](../evidence/implementations/fe-1525-headless-runbook-pn.md) — accepted workpiece leg, canonical callback fixture, provider-visible nested-schema failure, vacuous empty-net result, and explicit next-boundary decision. - [`../specs/petrinaut-batched-construction-tools.md`](../specs/petrinaut-batched-construction-tools.md) — candidate `pn_read`/`pn_edit` design input and its corrected transaction, outcome, identity, carrier, and ownership constraints. It does not select batching; this mission repairs the known single-action carrier first and admits a batch only if subsequent probes establish it as the least sufficient mechanism. - [`apps/brunch-agent/src/evaluations/runbook/headless-petrinaut-client.ts`](../../../../../apps/brunch-agent/src/evaluations/runbook/headless-petrinaut-client.ts), [`apps/brunch-agent/test/headless-petrinaut-client.test.ts`](../../../../../apps/brunch-agent/test/headless-petrinaut-client.test.ts), and [`../../packages/plugin-sdcpn/test/construction-tools.test.ts`](../../packages/plugin-sdcpn/test/construction-tools.test.ts) — current bounded six-tool callback route and its limits. From f2bf01a4c7cef1297d94b3981bf39bb3be13cbfb Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Thu, 3 Sep 2026 16:10:37 +0200 Subject: [PATCH 02/31] Accept tagged prepared workpiece history Co-authored-by: Cursor --- libs/@hashintel/brunch-agent/MISSION.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/libs/@hashintel/brunch-agent/MISSION.md b/libs/@hashintel/brunch-agent/MISSION.md index 2bfbac0e175..a258c58ccf8 100644 --- a/libs/@hashintel/brunch-agent/MISSION.md +++ b/libs/@hashintel/brunch-agent/MISSION.md @@ -2,7 +2,7 @@ ## Status -**Live on `ln/fe-1575-resumable-workpiece-petrinaut` from 2026-09-03.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) is in progress. This authority cut is committed separately before product or evaluation implementation begins. It was recut on restack the same day to carry the product-manager litmus adopted in [`MISSION.next.md`](MISSION.next.md#current-authority-and-accepted-spine) after the first cut: completion is the readiness gate below, not the first green two-tab pass. The 2026-09-04 Mission 5 human witness also made faithful transcript resume load-bearing here: per-message typed/Voice provenance disappeared after reload, and a stopped assistant entry returned as ordinary truncated content. The owner deferred both defects to this mission rather than expanding Mission 5. +**Live on `ln/fe-1575-resumable-workpiece-petrinaut` from 2026-09-03.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) is in progress. This authority cut is committed separately before product or evaluation implementation begins. It was recut on restack the same day to carry the product-manager litmus adopted in [`MISSION.next.md`](MISSION.next.md#current-authority-and-accepted-spine) after the first cut: completion is the readiness gate below, not the first green two-tab pass. The owner subsequently accepted the probe-backed prepared-history semantics under [Accepted fixture and boundary crossings](#accepted-fixture-and-boundary-crossings); that amendment must land separately before dependent implementation. The 2026-09-04 Mission 5 human witness also made faithful transcript resume load-bearing here: per-message typed/Voice provenance disappeared after reload, and a stopped assistant entry returned as ordinary truncated content. The owner deferred both defects to this mission rather than expanding Mission 5. ## Imperative @@ -39,13 +39,17 @@ The first unproved boundary is ordinary Brunch conversation → mounted canonica Prepare the existing final-inspection / dispatch-crew case as an explicitly test-authored fixture. Its starting workpiece and non-empty net preserve this narrow account: one crew is reserved during final inspection, sign-off releases it, the batch then becomes dispatch-ready, and timing plus failure/recovery remain unresolved. Its prepared material must identify its authorship and must not be presented as a Mission 4 candidate or model-produced evidence. +Deliver the prepared starting workpiece exactly once through Flue's public dispatch surface as a tagged structured signal. Its canonical record must remain `role: system`, `purpose: dispatch`, carry the fixture id, `test-authored` authorship, and non-claims as signal attributes, and preserve the exact Markdown body. This record is prepared revision zero. Later full `runbook-ir` blocks emitted in genuine assistant responses are model-produced revisions; the workpiece resolver selects the latest eligible revision without rewriting Flue's append-only history. This is analogous to last-one-wins selection of extension-contributed artifacts in a Pi raw session log, not permission to overwrite either log. + +The disposable production-route probe established the carrier facts: the tagged signal retained its exact body and attributes, an exact idempotent retry converged on the original submission without adding messages, and the snapshot survived process reopen unchanged. The current `ChatAgent` rejected fixture authorship supplied as `initialData` with `400` and created no history; `initialData` is not a substitute for the public workpiece source. A user delivery would impersonate the person, while faux-provider output, hand-authored assistant records, private canonical record types, direct database writes, and a second history store are not preparation routes. The probe's configured Anthropic credential was rejected with `401`, so its separately classified faux assistant response established no model-behavior claim. + Prepare the net with `Batch ready`, `Under final inspection`, `Ready for dispatch`, and `Dispatch crew available` places plus `Start final inspection` and `Sign-off` transitions. Preserve the batch-flow arcs and the return of the crew from sign-off, but deliberately omit the standard input arc that reserves the sole crew when final inspection starts. Use one realistic confirming answer: final inspection consumes the sole available dispatch crew, sign-off returns it, and timing plus recovery remain unknown. The least candidate mutation is one canonical weight-1 standard input arc from `Dispatch crew available` to `Start final inspection`. The exact before/after edge makes the semantic oracle discriminating while avoiding Mission 3's deeply nested schema failure. If that shallow mutation still cannot cross Flue faithfully, stop with the carrier blocker rather than weakening the claim. ```text stable prepared-fixture selector → resolve distinct fixture, Petrinaut document, and Flue conversation identities → open the prepared non-empty browser document and hydrate canonical Flue history -→ recover the latest Markdown workpiece revision by source message id plus content hash +→ recover prepared revision zero from the tagged dispatch record, or the latest eligible assistant revision, by source message id plus content hash → submit the realistic crew-reservation confirmation through the production panel door → Brunch emits an inspectable full workpiece revision without erasing prior meaning or the remaining unknown → SDCPN construction reads that current workpiece and the live browser document @@ -90,8 +94,8 @@ The mission completes only when the demo script works for this fixture and these Every final leaf has a discriminating oracle: -1. **The prepared fixture is honest and sufficient for this narrow test.** The committed fixture manifest and a cold-reader adjudication identify its test-authored source, process spine, constrained crew, release policy, quantity context, explicit unknown, prepared net meaning, and non-claims. The reader must do this without transcript archaeology. -2. **One evidence turn maintains the Markdown workpiece.** A production-agent fixture integration retains the exact Flue snapshot and mechanically recovers the latest `runbook-ir` block with source message id and SHA-256. Before/after adjudication must find the supplied contextual quantity, retained crew/release meaning, retained unsupported context, and no invented fact or hardened unknown. +1. **The prepared fixture is honest and sufficient for this narrow test.** The committed fixture manifest, raw Flue snapshot, and a cold-reader adjudication identify the prepared workpiece's tagged system/dispatch source, exact test-authored Markdown, process spine, constrained crew, release policy, quantity context, explicit unknown, prepared net meaning, and non-claims. The same inspection distinguishes every later assistant revision as model-produced and must not require transcript archaeology. +2. **One evidence turn maintains the Markdown workpiece.** A production-agent fixture integration mechanically recovers prepared revision zero from the tagged dispatch record, then selects the latest eligible assistant `runbook-ir` block after the confirming turn, retaining each source message id and SHA-256. Before/after adjudication must find the supplied contextual quantity, retained crew/release meaning, retained unsupported context, and no invented fact or hardened unknown. 3. **The real browser executes a correlated Petrinaut read and write.** Focused plugin/transport tests prove that `getLatestNetDefinition` and the selected `addArc` schema come mechanically from Petrinaut's canonical contracts, fixture mode advertises only the selected operations, duplicate result delivery does not apply the mutation twice, rejected input remains visible, and a mutation that would change nothing is reported as a no-op rather than as a change. The browser witness must retain tool name, call id, parsed input, execution output, resumed signal, and resulting canonical definition; a headless callback alone does not pass. 4. **The document change is meaningful rather than merely accepted.** A structural comparison proves there was no standard input arc from `Dispatch crew available` to `Start final inspection` before the turn and exactly one weight-1 arc afterward, while `Sign-off` still returns the crew and the prepared net remains non-empty. The changed workpiece retains the reservation/release meaning and unresolved timing/recovery. Parser/schema acceptance or a disconnected convenience element fails. 5. **The settled witness cannot bless partial state.** A focused failure test injects history/workpiece-recovery failure, rejected `addArc`, or missing/duplicate result correlation and shows that the prior settled manifest remains selected while the failure and any partial state are inspectable. Do not invent a localStorage failure interface solely to satisfy this leaf. @@ -110,6 +114,7 @@ Verification proceeds inside-out but closure requires the outer boundary: - Keep fixture id, Flue conversation id, latest workpiece source/revision, and Petrinaut document id/revision distinct and explicitly linked. One id must not impersonate all lifecycles. - Flue history remains the canonical conversation log. Browser message caches and fixture artifacts are projections or evidence, never a second authority. +- The tagged prepared signal is the only test-authored workpiece source admitted by this fixture. It remains a diagnostic system/dispatch record; latest-revision selection may supersede it with a genuine assistant workpiece but may not mutate, relabel, or hide its authorship. - Markdown remains the semantic workpiece. Recover its full latest version; do not introduce a comprehensive typed domain IR to make fixture lookup convenient. - Projection consumes the current workpiece. The transcript may establish provenance and help recover that artifact but may not become the primary construction IR. - Petrinaut owns canonical schemas, browser validation, mutations, and document state. Brunch imports or mechanically derives those contracts and does not hand-copy their field shapes. @@ -126,7 +131,6 @@ Verification proceeds inside-out but closure requires the outer boundary: - Whether the selected shallow `addArc` schema survives the provider-visible Flue carrier and results in exactly one browser mutation without reopening the broader nested-schema problem. - The least safe way to expose canonical `getLatestNetDefinition` plus `addArc` in a fixture conversation while retaining the headless-only guard for broader construction. -- How to prepare canonical Flue history reproducibly without pretending test-authored assistant content was model-produced; the preparation route and authorship must survive in the manifest. - Whether the latest `runbook-ir` message id and hash are sufficient workpiece revision identity or the two-tab consumer exposes a need for a separate persisted workpiece artifact. - Whether Mantine/localStorage synchronization plus the active `PetrinautDocHandle` is sufficient for the same-browser two-tab witness, and which document hash/revision signal best distinguishes settled from stale state. - Whether the known provider-visible nested-schema failure is absent for the selected flat mutation. Do not generalize one success to nested construction classes. @@ -138,7 +142,7 @@ Resolve these at the named production/browser boundaries. Clarifying prose alone Stop and surface evidence if: -- fixture preparation requires pretending a Mission 4 candidate exists or hides test-authored/model-authored boundaries; +- fixture preparation requires pretending a Mission 4 candidate exists, placing prepared text in a user or assistant record, accepting an untagged preparation signal, or otherwise hiding test-authored/model-authored boundaries; - the path conflates fixture, conversation, workpiece, and document identities or creates a second canonical conversation history; - the agent rereads transcript prose as its primary projection input because the current Markdown workpiece cannot carry the needed meaning; - parser/schema acceptance, document non-emptiness, or a disconnected convenience element is offered as semantic correspondence; From d3a9fc692fee69b21ee0752537157f2fb8d68211 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Thu, 3 Sep 2026 16:17:21 +0200 Subject: [PATCH 03/31] Reconcile Mission 6 with browser Flue transport Co-authored-by: Cursor --- libs/@hashintel/brunch-agent/MISSION.md | 42 ++++++++++++++----------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/libs/@hashintel/brunch-agent/MISSION.md b/libs/@hashintel/brunch-agent/MISSION.md index a258c58ccf8..fd903deff39 100644 --- a/libs/@hashintel/brunch-agent/MISSION.md +++ b/libs/@hashintel/brunch-agent/MISSION.md @@ -2,7 +2,7 @@ ## Status -**Live on `ln/fe-1575-resumable-workpiece-petrinaut` from 2026-09-03.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) is in progress. This authority cut is committed separately before product or evaluation implementation begins. It was recut on restack the same day to carry the product-manager litmus adopted in [`MISSION.next.md`](MISSION.next.md#current-authority-and-accepted-spine) after the first cut: completion is the readiness gate below, not the first green two-tab pass. The owner subsequently accepted the probe-backed prepared-history semantics under [Accepted fixture and boundary crossings](#accepted-fixture-and-boundary-crossings); that amendment must land separately before dependent implementation. The 2026-09-04 Mission 5 human witness also made faithful transcript resume load-bearing here: per-message typed/Voice provenance disappeared after reload, and a stopped assistant entry returned as ordinary truncated content. The owner deferred both defects to this mission rather than expanding Mission 5. +**Live on `ln/fe-1575-resumable-workpiece-petrinaut` from 2026-09-03.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) is in progress. This authority cut is committed separately before product or evaluation implementation begins. It was recut on restack the same day to carry the product-manager litmus adopted in [`MISSION.next.md`](MISSION.next.md#current-authority-and-accepted-spine) after the first cut: completion is the readiness gate below, not the first green two-tab pass. The owner subsequently accepted the probe-backed prepared-history semantics under [Accepted fixture and boundary crossings](#accepted-fixture-and-boundary-crossings), then corrected this mission to consume Mission 5's one-route browser Flue transport, automatic localStorage persistence, a runtime settled manifest, visible preparation language, and an actual Tab B continuation. Each authority amendment lands separately before dependent implementation. The 2026-09-04 Mission 5 human witness also made faithful transcript resume load-bearing here: per-message typed/Voice provenance disappeared after reload, and a stopped assistant entry returned as ordinary truncated content. The owner deferred both defects to this mission rather than expanding Mission 5. ## Imperative @@ -14,7 +14,7 @@ Mission 3 separately showed a recoverable Markdown workpiece and hermetic canoni **Release note:** Brunch edits the Petrinaut net you are looking at from the conversation, and your work survives closing the tab. -**Demo script (no engineer present):** with the local Brunch/Petrinaut development stack running, open the stable demo fixture selector for the labelled prepared crew-reservation case. Its canonical Brunch conversation, current Markdown workpiece, and non-empty Petrinaut net come back together. Tell Brunch the one new realistic fact the fixture is prepared for: final inspection uses the single dispatch crew, and sign-off releases it. Watch the workpiece update and a new arc appear in the live net from `Dispatch crew available` to `Start final inspection`. Save. Open the same fixture in a second tab and continue the conversation from the saved state. Confirm that messages retain their typed/Voice provenance and that an aborted assistant entry still presents as stopped rather than as an ordinary truncated answer. The fixture announces out loud that it is test-authored and prepared, and what it does not claim. +**Demo script (no engineer present):** with the local Brunch/Petrinaut development stack running, open the stable demo fixture selector for the labelled prepared crew-reservation case. Its canonical Brunch conversation, current Markdown workpiece, and non-empty Petrinaut net come back together. The fixture visibly states that it is test-authored and prepared, and what it does not claim. Tell Brunch the one new realistic fact the fixture is prepared for: final inspection uses the single dispatch crew, and sign-off releases it. Watch the workpiece update and a new arc appear in the live net from `Dispatch crew available` to `Start final inspection`. Wait until the fixture reports that the conversation, workpiece, and automatically mirrored document are settled. Open the same fixture in a second tab, confirm that messages retain their typed/Voice provenance and that an aborted assistant entry still presents as stopped rather than as an ordinary truncated answer, submit one follow-up message, and receive Brunch's response in the same conversation without duplicate submission or identity drift. **Previously impossible:** Brunch only produced off-canvas net JSON for manual load; nothing it did touched the live document or survived a reload. @@ -28,12 +28,12 @@ Mission 3 separately showed a recoverable Markdown workpiece and hermetic canoni The production browser already has most local pieces: -- `apps/petrinaut-website`'s local-storage demo owns an editable `PetrinautDocHandle`, writes handle changes to `petrinaut-sdcpn`, maps each net to a persistent Brunch conversation id, and hydrates panel messages from the Brunch history door; +- `apps/petrinaut-website`'s local-storage demo owns an editable `PetrinautDocHandle`, automatically writes handle changes to `petrinaut-sdcpn`, and maps each net to a persistent Brunch conversation id; - Petrinaut's stock AI panel already validates and executes canonical read, mutation, and command tools against the active browser document and returns the original tool-call id; -- `apps/brunch-agent` already maps the principal plus conversation id to one Flue conversation, exposes `GET /api/chat?id=…` history, resumes client-tool results as correlated Flue signals, and projects the resulting stream back to the panel; and +- live Mission 5 is replacing the server-side `GET`/`POST /api/chat` adapter with one browser `FlueClient` plus host-supplied AI SDK `ChatTransport` over the mounted `/agents/chat/:instanceId` route; that route carries typed turns, `history()` hydration, and correlated client-tool-result signals, and Mission 6 must consume rather than duplicate or reverse that transport; and - the SDCPN skill already emits a full recoverable `runbook-ir` block and requires construction to consume that workpiece rather than transcript archaeology. -The first unproved boundary is ordinary Brunch conversation → mounted canonical document read / least mutation → browser execution → correlated continuation. Today ordinary SDCPN conversations mount only the Petrinaut documentation reader as a browser tool; the validated construction subset is headless-only, and no stable fixture selector or coherent cross-tab witness joins the conversation, workpiece, and document lifecycles. +The first unproved boundary is ordinary Brunch conversation over Mission 5's browser Flue transport → mounted canonical document read / least mutation → browser execution → correlated Flue continuation. Today ordinary SDCPN conversations mount only the Petrinaut documentation reader as a browser tool; the validated construction subset is headless-only, and no stable fixture selector or coherent cross-tab witness joins the conversation, workpiece, and document lifecycles. Mission 6 may develop independent fixture/workpiece/document logic while Mission 5 proceeds, but it must consume Mission 5's landed browser transport before integrated or outer proof and must not add another conversation route in the interim. ### Accepted fixture and boundary crossings @@ -48,19 +48,20 @@ Prepare the net with `Batch ready`, `Under final inspection`, `Ready for dispatc ```text stable prepared-fixture selector → resolve distinct fixture, Petrinaut document, and Flue conversation identities -→ open the prepared non-empty browser document and hydrate canonical Flue history +→ open the prepared non-empty browser document and use the browser Flue client to idempotently deliver or recover the tagged revision-zero signal +→ hydrate canonical Flue history through `history()` on the mounted route → recover prepared revision zero from the tagged dispatch record, or the latest eligible assistant revision, by source message id plus content hash -→ submit the realistic crew-reservation confirmation through the production panel door +→ submit the realistic crew-reservation confirmation through Mission 5's production browser Flue transport → Brunch emits an inspectable full workpiece revision without erasing prior meaning or the remaining unknown → SDCPN construction reads that current workpiece and the live browser document → Brunch requests the least canonical meaningful mutation → Petrinaut validates and executes it against the bound document -→ the original tool-call id and result resume the same Flue conversation -→ inspect the canonical non-empty document and record a settled fixture witness only after conversation/workpiece/document state is observable -→ a second tab opens the same fixture selector, resolves the same identities and settled hashes, and can continue +→ the original tool-call id and result return as one correlated signal through the same browser Flue transport and resume the same conversation +→ inspect the canonical non-empty document and advance the runtime settled manifest only after conversation/workpiece/document state is observable +→ a second tab opens the same fixture selector, resolves the same identities and settled hashes, submits one follow-up, and receives Brunch's response ``` -The fixture witness is a small local viability manifest, not a new event log, independent workpiece store, or distributed transaction. It records distinct ids, prepared inputs, latest settled workpiece source/hash, document hash or local revision token, and limitations. A failed history load, workpiece recovery, rejected/no-op mutation, or missing result correlation must not advance that witness; the partial state remains visible for diagnosis. The existing automatic localStorage mirror is the only document-save mechanism unless a real failure proves it insufficient. +The settled fixture manifest is runtime local product state, not merely retained evaluation evidence: the stable selector uses it to choose the latest coherent observed bundle of distinct fixture, Flue conversation, workpiece source/hash, and Petrinaut document/hash or revision identities across reopen. It is a small viability pointer, not a new event log, independent workpiece store, or distributed transaction. A failed history load, workpiece recovery, rejected/no-op mutation, or missing result correlation must leave the prior settled bundle selected while partial state and failure remain visible for diagnosis. Retained witness artifacts copy and inspect this runtime state but do not select the product bundle. The existing automatic localStorage mirror is the only document-save mechanism unless a real failure proves it insufficient; this mission adds no explicit Save affordance. ### Expected touched paths @@ -73,10 +74,11 @@ libs/@hashintel/brunch-agent/ ├── packages/plugin-sdcpn/ ~ mount only the read/mutation capability earned by this tracer └── docs/evidence/ + prepared fixture manifest and browser witness apps/brunch-agent/ -├── src/agents/chat-agent/ and src/conversation/ ? only if normal client-tool mounting/correlation requires it +├── src/agents/chat-agent/ and src/conversation/ ? only if fixture-scoped mounting or workpiece recovery belongs outside the landed browser transport └── test/ + real Flue/client-tool fixture integration apps/petrinaut-website/ -└── src/main/app/local-storage-demo/ ~ fixture selection, prepared seed, settled witness, and cross-tab resume +└── src/main/app/local-storage-demo/ ~ consume Mission 5 transport; fixture selection, prepared signal, runtime settled manifest, and cross-tab continuation +libs/@hashintel/brunch-agent/packages/transport-aisdk/ ? consume the landed Mission 5 public surface; do not duplicate its implementation here libs/@hashintel/petrinaut-core/ or libs/@hashintel/petrinaut/ ? only for an observed canonical contract or browser-host defect ``` @@ -98,14 +100,14 @@ Every final leaf has a discriminating oracle: 2. **One evidence turn maintains the Markdown workpiece.** A production-agent fixture integration mechanically recovers prepared revision zero from the tagged dispatch record, then selects the latest eligible assistant `runbook-ir` block after the confirming turn, retaining each source message id and SHA-256. Before/after adjudication must find the supplied contextual quantity, retained crew/release meaning, retained unsupported context, and no invented fact or hardened unknown. 3. **The real browser executes a correlated Petrinaut read and write.** Focused plugin/transport tests prove that `getLatestNetDefinition` and the selected `addArc` schema come mechanically from Petrinaut's canonical contracts, fixture mode advertises only the selected operations, duplicate result delivery does not apply the mutation twice, rejected input remains visible, and a mutation that would change nothing is reported as a no-op rather than as a change. The browser witness must retain tool name, call id, parsed input, execution output, resumed signal, and resulting canonical definition; a headless callback alone does not pass. 4. **The document change is meaningful rather than merely accepted.** A structural comparison proves there was no standard input arc from `Dispatch crew available` to `Start final inspection` before the turn and exactly one weight-1 arc afterward, while `Sign-off` still returns the crew and the prepared net remains non-empty. The changed workpiece retains the reservation/release meaning and unresolved timing/recovery. Parser/schema acceptance or a disconnected convenience element fails. -5. **The settled witness cannot bless partial state.** A focused failure test injects history/workpiece-recovery failure, rejected `addArc`, or missing/duplicate result correlation and shows that the prior settled manifest remains selected while the failure and any partial state are inspectable. Do not invent a localStorage failure interface solely to satisfy this leaf. -6. **A second tab resumes the same fixture.** With `yarn dev:brunch` running, the recorded browser protocol opens the stable selector in Tab A, performs and settles the turn, then opens it in Tab B. The witness compares fixture id, document id and canonical definition hash, Flue conversation id and history, latest workpiece source/hash, per-message typed/Voice provenance, stopped-turn presentation, and absence of duplicate submission before one read or continuation succeeds in Tab B. An aborted entry rendered as ordinary truncated content fails this check even if a global latest-settlement banner still says stopped. Tab B opened against a stale or mismatched revision must refuse visibly rather than silently select older artifacts. +5. **The runtime settled manifest cannot bless partial state.** A focused failure test injects history/workpiece-recovery failure, rejected `addArc`, or missing/duplicate result correlation and shows that the prior coherent runtime bundle remains selected while the failure and any partial state are inspectable. A retained evidence manifest alone does not pass this leaf, and no localStorage failure interface is invented solely to satisfy it. +6. **A second tab resumes and continues the same fixture.** With `yarn dev:brunch` running, the recorded browser protocol opens the stable selector in Tab A, performs and settles the turn, then opens it in Tab B. The witness compares fixture id, document id and canonical definition hash, Flue conversation id and history, latest workpiece source/hash, runtime settled-manifest identity, per-message typed/Voice provenance, stopped-turn presentation, and absence of duplicate submission. An aborted entry rendered as ordinary truncated content fails this check even if a global latest-settlement banner still says stopped. Tab B must then submit one follow-up message and receive its correlated Brunch response in that same conversation. A read alone does not pass. Tab B opened against a stale or mismatched revision must refuse visibly rather than silently select older artifacts. 7. **The cut has not smuggled in the later architecture.** Public-schema and dependency inspection finds only fixture identity/revision links, Markdown recovery metadata, and canonical Petrinaut payloads—no closed process ontology, typed capture-to-workpiece reducer, graph database, second conversation log, or general projection engine. Verification proceeds inside-out but closure requires the outer boundary: -- **Inner:** fixture parsing and prepared-label checks; identity separation; workpiece recovery/hash; canonical `addArc` schema and exact before/after edge assertion; idempotent client-tool result handling; settled-witness refusal. -- **Middle:** the built production `ChatAgent` and `/api/chat` path hydrate the prepared Flue conversation, accept the evidence turn, recover the revised workpiece, and carry actual browser-tool calls/results. Run the focused workspaces through root Turbo (`test:unit`, `lint:tsc`, `lint:eslint`, and `build` where changed). +- **Inner:** fixture parsing and prepared-label checks; identity separation; workpiece recovery/hash; canonical `addArc` schema and exact before/after edge assertion; idempotent client-tool result handling; runtime-manifest refusal. +- **Middle:** the built production `ChatAgent` and Mission 5 browser `FlueClient`/`ChatTransport` path at `/agents/chat/:instanceId` hydrate the prepared conversation, accept the evidence turn, recover the revised workpiece, and carry actual browser-tool calls/results. No `GET` or `POST /api/chat` evidence passes. Run the focused workspaces through root Turbo (`test:unit`, `lint:tsc`, `lint:eslint`, and `build` where changed). - **Outer:** the two-tab `yarn dev:brunch` witness above, with retained before/after artifacts, one Voice-origin message, and one durably stopped assistant turn. A content-only transcript match does not establish faithful resume. - **Semantic:** a cold human accepts fixture/workpiece honesty and the workpiece-to-document correspondence. The oracle may falsify those claims; it may not rewrite the interaction or architecture policy. - **Product:** a product manager who did not watch the work runs the demo script from the imperative without an engineer and notices the advance. This is the last check before close, after the readiness gate; it is not a substitute for the oracles above. @@ -114,12 +116,13 @@ Verification proceeds inside-out but closure requires the outer boundary: - Keep fixture id, Flue conversation id, latest workpiece source/revision, and Petrinaut document id/revision distinct and explicitly linked. One id must not impersonate all lifecycles. - Flue history remains the canonical conversation log. Browser message caches and fixture artifacts are projections or evidence, never a second authority. +- Consume Mission 5's browser `FlueClient` plus host-supplied AI SDK `ChatTransport`; typed turns, prepared signals, history hydration, and client-tool results all cross `/agents/chat/:instanceId`. Do not keep, restore, or add another product conversation route. - The tagged prepared signal is the only test-authored workpiece source admitted by this fixture. It remains a diagnostic system/dispatch record; latest-revision selection may supersede it with a genuine assistant workpiece but may not mutate, relabel, or hide its authorship. - Markdown remains the semantic workpiece. Recover its full latest version; do not introduce a comprehensive typed domain IR to make fixture lookup convenient. - Projection consumes the current workpiece. The transcript may establish provenance and help recover that artifact but may not become the primary construction IR. - Petrinaut owns canonical schemas, browser validation, mutations, and document state. Brunch imports or mechanically derives those contracts and does not hand-copy their field shapes. - Client tools execute against the active bound browser document and return the original tool-call id. Stale, duplicate, cross-document, malformed, failed, and no-op outcomes fail visibly. -- Publish a new settled fixture witness only after the claimed Flue snapshot, workpiece revision, and document state can all be inspected. The witness does not make the browser and Flue stores transactional. Do not invent explicit save or cross-store transaction machinery without an observed recovery failure requiring it. +- Advance the runtime settled manifest only after the claimed Flue snapshot, workpiece revision, and document state can all be inspected. It selects the coherent local bundle but does not make the browser and Flue stores transactional. Automatic localStorage mirroring remains the only save behavior; do not invent an explicit Save affordance or cross-store transaction machinery without an observed recovery failure requiring it. - Preserve the accepted Mission 4 `useBrunchAgent()` plus `useSdcpnPlugin()` architecture. The app composes; the plugin owns SDCPN operation semantics; the transport carries results; the UI executes them. - Keep construction tools unavailable to unrelated ordinary conversations unless the real path proves the smallest safe selection can be scoped to this fixture/mode. Stock-assistant behavior must remain unchanged when Brunch is absent or unselected. - The fixture is local and deliberately prepared. Make no remote durability, capture provenance, automatic projection, behavioral execution, or concurrent collaboration claim. @@ -144,10 +147,11 @@ Stop and surface evidence if: - fixture preparation requires pretending a Mission 4 candidate exists, placing prepared text in a user or assistant record, accepting an untagged preparation signal, or otherwise hiding test-authored/model-authored boundaries; - the path conflates fixture, conversation, workpiece, and document identities or creates a second canonical conversation history; +- typed traffic, prepared signals, history, or client-tool results cross a product route other than Mission 5's mounted browser Flue route; - the agent rereads transcript prose as its primary projection input because the current Markdown workpiece cannot carry the needed meaning; - parser/schema acceptance, document non-emptiness, or a disconnected convenience element is offered as semantic correspondence; - client-tool results lose their original call id, can target the wrong document, or duplicate execution on retry/reload; -- a partial or failed write advances the settled witness, or second-tab reopening silently selects stale/mismatched artifacts; +- a partial or failed write advances the runtime settled manifest, second-tab reopening silently selects stale/mismatched artifacts, or Tab B proves only a read without a real continuation; - exposing one browser mutation requires mounting an unrestricted construction surface for every ordinary conversation; - the selected provider/Flue schema cannot faithfully carry the least meaningful mutation—record the crisp blocker rather than hand-copying Petrinaut schemas or widening into Mission 9; - the tracer needs a closed ontology, typed claim ledger, general projection engine, distributed transaction, or new durable service before a concrete failure demonstrates that need; or From ab6adfa6bda1c6e16248f0e1405d45f6ce9a5ac0 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Thu, 3 Sep 2026 16:50:35 +0200 Subject: [PATCH 04/31] Record Mission 5 as the Mission 6 transport prerequisite --- libs/@hashintel/brunch-agent/MISSION.next.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libs/@hashintel/brunch-agent/MISSION.next.md b/libs/@hashintel/brunch-agent/MISSION.next.md index 637512ab406..94a6b746f33 100644 --- a/libs/@hashintel/brunch-agent/MISSION.next.md +++ b/libs/@hashintel/brunch-agent/MISSION.next.md @@ -225,7 +225,7 @@ These tracks may start only under their own issue, branch, PR, and mission autho | Inferential observer fold | Decide before Mission 10 whether observed foreground strain earns promotion; otherwise retain phase-boundary synthesis | Missions 4–9 | | Provider-visible nested schema | Mission 6 tests only the least mutation needed by its meaningful fixture; Mission 9 closes the broader canonical projection classes after a crisp blocker or success | Mission 5 and non-construction Voice work | | Provenance interaction fixture | Mission 6 establishes minimal fixture identity; freeze the broader derivation fixture before Mission 7 why and Mission 9 automatic projection diverge | Voice work and prepared-fixture viability | -| Host choice/session lifecycle | Mission 5 proves Flue conversation reopen; Mission 6 proves fixture save/reopen; later host/picker breadth waits for its visible consumer | Either independent tracer | +| Host choice/session lifecycle | Mission 5 proves Flue conversation reopen; Mission 6 proves fixture save/reopen over Mission 5's landed browser transport; later host/picker breadth waits for its visible consumer | Mission 5 first, then Mission 6 | | Optimisation handoff contract | Chris/Yannis accept input/output contract and one fixture before Mission 11 is cut | Missions 4–10 | | Simulation-backed semantic check | Promote only if cheap and discriminating for the selected revision | First provenance tracer | @@ -482,3 +482,7 @@ The owner subsequently changed the integration premise: Voice should use canonic Later on 2026-09-03 the owner replaced the "visible/usable proof" completion criterion with the product-manager litmus defined in the accepted spine above. The observed problem was that each précis pinned completion to an evidence bundle at the first green throughline tracer, which convinces a builder but is invisible to a product manager, and that Draft Mission 9 carried engineering internals in its visible-advance section. The change re-pins completion to each mission's readiness gate for the named demo scenario, moves oracles out of the visible-advance sections, expands Mission 7 from one element to every consequential element of the demo net, and names the deployment posture problem for Missions 7, 9, and 10. Mission 5 was live on its own branch and was not touched by that commit; on restack, the live branch adopted the litmus in [`MISSION.md`](MISSION.md#product-manager-litmus), naming Stop-that-really-stops and one shared typed/spoken conversation as its product-manager-noticeable advance and its single-route consolidation as internal sequencing. Mission-specific detail lives in the affected drafts' `Visible product advance` and `Throughline proof floor` sections and in the [draft README](docs/mission-drafts/README.md). Mission 6 had been cut into root [`MISSION.md`](MISSION.md) on the FE-1575 branch from the pre-litmus draft earlier the same day. That cut was recut on restack rather than left as it stood: its proof section had named the evidence bundle (selector, manifest, snapshots, revisions) as the visible proof artifact and read as if the first green two-tab pass were completion. The recut moves the release note, demo script, and previously-impossible statement into the imperative, names the readiness gate as the completion bar, keeps the seven discriminating oracles as builder evidence, and records the local-only demo posture explicitly. No Mission 6 draft remains here. + +## 2026-09-03 Mission 5 becomes Mission 6's transport prerequisite + +Missions 5 and 6 were cut as independent siblings on this spine. Mission 5's recut then made one browser Flue `ChatTransport` the only door into a Brunch conversation and removed the server-side `/api/chat` route, `createPetrinautChatHandler`, the `GET ?id=` history door, and the app-side UI-stream projector that Mission 6's throughline had named as its departure point. The owner corrected Mission 6 to consume Mission 5's landed transport rather than wire against the route being deleted or copy Mission 5's in-progress implementation. Mission 6 implemented and verified its transport-independent substrate (prepared-signal recovery, fixture-scoped read and `addArc`, correlated-result settlement refusal, stable selector, document seed, runtime manifest) and then stopped at that boundary. The owner first chose to keep Mission 6 a sibling branch and wait for Mission 5 to land, because Mission 5's committed state was then documentation only and every line Mission 6 needed sat uncommitted. Mission 5 then committed its typed-panel transport tracer as three commits (`Expose the Flue browser chat transport`, `Wire the Petrinaut panel to the Flue route`, `Remove the legacy Petrinaut chat route`) ahead of its Voice work, and the owner reversed the wait: this branch was moved onto `ln/fe-1574-direct-voice-flue` so Mission 6 consumes only Mission 5's committed public surface. Splitting the transport consolidation into a shared substrate branch was rejected because it would sever half of Mission 5's imperative from its authority. Consequences accepted with the move: this branch's root `MISSION.md` is Mission 6's, so Mission 5's live authority is visible only on its own branch; Mission 6 cannot merge before Mission 5; and when Mission 5 closes and archives its authority this branch will need another restack. The independence claims in the spine above were corrected to match. From 31761bf70b8e6982c5d5099b9f933cbd36e29cd1 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Thu, 3 Sep 2026 22:42:49 +0200 Subject: [PATCH 05/31] Implement the Mission 6 resumable workpiece fixture over the Flue transport Prepare one honestly labelled crew-reservation fixture whose starting workpiece enters canonical Flue history exactly once as a tagged system dispatch signal with idempotent retry, scope the read/`addArc` client tools to that fixture, settle a runtime manifest only after conversation, workpiece, and document state are observable, and surface a visible refusal when the mounted Brunch route is absent. The fixture rides Mission 5's landed browser `ChatTransport`: the panel transport keeps the conversation tracker and accepts fixture-scoped client tool names as an option, the history hook keeps the live observation and additionally exposes the observed snapshot with its offset, and AI SDK user sends carry a deterministic idempotency key. The real two-tab witness remains blocked on the configured Anthropic credential; the blocker and handoff are recorded in the FE-1575 evidence note. No persona testing was run. --- .changeset/resumable-petrinaut-workpiece.md | 6 + .../src/conversation/client-tools.ts | 6 +- .../src/conversation/workpiece.ts | 68 ++++ .../src/evaluations/runbook/artifacts.ts | 58 +-- .../runbook/headless-petrinaut-client.ts | 21 +- .../architecture/boundaries.integration.ts | 7 +- .../test/architecture/boundaries.test.ts | 5 + .../prepared-workpiece.integration.test.ts | 70 ++++ .../test/prepared-workpiece.integration.ts | 276 +++++++++++++ apps/brunch-agent/test/workpiece.test.ts | 135 +++++++ .../brunch-panel-transport.test.ts | 79 ++++ .../brunch-panel-transport.ts | 17 +- .../crew-reservation-settled-manifest.test.ts | 380 ++++++++++++++++++ .../crew-reservation-settled-manifest.ts | 289 +++++++++++++ .../local-storage-demo-app.tsx | 158 +++++++- ...pare-crew-reservation-conversation.test.ts | 87 ++++ .../prepare-crew-reservation-conversation.ts | 90 +++++ .../prepared-crew-reservation-fixture.test.ts | 82 ++++ .../prepared-crew-reservation-fixture.ts | 154 +++++++ .../prepared-fixture-banner.test.tsx | 76 ++++ .../prepared-fixture-banner.tsx | 84 ++++ ...-crew-reservation-settled-manifest.test.ts | 113 ++++++ .../use-crew-reservation-settled-manifest.ts | 124 ++++++ .../use-flue-chat-history.test.ts | 81 +++- .../use-flue-chat-history.ts | 30 +- .../voice-preview.integration.test.ts | 1 + .../fe-1575-resumable-workpiece-petrinaut.md | 79 ++++ .../brunch-agent/packages/core/package.json | 4 + .../packages/core/src/workpiece.ts | 214 ++++++++++ .../packages/core/test/workpiece.test.ts | 174 ++++++++ .../brunch-agent/packages/core/vite.config.ts | 1 + .../packages/plugin-sdcpn/src/flue.ts | 25 +- .../src/tools/petrinaut-construction.ts | 9 + .../test/construction-tools.test.ts | 32 ++ .../packages/transport-aisdk/src/index.ts | 8 + .../test/chat-transport.test.ts | 26 ++ .../@hashintel/petrinaut/docs/ai-assistant.md | 12 + .../Editor/panels/ai-assistant-panel.tsx | 22 +- .../apply-petrinaut-ai-mutation.test.ts | 102 +++++ .../apply-petrinaut-ai-mutation.ts | 39 ++ 40 files changed, 3135 insertions(+), 109 deletions(-) create mode 100644 .changeset/resumable-petrinaut-workpiece.md create mode 100644 apps/brunch-agent/src/conversation/workpiece.ts create mode 100644 apps/brunch-agent/test/architecture/boundaries.test.ts create mode 100644 apps/brunch-agent/test/prepared-workpiece.integration.test.ts create mode 100644 apps/brunch-agent/test/prepared-workpiece.integration.ts create mode 100644 apps/brunch-agent/test/workpiece.test.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.test.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.test.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.test.tsx create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.tsx create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.test.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md create mode 100644 libs/@hashintel/brunch-agent/packages/core/src/workpiece.ts create mode 100644 libs/@hashintel/brunch-agent/packages/core/test/workpiece.test.ts create mode 100644 libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/apply-petrinaut-ai-mutation.test.ts create mode 100644 libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/apply-petrinaut-ai-mutation.ts diff --git a/.changeset/resumable-petrinaut-workpiece.md b/.changeset/resumable-petrinaut-workpiece.md new file mode 100644 index 00000000000..40e8ffd20ae --- /dev/null +++ b/.changeset/resumable-petrinaut-workpiece.md @@ -0,0 +1,6 @@ +--- +"@hashintel/petrinaut": patch +--- + +Report duplicate AI mutations as no-ops so hosts can distinguish an applied document change from +an already-present state when resuming a correlated browser tool call. diff --git a/apps/brunch-agent/src/conversation/client-tools.ts b/apps/brunch-agent/src/conversation/client-tools.ts index c238c9e3215..dd8e44d8b23 100644 --- a/apps/brunch-agent/src/conversation/client-tools.ts +++ b/apps/brunch-agent/src/conversation/client-tools.ts @@ -1,6 +1,9 @@ /** Flue-side client-tool signal contract: awaiting sentinel, result signal, tool names. */ -import { READ_PETRINAUT_DOC_TOOL_NAME } from "@hashintel/brunch-agent-plugin-sdcpn/flue"; +import { + PETRINAUT_FIXTURE_TOOL_NAMES, + READ_PETRINAUT_DOC_TOOL_NAME, +} from "@hashintel/brunch-agent-plugin-sdcpn/flue"; import { CLIENT_TOOL_RESULT_SIGNAL } from "@hashintel/brunch-agent-transport-aisdk"; import { AWAITING_CLIENT } from "@hashintel/brunch-agent/client-tools"; @@ -9,6 +12,7 @@ export { CLIENT_TOOL_RESULT_SIGNAL }; export const clientToolNames: ReadonlySet = new Set([ READ_PETRINAUT_DOC_TOOL_NAME, + ...PETRINAUT_FIXTURE_TOOL_NAMES, ]); const isRecord = (value: unknown): value is Record => diff --git a/apps/brunch-agent/src/conversation/workpiece.ts b/apps/brunch-agent/src/conversation/workpiece.ts new file mode 100644 index 00000000000..3a146af098b --- /dev/null +++ b/apps/brunch-agent/src/conversation/workpiece.ts @@ -0,0 +1,68 @@ +/** Recover the current Markdown workpiece from canonical Flue history. */ + +import { createHash } from "node:crypto"; + +import { + createPreparedWorkpieceDelivery, + latestRunbookIrBlock, + PREPARED_WORKPIECE_AUTHORSHIP, + PREPARED_WORKPIECE_CLAIM_BOUNDARY, + PREPARED_WORKPIECE_INITIAL_DATA_MODE, + PREPARED_WORKPIECE_SIGNAL_TAG, + PREPARED_WORKPIECE_SIGNAL_TYPE, + RUNBOOK_IR_FENCE, + selectRunbookWorkpiece, +} from "@hashintel/brunch-agent/workpiece"; + +import type { FlueConversationSnapshot } from "@flue/sdk"; + +const sha256 = (value: string): string => + createHash("sha256").update(value).digest("hex"); + +export { + createPreparedWorkpieceDelivery, + latestRunbookIrBlock, + PREPARED_WORKPIECE_AUTHORSHIP, + PREPARED_WORKPIECE_CLAIM_BOUNDARY, + PREPARED_WORKPIECE_INITIAL_DATA_MODE, + PREPARED_WORKPIECE_SIGNAL_TAG, + PREPARED_WORKPIECE_SIGNAL_TYPE, + RUNBOOK_IR_FENCE, +}; + +export interface RecoveredRunbookWorkpiece { + readonly authorship: "model-produced" | "test-authored"; + readonly content: string; + readonly fixtureId?: string; + readonly sha256: string; + readonly sourceKind: "assistant" | "prepared-signal"; + readonly sourceMessageId: string; + readonly sourceMessageSha256: string; + readonly sourceSubmissionId?: string; +} + +/** + * Add content and source hashes to the substrate-neutral current-workpiece + * selection used by both evaluations and the browser fixture. + */ +export const recoverRunbookWorkpiece = ( + snapshot: FlueConversationSnapshot, +): RecoveredRunbookWorkpiece | undefined => { + const selected = selectRunbookWorkpiece(snapshot); + if (selected === undefined) return undefined; + + return { + authorship: selected.authorship, + content: selected.content, + ...(selected.fixtureId === undefined + ? {} + : { fixtureId: selected.fixtureId }), + sha256: sha256(selected.content), + sourceKind: selected.sourceKind, + sourceMessageId: selected.sourceMessageId, + sourceMessageSha256: sha256(JSON.stringify(selected.sourceMessage)), + ...(selected.sourceSubmissionId === undefined + ? {} + : { sourceSubmissionId: selected.sourceSubmissionId }), + }; +}; diff --git a/apps/brunch-agent/src/evaluations/runbook/artifacts.ts b/apps/brunch-agent/src/evaluations/runbook/artifacts.ts index 05a50b46847..bdc39fc3035 100644 --- a/apps/brunch-agent/src/evaluations/runbook/artifacts.ts +++ b/apps/brunch-agent/src/evaluations/runbook/artifacts.ts @@ -2,56 +2,26 @@ import { basename } from "node:path"; -import { sha256 } from "./campaign-integrity.ts"; - -import type { FlueConversationPart, FlueConversationSnapshot } from "@flue/sdk"; - -export const RUNBOOK_IR_FENCE = "runbook-ir"; - -const runbookIrFencePattern = /```runbook-ir\s*\n([\s\S]*?)```/g; - -export const latestRunbookIrBlock = (text: string): string | undefined => { - const matches = [...text.matchAll(runbookIrFencePattern)]; - const last = matches.at(-1)?.[1]; - return last === undefined ? undefined : last.trim(); +import { + latestRunbookIrBlock, + recoverRunbookWorkpiece, + RUNBOOK_IR_FENCE, + type RecoveredRunbookWorkpiece, +} from "../../conversation/workpiece.ts"; + +import type { FlueConversationSnapshot } from "@flue/sdk"; + +export { + latestRunbookIrBlock, + recoverRunbookWorkpiece, + RUNBOOK_IR_FENCE, + type RecoveredRunbookWorkpiece, }; export const recoverRunbookIr = ( snapshot: FlueConversationSnapshot, ): string | undefined => recoverRunbookWorkpiece(snapshot)?.content; -export interface RecoveredRunbookWorkpiece { - readonly content: string; - readonly sha256: string; - readonly sourceMessageId: string; - readonly sourceMessageSha256: string; -} - -export const recoverRunbookWorkpiece = ( - snapshot: FlueConversationSnapshot, -): RecoveredRunbookWorkpiece | undefined => { - let recovered: RecoveredRunbookWorkpiece | undefined; - for (const message of snapshot.messages) { - if (message.purpose !== "assistant") continue; - const text = message.parts - .filter( - (part): part is Extract => - part.type === "text", - ) - .map((part) => part.text) - .join("\n"); - const content = latestRunbookIrBlock(text); - if (content === undefined) continue; - recovered = { - content, - sha256: sha256(content), - sourceMessageId: message.id, - sourceMessageSha256: sha256(JSON.stringify(message)), - }; - } - return recovered; -}; - export const interviewerToolNamesFrom = ( snapshot: FlueConversationSnapshot, ): readonly string[] => [ diff --git a/apps/brunch-agent/src/evaluations/runbook/headless-petrinaut-client.ts b/apps/brunch-agent/src/evaluations/runbook/headless-petrinaut-client.ts index 54cce1b64ee..b654e17eebf 100644 --- a/apps/brunch-agent/src/evaluations/runbook/headless-petrinaut-client.ts +++ b/apps/brunch-agent/src/evaluations/runbook/headless-petrinaut-client.ts @@ -12,7 +12,7 @@ import { getLatestNetDefinitionToolName, } from "@hashintel/petrinaut-core/ai"; -import type { Petrinaut } from "@hashintel/petrinaut-core"; +import type { Petrinaut, SDCPN } from "@hashintel/petrinaut-core"; export interface HeadlessPetrinautToolCall { readonly toolCallId: string; @@ -45,15 +45,18 @@ const constructionToolNames = new Set( const errorMessageFrom = (error: unknown): string => error instanceof Error ? error.message : String(error); -export const createHeadlessPetrinautClient = (title: string) => { +export const createHeadlessPetrinautClient = ( + title: string, + initial: SDCPN = { + places: [], + transitions: [], + types: [], + parameters: [], + differentialEquations: [], + }, +) => { const handle = createJsonDocHandle({ - initial: { - places: [], - transitions: [], - types: [], - parameters: [], - differentialEquations: [], - }, + initial, }); const instance = createPetrinaut({ document: handle }); const writableCallbacks = createPetrinautAiWritableCallbacks( diff --git a/apps/brunch-agent/test/architecture/boundaries.integration.ts b/apps/brunch-agent/test/architecture/boundaries.integration.ts index 11d2f9ae83c..f7b044eef51 100644 --- a/apps/brunch-agent/test/architecture/boundaries.integration.ts +++ b/apps/brunch-agent/test/architecture/boundaries.integration.ts @@ -379,13 +379,14 @@ describe("recorded Flue constraints hold by construction (spec §10)", () => { }); describe("core auxiliary subpaths stay in their assigned lanes", () => { - test("core exposes Flue composition, browser contracts, and storage support as explicit subpaths", () => { + test("core exposes Flue composition, browser, storage, and workpiece contracts as explicit subpaths", () => { const core = PACKAGES.find((pkg) => pkg.name === CORE)!; expect(Object.keys(core.manifest.exports ?? {})).toEqual([ ".", "./client-tools", "./flue", "./storage", + "./workpiece", ]); }); @@ -429,6 +430,8 @@ describe("the HASH smoke is runnable without a model key or a network (spec §12 "Types Flue's public conversation snapshot so the transcript projector can be unit-tested; the import is type-only — no provider key, no socket, no model call, no runtime boot.", "apps/brunch-agent/test/petrinaut-chat.integration.ts": "Boots the plain Flue chat agent on Flue's node runtime with pi-ai's faux provider, drives the browser ChatTransport against the mounted Flue route over app.fetch, and proves streamed reasoning/text, server tools, client-tool resume, SDK history ownership, SQLite restart, and harness-side idempotent apply-sweep — no provider key, no socket, no extraction model call. Run as a child process by petrinaut-chat.test.ts.", + "apps/brunch-agent/test/prepared-workpiece.integration.ts": + "Boots the built Flue ChatAgent with pi-ai's faux provider, creates a prepared fixture through one tagged public signal with fixture-scoped initial data, retries its deterministic idempotency key, and proves prepared/model workpiece selection from canonical history — no provider key, socket, or network model call.", "apps/brunch-agent/test/proof-artifacts.test.ts": "Types Flue's public conversation snapshot so canonical trace derivation, workpiece binding, and atomic evidence retention can be unit-tested against an in-memory fixture — no provider key, no socket, no model call, no runtime boot.", "apps/brunch-agent/test/runbook-artifacts.test.ts": @@ -439,6 +442,8 @@ describe("the HASH smoke is runnable without a model key or a network (spec §12 "Boots the built Flue ChatAgent with pi-ai's faux provider and a headless Petrinaut client to prove validated construct-only tool flow without a provider key, socket, or network model call.", "apps/brunch-agent/test/telemetry.test.ts": "Constructs Flue's content-free OpenTelemetry instrumentation with an injected exporter setup to prove disposal order; it registers no global instrumentation, opens no socket, and makes no provider call.", + "apps/brunch-agent/test/workpiece.test.ts": + "Types Flue's public conversation snapshot so the substrate-neutral workpiece selector and app-owned SHA-256 projection can be unit-tested against in-memory messages — no provider key, no socket, no model call, no runtime boot.", "libs/@hashintel/brunch-agent/packages/transport-aisdk/test/chat-transport.test.ts": "Types a stubbed public Flue client and stream chunks to prove finite AI SDK projection and client-tool signal admission — no runtime boot, provider key, socket, or model call.", "libs/@hashintel/brunch-agent/packages/transport-aisdk/test/transcript.test.ts": diff --git a/apps/brunch-agent/test/architecture/boundaries.test.ts b/apps/brunch-agent/test/architecture/boundaries.test.ts new file mode 100644 index 00000000000..712624bb2b6 --- /dev/null +++ b/apps/brunch-agent/test/architecture/boundaries.test.ts @@ -0,0 +1,5 @@ +/** + * Keep the filesystem-wide architecture suite runnable by Vitest while its + * implementation remains a non-test entry point for boundary self-inspection. + */ +import "./boundaries.integration.ts"; diff --git a/apps/brunch-agent/test/prepared-workpiece.integration.test.ts b/apps/brunch-agent/test/prepared-workpiece.integration.test.ts new file mode 100644 index 00000000000..25f523efb82 --- /dev/null +++ b/apps/brunch-agent/test/prepared-workpiece.integration.test.ts @@ -0,0 +1,70 @@ +import { mkdtemp, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { expect, test } from "vitest"; + +import { runNodeScript } from "./run-node-script"; + +test("the built ChatAgent preserves prepared and model workpiece provenance", async () => { + const databaseDirectory = await mkdtemp( + join(tmpdir(), "brunch-prepared-workpiece-"), + ); + try { + const { exitCode, stdout, stderr } = await runNodeScript( + join(import.meta.dirname, "prepared-workpiece.integration.ts"), + join(import.meta.dirname, "../../.."), + { + BRUNCH_CHAT_DB_PATH: join(databaseDirectory, "conversations.db"), + }, + ); + expect(exitCode, stderr || stdout).toBe(0); + const resultLine = stdout + .split("\n") + .find((line) => line.startsWith("PREPARED_WORKPIECE_HERMETIC ")); + expect(resultLine, stdout).toBeDefined(); + const result = JSON.parse( + resultLine!.slice("PREPARED_WORKPIECE_HERMETIC ".length), + ) as { + readonly clientToolCallIds: string[]; + readonly messageCountStableAcrossRetry: boolean; + readonly prepared: { + readonly authorship: string; + readonly content: string; + readonly sourceKind: string; + }; + readonly preparedDispatchCount: number; + readonly preparationSubmissionId: string; + readonly retryDeduplicated: boolean; + readonly retrySubmissionId: string; + readonly targetArcAdded: boolean; + readonly revision: { + readonly authorship: string; + readonly content: string; + readonly sourceKind: string; + }; + }; + + expect(result.retryDeduplicated).toBe(true); + expect(result.retrySubmissionId).toBe(result.preparationSubmissionId); + expect(result.messageCountStableAcrossRetry).toBe(true); + expect(result.preparedDispatchCount).toBe(1); + expect(result.clientToolCallIds).toEqual([ + "fixture-read-before-mutation", + "fixture-add-reservation-arc", + ]); + expect(result.targetArcAdded).toBe(true); + expect(result.prepared).toMatchObject({ + authorship: "test-authored", + content: "# Prepared revision\n\nTiming and recovery remain unresolved.", + sourceKind: "prepared-signal", + }); + expect(result.revision).toMatchObject({ + authorship: "model-produced", + sourceKind: "assistant", + }); + expect(result.revision.content).toContain("# Model revision one"); + } finally { + await rm(databaseDirectory, { recursive: true, force: true }); + } +}); diff --git a/apps/brunch-agent/test/prepared-workpiece.integration.ts b/apps/brunch-agent/test/prepared-workpiece.integration.ts new file mode 100644 index 00000000000..fa149429435 --- /dev/null +++ b/apps/brunch-agent/test/prepared-workpiece.integration.ts @@ -0,0 +1,276 @@ +import { tmpdir } from "node:os"; +import { join } from "node:path"; + +import { + fauxAssistantMessage, + fauxProvider, + fauxText, + fauxToolCall, +} from "@earendil-works/pi-ai"; +import { setProvider } from "@flue/runtime"; +import { createFlueClient } from "@flue/sdk"; + +import { + PETRINAUT_FIXTURE_TOOL_NAMES, + VALIDATED_FIXTURE_MUTATION_MODE, +} from "@hashintel/brunch-agent-plugin-sdcpn/flue"; + +import { + CLIENT_TOOL_RESULT_SIGNAL, + isAwaitingClient, +} from "../src/conversation/client-tools.ts"; +import { + agentOwnershipHeaders, + flueConversationIdFrom, +} from "../src/conversation/identity.ts"; +import { + createPreparedWorkpieceDelivery, + recoverRunbookWorkpiece, +} from "../src/conversation/workpiece.ts"; +import { createHeadlessPetrinautClient } from "../src/evaluations/runbook/headless-petrinaut-client.ts"; +import { loadBuiltBrunchApplication } from "../src/evaluations/runbook/load-built-application.ts"; +import { CHAT_AGENT_ROUTE } from "../src/http/routes.ts"; + +const modelId = "claude-haiku-4-5"; +const dispatchCrewPlaceId = "dispatch_crew_available"; +const startFinalInspectionTransitionId = "start_final_inspection"; +const preparedBody = [ + "Fixture authorship: test-authored.", + "```runbook-ir", + "# Prepared revision", + "", + "Timing and recovery remain unresolved.", + "```", +].join("\n"); +const preparedDelivery = createPreparedWorkpieceDelivery({ + body: preparedBody, + fixtureId: "crew-reservation-v1", + revision: 0, +}); + +process.env.BRUNCH_CHAT_MODEL = modelId; +process.env.BRUNCH_DEV_DB_PATH = + process.env.BRUNCH_CHAT_DB_PATH ?? + join(tmpdir(), `brunch-prepared-workpiece-${crypto.randomUUID()}.db`); + +const provider = fauxProvider({ + provider: "anthropic", + models: [{ id: modelId, reasoning: true }], +}); +setProvider(provider.provider); +provider.setResponses([ + fauxAssistantMessage([ + fauxText( + [ + "Preparation acknowledged.", + "```runbook-ir", + "# Echo that must not become a model revision", + "```", + ].join("\n"), + ), + ]), + fauxAssistantMessage( + [ + fauxToolCall( + "getLatestNetDefinition", + {}, + { id: "fixture-read-before-mutation" }, + ), + ], + { stopReason: "toolUse" }, + ), + fauxAssistantMessage( + [ + fauxToolCall( + "addArc", + { + transitionId: startFinalInspectionTransitionId, + arcDirection: "input", + placeId: dispatchCrewPlaceId, + weight: 1, + }, + { id: "fixture-add-reservation-arc" }, + ), + ], + { stopReason: "toolUse" }, + ), + fauxAssistantMessage([ + fauxText( + [ + "Confirmation incorporated while retaining the unknown.", + "```runbook-ir", + "# Model revision one", + "", + "The sole crew is reserved for final inspection and returned by sign-off.", + "", + "Timing and recovery remain unresolved.", + "```", + ].join("\n"), + ), + ]), +]); + +const identity = { + principalKey: "prepared-workpiece-test", + conversationId: "prepared-workpiece-test", +}; +const application = await loadBuiltBrunchApplication(); +const petrinautClient = createHeadlessPetrinautClient( + "Prepared crew reservation", + { + types: [], + parameters: [], + places: [ + { + id: dispatchCrewPlaceId, + name: "Dispatch crew available", + colorId: null, + dynamicsEnabled: false, + differentialEquationId: null, + x: 0, + y: 0, + }, + ], + transitions: [ + { + id: startFinalInspectionTransitionId, + name: "Start final inspection", + inputArcs: [], + outputArcs: [], + lambdaType: "predicate", + lambdaCode: "", + transitionKernelCode: "", + x: 180, + y: 0, + }, + ], + differentialEquations: [], + }, +); + +try { + const transport: typeof fetch = async (input, init) => + application.fetch( + input instanceof Request ? input : new Request(input, init), + ); + const client = createFlueClient({ + url: `http://brunch.local/agents/${CHAT_AGENT_ROUTE}/${flueConversationIdFrom(identity)}`, + fetch: transport, + headers: agentOwnershipHeaders(identity), + }); + const preparationPrompt = { + uid: null, + initialData: { mode: VALIDATED_FIXTURE_MUTATION_MODE }, + ...preparedDelivery, + } as const; + const preparation = await client.send(preparationPrompt); + await client.wait(preparation); + const preparedSnapshot = await client.history(); + const recoveredPrepared = recoverRunbookWorkpiece(preparedSnapshot); + + const retry = await client.send(preparationPrompt); + const afterRetry = await client.history(); + + const confirmation = await client.send({ + message: { + kind: "user", + body: "Final inspection consumes the sole crew; sign-off returns it.", + }, + }); + await client.wait(confirmation); + const completedCallIds = new Set(); + const serviceClientCalls = async (clientRound: number): Promise => { + if (clientRound >= 5) { + throw new Error("Prepared fixture exceeded five client-tool rounds."); + } + const snapshot = await client.history(); + const pendingCalls = snapshot.messages.flatMap((message) => + message.parts.flatMap((part) => { + if ( + part.type !== "dynamic-tool" || + !PETRINAUT_FIXTURE_TOOL_NAMES.includes( + part.toolName as (typeof PETRINAUT_FIXTURE_TOOL_NAMES)[number], + ) || + completedCallIds.has(part.toolCallId) || + part.state !== "output-available" || + !isAwaitingClient(part.output) + ) { + return []; + } + return [ + { + toolCallId: part.toolCallId, + toolName: part.toolName, + input: part.input, + }, + ]; + }), + ); + if (pendingCalls.length === 0) return; + + const results = await Promise.all( + pendingCalls.map((pendingCall) => petrinautClient.execute(pendingCall)), + ); + for (const result of results) completedCallIds.add(result.toolCallId); + const continuation = await client.send({ + message: { + kind: "signal", + type: CLIENT_TOOL_RESULT_SIGNAL, + tagName: CLIENT_TOOL_RESULT_SIGNAL, + body: JSON.stringify(results), + }, + }); + await client.wait(continuation); + await serviceClientCalls(clientRound + 1); + }; + await serviceClientCalls(0); + const revisedSnapshot = await client.history(); + const recoveredRevision = recoverRunbookWorkpiece(revisedSnapshot); + + process.stdout.write( + `PREPARED_WORKPIECE_HERMETIC ${JSON.stringify({ + preparationSubmissionId: preparation.submissionId, + retrySubmissionId: retry.submissionId, + retryDeduplicated: retry.deduplicated === true, + messageCountStableAcrossRetry: + preparedSnapshot.messages.length === afterRetry.messages.length, + prepared: recoveredPrepared, + revision: recoveredRevision, + clientToolCallIds: [...completedCallIds], + dynamicTools: revisedSnapshot.messages.flatMap((message) => + message.parts.flatMap((part) => + part.type === "dynamic-tool" + ? [ + { + toolCallId: part.toolCallId, + toolName: part.toolName, + state: part.state, + output: part.output, + errorText: part.errorText, + }, + ] + : [], + ), + ), + targetArcAdded: + petrinautClient + .definition() + .transitions.find(({ id }) => id === startFinalInspectionTransitionId) + ?.inputArcs.some( + (arc) => + arc.placeId === dispatchCrewPlaceId && + arc.type === "standard" && + arc.weight === 1, + ) === true, + preparedDispatchCount: revisedSnapshot.messages.filter( + (message) => + message.role === "system" && + message.purpose === "dispatch" && + message.signal?.tagName === "prepared-fixture", + ).length, + })}\n`, + ); +} finally { + petrinautClient.dispose(); + await application.stop(); +} diff --git a/apps/brunch-agent/test/workpiece.test.ts b/apps/brunch-agent/test/workpiece.test.ts new file mode 100644 index 00000000000..31419118c6a --- /dev/null +++ b/apps/brunch-agent/test/workpiece.test.ts @@ -0,0 +1,135 @@ +import { describe, expect, test } from "vitest"; + +import { + PREPARED_WORKPIECE_AUTHORSHIP, + PREPARED_WORKPIECE_CLAIM_BOUNDARY, + PREPARED_WORKPIECE_SIGNAL_TAG, + recoverRunbookWorkpiece, +} from "../src/conversation/workpiece.ts"; + +import type { + FlueConversationMessage, + FlueConversationSnapshot, +} from "@flue/sdk"; + +const workpiece = (name: string): string => + `\`\`\`runbook-ir\n# ${name}\n\`\`\``; + +const preparedMessage = ( + id = "prepared", + submissionId = "prepare-submission", +): FlueConversationMessage => ({ + id, + role: "system", + purpose: "dispatch", + display: "diagnostic", + submissionId, + signal: { + tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + attributes: { + authorship: PREPARED_WORKPIECE_AUTHORSHIP, + claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + fixtureId: "crew-reservation-v1", + }, + }, + parts: [{ type: "text", text: workpiece("Prepared"), state: "done" }], +}); + +const assistantMessage = ( + id: string, + submissionId: string, + name: string, +): FlueConversationMessage => ({ + id, + role: "assistant", + purpose: "assistant", + display: "visible", + submissionId, + parts: [{ type: "text", text: workpiece(name), state: "done" }], +}); + +const snapshot = ( + messages: FlueConversationMessage[], +): FlueConversationSnapshot => ({ + v: 1, + conversationId: "conversation", + offset: "1", + messages, + settlements: [], +}); + +describe("recoverRunbookWorkpiece", () => { + test("recovers the tagged prepared source without relabelling its authorship", () => { + expect( + recoverRunbookWorkpiece(snapshot([preparedMessage()])), + ).toMatchObject({ + authorship: "test-authored", + content: "# Prepared", + sourceKind: "prepared-signal", + sourceMessageId: "prepared", + sourceSubmissionId: "prepare-submission", + }); + }); + + test("does not treat the preparation response as a model-authored revision", () => { + expect( + recoverRunbookWorkpiece( + snapshot([ + preparedMessage(), + assistantMessage( + "preparation-response", + "prepare-submission", + "Echoed by preparation response", + ), + ]), + ), + ).toMatchObject({ + authorship: "test-authored", + content: "# Prepared", + sourceKind: "prepared-signal", + }); + }); + + test("selects the latest genuine assistant revision", () => { + expect( + recoverRunbookWorkpiece( + snapshot([ + preparedMessage(), + assistantMessage("revision-1", "turn-1", "Revision one"), + assistantMessage("revision-2", "turn-2", "Revision two"), + ]), + ), + ).toMatchObject({ + authorship: "model-produced", + content: "# Revision two", + sourceKind: "assistant", + sourceMessageId: "revision-2", + sourceSubmissionId: "turn-2", + }); + }); + + test("retains ordinary assistant-only workpiece recovery", () => { + expect( + recoverRunbookWorkpiece( + snapshot([ + assistantMessage("ordinary", "ordinary-turn", "Ordinary workpiece"), + ]), + ), + ).toMatchObject({ + authorship: "model-produced", + content: "# Ordinary workpiece", + sourceKind: "assistant", + }); + }); + + test("fails rather than choosing between multiple prepared sources", () => { + expect(() => + recoverRunbookWorkpiece( + snapshot([ + preparedMessage("prepared-1"), + preparedMessage("prepared-2", "prepare-submission-2"), + ]), + ), + ).toThrow(/more than one prepared workpiece source/u); + }); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.test.ts index 6df757d8614..78d0abc3b90 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.test.ts @@ -3,6 +3,7 @@ import { expect, test, vi } from "vitest"; import { BrunchPanelConversationTracker, createBrunchPanelTransport, + createUnavailableBrunchPanelTransport, } from "./brunch-panel-transport"; import type { AgentSendResult, FlueClient } from "@flue/sdk"; @@ -71,6 +72,7 @@ test("delegates one typed message to the supplied Flue conversation", async () = expect(send).toHaveBeenCalledOnce(); expect(send).toHaveBeenCalledWith({ + idempotencyKey: "ai-sdk:user:user-1", message: { kind: "user", body: "Typed tracer." }, signal: undefined, }); @@ -175,3 +177,80 @@ test("settles in-flight submissions before a durable abort can target them", asy await expect(rejected).rejects.toThrow("rejected admission"); await expect(tracker.settleInFlightSubmissions()).resolves.toBeUndefined(); }); + +test("returns a fixture-scoped mutation result through the same Flue client", async () => { + const admission: AgentSendResult = { + streamUrl: "http://brunch.test/stream", + offset: "offset-2", + submissionId: "submission-2", + uid: "uid-2", + }; + const send = vi.fn(async () => admission); + const wait = vi.fn(async () => {}); + const client = { + send, + wait, + } as Pick as FlueClient; + const transport = createBrunchPanelTransport( + Promise.resolve(client), + new BrunchPanelConversationTracker(), + { clientToolNames: new Set(["addArc"]) }, + ); + const stream = await transport.sendMessages({ + trigger: "submit-message", + chatId: "conversation-stable", + messageId: "assistant-1", + messages: [ + { + id: "assistant-1", + role: "assistant", + parts: [ + { + type: "dynamic-tool", + toolName: "addArc", + toolCallId: "add-arc-1", + state: "output-available", + input: {}, + output: { applied: true }, + }, + ], + }, + ], + abortSignal: undefined, + }); + await stream.pipeTo(new WritableStream()); + + expect(send).toHaveBeenCalledWith({ + idempotencyKey: "ai-sdk:client-tools:assistant-1:add-arc-1", + message: { + kind: "signal", + type: "client-tool-result", + tagName: "client-tool-result", + body: JSON.stringify([ + { + toolCallId: "add-arc-1", + toolName: "addArc", + output: { applied: true }, + }, + ]), + attributes: { toolCallIds: "add-arc-1" }, + }, + signal: undefined, + }); +}); + +test("refuses fixture traffic when the mounted Flue route is unavailable", async () => { + const transport = createUnavailableBrunchPanelTransport( + "Fixture route unavailable.", + ); + + await expect( + transport.sendMessages({ + trigger: "submit-message", + chatId: "conversation-stable", + messageId: undefined, + messages: [], + abortSignal: undefined, + }), + ).rejects.toThrow("Fixture route unavailable."); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts index 973075debb3..8e28759287d 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts @@ -233,7 +233,9 @@ const decorateBrunchStream = ( export const createBrunchPanelTransport = ( clientPromise: Promise, tracker: BrunchPanelConversationTracker, - hooks?: { + options?: { + /** Fixture-scoped client tools; defaults to the Petrinaut docs reader alone. */ + readonly clientToolNames?: ReadonlySet; readonly onAdmission?: (admission: AgentSendResult) => void; }, ): PetrinautAiChatTransport => ({ @@ -244,10 +246,10 @@ export const createBrunchPanelTransport = ( const client = await clientPromise; const transport = createFlueChatTransport({ client, - clientToolNames: brunchClientToolNames, + clientToolNames: options?.clientToolNames ?? brunchClientToolNames, onAdmission: (event) => { tracker.recordAdmission(event); - hooks?.onAdmission?.(event.admission); + options?.onAdmission?.(event.admission); }, onResponseMessage: ({ messageId, submissionId }) => tracker.recordResponse(messageId, submissionId), @@ -256,3 +258,12 @@ export const createBrunchPanelTransport = ( })(), ), }); + +export const createUnavailableBrunchPanelTransport = ( + reason: string, +): PetrinautAiChatTransport => ({ + reconnectToStream: async () => null, + sendMessages: async () => { + throw new Error(reason); + }, +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts new file mode 100644 index 00000000000..32bc94f8d21 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts @@ -0,0 +1,380 @@ +import { describe, expect, test } from "vitest"; + +import { + PREPARED_WORKPIECE_AUTHORSHIP, + PREPARED_WORKPIECE_CLAIM_BOUNDARY, + PREPARED_WORKPIECE_SIGNAL_TAG, + type WorkpieceHistoryMessage, +} from "@hashintel/brunch-agent/workpiece"; + +import { + hasCrewReservationTargetArc, + settleCrewReservationManifest, +} from "./crew-reservation-settled-manifest"; +import { + CREW_RESERVATION_FIXTURE_ID, + DISPATCH_CREW_PLACE_ID, + preparedCrewReservationNet, + preparedCrewReservationWorkpiece, + START_FINAL_INSPECTION_TRANSITION_ID, +} from "./prepared-crew-reservation-fixture"; + +const preparedMessage: WorkpieceHistoryMessage = { + id: "prepared-message", + role: "system", + purpose: "dispatch", + submissionId: "prepare-submission", + signal: { + tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + attributes: { + fixtureId: CREW_RESERVATION_FIXTURE_ID, + authorship: PREPARED_WORKPIECE_AUTHORSHIP, + claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + }, + }, + parts: [ + { + type: "text", + text: preparedCrewReservationWorkpiece, + }, + ], +}; + +const settledHistory = ( + messages: readonly WorkpieceHistoryMessage[] = [preparedMessage], +) => ({ + conversationId: "canonical-flue-conversation", + offset: "10", + messages, + settlements: [{ submissionId: "prepare-submission", outcome: "completed" }], +}); + +const targetMutationMessages = (): readonly [ + WorkpieceHistoryMessage, + WorkpieceHistoryMessage, +] => [ + { + id: "target-mutation-request", + role: "assistant", + purpose: "assistant", + submissionId: "confirmation-turn", + parts: [ + { + type: "dynamic-tool", + toolCallId: "target-arc-call", + toolName: "addArc", + input: { + transitionId: START_FINAL_INSPECTION_TRANSITION_ID, + arcDirection: "input", + placeId: DISPATCH_CREW_PLACE_ID, + weight: 1, + }, + }, + ], + }, + { + id: "target-mutation-result", + role: "system", + purpose: "dispatch", + submissionId: "mutation-continuation", + signal: { + tagName: "client-tool-result", + }, + parts: [ + { + type: "text", + text: JSON.stringify([ + { + toolCallId: "target-arc-call", + toolName: "addArc", + output: { applied: true }, + }, + ]), + }, + ], + }, +]; + +describe("crew-reservation settled manifest", () => { + test("records a coherent prepared bundle without inventing the target arc", async () => { + const result = await settleCrewReservationManifest({ + definition: preparedCrewReservationNet, + history: settledHistory(), + settledAt: "2026-09-03T12:00:00.000Z", + }); + + expect(result).toMatchObject({ + status: "settled", + manifest: { + fixtureId: CREW_RESERVATION_FIXTURE_ID, + revision: 0, + conversation: { + canonicalId: "canonical-flue-conversation", + }, + latestWorkpiece: { + authorship: "test-authored", + sourceMessageId: "prepared-message", + }, + document: { + targetArc: "absent", + }, + }, + }); + }); + + test("advances only after a completed model revision and document change", async () => { + const initial = await settleCrewReservationManifest({ + definition: preparedCrewReservationNet, + history: settledHistory(), + settledAt: "2026-09-03T12:00:00.000Z", + }); + if (initial.status !== "settled") { + throw new Error("Expected the prepared fixture to settle"); + } + + const revisedMessage: WorkpieceHistoryMessage = { + id: "revised-workpiece", + role: "assistant", + purpose: "assistant", + submissionId: "confirmation-turn", + parts: [ + { + type: "text", + text: preparedCrewReservationWorkpiece.replace( + "It deliberately lacks", + "The confirmation resolves", + ), + }, + ], + }; + const revisedDefinition = structuredClone(preparedCrewReservationNet); + const startInspection = revisedDefinition.transitions.find( + ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ); + if (startInspection === undefined) { + throw new Error("Missing prepared start-inspection transition"); + } + startInspection.inputArcs.push({ + placeId: DISPATCH_CREW_PLACE_ID, + type: "standard", + weight: 1, + }); + + const result = await settleCrewReservationManifest({ + definition: revisedDefinition, + history: { + ...settledHistory([ + preparedMessage, + ...targetMutationMessages(), + revisedMessage, + ]), + offset: "20", + settlements: [ + { submissionId: "prepare-submission", outcome: "completed" }, + { submissionId: "confirmation-turn", outcome: "completed" }, + ], + }, + previous: initial.manifest, + settledAt: "2026-09-03T12:05:00.000Z", + }); + + expect(hasCrewReservationTargetArc(revisedDefinition)).toBe(true); + expect(result).toMatchObject({ + status: "settled", + manifest: { + revision: 1, + latestWorkpiece: { authorship: "model-produced" }, + document: { targetArc: "present" }, + }, + }); + }); + + test("refuses a model revision without one successful correlated target mutation", async () => { + const revisedMessage: WorkpieceHistoryMessage = { + id: "revised-workpiece", + role: "assistant", + purpose: "assistant", + submissionId: "confirmation-turn", + parts: [{ type: "text", text: preparedCrewReservationWorkpiece }], + }; + const revisedDefinition = structuredClone(preparedCrewReservationNet); + const startInspection = revisedDefinition.transitions.find( + ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ); + if (startInspection === undefined) { + throw new Error("Missing prepared start-inspection transition"); + } + startInspection.inputArcs.push({ + placeId: DISPATCH_CREW_PLACE_ID, + type: "standard", + weight: 1, + }); + const history = { + ...settledHistory([preparedMessage, revisedMessage]), + settlements: [ + { submissionId: "prepare-submission", outcome: "completed" }, + { submissionId: "confirmation-turn", outcome: "completed" }, + ], + }; + + await expect( + settleCrewReservationManifest({ + definition: revisedDefinition, + history, + settledAt: "2026-09-03T12:05:00.000Z", + }), + ).resolves.toEqual({ + status: "refused", + reason: "missing-correlated-mutation", + }); + + const [targetCall, targetResult] = targetMutationMessages(); + await expect( + settleCrewReservationManifest({ + definition: revisedDefinition, + history: { + ...history, + messages: [ + preparedMessage, + targetCall, + { + ...targetResult, + parts: [ + { + type: "text", + text: JSON.stringify([ + { + toolCallId: "target-arc-call", + toolName: "addArc", + output: { applied: false, reason: "no-op" }, + }, + ]), + }, + ], + }, + revisedMessage, + ], + }, + settledAt: "2026-09-03T12:05:00.000Z", + }), + ).resolves.toEqual({ + status: "refused", + reason: "missing-correlated-mutation", + }); + + await expect( + settleCrewReservationManifest({ + definition: revisedDefinition, + history: { + ...history, + messages: [ + preparedMessage, + ...targetMutationMessages(), + targetMutationMessages()[1], + revisedMessage, + ], + }, + settledAt: "2026-09-03T12:05:00.000Z", + }), + ).resolves.toEqual({ + status: "refused", + reason: "missing-correlated-mutation", + }); + }); + + test("retains the previous bundle when recovery is partial", async () => { + const initial = await settleCrewReservationManifest({ + definition: preparedCrewReservationNet, + history: settledHistory(), + settledAt: "2026-09-03T12:00:00.000Z", + }); + if (initial.status !== "settled") { + throw new Error("Expected the prepared fixture to settle"); + } + + await expect( + settleCrewReservationManifest({ + definition: preparedCrewReservationNet, + history: { + ...settledHistory(), + conversationId: "different-conversation", + }, + previous: initial.manifest, + settledAt: "2026-09-03T12:05:00.000Z", + }), + ).resolves.toEqual({ + status: "refused", + reason: "conversation-mismatch", + }); + + await expect( + settleCrewReservationManifest({ + definition: preparedCrewReservationNet, + history: { + ...settledHistory(), + settlements: [], + }, + previous: initial.manifest, + settledAt: "2026-09-03T12:05:00.000Z", + }), + ).resolves.toEqual({ + status: "refused", + reason: "missing-completed-settlement", + }); + }); + + test("does not publish a new revision for an unchanged coherent bundle", async () => { + const initial = await settleCrewReservationManifest({ + definition: preparedCrewReservationNet, + history: settledHistory(), + settledAt: "2026-09-03T12:00:00.000Z", + }); + if (initial.status !== "settled") { + throw new Error("Expected the prepared fixture to settle"); + } + + await expect( + settleCrewReservationManifest({ + definition: preparedCrewReservationNet, + history: { ...settledHistory(), offset: "11" }, + previous: initial.manifest, + settledAt: "2026-09-03T12:05:00.000Z", + }), + ).resolves.toEqual(initial); + }); + + test("keeps the prepared bundle selected when the document changes first", async () => { + const initial = await settleCrewReservationManifest({ + definition: preparedCrewReservationNet, + history: settledHistory(), + settledAt: "2026-09-03T12:00:00.000Z", + }); + if (initial.status !== "settled") { + throw new Error("Expected the prepared fixture to settle"); + } + const partialDefinition = structuredClone(preparedCrewReservationNet); + const startInspection = partialDefinition.transitions.find( + ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ); + if (startInspection === undefined) { + throw new Error("Missing prepared start-inspection transition"); + } + startInspection.inputArcs.push({ + placeId: DISPATCH_CREW_PLACE_ID, + type: "standard", + weight: 1, + }); + + await expect( + settleCrewReservationManifest({ + definition: partialDefinition, + history: settledHistory(), + previous: initial.manifest, + settledAt: "2026-09-03T12:05:00.000Z", + }), + ).resolves.toEqual({ + status: "refused", + reason: "bundle-mismatch", + }); + }); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts new file mode 100644 index 00000000000..a3bea28e98a --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts @@ -0,0 +1,289 @@ +import { + selectRunbookWorkpiece, + type WorkpieceHistory, +} from "@hashintel/brunch-agent/workpiece"; +import { isSDCPNEqual, type SDCPN } from "@hashintel/petrinaut-core"; + +import { + CREW_RESERVATION_CONVERSATION_ID, + CREW_RESERVATION_DOCUMENT_ID, + CREW_RESERVATION_FIXTURE_ID, + DISPATCH_CREW_PLACE_ID, + preparedCrewReservationNet, + START_FINAL_INSPECTION_TRANSITION_ID, +} from "./prepared-crew-reservation-fixture"; + +export const CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY = + "brunch:prepared-fixture:crew-reservation-v1:settled"; + +export interface CrewReservationSettledManifest { + readonly conversation: { + readonly canonicalId: string; + readonly logicalId: typeof CREW_RESERVATION_CONVERSATION_ID; + readonly offset: string; + }; + readonly document: { + readonly id: typeof CREW_RESERVATION_DOCUMENT_ID; + readonly sha256: string; + readonly targetArc: "absent" | "present"; + }; + readonly fixtureId: typeof CREW_RESERVATION_FIXTURE_ID; + readonly latestWorkpiece: { + readonly authorship: "model-produced" | "test-authored"; + readonly contentSha256: string; + readonly sourceKind: "assistant" | "prepared-signal"; + readonly sourceMessageId: string; + readonly sourceMessageSha256: string; + readonly sourceSubmissionId: string; + }; + readonly manifestId: string; + readonly revision: number; + readonly settledAt: string; + readonly version: 1; +} + +export type CrewReservationSettlementResult = + | { + readonly manifest: CrewReservationSettledManifest; + readonly status: "settled"; + } + | { + readonly reason: + | "bundle-mismatch" + | "conversation-mismatch" + | "missing-correlated-mutation" + | "missing-completed-settlement" + | "missing-workpiece"; + readonly status: "refused"; + }; + +export type CrewReservationSettledHistory = WorkpieceHistory & { + readonly offset: string; + readonly settlements: readonly { + readonly outcome: string; + readonly submissionId: string; + }[]; +}; + +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null; + +const targetMutationCallIds = ( + history: CrewReservationSettledHistory, +): readonly string[] => + history.messages.flatMap((message) => + message.parts.flatMap((part) => { + if ( + !isRecord(part) || + part.type !== "dynamic-tool" || + part.toolName !== "addArc" || + typeof part.toolCallId !== "string" || + !isRecord(part.input) || + part.input.transitionId !== START_FINAL_INSPECTION_TRANSITION_ID || + part.input.arcDirection !== "input" || + part.input.placeId !== DISPATCH_CREW_PLACE_ID || + part.input.weight !== 1 + ) { + return []; + } + return [part.toolCallId]; + }), + ); + +const successfulMutationResultIds = ( + history: CrewReservationSettledHistory, +): readonly string[] => + history.messages.flatMap((message) => { + if ( + message.signal?.tagName !== "client-tool-result" && + message.signal?.type !== "client-tool-result" + ) { + return []; + } + const body = message.parts + .flatMap((part) => + part.type === "text" && typeof part.text === "string" + ? [part.text] + : [], + ) + .join(""); + try { + const results: unknown = JSON.parse(body); + if (!Array.isArray(results)) return []; + return results.flatMap((result) => { + if ( + !isRecord(result) || + result.toolName !== "addArc" || + typeof result.toolCallId !== "string" || + !isRecord(result.output) || + result.output.applied !== true + ) { + return []; + } + return [result.toolCallId]; + }); + } catch { + return []; + } + }); + +const hasOneCorrelatedTargetMutation = ( + history: CrewReservationSettledHistory, +): boolean => { + const targetCallIds = targetMutationCallIds(history); + const successfulResultIds = successfulMutationResultIds(history); + return ( + targetCallIds.length === 1 && + successfulResultIds.length === 1 && + targetCallIds[0] === successfulResultIds[0] + ); +}; + +const sha256 = async (value: string): Promise => { + const digest = await globalThis.crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode(value), + ); + return [...new Uint8Array(digest)] + .map((byte) => byte.toString(16).padStart(2, "0")) + .join(""); +}; + +export const hasCrewReservationTargetArc = (definition: SDCPN): boolean => { + const transition = definition.transitions.find( + ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ); + return ( + transition?.inputArcs.some( + (arc) => + arc.placeId === DISPATCH_CREW_PLACE_ID && + arc.type === "standard" && + arc.weight === 1, + ) ?? false + ); +}; + +const preparedCrewReservationNetWithTargetArc = (): SDCPN => { + const definition = structuredClone(preparedCrewReservationNet); + const transition = definition.transitions.find( + ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ); + if (transition === undefined) { + throw new Error("The prepared fixture has no start-inspection transition."); + } + transition.inputArcs.push({ + placeId: DISPATCH_CREW_PLACE_ID, + type: "standard", + weight: 1, + }); + return definition; +}; + +export const settleCrewReservationManifest = async (input: { + readonly definition: SDCPN; + readonly history: CrewReservationSettledHistory; + readonly previous?: CrewReservationSettledManifest; + readonly settledAt: string; +}): Promise => { + if ( + input.previous !== undefined && + input.previous.conversation.canonicalId !== input.history.conversationId + ) { + return { status: "refused", reason: "conversation-mismatch" }; + } + + const workpiece = selectRunbookWorkpiece(input.history); + if (workpiece === undefined || workpiece.sourceSubmissionId === undefined) { + return { status: "refused", reason: "missing-workpiece" }; + } + const sourceSettlement = input.history.settlements.find( + ({ submissionId }) => submissionId === workpiece.sourceSubmissionId, + ); + if (sourceSettlement?.outcome !== "completed") { + return { + status: "refused", + reason: "missing-completed-settlement", + }; + } + const targetArcPresent = hasCrewReservationTargetArc(input.definition); + if ( + workpiece.authorship === "model-produced" && + (!targetArcPresent || + !isSDCPNEqual( + input.definition, + preparedCrewReservationNetWithTargetArc(), + ) || + !hasOneCorrelatedTargetMutation(input.history)) + ) { + return { + status: "refused", + reason: "missing-correlated-mutation", + }; + } + + const [contentSha256, documentSha256, sourceMessageSha256] = + await Promise.all([ + sha256(workpiece.content), + sha256(JSON.stringify(input.definition)), + sha256(JSON.stringify(workpiece.sourceMessage)), + ]); + if (workpiece.authorship === "test-authored") { + const preparedDocumentSha256 = await sha256( + JSON.stringify(preparedCrewReservationNet), + ); + if ( + targetArcPresent || + documentSha256 !== preparedDocumentSha256 || + !isSDCPNEqual(input.definition, preparedCrewReservationNet) + ) { + return { status: "refused", reason: "bundle-mismatch" }; + } + } + if ( + input.previous?.latestWorkpiece.sourceMessageId === + workpiece.sourceMessageId + ) { + if ( + input.previous.document.sha256 !== documentSha256 || + input.previous.latestWorkpiece.sourceMessageSha256 !== + sourceMessageSha256 || + input.previous.latestWorkpiece.contentSha256 !== contentSha256 + ) { + return { status: "refused", reason: "bundle-mismatch" }; + } + return { status: "settled", manifest: input.previous }; + } + const revision = (input.previous?.revision ?? -1) + 1; + const withoutId = { + version: 1 as const, + fixtureId: CREW_RESERVATION_FIXTURE_ID, + revision, + settledAt: input.settledAt, + conversation: { + logicalId: CREW_RESERVATION_CONVERSATION_ID, + canonicalId: input.history.conversationId, + offset: input.history.offset, + }, + latestWorkpiece: { + authorship: workpiece.authorship, + contentSha256, + sourceKind: workpiece.sourceKind, + sourceMessageId: workpiece.sourceMessageId, + sourceMessageSha256, + sourceSubmissionId: workpiece.sourceSubmissionId, + }, + document: { + id: CREW_RESERVATION_DOCUMENT_ID, + sha256: documentSha256, + targetArc: targetArcPresent ? ("present" as const) : ("absent" as const), + }, + } satisfies Omit; + + return { + status: "settled", + manifest: { + ...withoutId, + manifestId: await sha256(JSON.stringify(withoutId)), + }, + }; +}; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx b/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx index 2fb825cb30b..78f2b2f938e 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx @@ -11,6 +11,7 @@ import { agentOwnershipHeaders, flueConversationIdWeb, } from "@hashintel/brunch-agent-transport-aisdk"; +import { selectRunbookWorkpiece } from "@hashintel/brunch-agent/workpiece"; import { createJsonDocHandle, type MinimalNetMetadata, @@ -50,9 +51,23 @@ import { getOrCreateBrunchConversationId } from "./brunch-conversation-id"; import { BrunchPanelConversationTracker, createBrunchPanelTransport, + createUnavailableBrunchPanelTransport, } from "./brunch-panel-transport"; import { resolveBrunchPreviewConfig } from "./brunch-preview-config"; import { getOrCreateBrunchPrincipal } from "./brunch-principal"; +import { prepareCrewReservationConversation } from "./prepare-crew-reservation-conversation"; +import { + CREW_RESERVATION_CLIENT_TOOL_NAMES, + CREW_RESERVATION_CONVERSATION_ID, + CREW_RESERVATION_DOCUMENT_ID, + isCrewReservationFixtureSelected, + preparedCrewReservationNet, +} from "./prepared-crew-reservation-fixture"; +import { + PreparedFixtureBanner, + PreparedFixtureSelector, +} from "./prepared-fixture-banner"; +import { useCrewReservationSettledManifest } from "./use-crew-reservation-settled-manifest"; import { useFlueChatHistory } from "./use-flue-chat-history"; import { useLocalStorageAiMessages } from "./use-local-storage-ai-messages"; import { @@ -73,6 +88,13 @@ const createDefaultStoredSDCPN = (): SDCPNInLocalStorage => ({ lastUpdated: new Date(0).toISOString(), }); +const preparedCrewReservationStoredSDCPN: SDCPNInLocalStorage = { + id: CREW_RESERVATION_DOCUMENT_ID, + title: "Prepared final inspection and dispatch", + sdcpn: preparedCrewReservationNet, + lastUpdated: new Date(0).toISOString(), +}; + const DEMO_CAPABILITIES = { disabledExtensions: [], } satisfies PetrinautHandleCapabilities; @@ -118,6 +140,9 @@ const createHandle = (net: SDCPNInLocalStorage): PetrinautDocHandle => }); const brunchPrincipal = getOrCreateBrunchPrincipal(); +const crewReservationClientToolNames: ReadonlySet = new Set( + CREW_RESERVATION_CLIENT_TOOL_NAMES, +); /** Every widget here must answer a tool named in `brunchClientToolNames`. */ export const brunchInteractiveTools: readonly PetrinautAiInteractiveTool[] = [ @@ -167,7 +192,16 @@ const createConversationTrackerFor = ( const getStoredSDCPNsForDisplay = ( storedSDCPNs: Record, + crewReservationFixtureSelected: boolean, ): Record => { + if (crewReservationFixtureSelected) { + return { + ...storedSDCPNs, + [CREW_RESERVATION_DOCUMENT_ID]: + storedSDCPNs[CREW_RESERVATION_DOCUMENT_ID] ?? + preparedCrewReservationStoredSDCPN, + }; + } if (Object.values(storedSDCPNs).length > 0) { return storedSDCPNs; } @@ -317,7 +351,26 @@ export const LocalStorageDemoApp = ({ const { aiMessagesByNetId, setAiMessagesByNetId } = useLocalStorageAiMessages(); const { storedSDCPNs, setStoredSDCPNs } = useLocalStorageSDCPNs(); - const storedSDCPNsForDisplay = getStoredSDCPNsForDisplay(storedSDCPNs); + const crewReservationFixtureSelected = isCrewReservationFixtureSelected( + window.location.search, + ); + const storedSDCPNsForDisplay = getStoredSDCPNsForDisplay( + storedSDCPNs, + crewReservationFixtureSelected, + ); + + useEffect(() => { + if ( + !crewReservationFixtureSelected || + storedSDCPNs[CREW_RESERVATION_DOCUMENT_ID] !== undefined + ) { + return; + } + setStoredSDCPNs((previous) => ({ + ...previous, + [CREW_RESERVATION_DOCUMENT_ID]: preparedCrewReservationStoredSDCPN, + })); + }, [crewReservationFixtureSelected, setStoredSDCPNs, storedSDCPNs]); useEffect(() => { if (!brunchPreviewConfig.isBrunchConfigured) { @@ -343,10 +396,13 @@ export const LocalStorageDemoApp = ({ (a, b) => new Date(b.lastUpdated).getTime() - new Date(a.lastUpdated).getTime(), )[0] ?? null; + const initiallySelectedNet = crewReservationFixtureSelected + ? storedSDCPNsForDisplay[CREW_RESERVATION_DOCUMENT_ID] + : mostRecentlyModifiedNet; // The net currently selected in the UI. const [currentNetId, setCurrentNetId] = useState( - () => mostRecentlyModifiedNet?.id ?? null, + () => initiallySelectedNet?.id ?? null, ); // Metadata and persisted SDCPN snapshot for the selected net. @@ -356,9 +412,7 @@ export const LocalStorageDemoApp = ({ // Live editable document handle for the selected net only. const [activeHandle, setActiveHandle] = useState(() => - mostRecentlyModifiedNet - ? createActiveHandle(mostRecentlyModifiedNet) - : null, + initiallySelectedNet ? createActiveHandle(initiallySelectedNet) : null, ); useEffect(() => { @@ -386,7 +440,9 @@ export const LocalStorageDemoApp = ({ }); }, [activeHandle, setStoredSDCPNs]); - const existingNets: MinimalNetMetadata[] = Object.values(storedSDCPNs) + const existingNets: MinimalNetMetadata[] = Object.values( + storedSDCPNsForDisplay, + ) .map((net) => ({ netId: net.id, title: net.title, @@ -481,16 +537,31 @@ export const LocalStorageDemoApp = ({ ); }; - const conversationId = currentNetId - ? getOrCreateBrunchConversationId(currentNetId) - : null; - const flueClientPromise = useMemo( + const preparedFixtureIsCurrent = + crewReservationFixtureSelected && + currentNetId === CREW_RESERVATION_DOCUMENT_ID; + const conversationId = + currentNetId === null + ? null + : preparedFixtureIsCurrent + ? CREW_RESERVATION_CONVERSATION_ID + : getOrCreateBrunchConversationId(currentNetId); + const rawFlueClientPromise = useMemo( () => brunchPreviewConfig.isBrunchConfigured && conversationId !== null ? createBrunchFlueClient(conversationId) : null, [conversationId], ); + const flueClientPromise = useMemo(() => { + if (rawFlueClientPromise === null || !preparedFixtureIsCurrent) { + return rawFlueClientPromise; + } + return rawFlueClientPromise.then(async (client) => { + await prepareCrewReservationConversation(client); + return client; + }); + }, [preparedFixtureIsCurrent, rawFlueClientPromise]); const conversationTracker = useMemo( // Correlation state belongs to one conversation and must not cross a net switch. () => createConversationTrackerFor(conversationId), @@ -499,6 +570,7 @@ export const LocalStorageDemoApp = ({ const flueHistory = useFlueChatHistory( flueClientPromise, conversationId ?? "", + preparedFixtureIsCurrent ? crewReservationClientToolNames : undefined, ); const brunchVoiceMode = useMemo( () => @@ -509,15 +581,47 @@ export const LocalStorageDemoApp = ({ ), [conversationTracker, flueHistory.settlements, openAIVoiceConfig], ); - const petrinautAiChatTransport = useMemo( - () => - flueClientPromise === null - ? stockChatTransport - : createBrunchPanelTransport(flueClientPromise, conversationTracker, { - onAdmission: flueHistory.refresh, - }), - [conversationTracker, flueClientPromise, flueHistory.refresh], - ); + const { settledManifest, status: settlementStatus } = + useCrewReservationSettledManifest({ + definition: preparedFixtureIsCurrent ? currentNet?.sdcpn : undefined, + enabled: preparedFixtureIsCurrent, + history: preparedFixtureIsCurrent ? flueHistory.snapshot : undefined, + historyError: preparedFixtureIsCurrent + ? flueHistory.error?.message + : undefined, + }); + const currentWorkpiece = (() => { + if (flueHistory.snapshot === undefined) return undefined; + try { + return selectRunbookWorkpiece(flueHistory.snapshot)?.content; + } catch { + return undefined; + } + })(); + const petrinautAiChatTransport = useMemo(() => { + if (flueClientPromise !== null) { + return createBrunchPanelTransport( + flueClientPromise, + conversationTracker, + { + ...(preparedFixtureIsCurrent + ? { clientToolNames: crewReservationClientToolNames } + : {}), + onAdmission: flueHistory.refresh, + }, + ); + } + return preparedFixtureIsCurrent + ? createUnavailableBrunchPanelTransport( + "The prepared fixture requires the mounted Brunch Flue route.", + ) + : stockChatTransport; + }, [ + conversationTracker, + flueClientPromise, + flueHistory.refresh, + preparedFixtureIsCurrent, + ]); const aiAssistant = useMemo( () => ({ @@ -602,7 +706,21 @@ export const LocalStorageDemoApp = ({ } return ( -
+
+ {preparedFixtureIsCurrent && ( + + )} + {!preparedFixtureIsCurrent && } { + test("recovers an existing prepared conversation without resubmitting", async () => { + const send = vi.fn(); + const wait = vi.fn(); + + await expect( + prepareCrewReservationConversation({ + history: vi.fn().mockResolvedValue(preparedHistory), + send, + wait, + }), + ).resolves.toEqual(preparedHistory); + expect(send).not.toHaveBeenCalled(); + expect(wait).not.toHaveBeenCalled(); + }); + + test("creates revision zero once through the tagged signal delivery", async () => { + const history = vi + .fn() + .mockRejectedValueOnce({ status: 404 }) + .mockResolvedValueOnce(preparedHistory); + const admission = { submissionId: "prepare-submission" }; + const send = vi.fn().mockResolvedValue(admission); + const wait = vi.fn().mockResolvedValue(undefined); + + await expect( + prepareCrewReservationConversation({ history, send, wait }), + ).resolves.toEqual(preparedHistory); + expect(send).toHaveBeenCalledWith({ + uid: null, + initialData: { mode: PREPARED_WORKPIECE_INITIAL_DATA_MODE }, + ...preparedCrewReservationDelivery, + }); + expect(wait).toHaveBeenCalledWith(admission); + expect(history).toHaveBeenCalledTimes(2); + }); + + test("refuses an existing conversation without this fixture source", async () => { + await expect( + prepareCrewReservationConversation({ + history: vi.fn().mockResolvedValue({ + ...preparedHistory, + messages: [], + }), + send: vi.fn(), + wait: vi.fn(), + }), + ).rejects.toThrow(/no recoverable workpiece/u); + }); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.ts new file mode 100644 index 00000000000..c0fcab5c3c5 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.ts @@ -0,0 +1,90 @@ +import { + PREPARED_WORKPIECE_INITIAL_DATA_MODE, + selectRunbookWorkpiece, + type WorkpieceHistory, +} from "@hashintel/brunch-agent/workpiece"; + +import { + CREW_RESERVATION_FIXTURE_ID, + preparedCrewReservationDelivery, +} from "./prepared-crew-reservation-fixture"; + +import type { AgentSendResult } from "@flue/sdk"; + +export type PreparedCrewReservationHistory = WorkpieceHistory & { + readonly offset: string; + readonly settlements: readonly { + readonly outcome: string; + readonly submissionId: string; + }[]; +}; + +export interface PreparedFixtureConversationClient { + readonly history: () => Promise; + readonly send: (input: { + readonly idempotencyKey: string; + readonly initialData: { + readonly mode: typeof PREPARED_WORKPIECE_INITIAL_DATA_MODE; + }; + readonly message: typeof preparedCrewReservationDelivery.message; + readonly uid: null; + }) => Promise; + readonly wait: (admission: AgentSendResult) => Promise; +} + +const isNotFound = (error: unknown): boolean => + typeof error === "object" && + error !== null && + "status" in error && + error.status === 404; + +const assertPreparedFixtureHistory = ( + history: PreparedCrewReservationHistory, +): PreparedCrewReservationHistory => { + const currentWorkpiece = selectRunbookWorkpiece(history); + if ( + currentWorkpiece?.sourceKind !== "prepared-signal" && + currentWorkpiece?.sourceKind !== "assistant" + ) { + throw new Error( + "The prepared fixture conversation has no recoverable workpiece.", + ); + } + const preparedSource = history.messages.find( + (message) => + message.signal?.tagName === + preparedCrewReservationDelivery.message.tagName, + ); + if ( + preparedSource?.signal?.attributes?.fixtureId !== + CREW_RESERVATION_FIXTURE_ID + ) { + throw new Error( + "The prepared fixture conversation belongs to a different fixture.", + ); + } + return history; +}; + +/** + * Create revision zero through Flue's public signal delivery, or recover the + * already-created append-only conversation. Concurrent tabs converge through + * the delivery's deterministic idempotency key. + */ +export const prepareCrewReservationConversation = async ( + client: PreparedFixtureConversationClient, +): Promise => { + try { + return assertPreparedFixtureHistory(await client.history()); + } catch (error) { + if (!isNotFound(error)) throw error; + } + + const admission = await client.send({ + uid: null, + initialData: { mode: PREPARED_WORKPIECE_INITIAL_DATA_MODE }, + ...preparedCrewReservationDelivery, + }); + await client.wait(admission); + return assertPreparedFixtureHistory(await client.history()); +}; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.test.ts new file mode 100644 index 00000000000..36bda9934fe --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.test.ts @@ -0,0 +1,82 @@ +import { describe, expect, test } from "vitest"; + +import { + CREW_RESERVATION_CLIENT_TOOL_NAMES, + CREW_RESERVATION_FIXTURE_ID, + DISPATCH_CREW_PLACE_ID, + isCrewReservationFixtureSelected, + preparedCrewReservationDelivery, + preparedCrewReservationNet, + preparedCrewReservationWorkpiece, + START_FINAL_INSPECTION_TRANSITION_ID, +} from "./prepared-crew-reservation-fixture"; + +const transitionById = (transitionId: string) => { + const transition = preparedCrewReservationNet.transitions.find( + (candidate) => candidate.id === transitionId, + ); + if (transition === undefined) { + throw new Error(`Missing prepared transition ${transitionId}`); + } + return transition; +}; + +describe("prepared crew-reservation fixture", () => { + test("advertises only the selected canonical read and mutation", () => { + expect(CREW_RESERVATION_CLIENT_TOOL_NAMES).toEqual([ + "getLatestNetDefinition", + "addArc", + ]); + }); + + test("has the batch flow and crew return but omits the target input arc", () => { + const startInspection = transitionById( + START_FINAL_INSPECTION_TRANSITION_ID, + ); + const signOff = transitionById("sign-off"); + + expect(startInspection.inputArcs).toContainEqual({ + placeId: "batch-ready", + type: "standard", + weight: 1, + }); + expect(startInspection.inputArcs).not.toContainEqual( + expect.objectContaining({ placeId: DISPATCH_CREW_PLACE_ID }), + ); + expect(signOff.outputArcs).toEqual( + expect.arrayContaining([ + { placeId: "ready-for-dispatch", weight: 1 }, + { placeId: DISPATCH_CREW_PLACE_ID, weight: 1 }, + ]), + ); + }); + + test("carries the quantity, unknowns, and honest claim boundary", () => { + expect(preparedCrewReservationWorkpiece).toContain( + "Exactly one dispatch crew", + ); + expect(preparedCrewReservationWorkpiece).toContain( + "timing, failure modes, and recovery behavior remain unresolved", + ); + expect(preparedCrewReservationWorkpiece).toContain( + "not model-produced evidence", + ); + expect(preparedCrewReservationDelivery.message.attributes).toEqual({ + fixtureId: CREW_RESERVATION_FIXTURE_ID, + authorship: "test-authored", + claimBoundary: "prepared-not-model-produced", + }); + }); + + test("selects only the explicit stable query value", () => { + expect( + isCrewReservationFixtureSelected( + `?brunch-fixture=${CREW_RESERVATION_FIXTURE_ID}`, + ), + ).toBe(true); + expect( + isCrewReservationFixtureSelected("?brunch-fixture=another-fixture"), + ).toBe(false); + expect(isCrewReservationFixtureSelected("")).toBe(false); + }); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.ts new file mode 100644 index 00000000000..69588ab02cf --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.ts @@ -0,0 +1,154 @@ +import { createPreparedWorkpieceDelivery } from "@hashintel/brunch-agent/workpiece"; +import { + getLatestNetDefinitionToolName, + type PetrinautAiToolName, +} from "@hashintel/petrinaut-core/ai"; + +import type { SDCPN } from "@hashintel/petrinaut-core"; + +export const CREW_RESERVATION_FIXTURE_ID = "crew-reservation-v1"; +export const CREW_RESERVATION_DOCUMENT_ID = + "mission-6-crew-reservation-document-v1"; +export const CREW_RESERVATION_CONVERSATION_ID = + "mission-6-crew-reservation-conversation-v1"; +export const CREW_RESERVATION_FIXTURE_QUERY = "brunch-fixture"; +export const CREW_RESERVATION_CLIENT_TOOL_NAMES = [ + getLatestNetDefinitionToolName, + "addArc", +] as const satisfies readonly PetrinautAiToolName[]; + +export const DISPATCH_CREW_PLACE_ID = "dispatch-crew-available"; +export const START_FINAL_INSPECTION_TRANSITION_ID = "start-final-inspection"; + +export const preparedCrewReservationWorkpiece = [ + "Fixture authorship: test-authored preparation for Mission 6.", + "Non-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.", + "", + "```runbook-ir", + "# Final inspection and dispatch workpiece", + "", + "## Purpose and posture", + "Maintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.", + "", + "## Operational account", + "- A batch that is ready enters final inspection.", + "- Final inspection reserves the sole available dispatch crew.", + "- Sign-off releases that crew and makes the batch ready for dispatch.", + "", + "## Quantity and resource policy", + "Exactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.", + "", + "## Current Petrinaut correspondence", + "The prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.", + "", + "## Explicit unknowns", + "Inspection and sign-off timing, failure modes, and recovery behavior remain unresolved.", + "", + "## Claim boundary", + "This prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.", + "```", +].join("\n"); + +export const preparedCrewReservationDelivery = createPreparedWorkpieceDelivery({ + body: preparedCrewReservationWorkpiece, + fixtureId: CREW_RESERVATION_FIXTURE_ID, + revision: 0, +}); + +export const preparedCrewReservationNet: SDCPN = { + places: [ + { + id: "batch-ready", + name: "Batch ready", + colorId: null, + dynamicsEnabled: false, + differentialEquationId: null, + x: 80, + y: 100, + }, + { + id: "under-final-inspection", + name: "Under final inspection", + colorId: null, + dynamicsEnabled: false, + differentialEquationId: null, + x: 420, + y: 100, + }, + { + id: "ready-for-dispatch", + name: "Ready for dispatch", + colorId: null, + dynamicsEnabled: false, + differentialEquationId: null, + x: 760, + y: 100, + }, + { + id: DISPATCH_CREW_PLACE_ID, + name: "Dispatch crew available", + colorId: null, + dynamicsEnabled: false, + differentialEquationId: null, + x: 420, + y: 360, + }, + ], + transitions: [ + { + id: START_FINAL_INSPECTION_TRANSITION_ID, + name: "Start final inspection", + inputArcs: [ + { + placeId: "batch-ready", + type: "standard", + weight: 1, + }, + ], + outputArcs: [ + { + placeId: "under-final-inspection", + weight: 1, + }, + ], + lambdaType: "predicate", + lambdaCode: "", + transitionKernelCode: "", + x: 250, + y: 100, + }, + { + id: "sign-off", + name: "Sign-off", + inputArcs: [ + { + placeId: "under-final-inspection", + type: "standard", + weight: 1, + }, + ], + outputArcs: [ + { + placeId: "ready-for-dispatch", + weight: 1, + }, + { + placeId: DISPATCH_CREW_PLACE_ID, + weight: 1, + }, + ], + lambdaType: "predicate", + lambdaCode: "", + transitionKernelCode: "", + x: 590, + y: 100, + }, + ], + types: [], + parameters: [], + differentialEquations: [], +}; + +export const isCrewReservationFixtureSelected = (search: string): boolean => + new URLSearchParams(search).get(CREW_RESERVATION_FIXTURE_QUERY) === + CREW_RESERVATION_FIXTURE_ID; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.test.tsx b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.test.tsx new file mode 100644 index 00000000000..4d307764689 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.test.tsx @@ -0,0 +1,76 @@ +import { renderToStaticMarkup } from "react-dom/server"; +import { describe, expect, test } from "vitest"; + +import { + CREW_RESERVATION_CONVERSATION_ID, + CREW_RESERVATION_DOCUMENT_ID, + CREW_RESERVATION_FIXTURE_ID, +} from "./prepared-crew-reservation-fixture"; +import { + PreparedFixtureBanner, + PreparedFixtureSelector, +} from "./prepared-fixture-banner"; + +describe("PreparedFixtureBanner", () => { + test("offers a stable labelled fixture selector", () => { + const markup = renderToStaticMarkup(); + + expect(markup).toContain("Prepared fixture selector"); + expect(markup).toContain("Open the labelled crew-reservation fixture"); + expect(markup).toContain("?brunch-fixture=crew-reservation-v1"); + }); + + test("visibly states authorship, non-claims, and automatic settlement", () => { + const markup = renderToStaticMarkup( + , + ); + + expect(markup).toContain("Test-authored prepared fixture"); + expect(markup).toContain("not model-produced evidence"); + expect(markup).toContain("does not claim capture provenance"); + expect(markup).toContain("automatically mirrored document"); + expect(markup).toContain("Current Markdown workpiece"); + expect(markup).toContain("Final inspection and dispatch workpiece"); + }); + + test("visibly retains the prior bundle when settlement is refused", () => { + const markup = renderToStaticMarkup( + , + ); + + expect(markup).toContain( + "Settlement refused (missing-correlated-mutation)", + ); + expect(markup).toContain("bundle revision 3 remains selected"); + }); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.tsx b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.tsx new file mode 100644 index 00000000000..d73ce5b8735 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.tsx @@ -0,0 +1,84 @@ +import { latestRunbookIrBlock } from "@hashintel/brunch-agent/workpiece"; + +import { + CREW_RESERVATION_FIXTURE_ID, + CREW_RESERVATION_FIXTURE_QUERY, + preparedCrewReservationWorkpiece, +} from "./prepared-crew-reservation-fixture"; + +import type { CrewReservationSettledManifest } from "./crew-reservation-settled-manifest"; +import type { CrewReservationSettlementStatus } from "./use-crew-reservation-settled-manifest"; + +const fixturePanelStyle = { + background: "rgba(255, 255, 255, 0.96)", + border: "1px solid #c9d2df", + borderRadius: 8, + boxShadow: "0 2px 8px rgba(20, 33, 50, 0.12)", + left: 16, + maxWidth: 520, + padding: "10px 12px", + position: "absolute", + top: 16, + zIndex: 20, +} as const; + +export const PreparedFixtureSelector = () => ( + +); + +export const PreparedFixtureBanner = ({ + currentWorkpiece = latestRunbookIrBlock(preparedCrewReservationWorkpiece), + settledManifest, + settlementStatus = { state: "preparing" }, +}: { + readonly currentWorkpiece?: string; + readonly settledManifest: CrewReservationSettledManifest | null; + readonly settlementStatus?: CrewReservationSettlementStatus; +}) => { + if (currentWorkpiece === undefined) { + throw new Error("The prepared fixture has no recoverable workpiece."); + } + + return ( + + ); +}; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.test.ts new file mode 100644 index 00000000000..d36e10ce9bd --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.test.ts @@ -0,0 +1,113 @@ +/** + * @vitest-environment jsdom + */ +import { cleanup, renderHook, waitFor } from "@testing-library/react"; +import { afterEach, beforeEach, expect, test } from "vitest"; + +import { + PREPARED_WORKPIECE_AUTHORSHIP, + PREPARED_WORKPIECE_CLAIM_BOUNDARY, + PREPARED_WORKPIECE_SIGNAL_TAG, +} from "@hashintel/brunch-agent/workpiece"; + +import { CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY } from "./crew-reservation-settled-manifest"; +import { + CREW_RESERVATION_FIXTURE_ID, + DISPATCH_CREW_PLACE_ID, + preparedCrewReservationNet, + preparedCrewReservationWorkpiece, + START_FINAL_INSPECTION_TRANSITION_ID, +} from "./prepared-crew-reservation-fixture"; +import { useCrewReservationSettledManifest } from "./use-crew-reservation-settled-manifest"; + +const preparedHistory = { + conversationId: "canonical-conversation", + offset: "2", + settlements: [{ submissionId: "prepare-submission", outcome: "completed" }], + messages: [ + { + id: "prepared-message", + role: "system", + purpose: "dispatch", + submissionId: "prepare-submission", + signal: { + tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + attributes: { + fixtureId: CREW_RESERVATION_FIXTURE_ID, + authorship: PREPARED_WORKPIECE_AUTHORSHIP, + claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + }, + }, + parts: [{ type: "text", text: preparedCrewReservationWorkpiece }], + }, + ], +}; + +beforeEach(() => { + window.localStorage.clear(); +}); + +afterEach(() => { + cleanup(); + window.localStorage.clear(); +}); + +test("keeps the prior runtime bundle selected while a document write is partial", async () => { + const { result, rerender } = renderHook( + ({ definition }: { definition: typeof preparedCrewReservationNet }) => + useCrewReservationSettledManifest({ + definition, + enabled: true, + history: preparedHistory, + historyError: undefined, + }), + { initialProps: { definition: preparedCrewReservationNet } }, + ); + + await waitFor(() => expect(result.current.status.state).toBe("settled")); + const settledManifest = result.current.settledManifest; + expect(settledManifest?.revision).toBe(0); + + const partialDefinition = structuredClone(preparedCrewReservationNet); + const startInspection = partialDefinition.transitions.find( + ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ); + if (startInspection === undefined) { + throw new Error("Missing prepared start-inspection transition"); + } + startInspection.inputArcs.push({ + placeId: DISPATCH_CREW_PLACE_ID, + type: "standard", + weight: 1, + }); + rerender({ definition: partialDefinition }); + + await waitFor(() => expect(result.current.status.state).toBe("refused")); + expect(result.current.settledManifest).toEqual(settledManifest); + expect( + JSON.parse( + window.localStorage.getItem( + CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY, + ) ?? "null", + ), + ).toEqual(settledManifest); +}); + +test("surfaces canonical history failure without publishing a bundle", async () => { + const { result } = renderHook(() => + useCrewReservationSettledManifest({ + definition: preparedCrewReservationNet, + enabled: true, + history: undefined, + historyError: "History unavailable.", + }), + ); + + await waitFor(() => expect(result.current.status.state).toBe("refused")); + expect(result.current.status).toEqual({ + state: "refused", + reason: "history-unavailable", + detail: "History unavailable.", + }); + expect(result.current.settledManifest).toBeNull(); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts new file mode 100644 index 00000000000..94ffe2328e9 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts @@ -0,0 +1,124 @@ +import { useLocalStorage } from "@mantine/hooks"; +import { useEffect, useRef, useState } from "react"; + +import { + CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY, + settleCrewReservationManifest, + type CrewReservationSettledHistory, + type CrewReservationSettledManifest, + type CrewReservationSettlementResult, +} from "./crew-reservation-settled-manifest"; + +import type { SDCPN } from "@hashintel/petrinaut-core"; + +export type CrewReservationSettlementStatus = + | { readonly state: "idle" | "preparing" } + | { readonly state: "settled" } + | { + readonly detail?: string; + readonly reason: + | Extract< + CrewReservationSettlementResult, + { status: "refused" } + >["reason"] + | "history-unavailable" + | "settlement-failed"; + readonly state: "refused"; + }; + +export const useCrewReservationSettledManifest = (input: { + readonly definition: SDCPN | undefined; + readonly enabled: boolean; + readonly history: CrewReservationSettledHistory | undefined; + readonly historyError: string | undefined; +}) => { + const [settledManifest, setSettledManifest] = + useLocalStorage({ + key: CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY, + defaultValue: null, + getInitialValueInEffect: false, + }); + const [observedStatus, setObservedStatus] = + useState({ state: "preparing" }); + const manifestRef = useRef(settledManifest); + const observationIdRef = useRef(0); + const queueRef = useRef(Promise.resolve()); + + useEffect(() => { + manifestRef.current = settledManifest; + }, [settledManifest]); + + useEffect(() => { + const observationId = observationIdRef.current + 1; + observationIdRef.current = observationId; + if ( + !input.enabled || + input.historyError !== undefined || + input.definition === undefined || + input.history === undefined + ) { + return; + } + + const definition = structuredClone(input.definition); + const history = input.history; + queueRef.current = queueRef.current.then(async () => { + if (observationId !== observationIdRef.current) return; + let result: CrewReservationSettlementResult; + try { + result = await settleCrewReservationManifest({ + definition, + history, + ...(manifestRef.current === null + ? {} + : { previous: manifestRef.current }), + settledAt: new Date().toISOString(), + }); + } catch (error) { + if (observationId === observationIdRef.current) { + setObservedStatus({ + state: "refused", + reason: "settlement-failed", + detail: + error instanceof Error + ? error.message + : "The coherent bundle could not be inspected.", + }); + } + return; + } + if (observationId !== observationIdRef.current) return; + if (result.status === "refused") { + setObservedStatus({ + state: "refused", + reason: result.reason, + }); + return; + } + if (result.manifest.manifestId !== manifestRef.current?.manifestId) { + manifestRef.current = result.manifest; + setSettledManifest(result.manifest); + } + setObservedStatus({ state: "settled" }); + }); + }, [ + input.definition, + input.enabled, + input.history, + input.historyError, + setSettledManifest, + ]); + + const status: CrewReservationSettlementStatus = !input.enabled + ? { state: "idle" } + : input.historyError !== undefined + ? { + state: "refused", + reason: "history-unavailable", + detail: input.historyError, + } + : input.definition === undefined || input.history === undefined + ? { state: "preparing" } + : observedStatus; + return { settledManifest, status }; +}; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.test.ts index f21c7a30033..e361451207c 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.test.ts @@ -2,7 +2,7 @@ import { FlueApiError } from "@flue/sdk"; /** * @vitest-environment jsdom */ -import { cleanup, renderHook, waitFor } from "@testing-library/react"; +import { act, cleanup, renderHook, waitFor } from "@testing-library/react"; import { afterEach, expect, test, vi } from "vitest"; import { useFlueChatHistory } from "./use-flue-chat-history"; @@ -207,3 +207,82 @@ test("closes the SDK observation on unmount", async () => { expect(harness.close).toHaveBeenCalledOnce(); }); + +test("projects fixture client-tool results from canonical signal history", async () => { + const harness = createObservationHarness({ + conversation: { + conversationId: "conversation-1", + settlements: [], + messages: [ + { + id: "assistant-1", + role: "assistant", + purpose: "assistant", + display: "visible", + parts: [ + { + type: "dynamic-tool", + toolName: "addArc", + toolCallId: "arc-1", + state: "output-available", + input: { placeId: "crew" }, + output: { awaiting: "client" }, + }, + ], + }, + { + id: "result-1", + role: "system", + purpose: "dispatch", + display: "diagnostic", + signal: { tagName: "client-tool-result" }, + parts: [ + { + type: "text", + text: JSON.stringify([ + { + toolCallId: "arc-1", + toolName: "addArc", + output: { applied: true }, + }, + ]), + state: "done", + }, + ], + }, + ], + }, + offset: "offset-2", + phase: "live", + error: undefined, + }); + const clientToolNames = new Set(["addArc"]); + const { result } = renderHook(() => + useFlueChatHistory( + harness.clientPromise, + "conversation-1", + clientToolNames, + ), + ); + + await waitFor(() => expect(result.current.ready).toBe(true)); + expect(result.current.messages?.[0]?.parts).toEqual([ + { + type: "tool-addArc", + toolCallId: "arc-1", + state: "output-available", + input: { placeId: "crew" }, + output: { applied: true }, + }, + ]); + expect(result.current.snapshot?.offset).toBe("offset-2"); + expect(result.current.snapshot?.messages.map(({ id }) => id)).toEqual([ + "assistant-1", + "result-1", + ]); + + act(() => { + result.current.refresh(); + }); + expect(harness.refresh).toHaveBeenCalledTimes(1); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts index 7e3bf752055..a8348381255 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts @@ -16,18 +16,29 @@ import type { PetrinautAiMessage } from "@hashintel/petrinaut/ui"; const noSettlements: readonly FlueConversationSettlement[] = []; +/** + * The observed canonical conversation together with the durable-stream offset + * it was read at. Fixture consumers use the offset to tell a settled bundle + * from a stale one; they never interpret it. + */ +export type FlueHistorySnapshot = FlueConversationState & { + readonly offset: string; +}; + const projectPetrinautMessages = ( conversation: FlueConversationState, + clientToolNames: ReadonlySet, ): PetrinautAiMessage[] => // The host owns this narrowing: its configured client-tool catalog is the // same catalog Petrinaut's message type exposes. snapshotToUiMessages(conversation, { - clientToolNames: brunchClientToolNames, + clientToolNames, }) as PetrinautAiMessage[]; export const useFlueChatHistory = ( clientPromise: Promise | null, conversationId: string, + clientToolNames: ReadonlySet = brunchClientToolNames, ): { readonly error: Error | undefined; readonly latestSettlement: FlueConversationSettlement | undefined; @@ -36,6 +47,7 @@ export const useFlueChatHistory = ( readonly ready: boolean; readonly refresh: () => void; readonly settlements: readonly FlueConversationSettlement[]; + readonly snapshot: FlueHistorySnapshot | undefined; } => { const observationRef = useRef(null); const [observed, setObserved] = useState<{ @@ -93,23 +105,27 @@ export const useFlueChatHistory = ( }; }, [clientPromise, conversationId]); - const snapshot = + const observation = observed?.conversationId === conversationId ? observed.snapshot : undefined; - const conversation = snapshot?.conversation; - const absent = snapshot?.phase === "absent"; + const conversation = observation?.conversation; + const absent = observation?.phase === "absent"; const ready = absent || conversation !== undefined; return { - error: snapshot?.error, + error: observation?.error, latestSettlement: conversation?.settlements.at(-1), messages: conversation === undefined ? absent ? [] : undefined - : projectPetrinautMessages(conversation), - phase: snapshot?.phase, + : projectPetrinautMessages(conversation, clientToolNames), + phase: observation?.phase, ready, refresh, settlements: conversation?.settlements ?? noSettlements, + snapshot: + conversation === undefined || observation?.offset === undefined + ? undefined + : { ...conversation, offset: observation.offset }, }; }; diff --git a/apps/petrinaut-website/src/main/app/voice-interview/voice-preview.integration.test.ts b/apps/petrinaut-website/src/main/app/voice-interview/voice-preview.integration.test.ts index 6e4a0a63095..ec153c77af7 100644 --- a/apps/petrinaut-website/src/main/app/voice-interview/voice-preview.integration.test.ts +++ b/apps/petrinaut-website/src/main/app/voice-interview/voice-preview.integration.test.ts @@ -522,6 +522,7 @@ describe("controlled voice preview", () => { expect.objectContaining({ type: "submission-accepted" }), ); expect(send).toHaveBeenCalledWith({ + idempotencyKey: "ai-sdk:user:voice-realtime:1:call-1", message: { kind: "user", body: "The supervisor approves it." }, signal: undefined, }); diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md new file mode 100644 index 00000000000..9b6f4d47dad --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md @@ -0,0 +1,79 @@ +# FE-1575 — resumable workpiece and Petrinaut document + +## Deterministic implementation evidence + +The prepared crew-reservation fixture uses distinct fixture, logical +conversation, canonical Flue conversation, workpiece-source, and Petrinaut +document identities. Revision zero is delivered through the public mounted +Flue route as one `prepared-fixture` system/dispatch signal with a deterministic +idempotency key. The browser transport derives stable keys for typed messages +and correlated client-tool-result signals. + +Focused tests cover: + +- exact prepared-signal retry and append-only workpiece selection; +- fixture-only `getLatestNetDefinition` and `addArc` advertisement; +- the built agent's read, mutation, original call-id result, and continuation; +- rejected and duplicate/no-op canonical browser mutations; +- exact prepared and revised document structure; +- history, workpiece, mutation-result, and document mismatch refusal; and +- retention of the prior runtime manifest while partial state remains visible. + +The affected Brunch, transport, plugin, Petrinaut, and website builds, type +checks, and lint checks passed on 2026-09-03. The app-wide lint checks retain +pre-existing warning-only findings; no persona suite was run. + +## Live browser attempt and blocker + +The local `yarn dev:brunch` stack served the mounted agent at +`/agents/chat/:instanceId` and the Petrinaut fixture at: + +```text +http://127.0.0.1:4915/?brunch-fixture=crew-reservation-v1 +``` + +The browser opened the non-empty prepared document and created canonical Flue +conversation `conv_01M1KZ1Z32SJ0800V94ZE59ENR`. Snapshot offset +`0000000000000000_0000000000000006` contained exactly one tagged +`prepared-fixture` dispatch record under submission +`sub_ik_b224f8e328e14cfa803c63d06376e5e9`, preserving the test-authored Markdown +body and claim-boundary attributes. + +That submission settled as `failed` because the configured Anthropic +credential returned HTTP 401 `authentication_error: invalid x-api-key`. +Consequently: + +- no model-behavior claim was made; +- no typed confirmation, client-tool mutation, or Tab B continuation was + attempted; +- the runtime settled manifest remained `null`; and +- the visible fixture status refused settlement as `history-unavailable` + instead of blessing the prepared document alone. + +This is the Mission 6 carrier blocker required by the stop rule, not a passing +two-tab witness. No success screenshot was retained. + +## Remaining external checks + +After a valid provider credential is supplied, rerun the demo script to retain +the successful before/after Flue snapshots, canonical definitions, runtime +manifest, call/result IDs, and Tab A/Tab B screenshots. Cold-reader semantic +adjudication and the product-manager demo remain separate human-harness checks; +they were not replaced with persona testing here. + +### Cold-reader handoff + +Give the reviewer only the prepared and model-revised workpieces plus their +tagged Flue records. Ask them to identify authorship, the exactly-one-crew +policy, the intended reservation and return, and every unresolved timing, +failure, and recovery point. Fail the check if the reader attributes revision +zero to the model or infers unsupported behavioral execution. + +### Product-manager handoff + +With a valid live provider credential, have the reviewer open the labelled +fixture in Tab A, confirm the visible non-claims, submit the crew-reservation +fact once, and wait for a settled bundle. They must inspect the exact added +weight-1 input arc, open the same fixture in Tab B, verify matching identities +and hashes, submit a follow-up, and receive its correlated Brunch response +without a duplicate prepared submission. A read-only Tab B does not pass. diff --git a/libs/@hashintel/brunch-agent/packages/core/package.json b/libs/@hashintel/brunch-agent/packages/core/package.json index 5ab4e8a9874..1b2634eb375 100644 --- a/libs/@hashintel/brunch-agent/packages/core/package.json +++ b/libs/@hashintel/brunch-agent/packages/core/package.json @@ -21,6 +21,10 @@ "./storage": { "types": "./src/storage.ts", "import": "./dist/storage.js" + }, + "./workpiece": { + "types": "./src/workpiece.ts", + "import": "./dist/workpiece.js" } }, "scripts": { diff --git a/libs/@hashintel/brunch-agent/packages/core/src/workpiece.ts b/libs/@hashintel/brunch-agent/packages/core/src/workpiece.ts new file mode 100644 index 00000000000..bd61a63c068 --- /dev/null +++ b/libs/@hashintel/brunch-agent/packages/core/src/workpiece.ts @@ -0,0 +1,214 @@ +/** + * Substrate-neutral selection of the current Markdown workpiece from an + * append-only conversation projection. + */ + +export const PREPARED_WORKPIECE_SIGNAL_TYPE = "brunch.fixture.prepared"; +export const PREPARED_WORKPIECE_SIGNAL_TAG = "prepared-fixture"; +export const PREPARED_WORKPIECE_AUTHORSHIP = "test-authored"; +export const PREPARED_WORKPIECE_CLAIM_BOUNDARY = "prepared-not-model-produced"; +export const PREPARED_WORKPIECE_INITIAL_DATA_MODE = + "validated-fixture-mutation"; +export const RUNBOOK_IR_FENCE = "runbook-ir"; + +type WorkpieceTextPart = { + readonly text: string; + readonly type: "text"; +}; + +export interface WorkpieceHistoryMessage { + readonly body?: string; + readonly id: string; + readonly parts: readonly ( + | WorkpieceTextPart + | { readonly type: string; readonly [key: string]: unknown } + )[]; + readonly purpose: string; + readonly role: string; + readonly signal?: { + readonly attributes?: Readonly>; + readonly tagName?: string; + readonly type?: string; + }; + readonly submissionId?: string; +} + +export interface WorkpieceHistory { + readonly conversationId: string; + readonly messages: readonly WorkpieceHistoryMessage[]; +} + +export interface PreparedWorkpieceDelivery { + readonly idempotencyKey: string; + readonly message: { + readonly attributes: { + readonly authorship: typeof PREPARED_WORKPIECE_AUTHORSHIP; + readonly claimBoundary: typeof PREPARED_WORKPIECE_CLAIM_BOUNDARY; + readonly fixtureId: string; + }; + readonly body: string; + readonly kind: "signal"; + readonly tagName: typeof PREPARED_WORKPIECE_SIGNAL_TAG; + readonly type: typeof PREPARED_WORKPIECE_SIGNAL_TYPE; + }; +} + +export interface SelectedRunbookWorkpiece { + readonly authorship: "model-produced" | "test-authored"; + readonly content: string; + readonly fixtureId?: string; + readonly sourceKind: "assistant" | "prepared-signal"; + readonly sourceMessage: WorkpieceHistoryMessage; + readonly sourceMessageId: string; + readonly sourceSubmissionId?: string; +} + +const runbookIrFencePattern = /```runbook-ir\s*\n([\s\S]*?)```/gu; + +export const latestRunbookIrBlock = (text: string): string | undefined => { + const matches = [...text.matchAll(runbookIrFencePattern)]; + const last = matches.at(-1)?.[1]; + return last === undefined ? undefined : last.trim(); +}; + +const textFrom = (message: WorkpieceHistoryMessage): string => + message.parts + .filter((part): part is WorkpieceTextPart => part.type === "text") + .map((part) => part.text) + .join("\n"); + +const preparedFixtureIdFrom = ( + message: WorkpieceHistoryMessage, +): string | undefined => { + const fixtureId = message.signal?.attributes?.fixtureId; + return typeof fixtureId === "string" && fixtureId.length > 0 + ? fixtureId + : undefined; +}; + +const isPreparedWorkpieceMessage = ( + message: WorkpieceHistoryMessage, +): boolean => + message.role === "system" && + message.purpose === "dispatch" && + message.signal?.tagName === PREPARED_WORKPIECE_SIGNAL_TAG && + message.signal.attributes?.authorship === PREPARED_WORKPIECE_AUTHORSHIP && + message.signal.attributes.claimBoundary === + PREPARED_WORKPIECE_CLAIM_BOUNDARY && + preparedFixtureIdFrom(message) !== undefined; + +const selectedFrom = ( + message: WorkpieceHistoryMessage, + source: Pick, +): SelectedRunbookWorkpiece | undefined => { + const content = latestRunbookIrBlock(textFrom(message)); + if (content === undefined) return undefined; + + return { + ...source, + content, + sourceMessage: message, + sourceMessageId: message.id, + ...(message.submissionId === undefined + ? {} + : { sourceSubmissionId: message.submissionId }), + }; +}; + +export const createPreparedWorkpieceDelivery = (input: { + readonly body: string; + readonly fixtureId: string; + readonly revision: number; +}): PreparedWorkpieceDelivery => { + if (input.fixtureId.length === 0) { + throw new Error("A prepared workpiece delivery requires a fixture id."); + } + if (latestRunbookIrBlock(input.body) === undefined) { + throw new Error( + "A prepared workpiece delivery requires a full runbook-ir block.", + ); + } + + return { + idempotencyKey: `${PREPARED_WORKPIECE_SIGNAL_TAG}:${input.fixtureId}:revision-${input.revision}`, + message: { + kind: "signal", + type: PREPARED_WORKPIECE_SIGNAL_TYPE, + tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + body: input.body, + attributes: { + fixtureId: input.fixtureId, + authorship: PREPARED_WORKPIECE_AUTHORSHIP, + claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + }, + }, + }; +}; + +/** + * Prepared revision zero is a tagged dispatch record. Later assistant + * workpieces win in log order, except for the assistant reply produced by the + * preparation submission itself. + */ +export const selectRunbookWorkpiece = ( + history: WorkpieceHistory, +): SelectedRunbookWorkpiece | undefined => { + const preparedCandidates = history.messages.filter( + (message) => message.signal?.tagName === PREPARED_WORKPIECE_SIGNAL_TAG, + ); + if (preparedCandidates.length > 1) { + throw new Error( + `Conversation ${history.conversationId} has more than one prepared workpiece source.`, + ); + } + + const preparedMessage = preparedCandidates.at(0); + if ( + preparedMessage !== undefined && + !isPreparedWorkpieceMessage(preparedMessage) + ) { + throw new Error( + `Conversation ${history.conversationId} has a malformed prepared workpiece source.`, + ); + } + + const preparationSubmissionId = preparedMessage?.submissionId; + let selected: SelectedRunbookWorkpiece | undefined; + + for (const message of history.messages) { + if (message === preparedMessage) { + const preparedWorkpiece = selectedFrom(message, { + authorship: PREPARED_WORKPIECE_AUTHORSHIP, + sourceKind: "prepared-signal", + }); + if (preparedWorkpiece === undefined) { + throw new Error( + `Conversation ${history.conversationId} has a prepared source without a runbook-ir block.`, + ); + } + const fixtureId = preparedFixtureIdFrom(message); + if (fixtureId === undefined) { + throw new Error( + `Conversation ${history.conversationId} has a malformed prepared workpiece source.`, + ); + } + selected = { ...preparedWorkpiece, fixtureId }; + continue; + } + if ( + message.purpose !== "assistant" || + message.role !== "assistant" || + (preparationSubmissionId !== undefined && + message.submissionId === preparationSubmissionId) + ) { + continue; + } + const assistantWorkpiece = selectedFrom(message, { + authorship: "model-produced", + sourceKind: "assistant", + }); + if (assistantWorkpiece !== undefined) selected = assistantWorkpiece; + } + + return selected; +}; diff --git a/libs/@hashintel/brunch-agent/packages/core/test/workpiece.test.ts b/libs/@hashintel/brunch-agent/packages/core/test/workpiece.test.ts new file mode 100644 index 00000000000..7b3c6f452d8 --- /dev/null +++ b/libs/@hashintel/brunch-agent/packages/core/test/workpiece.test.ts @@ -0,0 +1,174 @@ +import { describe, expect, test } from "vitest"; + +import { + createPreparedWorkpieceDelivery, + PREPARED_WORKPIECE_AUTHORSHIP, + PREPARED_WORKPIECE_CLAIM_BOUNDARY, + PREPARED_WORKPIECE_SIGNAL_TAG, + selectRunbookWorkpiece, + type WorkpieceHistory, + type WorkpieceHistoryMessage, +} from "../src/workpiece"; + +const workpiece = (name: string): string => + `\`\`\`runbook-ir\n# ${name}\n\`\`\``; + +const preparedMessage = ( + id = "prepared", + submissionId = "prepare-submission", +): WorkpieceHistoryMessage => ({ + id, + role: "system", + purpose: "dispatch", + submissionId, + signal: { + tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + attributes: { + authorship: PREPARED_WORKPIECE_AUTHORSHIP, + claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + fixtureId: "crew-reservation-v1", + }, + }, + parts: [{ type: "text", text: workpiece("Prepared") }], +}); + +const assistantMessage = ( + id: string, + submissionId: string, + name: string, +): WorkpieceHistoryMessage => ({ + id, + role: "assistant", + purpose: "assistant", + submissionId, + parts: [{ type: "text", text: workpiece(name) }], +}); + +const history = ( + messages: readonly WorkpieceHistoryMessage[], +): WorkpieceHistory => ({ + conversationId: "conversation", + messages, +}); + +describe("prepared workpiece delivery", () => { + test("carries explicit authorship and a revision-stable idempotency key", () => { + expect( + createPreparedWorkpieceDelivery({ + fixtureId: "crew-reservation-v1", + revision: 0, + body: workpiece("Prepared"), + }), + ).toEqual({ + idempotencyKey: "prepared-fixture:crew-reservation-v1:revision-0", + message: { + kind: "signal", + type: "brunch.fixture.prepared", + tagName: "prepared-fixture", + body: workpiece("Prepared"), + attributes: { + fixtureId: "crew-reservation-v1", + authorship: "test-authored", + claimBoundary: "prepared-not-model-produced", + }, + }, + }); + }); + + test("refuses prepared content without a runbook-ir block", () => { + expect(() => + createPreparedWorkpieceDelivery({ + fixtureId: "crew-reservation-v1", + revision: 0, + body: "# Not fenced", + }), + ).toThrow(/requires a full runbook-ir block/u); + }); +}); + +describe("selectRunbookWorkpiece", () => { + test("selects prepared revision zero with its honest authorship", () => { + expect(selectRunbookWorkpiece(history([preparedMessage()]))).toMatchObject({ + authorship: "test-authored", + content: "# Prepared", + fixtureId: "crew-reservation-v1", + sourceKind: "prepared-signal", + sourceMessageId: "prepared", + }); + }); + + test("ignores the assistant response to preparation", () => { + expect( + selectRunbookWorkpiece( + history([ + preparedMessage(), + assistantMessage( + "preparation-response", + "prepare-submission", + "Echo", + ), + ]), + ), + ).toMatchObject({ + authorship: "test-authored", + content: "# Prepared", + }); + }); + + test("selects the latest genuine assistant revision", () => { + expect( + selectRunbookWorkpiece( + history([ + preparedMessage(), + assistantMessage("revision-1", "turn-1", "Revision one"), + assistantMessage("revision-2", "turn-2", "Revision two"), + ]), + ), + ).toMatchObject({ + authorship: "model-produced", + content: "# Revision two", + sourceKind: "assistant", + sourceMessageId: "revision-2", + }); + }); + + test("uses canonical log order when the prepared source follows older assistant text", () => { + expect( + selectRunbookWorkpiece( + history([ + assistantMessage("older", "older-turn", "Older assistant text"), + preparedMessage(), + ]), + ), + ).toMatchObject({ + authorship: "test-authored", + content: "# Prepared", + sourceMessageId: "prepared", + }); + }); + + test("refuses malformed and duplicate prepared sources", () => { + expect(() => + selectRunbookWorkpiece( + history([ + { + ...preparedMessage(), + signal: { + tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + attributes: { authorship: "model-produced" }, + }, + }, + ]), + ), + ).toThrow(/malformed prepared workpiece source/u); + + expect(() => + selectRunbookWorkpiece( + history([ + preparedMessage("prepared-1"), + preparedMessage("prepared-2", "prepare-submission-2"), + ]), + ), + ).toThrow(/more than one prepared workpiece source/u); + }); +}); diff --git a/libs/@hashintel/brunch-agent/packages/core/vite.config.ts b/libs/@hashintel/brunch-agent/packages/core/vite.config.ts index 291e5b9c4bf..986fb63fdc4 100644 --- a/libs/@hashintel/brunch-agent/packages/core/vite.config.ts +++ b/libs/@hashintel/brunch-agent/packages/core/vite.config.ts @@ -14,6 +14,7 @@ export default defineConfig({ flue: fileURLToPath(new URL("src/flue.ts", import.meta.url)), index: fileURLToPath(new URL("src/index.ts", import.meta.url)), storage: fileURLToPath(new URL("src/storage.ts", import.meta.url)), + workpiece: fileURLToPath(new URL("src/workpiece.ts", import.meta.url)), }, fileName: (_format, entryName) => `${entryName}.js`, formats: ["es"], diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts index 3c48ef1a56f..5e106589f7f 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts @@ -6,22 +6,32 @@ import { } from "@flue/runtime"; import * as v from "valibot"; +import { PREPARED_WORKPIECE_INITIAL_DATA_MODE } from "@hashintel/brunch-agent/workpiece"; + import sdcpnAppend from "./prompts/APPEND_SYSTEM.md?raw"; import { SDCPN_MODELLING_SKILL_NAME, sdcpnModellingSkill, } from "./skills/sdcpn-modelling/skill"; -import { petrinautConstructionTools } from "./tools/petrinaut-construction"; +import { + petrinautConstructionTools, + petrinautFixtureTools, +} from "./tools/petrinaut-construction"; import { READ_PETRINAUT_DOC_TOOL_NAME, readPetrinautDoc, } from "./tools/read-petrinaut-doc"; export const VALIDATED_CONSTRUCTION_MODE = "validated-construction"; +export const VALIDATED_FIXTURE_MUTATION_MODE = + PREPARED_WORKPIECE_INITIAL_DATA_MODE; export const sdcpnInitialDataSchema = v.optional( v.object({ - mode: v.literal(VALIDATED_CONSTRUCTION_MODE), + mode: v.picklist([ + VALIDATED_CONSTRUCTION_MODE, + VALIDATED_FIXTURE_MUTATION_MODE, + ]), }), ); @@ -44,6 +54,15 @@ This is a construct-only headless conversation. Use only the supplied runbook IR for (const constructionTool of petrinautConstructionTools) { useTool(constructionTool); } + } else if (initialData?.mode === VALIDATED_FIXTURE_MUTATION_MODE) { + useInstruction( + ` +This is a visibly labelled prepared-fixture conversation. Treat its tagged prepared runbook-ir dispatch as test-authored revision zero, maintain the full Markdown workpiece in later responses, preserve explicit unknowns, and do not relabel prepared material as model-produced. Use only the mounted canonical Petrinaut read and least arc mutation when confirmed evidence calls for that change. Read the live document before mutating it, report rejected or no-op outcomes honestly, and do not construct unrelated net content. +`.replace(/^\s+|\s+$/gu, ""), + ); + for (const fixtureTool of petrinautFixtureTools) { + useTool(fixtureTool); + } } } @@ -51,6 +70,8 @@ export { READ_PETRINAUT_DOC_TOOL_NAME, readPetrinautDoc }; export { SDCPN_MODELLING_SKILL_NAME }; export { PETRINAUT_CONSTRUCTION_TOOL_NAMES, + PETRINAUT_FIXTURE_TOOL_NAMES, petrinautConstructionTools, + petrinautFixtureTools, type PetrinautConstructionToolName, } from "./tools/petrinaut-construction"; diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts index 9f45f05ad1f..41167c67c23 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts @@ -13,6 +13,11 @@ export const PETRINAUT_CONSTRUCTION_TOOL_NAMES = [ "addArc", ] as const satisfies readonly (keyof typeof petrinautAiTools)[]; +export const PETRINAUT_FIXTURE_TOOL_NAMES = [ + "getLatestNetDefinition", + "addArc", +] as const satisfies readonly (keyof typeof petrinautAiTools)[]; + export type PetrinautConstructionToolName = (typeof PETRINAUT_CONSTRUCTION_TOOL_NAMES)[number]; @@ -91,3 +96,7 @@ const definePetrinautConstructionTool = ( export const petrinautConstructionTools = PETRINAUT_CONSTRUCTION_TOOL_NAMES.map( definePetrinautConstructionTool, ); + +export const petrinautFixtureTools = PETRINAUT_FIXTURE_TOOL_NAMES.map( + definePetrinautConstructionTool, +); diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts index 1ca9cb0e53a..e259a3fa77b 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts @@ -3,9 +3,16 @@ import { describe, expect, test } from "vitest"; import { petrinautAiTools } from "@hashintel/petrinaut-core/ai"; +import { + sdcpnInitialDataSchema, + VALIDATED_CONSTRUCTION_MODE, + VALIDATED_FIXTURE_MUTATION_MODE, +} from "../src/flue"; import { PETRINAUT_CONSTRUCTION_TOOL_NAMES, + PETRINAUT_FIXTURE_TOOL_NAMES, petrinautConstructionTools, + petrinautFixtureTools, } from "../src/tools/petrinaut-construction"; const toolByName = (toolName: string) => { @@ -18,12 +25,37 @@ const toolByName = (toolName: string) => { }; describe("Petrinaut construction tools", () => { + test("accepts only the ordinary headless and prepared-fixture modes", () => { + expect(v.parse(sdcpnInitialDataSchema, undefined)).toBeUndefined(); + expect( + v.parse(sdcpnInitialDataSchema, { + mode: VALIDATED_CONSTRUCTION_MODE, + }), + ).toEqual({ mode: VALIDATED_CONSTRUCTION_MODE }); + expect( + v.parse(sdcpnInitialDataSchema, { + mode: VALIDATED_FIXTURE_MUTATION_MODE, + }), + ).toEqual({ mode: VALIDATED_FIXTURE_MUTATION_MODE }); + expect(() => + v.parse(sdcpnInitialDataSchema, { + mode: "unrestricted-construction", + }), + ).toThrow(/Invalid type/u); + }); + test("exposes exactly the bounded canonical subset", () => { expect(petrinautConstructionTools.map((tool) => tool.name)).toEqual([ ...PETRINAUT_CONSTRUCTION_TOOL_NAMES, ]); }); + test("limits prepared fixtures to one canonical read and arc mutation", () => { + expect(petrinautFixtureTools.map((tool) => tool.name)).toEqual([ + ...PETRINAUT_FIXTURE_TOOL_NAMES, + ]); + }); + test("mechanically carries the canonical input contract", () => { for (const toolName of PETRINAUT_CONSTRUCTION_TOOL_NAMES) { const constructionTool = toolByName(toolName); diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts index 0cbd6daf63f..336824e5a1a 100644 --- a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts @@ -286,10 +286,18 @@ export const createFlueChatTransport = < }, }; })(); + const idempotencyKey = + messageId === undefined + ? `ai-sdk:user:${userMessage!.id}` + : `ai-sdk:client-tools:${messageId}:${toolResults + .map(({ toolCallId }) => toolCallId) + .sort() + .join(",")}`; let admission: AgentSendResult; try { admission = await options.client.send({ + idempotencyKey, message, signal: abortSignal, }); diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/chat-transport.test.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/chat-transport.test.ts index 9885ebfd2d3..664fd5ad285 100644 --- a/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/chat-transport.test.ts +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/chat-transport.test.ts @@ -194,6 +194,7 @@ test("admits one user message and projects a finite per-turn stream", async () = expect(send).toHaveBeenCalledOnce(); expect(send).toHaveBeenCalledWith({ + idempotencyKey: "ai-sdk:user:user-1", message: { kind: "user", body: "Run the transport tracer." }, signal: undefined, }); @@ -238,6 +239,7 @@ test("admits one client-tool result signal and resumes its assistant id", async ); expect(send).toHaveBeenCalledWith({ + idempotencyKey: "ai-sdk:client-tools:assistant-original:tool-1", message: { kind: "signal", type: "client-tool-result", @@ -259,6 +261,30 @@ test("admits one client-tool result signal and resumes its assistant id", async }); }); +test("derives the same idempotency key for exact AI SDK retries", async () => { + const { client, send } = clientWith(completedEvents); + const transport = createFlueChatTransport({ + client, + clientToolNames: new Set(), + }); + const options = sendOptions([ + { + id: "stable-user-message", + role: "user", + parts: [{ type: "text", text: "Admit this once." }], + }, + ]); + + await transport.sendMessages(options); + await transport.sendMessages(options); + + expect(send).toHaveBeenCalledTimes(2); + expect(send.mock.calls.map(([input]) => input.idempotencyKey)).toEqual([ + "ai-sdk:user:stable-user-message", + "ai-sdk:user:stable-user-message", + ]); +}); + test("starts with history-only reconnection", async () => { const { client } = clientWith([]); const transport = createFlueChatTransport({ diff --git a/libs/@hashintel/petrinaut/docs/ai-assistant.md b/libs/@hashintel/petrinaut/docs/ai-assistant.md index ace28fc27be..47790bc1cc4 100644 --- a/libs/@hashintel/petrinaut/docs/ai-assistant.md +++ b/libs/@hashintel/petrinaut/docs/ai-assistant.md @@ -26,6 +26,18 @@ If an assistant request fails, Petrinaut shows the error in a brief toast rather Hosts may provide canonical conversation rehydration. In that case, reopening the same assistant shows its settled and stopped turns without resubmitting a message or replaying Voice audio. +### Prepared local demo fixture + +The local Petrinaut development demo offers a labelled crew-reservation fixture when Brunch is +configured. Opening it restores a test-authored Markdown workpiece, a non-empty final-inspection +net, and their canonical Brunch conversation. The status panel distinguishes prepared text from +model-produced revisions and states the fixture's non-claims. + +The document is mirrored to browser local storage automatically; there is no separate Save action. +Wait for the status panel to report a settled bundle before reopening the same fixture in another +tab. A refused status leaves the previous coherent bundle selected and names the failed history, +workpiece, mutation-correlation, or document check instead of claiming that partial state settled. + When the Brunch voice preview is enabled and available, an empty composer shows a waveform action titled **Start voice mode**. Typing non-whitespace text replaces it with **Send**. The same dynamic action appears in the first-run prompt and the assistant panel; if voice is unavailable, the empty diff --git a/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx b/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx index e3c70c88686..966f0b3af48 100644 --- a/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx +++ b/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx @@ -5,7 +5,6 @@ import { use, useCallback, useEffect, useRef, useState } from "react"; import { aiCommandActionInputSchemas, type AiCommandActionName, - createPetrinautAiWritableCallbacks, getLatestNetDefinitionToolName, getNetCompilationErrorsToolName, mutationActionInputSchemas as petrinautAiMutationToolInputSchemas, @@ -37,6 +36,7 @@ import { REVIEW_CHIPS, STARTER_CHIPS, } from "./ai-assistant-panel/ai-assistant-contents/prompt-chips"; +import { applyPetrinautAiMutation } from "./ai-assistant-panel/apply-petrinaut-ai-mutation"; import { createDiagnosticsAwareAiTransport } from "./ai-assistant-panel/create-diagnostics-aware-ai-transport"; import { createReasoningTimingAwareAiTransport } from "./ai-assistant-panel/create-reasoning-timing-aware-ai-transport"; import { finalizeStreamingMessageParts } from "./ai-assistant-panel/finalize-streaming-message-parts"; @@ -51,7 +51,6 @@ import { type AiToolCall, type AiToolTarget, summarizeApplyAutoLayout, - summarizePetrinautAiToolCall, toPetrinautAiToolOutput, } from "./ai-assistant-panel/tool-summaries"; @@ -257,25 +256,6 @@ const waitForDiagnosticsRefresh = async ({ }); }; -const applyPetrinautAiMutation = ({ - aiToolCall, - instance, -}: { - aiToolCall: Extract; - instance: Petrinaut; -}): AiToolOutput => { - const definition = instance.definition.get(); - const toolCallbacks = createPetrinautAiWritableCallbacks(instance); - const summary = summarizePetrinautAiToolCall(aiToolCall, { definition }); - const callback = toolCallbacks[aiToolCall.toolName] as ( - input: typeof aiToolCall.input, - ) => void; - - callback(aiToolCall.input); - - return toPetrinautAiToolOutput(summary); -}; - const applyPetrinautAiCommand = async ({ aiToolCall, instance, diff --git a/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/apply-petrinaut-ai-mutation.test.ts b/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/apply-petrinaut-ai-mutation.test.ts new file mode 100644 index 00000000000..8b221aad305 --- /dev/null +++ b/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/apply-petrinaut-ai-mutation.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, test } from "vitest"; + +import { + createJsonDocHandle, + createPetrinaut, + type SDCPN, +} from "@hashintel/petrinaut-core"; + +import { applyPetrinautAiMutation } from "./apply-petrinaut-ai-mutation"; + +const definition: SDCPN = { + places: [ + { + id: "crew", + name: "Crew", + colorId: null, + dynamicsEnabled: false, + differentialEquationId: null, + x: 0, + y: 0, + }, + ], + transitions: [ + { + id: "start", + name: "Start", + inputArcs: [], + outputArcs: [], + lambdaType: "predicate", + lambdaCode: "", + transitionKernelCode: "", + x: 100, + y: 0, + }, + ], + types: [], + parameters: [], + differentialEquations: [], +}; + +describe("applyPetrinautAiMutation", () => { + test("reports a duplicate canonical arc as a no-op", () => { + const instance = createPetrinaut({ + document: createJsonDocHandle({ + id: "document", + initial: definition, + capabilities: { disabledExtensions: [] }, + }), + }); + const call = { + toolName: "addArc" as const, + input: { + transitionId: "start", + arcDirection: "input" as const, + placeId: "crew", + weight: 1, + type: "standard" as const, + }, + }; + + expect(applyPetrinautAiMutation({ aiToolCall: call, instance })).toEqual( + expect.objectContaining({ applied: true }), + ); + expect(applyPetrinautAiMutation({ aiToolCall: call, instance })).toEqual({ + applied: false, + reason: + "Added input arc was a no-op because the document already had that state.", + }); + expect(instance.definition.get().transitions[0]?.inputArcs).toHaveLength(1); + + instance.dispose(); + }); + + test("leaves the document unchanged when a canonical arc is rejected", () => { + const instance = createPetrinaut({ + document: createJsonDocHandle({ + id: "document", + initial: definition, + capabilities: { disabledExtensions: [] }, + }), + }); + + expect(() => + applyPetrinautAiMutation({ + aiToolCall: { + toolName: "addArc", + input: { + transitionId: "start", + arcDirection: "input", + placeId: "missing-place", + weight: 1, + type: "standard", + }, + }, + instance, + }), + ).toThrow(/missing-place/u); + expect(instance.definition.get().transitions[0]?.inputArcs).toEqual([]); + + instance.dispose(); + }); +}); diff --git a/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/apply-petrinaut-ai-mutation.ts b/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/apply-petrinaut-ai-mutation.ts new file mode 100644 index 00000000000..3d475821387 --- /dev/null +++ b/libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/apply-petrinaut-ai-mutation.ts @@ -0,0 +1,39 @@ +import { + createPetrinautAiWritableCallbacks, + isSDCPNEqual, + type Petrinaut, + type PetrinautAiMutationToolName, +} from "@hashintel/petrinaut-core"; + +import { + type AiToolCall, + type AiToolOutput, + summarizePetrinautAiToolCall, + toPetrinautAiToolOutput, +} from "./tool-summaries"; + +export const applyPetrinautAiMutation = ({ + aiToolCall, + instance, +}: { + aiToolCall: Extract; + instance: Petrinaut; +}): AiToolOutput => { + const definition = instance.definition.get(); + const toolCallbacks = createPetrinautAiWritableCallbacks(instance); + const summary = summarizePetrinautAiToolCall(aiToolCall, { definition }); + const callback = toolCallbacks[aiToolCall.toolName] as ( + input: typeof aiToolCall.input, + ) => void; + + callback(aiToolCall.input); + + if (isSDCPNEqual(definition, instance.definition.get())) { + return { + applied: false, + reason: `${summary.title} was a no-op because the document already had that state.`, + }; + } + + return toPetrinautAiToolOutput(summary); +}; From 8ccb18cd2c83d8b388e7710c14d48143d540dbff Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 09:32:48 +0200 Subject: [PATCH 06/31] Correct Mission 6 bundle recovery and preparation Co-authored-by: Cursor --- .../src/conversation/client-tools.ts | 4 +- .../src/conversation/workpiece.ts | 23 +-- .../evaluations/persona/proof-artifacts.ts | 2 +- .../src/evaluations/runbook/artifacts.ts | 18 +- .../test/prepared-workpiece.integration.ts | 16 +- .../test/runbook-artifacts.test.ts | 13 +- apps/brunch-agent/test/workpiece.test.ts | 132 ++---------- .../crew-reservation-history.ts | 14 ++ .../crew-reservation-settled-manifest.test.ts | 38 ++-- .../crew-reservation-settled-manifest.ts | 195 ++++++++---------- .../local-storage-demo-app.tsx | 137 ++++++------ ...pare-crew-reservation-conversation.test.ts | 12 +- .../prepare-crew-reservation-conversation.ts | 29 +-- .../prepared-crew-reservation-fixture.test.ts | 22 +- .../prepared-crew-reservation-fixture.ts | 26 +-- .../prepared-fixture-banner.test.tsx | 36 ++-- .../prepared-fixture-banner.tsx | 58 +++--- .../resolve-crew-reservation-bundle.test.ts | 149 +++++++++++++ .../resolve-crew-reservation-bundle.ts | 66 ++++++ .../use-crew-reservation-fixture-session.ts | 103 +++++++++ ...-crew-reservation-settled-manifest.test.ts | 99 ++++++--- .../use-crew-reservation-settled-manifest.ts | 102 ++++++--- .../use-local-storage-sdcpns.ts | 6 + ...pare-crew-reservation-conversation.test.ts | 31 +++ ...e-prepare-crew-reservation-conversation.ts | 55 +++++ .../fe-1575-resumable-workpiece-petrinaut.md | 6 +- .../packages/core/src/workpiece.ts | 42 ++-- .../packages/core/test/workpiece.test.ts | 14 +- .../packages/plugin-sdcpn/src/flue.ts | 11 +- .../src/tools/petrinaut-construction.ts | 16 +- .../test/construction-tools.test.ts | 10 +- .../src/client-tool-history.ts | 104 ++++++++++ .../packages/transport-aisdk/src/index.ts | 7 + .../test/client-tool-history.test.ts | 64 ++++++ 34 files changed, 1123 insertions(+), 537 deletions(-) create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-history.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-fixture-session.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.test.ts create mode 100644 apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.ts create mode 100644 libs/@hashintel/brunch-agent/packages/transport-aisdk/src/client-tool-history.ts create mode 100644 libs/@hashintel/brunch-agent/packages/transport-aisdk/test/client-tool-history.test.ts diff --git a/apps/brunch-agent/src/conversation/client-tools.ts b/apps/brunch-agent/src/conversation/client-tools.ts index dd8e44d8b23..68b48d43b5d 100644 --- a/apps/brunch-agent/src/conversation/client-tools.ts +++ b/apps/brunch-agent/src/conversation/client-tools.ts @@ -1,7 +1,7 @@ /** Flue-side client-tool signal contract: awaiting sentinel, result signal, tool names. */ import { - PETRINAUT_FIXTURE_TOOL_NAMES, + petrinautFixtureToolNames, READ_PETRINAUT_DOC_TOOL_NAME, } from "@hashintel/brunch-agent-plugin-sdcpn/flue"; import { CLIENT_TOOL_RESULT_SIGNAL } from "@hashintel/brunch-agent-transport-aisdk"; @@ -12,7 +12,7 @@ export { CLIENT_TOOL_RESULT_SIGNAL }; export const clientToolNames: ReadonlySet = new Set([ READ_PETRINAUT_DOC_TOOL_NAME, - ...PETRINAUT_FIXTURE_TOOL_NAMES, + ...petrinautFixtureToolNames, ]); const isRecord = (value: unknown): value is Record => diff --git a/apps/brunch-agent/src/conversation/workpiece.ts b/apps/brunch-agent/src/conversation/workpiece.ts index 3a146af098b..d8ac8ae9b69 100644 --- a/apps/brunch-agent/src/conversation/workpiece.ts +++ b/apps/brunch-agent/src/conversation/workpiece.ts @@ -2,34 +2,13 @@ import { createHash } from "node:crypto"; -import { - createPreparedWorkpieceDelivery, - latestRunbookIrBlock, - PREPARED_WORKPIECE_AUTHORSHIP, - PREPARED_WORKPIECE_CLAIM_BOUNDARY, - PREPARED_WORKPIECE_INITIAL_DATA_MODE, - PREPARED_WORKPIECE_SIGNAL_TAG, - PREPARED_WORKPIECE_SIGNAL_TYPE, - RUNBOOK_IR_FENCE, - selectRunbookWorkpiece, -} from "@hashintel/brunch-agent/workpiece"; +import { selectRunbookWorkpiece } from "@hashintel/brunch-agent/workpiece"; import type { FlueConversationSnapshot } from "@flue/sdk"; const sha256 = (value: string): string => createHash("sha256").update(value).digest("hex"); -export { - createPreparedWorkpieceDelivery, - latestRunbookIrBlock, - PREPARED_WORKPIECE_AUTHORSHIP, - PREPARED_WORKPIECE_CLAIM_BOUNDARY, - PREPARED_WORKPIECE_INITIAL_DATA_MODE, - PREPARED_WORKPIECE_SIGNAL_TAG, - PREPARED_WORKPIECE_SIGNAL_TYPE, - RUNBOOK_IR_FENCE, -}; - export interface RecoveredRunbookWorkpiece { readonly authorship: "model-produced" | "test-authored"; readonly content: string; diff --git a/apps/brunch-agent/src/evaluations/persona/proof-artifacts.ts b/apps/brunch-agent/src/evaluations/persona/proof-artifacts.ts index 0c3c71409e7..8d5d32c67a7 100644 --- a/apps/brunch-agent/src/evaluations/persona/proof-artifacts.ts +++ b/apps/brunch-agent/src/evaluations/persona/proof-artifacts.ts @@ -9,7 +9,7 @@ import { import { isAwaitingClient } from "../../conversation/client-tools.ts"; import { formatFlueTranscript } from "../../conversation/transcript.ts"; -import { recoverRunbookWorkpiece } from "../runbook/artifacts.ts"; +import { recoverRunbookWorkpiece } from "../../conversation/workpiece.ts"; interface ProofEventBase { readonly sequence: number; diff --git a/apps/brunch-agent/src/evaluations/runbook/artifacts.ts b/apps/brunch-agent/src/evaluations/runbook/artifacts.ts index bdc39fc3035..fb1923706d2 100644 --- a/apps/brunch-agent/src/evaluations/runbook/artifacts.ts +++ b/apps/brunch-agent/src/evaluations/runbook/artifacts.ts @@ -2,21 +2,11 @@ import { basename } from "node:path"; -import { - latestRunbookIrBlock, - recoverRunbookWorkpiece, - RUNBOOK_IR_FENCE, - type RecoveredRunbookWorkpiece, -} from "../../conversation/workpiece.ts"; +import { runbookIrFence } from "@hashintel/brunch-agent/workpiece"; -import type { FlueConversationSnapshot } from "@flue/sdk"; +import { recoverRunbookWorkpiece } from "../../conversation/workpiece.ts"; -export { - latestRunbookIrBlock, - recoverRunbookWorkpiece, - RUNBOOK_IR_FENCE, - type RecoveredRunbookWorkpiece, -}; +import type { FlueConversationSnapshot } from "@flue/sdk"; export const recoverRunbookIr = ( snapshot: FlueConversationSnapshot, @@ -123,7 +113,7 @@ export const ordinaryElicitationViolationsFrom = ( } if ( firstWorkpiecePosition === undefined && - part.text.includes(`\`\`\`${RUNBOOK_IR_FENCE}`) + part.text.includes(`\`\`\`${runbookIrFence}`) ) { firstWorkpiecePosition = position; } diff --git a/apps/brunch-agent/test/prepared-workpiece.integration.ts b/apps/brunch-agent/test/prepared-workpiece.integration.ts index fa149429435..3c6ea36699f 100644 --- a/apps/brunch-agent/test/prepared-workpiece.integration.ts +++ b/apps/brunch-agent/test/prepared-workpiece.integration.ts @@ -11,9 +11,10 @@ import { setProvider } from "@flue/runtime"; import { createFlueClient } from "@flue/sdk"; import { - PETRINAUT_FIXTURE_TOOL_NAMES, - VALIDATED_FIXTURE_MUTATION_MODE, + petrinautFixtureToolNames, + validatedFixtureMutationMode, } from "@hashintel/brunch-agent-plugin-sdcpn/flue"; +import { createPreparedWorkpieceDelivery } from "@hashintel/brunch-agent/workpiece"; import { CLIENT_TOOL_RESULT_SIGNAL, @@ -23,10 +24,7 @@ import { agentOwnershipHeaders, flueConversationIdFrom, } from "../src/conversation/identity.ts"; -import { - createPreparedWorkpieceDelivery, - recoverRunbookWorkpiece, -} from "../src/conversation/workpiece.ts"; +import { recoverRunbookWorkpiece } from "../src/conversation/workpiece.ts"; import { createHeadlessPetrinautClient } from "../src/evaluations/runbook/headless-petrinaut-client.ts"; import { loadBuiltBrunchApplication } from "../src/evaluations/runbook/load-built-application.ts"; import { CHAT_AGENT_ROUTE } from "../src/http/routes.ts"; @@ -160,7 +158,7 @@ try { }); const preparationPrompt = { uid: null, - initialData: { mode: VALIDATED_FIXTURE_MUTATION_MODE }, + initialData: { mode: validatedFixtureMutationMode }, ...preparedDelivery, } as const; const preparation = await client.send(preparationPrompt); @@ -188,8 +186,8 @@ try { message.parts.flatMap((part) => { if ( part.type !== "dynamic-tool" || - !PETRINAUT_FIXTURE_TOOL_NAMES.includes( - part.toolName as (typeof PETRINAUT_FIXTURE_TOOL_NAMES)[number], + !petrinautFixtureToolNames.includes( + part.toolName as (typeof petrinautFixtureToolNames)[number], ) || completedCallIds.has(part.toolCallId) || part.state !== "output-available" || diff --git a/apps/brunch-agent/test/runbook-artifacts.test.ts b/apps/brunch-agent/test/runbook-artifacts.test.ts index ec065240c0c..1203e25f189 100644 --- a/apps/brunch-agent/test/runbook-artifacts.test.ts +++ b/apps/brunch-agent/test/runbook-artifacts.test.ts @@ -2,10 +2,13 @@ import { describe, expect, test } from "vitest"; import { latestRunbookIrBlock, + runbookIrFence, +} from "@hashintel/brunch-agent/workpiece"; + +import { recoverRunbookWorkpiece } from "../src/conversation/workpiece.ts"; +import { ordinaryElicitationViolationsFrom, recoverRunbookIr, - recoverRunbookWorkpiece, - RUNBOOK_IR_FENCE, skillResourcePathsFrom, } from "../src/evaluations/runbook/artifacts.ts"; @@ -27,11 +30,11 @@ const snapshotWithAssistantText = (text: string): FlueConversationSnapshot => describe("runbook artifact recovery", () => { test("takes the last fenced IR block", () => { const text = [ - "```" + RUNBOOK_IR_FENCE, + "```" + runbookIrFence, "# first", "```", "later", - "```" + RUNBOOK_IR_FENCE, + "```" + runbookIrFence, "# second", "```", ].join("\n"); @@ -41,7 +44,7 @@ describe("runbook artifact recovery", () => { test("recovers an IR from assistant history", () => { const snapshot = snapshotWithAssistantText( [ - "```" + RUNBOOK_IR_FENCE, + "```" + runbookIrFence, "# Runbook IR", "## Purpose and outcome", "```", diff --git a/apps/brunch-agent/test/workpiece.test.ts b/apps/brunch-agent/test/workpiece.test.ts index 31419118c6a..490a18a7eec 100644 --- a/apps/brunch-agent/test/workpiece.test.ts +++ b/apps/brunch-agent/test/workpiece.test.ts @@ -1,135 +1,43 @@ import { describe, expect, test } from "vitest"; -import { - PREPARED_WORKPIECE_AUTHORSHIP, - PREPARED_WORKPIECE_CLAIM_BOUNDARY, - PREPARED_WORKPIECE_SIGNAL_TAG, - recoverRunbookWorkpiece, -} from "../src/conversation/workpiece.ts"; +import { recoverRunbookWorkpiece } from "../src/conversation/workpiece.ts"; import type { FlueConversationMessage, FlueConversationSnapshot, } from "@flue/sdk"; -const workpiece = (name: string): string => - `\`\`\`runbook-ir\n# ${name}\n\`\`\``; - -const preparedMessage = ( - id = "prepared", - submissionId = "prepare-submission", -): FlueConversationMessage => ({ - id, - role: "system", - purpose: "dispatch", - display: "diagnostic", - submissionId, - signal: { - tagName: PREPARED_WORKPIECE_SIGNAL_TAG, - attributes: { - authorship: PREPARED_WORKPIECE_AUTHORSHIP, - claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, - fixtureId: "crew-reservation-v1", - }, - }, - parts: [{ type: "text", text: workpiece("Prepared"), state: "done" }], -}); - -const assistantMessage = ( - id: string, - submissionId: string, - name: string, -): FlueConversationMessage => ({ - id, +const revisionMessage: FlueConversationMessage = { + id: "revision", role: "assistant", purpose: "assistant", display: "visible", - submissionId, - parts: [{ type: "text", text: workpiece(name), state: "done" }], -}); + submissionId: "turn-1", + parts: [ + { type: "text", text: "```runbook-ir\n# Revision\n```", state: "done" }, + ], +}; -const snapshot = ( - messages: FlueConversationMessage[], -): FlueConversationSnapshot => ({ +const snapshot: FlueConversationSnapshot = { v: 1, conversationId: "conversation", offset: "1", - messages, + messages: [revisionMessage], settlements: [], -}); +}; describe("recoverRunbookWorkpiece", () => { - test("recovers the tagged prepared source without relabelling its authorship", () => { - expect( - recoverRunbookWorkpiece(snapshot([preparedMessage()])), - ).toMatchObject({ - authorship: "test-authored", - content: "# Prepared", - sourceKind: "prepared-signal", - sourceMessageId: "prepared", - sourceSubmissionId: "prepare-submission", - }); - }); - - test("does not treat the preparation response as a model-authored revision", () => { - expect( - recoverRunbookWorkpiece( - snapshot([ - preparedMessage(), - assistantMessage( - "preparation-response", - "prepare-submission", - "Echoed by preparation response", - ), - ]), - ), - ).toMatchObject({ - authorship: "test-authored", - content: "# Prepared", - sourceKind: "prepared-signal", - }); - }); - - test("selects the latest genuine assistant revision", () => { - expect( - recoverRunbookWorkpiece( - snapshot([ - preparedMessage(), - assistantMessage("revision-1", "turn-1", "Revision one"), - assistantMessage("revision-2", "turn-2", "Revision two"), - ]), - ), - ).toMatchObject({ + test("accepts a Flue snapshot and adds stable content and source hashes", () => { + expect(recoverRunbookWorkpiece(snapshot)).toEqual({ authorship: "model-produced", - content: "# Revision two", + content: "# Revision", + sha256: + "330eeebe84d31400de2dad6ea1783ed1a0d0c5487ab32e63e58a6fffe201c4cb", sourceKind: "assistant", - sourceMessageId: "revision-2", - sourceSubmissionId: "turn-2", + sourceMessageId: "revision", + sourceMessageSha256: + "eced072a0cecc954fa63a7f9664e1dffea1a685f71d2b835a9af971a115718e5", + sourceSubmissionId: "turn-1", }); }); - - test("retains ordinary assistant-only workpiece recovery", () => { - expect( - recoverRunbookWorkpiece( - snapshot([ - assistantMessage("ordinary", "ordinary-turn", "Ordinary workpiece"), - ]), - ), - ).toMatchObject({ - authorship: "model-produced", - content: "# Ordinary workpiece", - sourceKind: "assistant", - }); - }); - - test("fails rather than choosing between multiple prepared sources", () => { - expect(() => - recoverRunbookWorkpiece( - snapshot([ - preparedMessage("prepared-1"), - preparedMessage("prepared-2", "prepare-submission-2"), - ]), - ), - ).toThrow(/more than one prepared workpiece source/u); - }); }); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-history.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-history.ts new file mode 100644 index 00000000000..f5030832123 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-history.ts @@ -0,0 +1,14 @@ +import type { WorkpieceHistory } from "@hashintel/brunch-agent/workpiece"; + +/** + * Canonical Flue history plus the durable offset observed by the browser. + * Preparation and settlement share this shape rather than independently + * extending the workpiece projection. + */ +export type CrewReservationHistory = WorkpieceHistory & { + readonly offset: string; + readonly settlements: readonly { + readonly outcome: string; + readonly submissionId: string; + }[]; +}; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts index 32bc94f8d21..ab6d5a6a626 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts @@ -1,9 +1,9 @@ import { describe, expect, test } from "vitest"; import { - PREPARED_WORKPIECE_AUTHORSHIP, - PREPARED_WORKPIECE_CLAIM_BOUNDARY, - PREPARED_WORKPIECE_SIGNAL_TAG, + preparedWorkpieceAuthorship, + preparedWorkpieceClaimBoundary, + preparedWorkpieceSignalTag, type WorkpieceHistoryMessage, } from "@hashintel/brunch-agent/workpiece"; @@ -12,11 +12,11 @@ import { settleCrewReservationManifest, } from "./crew-reservation-settled-manifest"; import { - CREW_RESERVATION_FIXTURE_ID, - DISPATCH_CREW_PLACE_ID, + crewReservationFixtureId, + dispatchCrewPlaceId, preparedCrewReservationNet, preparedCrewReservationWorkpiece, - START_FINAL_INSPECTION_TRANSITION_ID, + startFinalInspectionTransitionId, } from "./prepared-crew-reservation-fixture"; const preparedMessage: WorkpieceHistoryMessage = { @@ -25,11 +25,11 @@ const preparedMessage: WorkpieceHistoryMessage = { purpose: "dispatch", submissionId: "prepare-submission", signal: { - tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + tagName: preparedWorkpieceSignalTag, attributes: { - fixtureId: CREW_RESERVATION_FIXTURE_ID, - authorship: PREPARED_WORKPIECE_AUTHORSHIP, - claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + fixtureId: crewReservationFixtureId, + authorship: preparedWorkpieceAuthorship, + claimBoundary: preparedWorkpieceClaimBoundary, }, }, parts: [ @@ -64,9 +64,9 @@ const targetMutationMessages = (): readonly [ toolCallId: "target-arc-call", toolName: "addArc", input: { - transitionId: START_FINAL_INSPECTION_TRANSITION_ID, + transitionId: startFinalInspectionTransitionId, arcDirection: "input", - placeId: DISPATCH_CREW_PLACE_ID, + placeId: dispatchCrewPlaceId, weight: 1, }, }, @@ -106,7 +106,7 @@ describe("crew-reservation settled manifest", () => { expect(result).toMatchObject({ status: "settled", manifest: { - fixtureId: CREW_RESERVATION_FIXTURE_ID, + fixtureId: crewReservationFixtureId, revision: 0, conversation: { canonicalId: "canonical-flue-conversation", @@ -149,13 +149,13 @@ describe("crew-reservation settled manifest", () => { }; const revisedDefinition = structuredClone(preparedCrewReservationNet); const startInspection = revisedDefinition.transitions.find( - ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ({ id }) => id === startFinalInspectionTransitionId, ); if (startInspection === undefined) { throw new Error("Missing prepared start-inspection transition"); } startInspection.inputArcs.push({ - placeId: DISPATCH_CREW_PLACE_ID, + placeId: dispatchCrewPlaceId, type: "standard", weight: 1, }); @@ -199,13 +199,13 @@ describe("crew-reservation settled manifest", () => { }; const revisedDefinition = structuredClone(preparedCrewReservationNet); const startInspection = revisedDefinition.transitions.find( - ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ({ id }) => id === startFinalInspectionTransitionId, ); if (startInspection === undefined) { throw new Error("Missing prepared start-inspection transition"); } startInspection.inputArcs.push({ - placeId: DISPATCH_CREW_PLACE_ID, + placeId: dispatchCrewPlaceId, type: "standard", weight: 1, }); @@ -354,13 +354,13 @@ describe("crew-reservation settled manifest", () => { } const partialDefinition = structuredClone(preparedCrewReservationNet); const startInspection = partialDefinition.transitions.find( - ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ({ id }) => id === startFinalInspectionTransitionId, ); if (startInspection === undefined) { throw new Error("Missing prepared start-inspection transition"); } startInspection.inputArcs.push({ - placeId: DISPATCH_CREW_PLACE_ID, + placeId: dispatchCrewPlaceId, type: "standard", weight: 1, }); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts index a3bea28e98a..01767ed99a4 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts @@ -1,42 +1,67 @@ -import { - selectRunbookWorkpiece, - type WorkpieceHistory, -} from "@hashintel/brunch-agent/workpiece"; +import { clientToolHistoryFrom } from "@hashintel/brunch-agent-transport-aisdk"; +import { selectRunbookWorkpiece } from "@hashintel/brunch-agent/workpiece"; import { isSDCPNEqual, type SDCPN } from "@hashintel/petrinaut-core"; import { - CREW_RESERVATION_CONVERSATION_ID, - CREW_RESERVATION_DOCUMENT_ID, - CREW_RESERVATION_FIXTURE_ID, - DISPATCH_CREW_PLACE_ID, + crewReservationConversationId, + crewReservationDocumentId, + crewReservationFixtureId, + dispatchCrewPlaceId, preparedCrewReservationNet, - START_FINAL_INSPECTION_TRANSITION_ID, + startFinalInspectionTransitionId, } from "./prepared-crew-reservation-fixture"; -export const CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY = +import type { CrewReservationHistory } from "./crew-reservation-history"; + +export const crewReservationSettledManifestStorageKey = "brunch:prepared-fixture:crew-reservation-v1:settled"; +declare const manifestValueBrand: unique symbol; +type ManifestValue = string & { + readonly [manifestValueBrand]: Kind; +}; + +export type CanonicalConversationId = ManifestValue<"canonical-conversation">; +export type ConversationOffset = ManifestValue<"conversation-offset">; +export type FlueMessageId = ManifestValue<"flue-message">; +export type FlueSubmissionId = ManifestValue<"flue-submission">; +export type ManifestId = ManifestValue<"manifest">; +export type Sha256Digest = ManifestValue<"sha256">; + +export const asCanonicalConversationId = ( + value: string, +): CanonicalConversationId => value as CanonicalConversationId; +export const asConversationOffset = (value: string): ConversationOffset => + value as ConversationOffset; +export const asFlueMessageId = (value: string): FlueMessageId => + value as FlueMessageId; +export const asFlueSubmissionId = (value: string): FlueSubmissionId => + value as FlueSubmissionId; +export const asManifestId = (value: string): ManifestId => value as ManifestId; +export const asSha256Digest = (value: string): Sha256Digest => + value as Sha256Digest; + export interface CrewReservationSettledManifest { readonly conversation: { - readonly canonicalId: string; - readonly logicalId: typeof CREW_RESERVATION_CONVERSATION_ID; - readonly offset: string; + readonly canonicalId: CanonicalConversationId; + readonly logicalId: typeof crewReservationConversationId; + readonly offset: ConversationOffset; }; readonly document: { - readonly id: typeof CREW_RESERVATION_DOCUMENT_ID; - readonly sha256: string; + readonly id: typeof crewReservationDocumentId; + readonly sha256: Sha256Digest; readonly targetArc: "absent" | "present"; }; - readonly fixtureId: typeof CREW_RESERVATION_FIXTURE_ID; + readonly fixtureId: typeof crewReservationFixtureId; readonly latestWorkpiece: { readonly authorship: "model-produced" | "test-authored"; - readonly contentSha256: string; + readonly contentSha256: Sha256Digest; readonly sourceKind: "assistant" | "prepared-signal"; - readonly sourceMessageId: string; - readonly sourceMessageSha256: string; - readonly sourceSubmissionId: string; + readonly sourceMessageId: FlueMessageId; + readonly sourceMessageSha256: Sha256Digest; + readonly sourceSubmissionId: FlueSubmissionId; }; - readonly manifestId: string; + readonly manifestId: ManifestId; readonly revision: number; readonly settledAt: string; readonly version: 1; @@ -57,78 +82,38 @@ export type CrewReservationSettlementResult = readonly status: "refused"; }; -export type CrewReservationSettledHistory = WorkpieceHistory & { - readonly offset: string; - readonly settlements: readonly { - readonly outcome: string; - readonly submissionId: string; - }[]; -}; - -const isRecord = (value: unknown): value is Record => - typeof value === "object" && value !== null; - const targetMutationCallIds = ( - history: CrewReservationSettledHistory, -): readonly string[] => - history.messages.flatMap((message) => - message.parts.flatMap((part) => { - if ( - !isRecord(part) || - part.type !== "dynamic-tool" || - part.toolName !== "addArc" || - typeof part.toolCallId !== "string" || - !isRecord(part.input) || - part.input.transitionId !== START_FINAL_INSPECTION_TRANSITION_ID || - part.input.arcDirection !== "input" || - part.input.placeId !== DISPATCH_CREW_PLACE_ID || - part.input.weight !== 1 - ) { - return []; - } - return [part.toolCallId]; - }), + history: CrewReservationHistory, +): readonly string[] => { + const { calls } = clientToolHistoryFrom(history.messages); + return calls.flatMap(({ input, toolCallId, toolName }) => + toolName === "addArc" && + input.transitionId === startFinalInspectionTransitionId && + input.arcDirection === "input" && + input.placeId === dispatchCrewPlaceId && + input.weight === 1 + ? [toolCallId] + : [], ); +}; const successfulMutationResultIds = ( - history: CrewReservationSettledHistory, -): readonly string[] => - history.messages.flatMap((message) => { - if ( - message.signal?.tagName !== "client-tool-result" && - message.signal?.type !== "client-tool-result" - ) { - return []; - } - const body = message.parts - .flatMap((part) => - part.type === "text" && typeof part.text === "string" - ? [part.text] - : [], - ) - .join(""); - try { - const results: unknown = JSON.parse(body); - if (!Array.isArray(results)) return []; - return results.flatMap((result) => { - if ( - !isRecord(result) || - result.toolName !== "addArc" || - typeof result.toolCallId !== "string" || - !isRecord(result.output) || - result.output.applied !== true - ) { - return []; - } - return [result.toolCallId]; - }); - } catch { - return []; - } - }); + history: CrewReservationHistory, +): readonly string[] => { + const { results } = clientToolHistoryFrom(history.messages); + return results.flatMap(({ output, toolCallId, toolName }) => + toolName === "addArc" && + typeof output === "object" && + output !== null && + "applied" in output && + output.applied === true + ? [toolCallId] + : [], + ); +}; const hasOneCorrelatedTargetMutation = ( - history: CrewReservationSettledHistory, + history: CrewReservationHistory, ): boolean => { const targetCallIds = targetMutationCallIds(history); const successfulResultIds = successfulMutationResultIds(history); @@ -139,24 +124,26 @@ const hasOneCorrelatedTargetMutation = ( ); }; -const sha256 = async (value: string): Promise => { +const sha256 = async (value: string): Promise => { const digest = await globalThis.crypto.subtle.digest( "SHA-256", new TextEncoder().encode(value), ); - return [...new Uint8Array(digest)] - .map((byte) => byte.toString(16).padStart(2, "0")) - .join(""); + return asSha256Digest( + [...new Uint8Array(digest)] + .map((byte) => byte.toString(16).padStart(2, "0")) + .join(""), + ); }; export const hasCrewReservationTargetArc = (definition: SDCPN): boolean => { const transition = definition.transitions.find( - ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ({ id }) => id === startFinalInspectionTransitionId, ); return ( transition?.inputArcs.some( (arc) => - arc.placeId === DISPATCH_CREW_PLACE_ID && + arc.placeId === dispatchCrewPlaceId && arc.type === "standard" && arc.weight === 1, ) ?? false @@ -166,13 +153,13 @@ export const hasCrewReservationTargetArc = (definition: SDCPN): boolean => { const preparedCrewReservationNetWithTargetArc = (): SDCPN => { const definition = structuredClone(preparedCrewReservationNet); const transition = definition.transitions.find( - ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ({ id }) => id === startFinalInspectionTransitionId, ); if (transition === undefined) { throw new Error("The prepared fixture has no start-inspection transition."); } transition.inputArcs.push({ - placeId: DISPATCH_CREW_PLACE_ID, + placeId: dispatchCrewPlaceId, type: "standard", weight: 1, }); @@ -181,7 +168,7 @@ const preparedCrewReservationNetWithTargetArc = (): SDCPN => { export const settleCrewReservationManifest = async (input: { readonly definition: SDCPN; - readonly history: CrewReservationSettledHistory; + readonly history: CrewReservationHistory; readonly previous?: CrewReservationSettledManifest; readonly settledAt: string; }): Promise => { @@ -256,24 +243,24 @@ export const settleCrewReservationManifest = async (input: { const revision = (input.previous?.revision ?? -1) + 1; const withoutId = { version: 1 as const, - fixtureId: CREW_RESERVATION_FIXTURE_ID, + fixtureId: crewReservationFixtureId, revision, settledAt: input.settledAt, conversation: { - logicalId: CREW_RESERVATION_CONVERSATION_ID, - canonicalId: input.history.conversationId, - offset: input.history.offset, + logicalId: crewReservationConversationId, + canonicalId: asCanonicalConversationId(input.history.conversationId), + offset: asConversationOffset(input.history.offset), }, latestWorkpiece: { authorship: workpiece.authorship, contentSha256, sourceKind: workpiece.sourceKind, - sourceMessageId: workpiece.sourceMessageId, + sourceMessageId: asFlueMessageId(workpiece.sourceMessageId), sourceMessageSha256, - sourceSubmissionId: workpiece.sourceSubmissionId, + sourceSubmissionId: asFlueSubmissionId(workpiece.sourceSubmissionId), }, document: { - id: CREW_RESERVATION_DOCUMENT_ID, + id: crewReservationDocumentId, sha256: documentSha256, targetArc: targetArcPresent ? ("present" as const) : ("absent" as const), }, @@ -283,7 +270,7 @@ export const settleCrewReservationManifest = async (input: { status: "settled", manifest: { ...withoutId, - manifestId: await sha256(JSON.stringify(withoutId)), + manifestId: asManifestId(await sha256(JSON.stringify(withoutId))), }, }; }; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx b/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx index 78f2b2f938e..34a8de13119 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx @@ -5,13 +5,12 @@ import { createFlueClient, type FlueConversationSettlement } from "@flue/sdk"; import { castDraft, produce } from "immer"; -import { useEffect, useMemo, useState } from "react"; +import { useCallback, useEffect, useMemo, useState } from "react"; import { agentOwnershipHeaders, flueConversationIdWeb, } from "@hashintel/brunch-agent-transport-aisdk"; -import { selectRunbookWorkpiece } from "@hashintel/brunch-agent/workpiece"; import { createJsonDocHandle, type MinimalNetMetadata, @@ -55,11 +54,8 @@ import { } from "./brunch-panel-transport"; import { resolveBrunchPreviewConfig } from "./brunch-preview-config"; import { getOrCreateBrunchPrincipal } from "./brunch-principal"; -import { prepareCrewReservationConversation } from "./prepare-crew-reservation-conversation"; import { - CREW_RESERVATION_CLIENT_TOOL_NAMES, - CREW_RESERVATION_CONVERSATION_ID, - CREW_RESERVATION_DOCUMENT_ID, + crewReservationDocumentId, isCrewReservationFixtureSelected, preparedCrewReservationNet, } from "./prepared-crew-reservation-fixture"; @@ -67,7 +63,12 @@ import { PreparedFixtureBanner, PreparedFixtureSelector, } from "./prepared-fixture-banner"; -import { useCrewReservationSettledManifest } from "./use-crew-reservation-settled-manifest"; +import { resolveCrewReservationBundle } from "./resolve-crew-reservation-bundle"; +import { + crewReservationFixtureConfiguration, + useCrewReservationFixtureSession, +} from "./use-crew-reservation-fixture-session"; +import { useCrewReservationSettledManifestStorage } from "./use-crew-reservation-settled-manifest"; import { useFlueChatHistory } from "./use-flue-chat-history"; import { useLocalStorageAiMessages } from "./use-local-storage-ai-messages"; import { @@ -89,7 +90,7 @@ const createDefaultStoredSDCPN = (): SDCPNInLocalStorage => ({ }); const preparedCrewReservationStoredSDCPN: SDCPNInLocalStorage = { - id: CREW_RESERVATION_DOCUMENT_ID, + id: crewReservationDocumentId, title: "Prepared final inspection and dispatch", sdcpn: preparedCrewReservationNet, lastUpdated: new Date(0).toISOString(), @@ -140,9 +141,6 @@ const createHandle = (net: SDCPNInLocalStorage): PetrinautDocHandle => }); const brunchPrincipal = getOrCreateBrunchPrincipal(); -const crewReservationClientToolNames: ReadonlySet = new Set( - CREW_RESERVATION_CLIENT_TOOL_NAMES, -); /** Every widget here must answer a tool named in `brunchClientToolNames`. */ export const brunchInteractiveTools: readonly PetrinautAiInteractiveTool[] = [ @@ -192,14 +190,12 @@ const createConversationTrackerFor = ( const getStoredSDCPNsForDisplay = ( storedSDCPNs: Record, - crewReservationFixtureSelected: boolean, + crewReservationDocument: SDCPNInLocalStorage | undefined, ): Record => { - if (crewReservationFixtureSelected) { + if (crewReservationDocument !== undefined) { return { ...storedSDCPNs, - [CREW_RESERVATION_DOCUMENT_ID]: - storedSDCPNs[CREW_RESERVATION_DOCUMENT_ID] ?? - preparedCrewReservationStoredSDCPN, + [crewReservationDocument.id]: crewReservationDocument, }; } if (Object.values(storedSDCPNs).length > 0) { @@ -351,27 +347,56 @@ export const LocalStorageDemoApp = ({ const { aiMessagesByNetId, setAiMessagesByNetId } = useLocalStorageAiMessages(); const { storedSDCPNs, setStoredSDCPNs } = useLocalStorageSDCPNs(); + const { settledManifest, setSettledManifest } = + useCrewReservationSettledManifestStorage(); const crewReservationFixtureSelected = isCrewReservationFixtureSelected( window.location.search, ); + const crewReservationBundle = crewReservationFixtureSelected + ? resolveCrewReservationBundle({ + fallbackDocument: preparedCrewReservationStoredSDCPN, + manifest: settledManifest, + storedDocument: storedSDCPNs[crewReservationDocumentId], + }) + : undefined; const storedSDCPNsForDisplay = getStoredSDCPNsForDisplay( storedSDCPNs, - crewReservationFixtureSelected, + crewReservationBundle?.selectedDocument, ); useEffect(() => { if ( !crewReservationFixtureSelected || - storedSDCPNs[CREW_RESERVATION_DOCUMENT_ID] !== undefined + storedSDCPNs[crewReservationDocumentId] !== undefined ) { return; } setStoredSDCPNs((previous) => ({ ...previous, - [CREW_RESERVATION_DOCUMENT_ID]: preparedCrewReservationStoredSDCPN, + [crewReservationDocumentId]: preparedCrewReservationStoredSDCPN, })); }, [crewReservationFixtureSelected, setStoredSDCPNs, storedSDCPNs]); + const persistCrewReservationSnapshot = useCallback( + (sha256: string, definition: SDCPN) => { + setStoredSDCPNs((previous) => + produce(previous, (draft) => { + const document = + draft[crewReservationDocumentId] ?? + preparedCrewReservationStoredSDCPN; + draft[crewReservationDocumentId] = { + ...document, + coherentSnapshots: { + ...document.coherentSnapshots, + [sha256]: structuredClone(definition), + }, + }; + }), + ); + }, + [setStoredSDCPNs], + ); + useEffect(() => { if (!brunchPreviewConfig.isBrunchConfigured) { return; @@ -397,7 +422,7 @@ export const LocalStorageDemoApp = ({ new Date(b.lastUpdated).getTime() - new Date(a.lastUpdated).getTime(), )[0] ?? null; const initiallySelectedNet = crewReservationFixtureSelected - ? storedSDCPNsForDisplay[CREW_RESERVATION_DOCUMENT_ID] + ? storedSDCPNsForDisplay[crewReservationDocumentId] : mostRecentlyModifiedNet; // The net currently selected in the UI. @@ -539,29 +564,22 @@ export const LocalStorageDemoApp = ({ const preparedFixtureIsCurrent = crewReservationFixtureSelected && - currentNetId === CREW_RESERVATION_DOCUMENT_ID; + currentNetId === crewReservationDocumentId; + const fixtureConfiguration = preparedFixtureIsCurrent + ? crewReservationFixtureConfiguration + : undefined; const conversationId = currentNetId === null ? null - : preparedFixtureIsCurrent - ? CREW_RESERVATION_CONVERSATION_ID - : getOrCreateBrunchConversationId(currentNetId); - const rawFlueClientPromise = useMemo( + : (fixtureConfiguration?.conversationId ?? + getOrCreateBrunchConversationId(currentNetId)); + const flueClientPromise = useMemo( () => brunchPreviewConfig.isBrunchConfigured && conversationId !== null ? createBrunchFlueClient(conversationId) : null, [conversationId], ); - const flueClientPromise = useMemo(() => { - if (rawFlueClientPromise === null || !preparedFixtureIsCurrent) { - return rawFlueClientPromise; - } - return rawFlueClientPromise.then(async (client) => { - await prepareCrewReservationConversation(client); - return client; - }); - }, [preparedFixtureIsCurrent, rawFlueClientPromise]); const conversationTracker = useMemo( // Correlation state belongs to one conversation and must not cross a net switch. () => createConversationTrackerFor(conversationId), @@ -570,7 +588,7 @@ export const LocalStorageDemoApp = ({ const flueHistory = useFlueChatHistory( flueClientPromise, conversationId ?? "", - preparedFixtureIsCurrent ? crewReservationClientToolNames : undefined, + fixtureConfiguration?.clientToolNames, ); const brunchVoiceMode = useMemo( () => @@ -581,46 +599,43 @@ export const LocalStorageDemoApp = ({ ), [conversationTracker, flueHistory.settlements, openAIVoiceConfig], ); - const { settledManifest, status: settlementStatus } = - useCrewReservationSettledManifest({ - definition: preparedFixtureIsCurrent ? currentNet?.sdcpn : undefined, - enabled: preparedFixtureIsCurrent, - history: preparedFixtureIsCurrent ? flueHistory.snapshot : undefined, - historyError: preparedFixtureIsCurrent - ? flueHistory.error?.message - : undefined, - }); - const currentWorkpiece = (() => { - if (flueHistory.snapshot === undefined) return undefined; - try { - return selectRunbookWorkpiece(flueHistory.snapshot)?.content; - } catch { - return undefined; - } - })(); + const crewReservationSession = useCrewReservationFixtureSession({ + clientPromise: flueClientPromise, + definition: storedSDCPNs[crewReservationDocumentId]?.sdcpn, + enabled: fixtureConfiguration !== undefined, + history: flueHistory.snapshot, + historyError: flueHistory.error?.message, + persistCoherentSnapshot: persistCrewReservationSnapshot, + refreshHistory: flueHistory.refresh, + setSettledManifest, + settledManifest, + snapshotMissing: crewReservationBundle?.snapshotMissing ?? false, + }); const petrinautAiChatTransport = useMemo(() => { - if (flueClientPromise !== null) { + if (flueClientPromise !== null && crewReservationSession.transportReady) { return createBrunchPanelTransport( flueClientPromise, conversationTracker, { - ...(preparedFixtureIsCurrent - ? { clientToolNames: crewReservationClientToolNames } - : {}), + ...(fixtureConfiguration === undefined + ? {} + : { clientToolNames: fixtureConfiguration.clientToolNames }), onAdmission: flueHistory.refresh, }, ); } - return preparedFixtureIsCurrent + return fixtureConfiguration !== undefined ? createUnavailableBrunchPanelTransport( - "The prepared fixture requires the mounted Brunch Flue route.", + crewReservationSession.transportUnavailableReason, ) : stockChatTransport; }, [ conversationTracker, + crewReservationSession.transportReady, + crewReservationSession.transportUnavailableReason, + fixtureConfiguration, flueClientPromise, flueHistory.refresh, - preparedFixtureIsCurrent, ]); const aiAssistant = useMemo( @@ -715,9 +730,9 @@ export const LocalStorageDemoApp = ({ > {preparedFixtureIsCurrent && ( )} {!preparedFixtureIsCurrent && } diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.test.ts index 64270890faa..23a69be894d 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.test.ts @@ -1,13 +1,13 @@ import { describe, expect, test, vi } from "vitest"; import { - PREPARED_WORKPIECE_INITIAL_DATA_MODE, - PREPARED_WORKPIECE_SIGNAL_TAG, + preparedWorkpieceInitialDataMode, + preparedWorkpieceSignalTag, } from "@hashintel/brunch-agent/workpiece"; import { prepareCrewReservationConversation } from "./prepare-crew-reservation-conversation"; import { - CREW_RESERVATION_FIXTURE_ID, + crewReservationFixtureId, preparedCrewReservationDelivery, preparedCrewReservationWorkpiece, } from "./prepared-crew-reservation-fixture"; @@ -23,9 +23,9 @@ const preparedHistory = { purpose: "dispatch", submissionId: "prepare-submission", signal: { - tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + tagName: preparedWorkpieceSignalTag, attributes: { - fixtureId: CREW_RESERVATION_FIXTURE_ID, + fixtureId: crewReservationFixtureId, authorship: "test-authored", claimBoundary: "prepared-not-model-produced", }, @@ -65,7 +65,7 @@ describe("prepareCrewReservationConversation", () => { ).resolves.toEqual(preparedHistory); expect(send).toHaveBeenCalledWith({ uid: null, - initialData: { mode: PREPARED_WORKPIECE_INITIAL_DATA_MODE }, + initialData: { mode: preparedWorkpieceInitialDataMode }, ...preparedCrewReservationDelivery, }); expect(wait).toHaveBeenCalledWith(admission); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.ts index c0fcab5c3c5..7c8625c06b7 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepare-crew-reservation-conversation.ts @@ -1,30 +1,22 @@ import { - PREPARED_WORKPIECE_INITIAL_DATA_MODE, + preparedWorkpieceInitialDataMode, selectRunbookWorkpiece, - type WorkpieceHistory, } from "@hashintel/brunch-agent/workpiece"; import { - CREW_RESERVATION_FIXTURE_ID, + crewReservationFixtureId, preparedCrewReservationDelivery, } from "./prepared-crew-reservation-fixture"; +import type { CrewReservationHistory } from "./crew-reservation-history"; import type { AgentSendResult } from "@flue/sdk"; -export type PreparedCrewReservationHistory = WorkpieceHistory & { - readonly offset: string; - readonly settlements: readonly { - readonly outcome: string; - readonly submissionId: string; - }[]; -}; - export interface PreparedFixtureConversationClient { - readonly history: () => Promise; + readonly history: () => Promise; readonly send: (input: { readonly idempotencyKey: string; readonly initialData: { - readonly mode: typeof PREPARED_WORKPIECE_INITIAL_DATA_MODE; + readonly mode: typeof preparedWorkpieceInitialDataMode; }; readonly message: typeof preparedCrewReservationDelivery.message; readonly uid: null; @@ -39,8 +31,8 @@ const isNotFound = (error: unknown): boolean => error.status === 404; const assertPreparedFixtureHistory = ( - history: PreparedCrewReservationHistory, -): PreparedCrewReservationHistory => { + history: CrewReservationHistory, +): CrewReservationHistory => { const currentWorkpiece = selectRunbookWorkpiece(history); if ( currentWorkpiece?.sourceKind !== "prepared-signal" && @@ -56,8 +48,7 @@ const assertPreparedFixtureHistory = ( preparedCrewReservationDelivery.message.tagName, ); if ( - preparedSource?.signal?.attributes?.fixtureId !== - CREW_RESERVATION_FIXTURE_ID + preparedSource?.signal?.attributes?.fixtureId !== crewReservationFixtureId ) { throw new Error( "The prepared fixture conversation belongs to a different fixture.", @@ -73,7 +64,7 @@ const assertPreparedFixtureHistory = ( */ export const prepareCrewReservationConversation = async ( client: PreparedFixtureConversationClient, -): Promise => { +): Promise => { try { return assertPreparedFixtureHistory(await client.history()); } catch (error) { @@ -82,7 +73,7 @@ export const prepareCrewReservationConversation = async ( const admission = await client.send({ uid: null, - initialData: { mode: PREPARED_WORKPIECE_INITIAL_DATA_MODE }, + initialData: { mode: preparedWorkpieceInitialDataMode }, ...preparedCrewReservationDelivery, }); await client.wait(admission); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.test.ts index 36bda9934fe..9374b8df606 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.test.ts @@ -1,14 +1,14 @@ import { describe, expect, test } from "vitest"; import { - CREW_RESERVATION_CLIENT_TOOL_NAMES, - CREW_RESERVATION_FIXTURE_ID, - DISPATCH_CREW_PLACE_ID, + crewReservationFixtureClientToolNames, + crewReservationFixtureId, + dispatchCrewPlaceId, isCrewReservationFixtureSelected, preparedCrewReservationDelivery, preparedCrewReservationNet, preparedCrewReservationWorkpiece, - START_FINAL_INSPECTION_TRANSITION_ID, + startFinalInspectionTransitionId, } from "./prepared-crew-reservation-fixture"; const transitionById = (transitionId: string) => { @@ -23,16 +23,14 @@ const transitionById = (transitionId: string) => { describe("prepared crew-reservation fixture", () => { test("advertises only the selected canonical read and mutation", () => { - expect(CREW_RESERVATION_CLIENT_TOOL_NAMES).toEqual([ + expect(crewReservationFixtureClientToolNames).toEqual([ "getLatestNetDefinition", "addArc", ]); }); test("has the batch flow and crew return but omits the target input arc", () => { - const startInspection = transitionById( - START_FINAL_INSPECTION_TRANSITION_ID, - ); + const startInspection = transitionById(startFinalInspectionTransitionId); const signOff = transitionById("sign-off"); expect(startInspection.inputArcs).toContainEqual({ @@ -41,12 +39,12 @@ describe("prepared crew-reservation fixture", () => { weight: 1, }); expect(startInspection.inputArcs).not.toContainEqual( - expect.objectContaining({ placeId: DISPATCH_CREW_PLACE_ID }), + expect.objectContaining({ placeId: dispatchCrewPlaceId }), ); expect(signOff.outputArcs).toEqual( expect.arrayContaining([ { placeId: "ready-for-dispatch", weight: 1 }, - { placeId: DISPATCH_CREW_PLACE_ID, weight: 1 }, + { placeId: dispatchCrewPlaceId, weight: 1 }, ]), ); }); @@ -62,7 +60,7 @@ describe("prepared crew-reservation fixture", () => { "not model-produced evidence", ); expect(preparedCrewReservationDelivery.message.attributes).toEqual({ - fixtureId: CREW_RESERVATION_FIXTURE_ID, + fixtureId: crewReservationFixtureId, authorship: "test-authored", claimBoundary: "prepared-not-model-produced", }); @@ -71,7 +69,7 @@ describe("prepared crew-reservation fixture", () => { test("selects only the explicit stable query value", () => { expect( isCrewReservationFixtureSelected( - `?brunch-fixture=${CREW_RESERVATION_FIXTURE_ID}`, + `?brunch-fixture=${crewReservationFixtureId}`, ), ).toBe(true); expect( diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.ts index 69588ab02cf..92be1cc9a9c 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-crew-reservation-fixture.ts @@ -6,19 +6,19 @@ import { import type { SDCPN } from "@hashintel/petrinaut-core"; -export const CREW_RESERVATION_FIXTURE_ID = "crew-reservation-v1"; -export const CREW_RESERVATION_DOCUMENT_ID = +export const crewReservationFixtureId = "crew-reservation-v1"; +export const crewReservationDocumentId = "mission-6-crew-reservation-document-v1"; -export const CREW_RESERVATION_CONVERSATION_ID = +export const crewReservationConversationId = "mission-6-crew-reservation-conversation-v1"; -export const CREW_RESERVATION_FIXTURE_QUERY = "brunch-fixture"; -export const CREW_RESERVATION_CLIENT_TOOL_NAMES = [ +export const crewReservationFixtureQuery = "brunch-fixture"; +export const crewReservationFixtureClientToolNames = [ getLatestNetDefinitionToolName, "addArc", ] as const satisfies readonly PetrinautAiToolName[]; -export const DISPATCH_CREW_PLACE_ID = "dispatch-crew-available"; -export const START_FINAL_INSPECTION_TRANSITION_ID = "start-final-inspection"; +export const dispatchCrewPlaceId = "dispatch-crew-available"; +export const startFinalInspectionTransitionId = "start-final-inspection"; export const preparedCrewReservationWorkpiece = [ "Fixture authorship: test-authored preparation for Mission 6.", @@ -51,7 +51,7 @@ export const preparedCrewReservationWorkpiece = [ export const preparedCrewReservationDelivery = createPreparedWorkpieceDelivery({ body: preparedCrewReservationWorkpiece, - fixtureId: CREW_RESERVATION_FIXTURE_ID, + fixtureId: crewReservationFixtureId, revision: 0, }); @@ -85,7 +85,7 @@ export const preparedCrewReservationNet: SDCPN = { y: 100, }, { - id: DISPATCH_CREW_PLACE_ID, + id: dispatchCrewPlaceId, name: "Dispatch crew available", colorId: null, dynamicsEnabled: false, @@ -96,7 +96,7 @@ export const preparedCrewReservationNet: SDCPN = { ], transitions: [ { - id: START_FINAL_INSPECTION_TRANSITION_ID, + id: startFinalInspectionTransitionId, name: "Start final inspection", inputArcs: [ { @@ -133,7 +133,7 @@ export const preparedCrewReservationNet: SDCPN = { weight: 1, }, { - placeId: DISPATCH_CREW_PLACE_ID, + placeId: dispatchCrewPlaceId, weight: 1, }, ], @@ -150,5 +150,5 @@ export const preparedCrewReservationNet: SDCPN = { }; export const isCrewReservationFixtureSelected = (search: string): boolean => - new URLSearchParams(search).get(CREW_RESERVATION_FIXTURE_QUERY) === - CREW_RESERVATION_FIXTURE_ID; + new URLSearchParams(search).get(crewReservationFixtureQuery) === + crewReservationFixtureId; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.test.tsx b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.test.tsx index 4d307764689..28ad5065b61 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.test.tsx +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.test.tsx @@ -2,9 +2,17 @@ import { renderToStaticMarkup } from "react-dom/server"; import { describe, expect, test } from "vitest"; import { - CREW_RESERVATION_CONVERSATION_ID, - CREW_RESERVATION_DOCUMENT_ID, - CREW_RESERVATION_FIXTURE_ID, + asCanonicalConversationId, + asConversationOffset, + asFlueMessageId, + asFlueSubmissionId, + asManifestId, + asSha256Digest, +} from "./crew-reservation-settled-manifest"; +import { + crewReservationConversationId, + crewReservationDocumentId, + crewReservationFixtureId, } from "./prepared-crew-reservation-fixture"; import { PreparedFixtureBanner, @@ -38,26 +46,26 @@ describe("PreparedFixtureBanner", () => { (
{settlementStatus.state === "refused" - ? `Settlement refused (${settlementStatus.reason}); ${ - settledManifest === null - ? "no coherent bundle is selected" - : `bundle revision ${settledManifest.revision} remains selected` - }.${settlementStatus.detail === undefined ? "" : ` ${settlementStatus.detail}`}` + ? settlementStatus.reason === "bundle-snapshot-unavailable" + ? `Settlement refused (${settlementStatus.reason}); the selected document revision is unavailable and the live mirror is shown only for diagnosis.` + : `Settlement refused (${settlementStatus.reason}); ${ + settledManifest === null + ? "no coherent bundle is selected" + : `bundle revision ${settledManifest.revision} remains selected` + }.${settlementStatus.detail === undefined ? "" : ` ${settlementStatus.detail}`}` : settlementStatus.state !== "settled" || settledManifest === null ? "Preparing the conversation, workpiece, and automatically mirrored document…" : `Settled bundle revision ${settledManifest.revision}; target crew-reservation arc ${settledManifest.document.targetArc}.`}
-
- Current Markdown workpiece -
-          {currentWorkpiece}
-        
-
+ {displayedWorkpiece === undefined ? ( +
The selected bundle’s Markdown workpiece is unavailable.
+ ) : ( +
+ Current Markdown workpiece +
+            {displayedWorkpiece}
+          
+
+ )} ); }; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts new file mode 100644 index 00000000000..169ad433863 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts @@ -0,0 +1,149 @@ +import { describe, expect, test } from "vitest"; + +import { + preparedWorkpieceAuthorship, + preparedWorkpieceClaimBoundary, + preparedWorkpieceSignalTag, +} from "@hashintel/brunch-agent/workpiece"; + +import { + asCanonicalConversationId, + asConversationOffset, + asFlueMessageId, + asFlueSubmissionId, + asManifestId, + asSha256Digest, + type CrewReservationSettledManifest, +} from "./crew-reservation-settled-manifest"; +import { + crewReservationConversationId, + crewReservationDocumentId, + crewReservationFixtureId, + preparedCrewReservationNet, + preparedCrewReservationWorkpiece, +} from "./prepared-crew-reservation-fixture"; +import { + resolveCrewReservationBundle, + workpieceForCrewReservationBundle, +} from "./resolve-crew-reservation-bundle"; + +import type { SDCPNInLocalStorage } from "./use-local-storage-sdcpns"; + +const manifest: CrewReservationSettledManifest = { + version: 1, + fixtureId: crewReservationFixtureId, + manifestId: asManifestId("manifest"), + revision: 0, + settledAt: "2026-09-04T08:00:00.000Z", + conversation: { + canonicalId: asCanonicalConversationId("canonical"), + logicalId: crewReservationConversationId, + offset: asConversationOffset("2"), + }, + document: { + id: crewReservationDocumentId, + sha256: asSha256Digest("coherent-hash"), + targetArc: "absent", + }, + latestWorkpiece: { + authorship: "test-authored", + contentSha256: asSha256Digest("content"), + sourceKind: "prepared-signal", + sourceMessageId: asFlueMessageId("prepared-message"), + sourceMessageSha256: asSha256Digest("message"), + sourceSubmissionId: asFlueSubmissionId("prepare-submission"), + }, +}; + +const fallbackDocument: SDCPNInLocalStorage = { + id: crewReservationDocumentId, + title: "Prepared", + sdcpn: preparedCrewReservationNet, + lastUpdated: "1970-01-01T00:00:00.000Z", +}; + +describe("resolveCrewReservationBundle", () => { + test("selects the content-addressed coherent document over a partial mirror", () => { + const partialDefinition = structuredClone(preparedCrewReservationNet); + const firstPlace = partialDefinition.places.at(0); + if (firstPlace === undefined) { + throw new Error("The prepared fixture has no places."); + } + firstPlace.name = "Partial write"; + + const selection = resolveCrewReservationBundle({ + fallbackDocument, + manifest, + storedDocument: { + ...fallbackDocument, + sdcpn: partialDefinition, + coherentSnapshots: { + "coherent-hash": preparedCrewReservationNet, + }, + }, + }); + + expect(selection.snapshotMissing).toBe(false); + expect(selection.selectedDocument.sdcpn).toEqual( + preparedCrewReservationNet, + ); + expect(selection.selectedDocument.sdcpn).not.toEqual(partialDefinition); + expect(selection.observedDocument.sdcpn).toEqual(partialDefinition); + }); + + test("keeps a missing snapshot diagnosable without inventing a revision", () => { + const selection = resolveCrewReservationBundle({ + fallbackDocument, + manifest, + storedDocument: fallbackDocument, + }); + + expect(selection).toEqual({ + observedDocument: fallbackDocument, + selectedDocument: fallbackDocument, + snapshotMissing: true, + }); + }); +}); + +test("selects the workpiece source named by the settled manifest", () => { + const newerWorkpiece = "```runbook-ir\n# Unsettled newer workpiece\n```"; + expect( + workpieceForCrewReservationBundle( + { + conversationId: "canonical", + offset: "3", + settlements: [], + messages: [ + { + id: "prepared-message", + role: "system", + purpose: "dispatch", + submissionId: "prepare-submission", + signal: { + tagName: preparedWorkpieceSignalTag, + attributes: { + fixtureId: crewReservationFixtureId, + authorship: preparedWorkpieceAuthorship, + claimBoundary: preparedWorkpieceClaimBoundary, + }, + }, + parts: [ + { + type: "text", + text: preparedCrewReservationWorkpiece, + }, + ], + }, + { + id: "newer-message", + role: "assistant", + purpose: "assistant", + parts: [{ type: "text", text: newerWorkpiece }], + }, + ], + }, + manifest, + ), + ).toContain("# Final inspection and dispatch workpiece"); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.ts new file mode 100644 index 00000000000..065568d3320 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.ts @@ -0,0 +1,66 @@ +import { + latestRunbookIrBlock, + selectRunbookWorkpiece, +} from "@hashintel/brunch-agent/workpiece"; + +import type { CrewReservationHistory } from "./crew-reservation-history"; +import type { CrewReservationSettledManifest } from "./crew-reservation-settled-manifest"; +import type { SDCPNInLocalStorage } from "./use-local-storage-sdcpns"; + +export interface CrewReservationBundleSelection { + readonly observedDocument: SDCPNInLocalStorage; + readonly selectedDocument: SDCPNInLocalStorage; + readonly snapshotMissing: boolean; +} + +export const resolveCrewReservationBundle = (input: { + readonly fallbackDocument: SDCPNInLocalStorage; + readonly manifest: CrewReservationSettledManifest | null; + readonly storedDocument: SDCPNInLocalStorage | undefined; +}): CrewReservationBundleSelection => { + const liveDocument = input.storedDocument ?? input.fallbackDocument; + if (input.manifest === null) { + return { + observedDocument: liveDocument, + selectedDocument: liveDocument, + snapshotMissing: false, + }; + } + + const coherentDefinition = + liveDocument.coherentSnapshots?.[input.manifest.document.sha256]; + if (coherentDefinition === undefined) { + return { + observedDocument: liveDocument, + selectedDocument: liveDocument, + snapshotMissing: true, + }; + } + + return { + observedDocument: liveDocument, + selectedDocument: { + ...liveDocument, + sdcpn: coherentDefinition, + }, + snapshotMissing: false, + }; +}; + +export const workpieceForCrewReservationBundle = ( + history: CrewReservationHistory | undefined, + manifest: CrewReservationSettledManifest | null, +): string | undefined => { + if (history === undefined) return undefined; + if (manifest === null) return selectRunbookWorkpiece(history)?.content; + + const selectedMessage = history.messages.find( + ({ id }) => id === manifest.latestWorkpiece.sourceMessageId, + ); + if (selectedMessage === undefined) return undefined; + return latestRunbookIrBlock( + selectedMessage.parts + .flatMap((part) => (part.type === "text" ? [part.text] : [])) + .join("\n"), + ); +}; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-fixture-session.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-fixture-session.ts new file mode 100644 index 00000000000..fa48ec861ed --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-fixture-session.ts @@ -0,0 +1,103 @@ +import { useEffect, useMemo } from "react"; + +import { + crewReservationConversationId, + crewReservationFixtureClientToolNames, +} from "./prepared-crew-reservation-fixture"; +import { workpieceForCrewReservationBundle } from "./resolve-crew-reservation-bundle"; +import { useCrewReservationSettlement } from "./use-crew-reservation-settled-manifest"; +import { usePrepareCrewReservationConversation } from "./use-prepare-crew-reservation-conversation"; + +import type { CrewReservationHistory } from "./crew-reservation-history"; +import type { CrewReservationSettledManifest } from "./crew-reservation-settled-manifest"; +import type { FlueClient } from "@flue/sdk"; +import type { SDCPN } from "@hashintel/petrinaut-core"; + +const clientToolNames: ReadonlySet = new Set( + crewReservationFixtureClientToolNames, +); + +export const crewReservationFixtureConfiguration = { + clientToolNames, + conversationId: crewReservationConversationId, +} as const; + +export const useCrewReservationFixtureSession = (input: { + readonly clientPromise: Promise | null; + readonly definition: SDCPN | undefined; + readonly enabled: boolean; + readonly history: CrewReservationHistory | undefined; + readonly historyError: string | undefined; + readonly persistCoherentSnapshot: (sha256: string, definition: SDCPN) => void; + readonly refreshHistory: () => void; + readonly setSettledManifest: ( + value: + | CrewReservationSettledManifest + | null + | (( + previous: CrewReservationSettledManifest | null, + ) => CrewReservationSettledManifest | null), + ) => void; + readonly settledManifest: CrewReservationSettledManifest | null; + readonly snapshotMissing: boolean; +}) => { + const { + clientPromise, + definition, + enabled, + history, + historyError, + persistCoherentSnapshot, + refreshHistory, + setSettledManifest, + settledManifest, + snapshotMissing, + } = input; + const preparationStatus = usePrepareCrewReservationConversation( + clientPromise, + enabled, + ); + + useEffect(() => { + if ( + preparationStatus.state === "ready" || + preparationStatus.state === "failed" + ) { + refreshHistory(); + } + }, [preparationStatus.state, refreshHistory]); + + const settlementStatus = useCrewReservationSettlement({ + definition: enabled ? definition : undefined, + enabled, + history: enabled ? history : undefined, + historyError: enabled ? historyError : undefined, + persistCoherentSnapshot, + preparationError: + preparationStatus.state === "failed" + ? preparationStatus.error + : undefined, + setSettledManifest, + settledManifest, + snapshotMissing, + }); + + const currentWorkpiece = useMemo(() => { + try { + return workpieceForCrewReservationBundle(history, settledManifest); + } catch { + return undefined; + } + }, [history, settledManifest]); + + return { + currentWorkpiece, + preparationStatus, + settlementStatus, + transportReady: !enabled || preparationStatus.state === "ready", + transportUnavailableReason: + preparationStatus.state === "failed" + ? preparationStatus.error + : "The prepared fixture conversation is still being prepared.", + }; +}; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.test.ts index d36e10ce9bd..2d199f9577c 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.test.ts @@ -2,23 +2,26 @@ * @vitest-environment jsdom */ import { cleanup, renderHook, waitFor } from "@testing-library/react"; -import { afterEach, beforeEach, expect, test } from "vitest"; +import { afterEach, beforeEach, expect, test, vi } from "vitest"; import { - PREPARED_WORKPIECE_AUTHORSHIP, - PREPARED_WORKPIECE_CLAIM_BOUNDARY, - PREPARED_WORKPIECE_SIGNAL_TAG, + preparedWorkpieceAuthorship, + preparedWorkpieceClaimBoundary, + preparedWorkpieceSignalTag, } from "@hashintel/brunch-agent/workpiece"; -import { CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY } from "./crew-reservation-settled-manifest"; +import { crewReservationSettledManifestStorageKey } from "./crew-reservation-settled-manifest"; import { - CREW_RESERVATION_FIXTURE_ID, - DISPATCH_CREW_PLACE_ID, + crewReservationFixtureId, + dispatchCrewPlaceId, preparedCrewReservationNet, preparedCrewReservationWorkpiece, - START_FINAL_INSPECTION_TRANSITION_ID, + startFinalInspectionTransitionId, } from "./prepared-crew-reservation-fixture"; -import { useCrewReservationSettledManifest } from "./use-crew-reservation-settled-manifest"; +import { + useCrewReservationSettlement, + useCrewReservationSettledManifestStorage, +} from "./use-crew-reservation-settled-manifest"; const preparedHistory = { conversationId: "canonical-conversation", @@ -31,11 +34,11 @@ const preparedHistory = { purpose: "dispatch", submissionId: "prepare-submission", signal: { - tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + tagName: preparedWorkpieceSignalTag, attributes: { - fixtureId: CREW_RESERVATION_FIXTURE_ID, - authorship: PREPARED_WORKPIECE_AUTHORSHIP, - claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + fixtureId: crewReservationFixtureId, + authorship: preparedWorkpieceAuthorship, + claimBoundary: preparedWorkpieceClaimBoundary, }, }, parts: [{ type: "text", text: preparedCrewReservationWorkpiece }], @@ -53,30 +56,43 @@ afterEach(() => { }); test("keeps the prior runtime bundle selected while a document write is partial", async () => { + const persistCoherentSnapshot = vi.fn(); const { result, rerender } = renderHook( - ({ definition }: { definition: typeof preparedCrewReservationNet }) => - useCrewReservationSettledManifest({ + ({ definition }: { definition: typeof preparedCrewReservationNet }) => { + const storage = useCrewReservationSettledManifestStorage(); + const status = useCrewReservationSettlement({ definition, enabled: true, history: preparedHistory, historyError: undefined, - }), + persistCoherentSnapshot, + preparationError: undefined, + setSettledManifest: storage.setSettledManifest, + settledManifest: storage.settledManifest, + snapshotMissing: false, + }); + return { ...storage, status }; + }, { initialProps: { definition: preparedCrewReservationNet } }, ); await waitFor(() => expect(result.current.status.state).toBe("settled")); const settledManifest = result.current.settledManifest; expect(settledManifest?.revision).toBe(0); + expect(persistCoherentSnapshot).toHaveBeenCalledWith( + settledManifest?.document.sha256, + preparedCrewReservationNet, + ); const partialDefinition = structuredClone(preparedCrewReservationNet); const startInspection = partialDefinition.transitions.find( - ({ id }) => id === START_FINAL_INSPECTION_TRANSITION_ID, + ({ id }) => id === startFinalInspectionTransitionId, ); if (startInspection === undefined) { throw new Error("Missing prepared start-inspection transition"); } startInspection.inputArcs.push({ - placeId: DISPATCH_CREW_PLACE_ID, + placeId: dispatchCrewPlaceId, type: "standard", weight: 1, }); @@ -86,22 +102,29 @@ test("keeps the prior runtime bundle selected while a document write is partial" expect(result.current.settledManifest).toEqual(settledManifest); expect( JSON.parse( - window.localStorage.getItem( - CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY, - ) ?? "null", + window.localStorage.getItem(crewReservationSettledManifestStorageKey) ?? + "null", ), ).toEqual(settledManifest); }); test("surfaces canonical history failure without publishing a bundle", async () => { - const { result } = renderHook(() => - useCrewReservationSettledManifest({ + const persistCoherentSnapshot = vi.fn(); + const { result } = renderHook(() => { + const storage = useCrewReservationSettledManifestStorage(); + const status = useCrewReservationSettlement({ definition: preparedCrewReservationNet, enabled: true, history: undefined, historyError: "History unavailable.", - }), - ); + persistCoherentSnapshot, + preparationError: undefined, + setSettledManifest: storage.setSettledManifest, + settledManifest: storage.settledManifest, + snapshotMissing: false, + }); + return { ...storage, status }; + }); await waitFor(() => expect(result.current.status.state).toBe("refused")); expect(result.current.status).toEqual({ @@ -111,3 +134,29 @@ test("surfaces canonical history failure without publishing a bundle", async () }); expect(result.current.settledManifest).toBeNull(); }); + +test("distinguishes preparation failure from unavailable history", async () => { + const persistCoherentSnapshot = vi.fn(); + const { result } = renderHook(() => { + const storage = useCrewReservationSettledManifestStorage(); + const status = useCrewReservationSettlement({ + definition: preparedCrewReservationNet, + enabled: true, + history: undefined, + historyError: undefined, + persistCoherentSnapshot, + preparationError: "Provider authentication failed.", + setSettledManifest: storage.setSettledManifest, + settledManifest: storage.settledManifest, + snapshotMissing: false, + }); + return { ...storage, status }; + }); + + expect(result.current.status).toEqual({ + state: "refused", + reason: "preparation-failed", + detail: "Provider authentication failed.", + }); + expect(result.current.settledManifest).toBeNull(); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts index 94ffe2328e9..003cca50400 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts @@ -2,13 +2,13 @@ import { useLocalStorage } from "@mantine/hooks"; import { useEffect, useRef, useState } from "react"; import { - CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY, + crewReservationSettledManifestStorageKey, settleCrewReservationManifest, - type CrewReservationSettledHistory, type CrewReservationSettledManifest, type CrewReservationSettlementResult, } from "./crew-reservation-settled-manifest"; +import type { CrewReservationHistory } from "./crew-reservation-history"; import type { SDCPN } from "@hashintel/petrinaut-core"; export type CrewReservationSettlementStatus = @@ -21,23 +21,52 @@ export type CrewReservationSettlementStatus = CrewReservationSettlementResult, { status: "refused" } >["reason"] + | "bundle-snapshot-unavailable" | "history-unavailable" + | "preparation-failed" | "settlement-failed"; readonly state: "refused"; }; -export const useCrewReservationSettledManifest = (input: { - readonly definition: SDCPN | undefined; - readonly enabled: boolean; - readonly history: CrewReservationSettledHistory | undefined; - readonly historyError: string | undefined; -}) => { +export const useCrewReservationSettledManifestStorage = () => { const [settledManifest, setSettledManifest] = useLocalStorage({ - key: CREW_RESERVATION_SETTLED_MANIFEST_STORAGE_KEY, + key: crewReservationSettledManifestStorageKey, defaultValue: null, getInitialValueInEffect: false, }); + return { settledManifest, setSettledManifest }; +}; + +export const useCrewReservationSettlement = (input: { + readonly definition: SDCPN | undefined; + readonly enabled: boolean; + readonly history: CrewReservationHistory | undefined; + readonly historyError: string | undefined; + readonly persistCoherentSnapshot: (sha256: string, definition: SDCPN) => void; + readonly preparationError: string | undefined; + readonly setSettledManifest: ( + value: + | CrewReservationSettledManifest + | null + | (( + previous: CrewReservationSettledManifest | null, + ) => CrewReservationSettledManifest | null), + ) => void; + readonly settledManifest: CrewReservationSettledManifest | null; + readonly snapshotMissing: boolean; +}) => { + const { + definition, + enabled, + history, + historyError, + persistCoherentSnapshot, + preparationError, + setSettledManifest, + settledManifest, + snapshotMissing, + } = input; const [observedStatus, setObservedStatus] = useState({ state: "preparing" }); const manifestRef = useRef(settledManifest); @@ -52,23 +81,23 @@ export const useCrewReservationSettledManifest = (input: { const observationId = observationIdRef.current + 1; observationIdRef.current = observationId; if ( - !input.enabled || - input.historyError !== undefined || - input.definition === undefined || - input.history === undefined + !enabled || + historyError !== undefined || + definition === undefined || + history === undefined ) { return; } - const definition = structuredClone(input.definition); - const history = input.history; + const definitionSnapshot = structuredClone(definition); + const historySnapshot = history; queueRef.current = queueRef.current.then(async () => { if (observationId !== observationIdRef.current) return; let result: CrewReservationSettlementResult; try { result = await settleCrewReservationManifest({ - definition, - history, + definition: definitionSnapshot, + history: historySnapshot, ...(manifestRef.current === null ? {} : { previous: manifestRef.current }), @@ -95,6 +124,10 @@ export const useCrewReservationSettledManifest = (input: { }); return; } + persistCoherentSnapshot( + result.manifest.document.sha256, + definitionSnapshot, + ); if (result.manifest.manifestId !== manifestRef.current?.manifestId) { manifestRef.current = result.manifest; setSettledManifest(result.manifest); @@ -102,23 +135,36 @@ export const useCrewReservationSettledManifest = (input: { setObservedStatus({ state: "settled" }); }); }, [ - input.definition, - input.enabled, - input.history, - input.historyError, + definition, + enabled, + history, + historyError, + persistCoherentSnapshot, setSettledManifest, ]); - const status: CrewReservationSettlementStatus = !input.enabled + const status: CrewReservationSettlementStatus = !enabled ? { state: "idle" } - : input.historyError !== undefined + : historyError !== undefined ? { state: "refused", reason: "history-unavailable", - detail: input.historyError, + detail: historyError, } - : input.definition === undefined || input.history === undefined - ? { state: "preparing" } - : observedStatus; - return { settledManifest, status }; + : snapshotMissing + ? { + state: "refused", + reason: "bundle-snapshot-unavailable", + } + : preparationError !== undefined && + (definition === undefined || history === undefined) + ? { + state: "refused", + reason: "preparation-failed", + detail: preparationError, + } + : definition === undefined || history === undefined + ? { state: "preparing" } + : observedStatus; + return status; }; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-local-storage-sdcpns.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-local-storage-sdcpns.ts index 12a20fe3376..e8c44be1577 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-local-storage-sdcpns.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-local-storage-sdcpns.ts @@ -5,6 +5,12 @@ import type { SDCPN } from "@hashintel/petrinaut-core"; const rootLocalStorageKey = "petrinaut-sdcpn"; export type SDCPNInLocalStorage = { + /** + * Content-addressed coherent revisions retained by prepared fixtures. The + * live `sdcpn` remains the automatic mirror; these snapshots give a settled + * manifest a concrete document revision to select after a partial write. + */ + coherentSnapshots?: Record; id: string; lastUpdated: string; // ISO timestamp sdcpn: SDCPN; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.test.ts new file mode 100644 index 00000000000..d0d2bdc91c6 --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.test.ts @@ -0,0 +1,31 @@ +/** + * @vitest-environment jsdom + */ +import { renderHook, waitFor } from "@testing-library/react"; +import { expect, test, vi } from "vitest"; + +import { usePrepareCrewReservationConversation } from "./use-prepare-crew-reservation-conversation"; + +import type { FlueClient } from "@flue/sdk"; + +test("reports preparation failure without rejecting the shared client", async () => { + const client = { + history: vi.fn().mockRejectedValue({ status: 404 }), + send: vi.fn().mockResolvedValue({ submissionId: "preparation" }), + wait: vi + .fn() + .mockRejectedValue(new Error("Provider authentication failed")), + } as unknown as FlueClient; + const clientPromise = Promise.resolve(client); + + const { result } = renderHook(() => + usePrepareCrewReservationConversation(clientPromise, true), + ); + + await waitFor(() => expect(result.current.state).toBe("failed")); + expect(result.current).toEqual({ + state: "failed", + error: "Provider authentication failed", + }); + await expect(clientPromise).resolves.toBe(client); +}); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.ts new file mode 100644 index 00000000000..cba89b08b3c --- /dev/null +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.ts @@ -0,0 +1,55 @@ +import { useEffect, useState } from "react"; + +import { prepareCrewReservationConversation } from "./prepare-crew-reservation-conversation"; + +import type { FlueClient } from "@flue/sdk"; + +export type CrewReservationPreparationStatus = + | { readonly state: "idle" | "preparing" | "ready" } + | { readonly error: string; readonly state: "failed" }; + +export const usePrepareCrewReservationConversation = ( + clientPromise: Promise | null, + enabled: boolean, +): CrewReservationPreparationStatus => { + const [observed, setObserved] = useState<{ + readonly clientPromise: Promise; + readonly status: CrewReservationPreparationStatus; + }>(); + + useEffect(() => { + if (!enabled || clientPromise === null) return; + + let cancelled = false; + const prepare = async (): Promise => { + try { + const client = await clientPromise; + await prepareCrewReservationConversation(client); + if (!cancelled) { + setObserved({ clientPromise, status: { state: "ready" } }); + } + } catch (error) { + if (cancelled) return; + setObserved({ + clientPromise, + status: { + state: "failed", + error: + error instanceof Error + ? error.message + : "The prepared conversation could not be initialized.", + }, + }); + } + }; + void prepare(); + return () => { + cancelled = true; + }; + }, [clientPromise, enabled]); + + if (!enabled) return { state: "idle" }; + return observed?.clientPromise === clientPromise + ? observed.status + : { state: "preparing" }; +}; diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md index 9b6f4d47dad..145b4bc08cf 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md @@ -50,8 +50,10 @@ Consequently: - the visible fixture status refused settlement as `history-unavailable` instead of blessing the prepared document alone. -This is the Mission 6 carrier blocker required by the stop rule, not a passing -two-tab witness. No success screenshot was retained. +This is an authentication/environment blocker on the outer witness, not +evidence that the selected provider-visible schema or Flue carrier cannot +faithfully carry the mutation. It is not a passing two-tab witness. No success +screenshot was retained. ## Remaining external checks diff --git a/libs/@hashintel/brunch-agent/packages/core/src/workpiece.ts b/libs/@hashintel/brunch-agent/packages/core/src/workpiece.ts index bd61a63c068..ab1430aa1dc 100644 --- a/libs/@hashintel/brunch-agent/packages/core/src/workpiece.ts +++ b/libs/@hashintel/brunch-agent/packages/core/src/workpiece.ts @@ -3,13 +3,12 @@ * append-only conversation projection. */ -export const PREPARED_WORKPIECE_SIGNAL_TYPE = "brunch.fixture.prepared"; -export const PREPARED_WORKPIECE_SIGNAL_TAG = "prepared-fixture"; -export const PREPARED_WORKPIECE_AUTHORSHIP = "test-authored"; -export const PREPARED_WORKPIECE_CLAIM_BOUNDARY = "prepared-not-model-produced"; -export const PREPARED_WORKPIECE_INITIAL_DATA_MODE = - "validated-fixture-mutation"; -export const RUNBOOK_IR_FENCE = "runbook-ir"; +export const preparedWorkpieceSignalType = "brunch.fixture.prepared"; +export const preparedWorkpieceSignalTag = "prepared-fixture"; +export const preparedWorkpieceAuthorship = "test-authored"; +export const preparedWorkpieceClaimBoundary = "prepared-not-model-produced"; +export const preparedWorkpieceInitialDataMode = "validated-fixture-mutation"; +export const runbookIrFence = "runbook-ir"; type WorkpieceTextPart = { readonly text: string; @@ -42,14 +41,14 @@ export interface PreparedWorkpieceDelivery { readonly idempotencyKey: string; readonly message: { readonly attributes: { - readonly authorship: typeof PREPARED_WORKPIECE_AUTHORSHIP; - readonly claimBoundary: typeof PREPARED_WORKPIECE_CLAIM_BOUNDARY; + readonly authorship: typeof preparedWorkpieceAuthorship; + readonly claimBoundary: typeof preparedWorkpieceClaimBoundary; readonly fixtureId: string; }; readonly body: string; readonly kind: "signal"; - readonly tagName: typeof PREPARED_WORKPIECE_SIGNAL_TAG; - readonly type: typeof PREPARED_WORKPIECE_SIGNAL_TYPE; + readonly tagName: typeof preparedWorkpieceSignalTag; + readonly type: typeof preparedWorkpieceSignalType; }; } @@ -91,10 +90,9 @@ const isPreparedWorkpieceMessage = ( ): boolean => message.role === "system" && message.purpose === "dispatch" && - message.signal?.tagName === PREPARED_WORKPIECE_SIGNAL_TAG && - message.signal.attributes?.authorship === PREPARED_WORKPIECE_AUTHORSHIP && - message.signal.attributes.claimBoundary === - PREPARED_WORKPIECE_CLAIM_BOUNDARY && + message.signal?.tagName === preparedWorkpieceSignalTag && + message.signal.attributes?.authorship === preparedWorkpieceAuthorship && + message.signal.attributes.claimBoundary === preparedWorkpieceClaimBoundary && preparedFixtureIdFrom(message) !== undefined; const selectedFrom = ( @@ -130,16 +128,16 @@ export const createPreparedWorkpieceDelivery = (input: { } return { - idempotencyKey: `${PREPARED_WORKPIECE_SIGNAL_TAG}:${input.fixtureId}:revision-${input.revision}`, + idempotencyKey: `${preparedWorkpieceSignalTag}:${input.fixtureId}:revision-${input.revision}`, message: { kind: "signal", - type: PREPARED_WORKPIECE_SIGNAL_TYPE, - tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + type: preparedWorkpieceSignalType, + tagName: preparedWorkpieceSignalTag, body: input.body, attributes: { fixtureId: input.fixtureId, - authorship: PREPARED_WORKPIECE_AUTHORSHIP, - claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + authorship: preparedWorkpieceAuthorship, + claimBoundary: preparedWorkpieceClaimBoundary, }, }, }; @@ -154,7 +152,7 @@ export const selectRunbookWorkpiece = ( history: WorkpieceHistory, ): SelectedRunbookWorkpiece | undefined => { const preparedCandidates = history.messages.filter( - (message) => message.signal?.tagName === PREPARED_WORKPIECE_SIGNAL_TAG, + (message) => message.signal?.tagName === preparedWorkpieceSignalTag, ); if (preparedCandidates.length > 1) { throw new Error( @@ -178,7 +176,7 @@ export const selectRunbookWorkpiece = ( for (const message of history.messages) { if (message === preparedMessage) { const preparedWorkpiece = selectedFrom(message, { - authorship: PREPARED_WORKPIECE_AUTHORSHIP, + authorship: preparedWorkpieceAuthorship, sourceKind: "prepared-signal", }); if (preparedWorkpiece === undefined) { diff --git a/libs/@hashintel/brunch-agent/packages/core/test/workpiece.test.ts b/libs/@hashintel/brunch-agent/packages/core/test/workpiece.test.ts index 7b3c6f452d8..bb4ff0ffea0 100644 --- a/libs/@hashintel/brunch-agent/packages/core/test/workpiece.test.ts +++ b/libs/@hashintel/brunch-agent/packages/core/test/workpiece.test.ts @@ -2,9 +2,9 @@ import { describe, expect, test } from "vitest"; import { createPreparedWorkpieceDelivery, - PREPARED_WORKPIECE_AUTHORSHIP, - PREPARED_WORKPIECE_CLAIM_BOUNDARY, - PREPARED_WORKPIECE_SIGNAL_TAG, + preparedWorkpieceAuthorship, + preparedWorkpieceClaimBoundary, + preparedWorkpieceSignalTag, selectRunbookWorkpiece, type WorkpieceHistory, type WorkpieceHistoryMessage, @@ -22,10 +22,10 @@ const preparedMessage = ( purpose: "dispatch", submissionId, signal: { - tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + tagName: preparedWorkpieceSignalTag, attributes: { - authorship: PREPARED_WORKPIECE_AUTHORSHIP, - claimBoundary: PREPARED_WORKPIECE_CLAIM_BOUNDARY, + authorship: preparedWorkpieceAuthorship, + claimBoundary: preparedWorkpieceClaimBoundary, fixtureId: "crew-reservation-v1", }, }, @@ -154,7 +154,7 @@ describe("selectRunbookWorkpiece", () => { { ...preparedMessage(), signal: { - tagName: PREPARED_WORKPIECE_SIGNAL_TAG, + tagName: preparedWorkpieceSignalTag, attributes: { authorship: "model-produced" }, }, }, diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts index 5e106589f7f..6afa49c5ef0 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts @@ -6,7 +6,7 @@ import { } from "@flue/runtime"; import * as v from "valibot"; -import { PREPARED_WORKPIECE_INITIAL_DATA_MODE } from "@hashintel/brunch-agent/workpiece"; +import { preparedWorkpieceInitialDataMode } from "@hashintel/brunch-agent/workpiece"; import sdcpnAppend from "./prompts/APPEND_SYSTEM.md?raw"; import { @@ -23,14 +23,13 @@ import { } from "./tools/read-petrinaut-doc"; export const VALIDATED_CONSTRUCTION_MODE = "validated-construction"; -export const VALIDATED_FIXTURE_MUTATION_MODE = - PREPARED_WORKPIECE_INITIAL_DATA_MODE; +export const validatedFixtureMutationMode = preparedWorkpieceInitialDataMode; export const sdcpnInitialDataSchema = v.optional( v.object({ mode: v.picklist([ VALIDATED_CONSTRUCTION_MODE, - VALIDATED_FIXTURE_MUTATION_MODE, + validatedFixtureMutationMode, ]), }), ); @@ -54,7 +53,7 @@ This is a construct-only headless conversation. Use only the supplied runbook IR for (const constructionTool of petrinautConstructionTools) { useTool(constructionTool); } - } else if (initialData?.mode === VALIDATED_FIXTURE_MUTATION_MODE) { + } else if (initialData?.mode === validatedFixtureMutationMode) { useInstruction( ` This is a visibly labelled prepared-fixture conversation. Treat its tagged prepared runbook-ir dispatch as test-authored revision zero, maintain the full Markdown workpiece in later responses, preserve explicit unknowns, and do not relabel prepared material as model-produced. Use only the mounted canonical Petrinaut read and least arc mutation when confirmed evidence calls for that change. Read the live document before mutating it, report rejected or no-op outcomes honestly, and do not construct unrelated net content. @@ -70,7 +69,7 @@ export { READ_PETRINAUT_DOC_TOOL_NAME, readPetrinautDoc }; export { SDCPN_MODELLING_SKILL_NAME }; export { PETRINAUT_CONSTRUCTION_TOOL_NAMES, - PETRINAUT_FIXTURE_TOOL_NAMES, + petrinautFixtureToolNames, petrinautConstructionTools, petrinautFixtureTools, type PetrinautConstructionToolName, diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts index 41167c67c23..42e5f49f57c 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts @@ -13,13 +13,14 @@ export const PETRINAUT_CONSTRUCTION_TOOL_NAMES = [ "addArc", ] as const satisfies readonly (keyof typeof petrinautAiTools)[]; -export const PETRINAUT_FIXTURE_TOOL_NAMES = [ +export const petrinautFixtureToolNames = [ "getLatestNetDefinition", "addArc", ] as const satisfies readonly (keyof typeof petrinautAiTools)[]; export type PetrinautConstructionToolName = (typeof PETRINAUT_CONSTRUCTION_TOOL_NAMES)[number]; +type PetrinautFixtureToolName = (typeof petrinautFixtureToolNames)[number]; const issuePathFrom = ( input: Record, @@ -97,6 +98,15 @@ export const petrinautConstructionTools = PETRINAUT_CONSTRUCTION_TOOL_NAMES.map( definePetrinautConstructionTool, ); -export const petrinautFixtureTools = PETRINAUT_FIXTURE_TOOL_NAMES.map( - definePetrinautConstructionTool, +const isPetrinautFixtureTool = ( + tool: (typeof petrinautConstructionTools)[number], +): tool is (typeof petrinautConstructionTools)[number] & { + readonly name: PetrinautFixtureToolName; +} => + petrinautFixtureToolNames.some((fixtureToolName) => { + return fixtureToolName === tool.name; + }); + +export const petrinautFixtureTools = petrinautConstructionTools.filter( + isPetrinautFixtureTool, ); diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts index e259a3fa77b..95bd7df500d 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts @@ -6,11 +6,11 @@ import { petrinautAiTools } from "@hashintel/petrinaut-core/ai"; import { sdcpnInitialDataSchema, VALIDATED_CONSTRUCTION_MODE, - VALIDATED_FIXTURE_MUTATION_MODE, + validatedFixtureMutationMode, } from "../src/flue"; import { PETRINAUT_CONSTRUCTION_TOOL_NAMES, - PETRINAUT_FIXTURE_TOOL_NAMES, + petrinautFixtureToolNames, petrinautConstructionTools, petrinautFixtureTools, } from "../src/tools/petrinaut-construction"; @@ -34,9 +34,9 @@ describe("Petrinaut construction tools", () => { ).toEqual({ mode: VALIDATED_CONSTRUCTION_MODE }); expect( v.parse(sdcpnInitialDataSchema, { - mode: VALIDATED_FIXTURE_MUTATION_MODE, + mode: validatedFixtureMutationMode, }), - ).toEqual({ mode: VALIDATED_FIXTURE_MUTATION_MODE }); + ).toEqual({ mode: validatedFixtureMutationMode }); expect(() => v.parse(sdcpnInitialDataSchema, { mode: "unrestricted-construction", @@ -52,7 +52,7 @@ describe("Petrinaut construction tools", () => { test("limits prepared fixtures to one canonical read and arc mutation", () => { expect(petrinautFixtureTools.map((tool) => tool.name)).toEqual([ - ...PETRINAUT_FIXTURE_TOOL_NAMES, + ...petrinautFixtureToolNames, ]); }); diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/client-tool-history.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/client-tool-history.ts new file mode 100644 index 00000000000..114150c2f83 --- /dev/null +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/client-tool-history.ts @@ -0,0 +1,104 @@ +import { CLIENT_TOOL_RESULT_SIGNAL } from "./client-tool-result"; + +export interface ClientToolHistoryCall { + readonly input: Readonly>; + readonly toolCallId: string; + readonly toolName: string; +} + +export interface ClientToolHistoryResult { + readonly output: unknown; + readonly toolCallId: string; + readonly toolName: string; +} + +export interface ClientToolHistory { + readonly calls: readonly ClientToolHistoryCall[]; + readonly results: readonly ClientToolHistoryResult[]; +} + +export interface ClientToolHistoryMessage { + readonly parts: readonly unknown[]; + readonly signal?: { + readonly tagName?: string; + readonly type?: string; + }; +} + +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null; + +const callsFrom = ( + messages: readonly ClientToolHistoryMessage[], +): readonly ClientToolHistoryCall[] => + messages.flatMap((message) => + message.parts.flatMap((part) => { + if ( + !isRecord(part) || + part.type !== "dynamic-tool" || + typeof part.toolName !== "string" || + typeof part.toolCallId !== "string" || + !isRecord(part.input) + ) { + return []; + } + return [ + { + input: part.input, + toolCallId: part.toolCallId, + toolName: part.toolName, + }, + ]; + }), + ); + +const resultsFrom = ( + messages: readonly ClientToolHistoryMessage[], +): readonly ClientToolHistoryResult[] => + messages.flatMap((message) => { + if ( + message.signal?.tagName !== CLIENT_TOOL_RESULT_SIGNAL && + message.signal?.type !== CLIENT_TOOL_RESULT_SIGNAL + ) { + return []; + } + + const body = message.parts + .flatMap((part) => + isRecord(part) && part.type === "text" && typeof part.text === "string" + ? [part.text] + : [], + ) + .join(""); + + try { + const parsed: unknown = JSON.parse(body); + if (!Array.isArray(parsed)) return []; + return parsed.flatMap((result) => { + if ( + !isRecord(result) || + typeof result.toolName !== "string" || + typeof result.toolCallId !== "string" || + !("output" in result) + ) { + return []; + } + return [ + { + output: result.output, + toolCallId: result.toolCallId, + toolName: result.toolName, + }, + ]; + }); + } catch { + return []; + } + }); + +export const clientToolHistoryFrom = ( + messages: readonly ClientToolHistoryMessage[], +): ClientToolHistory => ({ + calls: callsFrom(messages), + results: resultsFrom(messages), +}); diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts index 336824e5a1a..d6160023d9d 100644 --- a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts @@ -7,6 +7,13 @@ import { createFlueUiStream } from "./ui-stream"; import type { AgentSendResult, DeliveredMessage, FlueClient } from "@flue/sdk"; import type { ChatTransport, UIMessage, UIMessageChunk } from "ai"; +export { + clientToolHistoryFrom, + type ClientToolHistory, + type ClientToolHistoryCall, + type ClientToolHistoryMessage, + type ClientToolHistoryResult, +} from "./client-tool-history"; export { BRUNCH_CONVERSATION_HEADER, BRUNCH_PRINCIPAL_HEADER } from "./headers"; export { CLIENT_TOOL_RESULT_SIGNAL } from "./client-tool-result"; export { diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/client-tool-history.test.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/client-tool-history.test.ts new file mode 100644 index 00000000000..bfc3abd64c8 --- /dev/null +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/client-tool-history.test.ts @@ -0,0 +1,64 @@ +import { describe, expect, test } from "vitest"; + +import { CLIENT_TOOL_RESULT_SIGNAL, clientToolHistoryFrom } from "../src/index"; + +describe("clientToolHistoryFrom", () => { + test("projects generic calls and correlated client result envelopes", () => { + expect( + clientToolHistoryFrom([ + { + parts: [ + { + type: "dynamic-tool", + toolName: "addArc", + toolCallId: "call-1", + input: { placeId: "place-1" }, + }, + ], + }, + { + signal: { tagName: CLIENT_TOOL_RESULT_SIGNAL }, + parts: [ + { + type: "text", + text: JSON.stringify([ + { + toolName: "addArc", + toolCallId: "call-1", + output: { applied: true }, + }, + ]), + }, + ], + }, + ]), + ).toEqual({ + calls: [ + { + input: { placeId: "place-1" }, + toolCallId: "call-1", + toolName: "addArc", + }, + ], + results: [ + { + output: { applied: true }, + toolCallId: "call-1", + toolName: "addArc", + }, + ], + }); + }); + + test("ignores malformed calls and result bodies", () => { + expect( + clientToolHistoryFrom([ + { parts: [{ type: "dynamic-tool", toolName: "addArc" }] }, + { + signal: { type: CLIENT_TOOL_RESULT_SIGNAL }, + parts: [{ type: "text", text: "not-json" }], + }, + ]), + ).toEqual({ calls: [], results: [] }); + }); +}); From d93ca8e889c5251c63040ce554018059c3c4c730 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 10:13:35 +0200 Subject: [PATCH 07/31] Normalize provider inputs for Petrinaut client tools Co-authored-by: Cursor --- .../brunch-panel-transport.ts | 7 ++++ .../crew-reservation-settled-manifest.test.ts | 27 ++++++++++--- .../crew-reservation-settled-manifest.ts | 34 ++++++++++------- .../local-storage-demo-app.tsx | 17 ++++++--- .../use-crew-reservation-fixture-session.ts | 20 +++++++++- .../use-flue-chat-history.ts | 17 ++++++++- ...pare-crew-reservation-conversation.test.ts | 7 +++- ...e-prepare-crew-reservation-conversation.ts | 38 +++++++++++++------ .../src/tools/petrinaut-construction.ts | 14 ++++++- .../test/construction-tools.test.ts | 13 +++++++ .../packages/transport-aisdk/src/index.ts | 5 +++ .../transport-aisdk/src/transcript.ts | 25 ++++++++---- .../packages/transport-aisdk/src/ui-stream.ts | 12 +++++- .../transport-aisdk/test/ui-stream.test.ts | 34 +++++++++++++++++ libs/@hashintel/petrinaut-core/src/ai.test.ts | 16 ++++++++ libs/@hashintel/petrinaut-core/src/ai.ts | 29 ++++++++++++++ 16 files changed, 263 insertions(+), 52 deletions(-) diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts index 8e28759287d..3e289ff7bcb 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/brunch-panel-transport.ts @@ -236,6 +236,10 @@ export const createBrunchPanelTransport = ( options?: { /** Fixture-scoped client tools; defaults to the Petrinaut docs reader alone. */ readonly clientToolNames?: ReadonlySet; + readonly mapClientToolInput?: (input: { + readonly input: unknown; + readonly toolName: string; + }) => unknown; readonly onAdmission?: (admission: AgentSendResult) => void; }, ): PetrinautAiChatTransport => ({ @@ -247,6 +251,9 @@ export const createBrunchPanelTransport = ( const transport = createFlueChatTransport({ client, clientToolNames: options?.clientToolNames ?? brunchClientToolNames, + ...(options?.mapClientToolInput === undefined + ? {} + : { mapClientToolInput: options.mapClientToolInput }), onAdmission: (event) => { tracker.recordAdmission(event); options?.onAdmission?.(event.admission); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts index ab6d5a6a626..ddb0f5396c9 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.test.ts @@ -49,10 +49,9 @@ const settledHistory = ( settlements: [{ submissionId: "prepare-submission", outcome: "completed" }], }); -const targetMutationMessages = (): readonly [ - WorkpieceHistoryMessage, - WorkpieceHistoryMessage, -] => [ +const targetMutationMessages = ( + toolCallId = "target-arc-call", +): readonly [WorkpieceHistoryMessage, WorkpieceHistoryMessage] => [ { id: "target-mutation-request", role: "assistant", @@ -61,7 +60,7 @@ const targetMutationMessages = (): readonly [ parts: [ { type: "dynamic-tool", - toolCallId: "target-arc-call", + toolCallId, toolName: "addArc", input: { transitionId: startFinalInspectionTransitionId, @@ -85,7 +84,7 @@ const targetMutationMessages = (): readonly [ type: "text", text: JSON.stringify([ { - toolCallId: "target-arc-call", + toolCallId, toolName: "addArc", output: { applied: true }, }, @@ -276,6 +275,22 @@ describe("crew-reservation settled manifest", () => { }, settledAt: "2026-09-03T12:05:00.000Z", }), + ).resolves.toMatchObject({ status: "settled" }); + + await expect( + settleCrewReservationManifest({ + definition: revisedDefinition, + history: { + ...history, + messages: [ + preparedMessage, + ...targetMutationMessages(), + ...targetMutationMessages("second-target-arc-call"), + revisedMessage, + ], + }, + settledAt: "2026-09-03T12:05:00.000Z", + }), ).resolves.toEqual({ status: "refused", reason: "missing-correlated-mutation", diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts index 01767ed99a4..d94d5111314 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts @@ -1,6 +1,7 @@ import { clientToolHistoryFrom } from "@hashintel/brunch-agent-transport-aisdk"; import { selectRunbookWorkpiece } from "@hashintel/brunch-agent/workpiece"; import { isSDCPNEqual, type SDCPN } from "@hashintel/petrinaut-core"; +import { normalizePetrinautAiToolInput } from "@hashintel/petrinaut-core/ai"; import { crewReservationConversationId, @@ -41,6 +42,9 @@ export const asManifestId = (value: string): ManifestId => value as ManifestId; export const asSha256Digest = (value: string): Sha256Digest => value as Sha256Digest; +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null; + export interface CrewReservationSettledManifest { readonly conversation: { readonly canonicalId: CanonicalConversationId; @@ -86,15 +90,17 @@ const targetMutationCallIds = ( history: CrewReservationHistory, ): readonly string[] => { const { calls } = clientToolHistoryFrom(history.messages); - return calls.flatMap(({ input, toolCallId, toolName }) => - toolName === "addArc" && - input.transitionId === startFinalInspectionTransitionId && - input.arcDirection === "input" && - input.placeId === dispatchCrewPlaceId && - input.weight === 1 + return calls.flatMap(({ input, toolCallId, toolName }) => { + if (toolName !== "addArc") return []; + const normalizedInput = normalizePetrinautAiToolInput("addArc", input); + return isRecord(normalizedInput) && + normalizedInput.transitionId === startFinalInspectionTransitionId && + normalizedInput.arcDirection === "input" && + normalizedInput.placeId === dispatchCrewPlaceId && + normalizedInput.weight === 1 ? [toolCallId] - : [], - ); + : []; + }); }; const successfulMutationResultIds = ( @@ -115,13 +121,13 @@ const successfulMutationResultIds = ( const hasOneCorrelatedTargetMutation = ( history: CrewReservationHistory, ): boolean => { - const targetCallIds = targetMutationCallIds(history); - const successfulResultIds = successfulMutationResultIds(history); - return ( - targetCallIds.length === 1 && - successfulResultIds.length === 1 && - targetCallIds[0] === successfulResultIds[0] + const successfulResultIds = new Set(successfulMutationResultIds(history)); + const correlatedTargetCallIds = new Set( + targetMutationCallIds(history).filter((toolCallId) => + successfulResultIds.has(toolCallId), + ), ); + return correlatedTargetCallIds.size === 1; }; const sha256 = async (value: string): Promise => { diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx b/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx index 34a8de13119..1bf304f08f6 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx @@ -589,6 +589,7 @@ export const LocalStorageDemoApp = ({ flueClientPromise, conversationId ?? "", fixtureConfiguration?.clientToolNames, + fixtureConfiguration?.mapClientToolInput, ); const brunchVoiceMode = useMemo( () => @@ -611,15 +612,22 @@ export const LocalStorageDemoApp = ({ settledManifest, snapshotMissing: crewReservationBundle?.snapshotMissing ?? false, }); + const transportClientPromise = + fixtureConfiguration === undefined + ? flueClientPromise + : crewReservationSession.transportClientPromise; const petrinautAiChatTransport = useMemo(() => { - if (flueClientPromise !== null && crewReservationSession.transportReady) { + if (transportClientPromise !== null) { return createBrunchPanelTransport( - flueClientPromise, + transportClientPromise, conversationTracker, { ...(fixtureConfiguration === undefined ? {} - : { clientToolNames: fixtureConfiguration.clientToolNames }), + : { + clientToolNames: fixtureConfiguration.clientToolNames, + mapClientToolInput: fixtureConfiguration.mapClientToolInput, + }), onAdmission: flueHistory.refresh, }, ); @@ -631,11 +639,10 @@ export const LocalStorageDemoApp = ({ : stockChatTransport; }, [ conversationTracker, - crewReservationSession.transportReady, crewReservationSession.transportUnavailableReason, fixtureConfiguration, - flueClientPromise, flueHistory.refresh, + transportClientPromise, ]); const aiAssistant = useMemo( diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-fixture-session.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-fixture-session.ts index fa48ec861ed..415c58f9e5a 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-fixture-session.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-fixture-session.ts @@ -1,5 +1,10 @@ import { useEffect, useMemo } from "react"; +import { + getLatestNetDefinitionToolName, + normalizePetrinautAiToolInput, +} from "@hashintel/petrinaut-core/ai"; + import { crewReservationConversationId, crewReservationFixtureClientToolNames, @@ -20,6 +25,16 @@ const clientToolNames: ReadonlySet = new Set( export const crewReservationFixtureConfiguration = { clientToolNames, conversationId: crewReservationConversationId, + mapClientToolInput: ({ + input, + toolName, + }: { + readonly input: unknown; + readonly toolName: string; + }) => + toolName === "addArc" || toolName === getLatestNetDefinitionToolName + ? normalizePetrinautAiToolInput(toolName, input) + : input, } as const; export const useCrewReservationFixtureSession = (input: { @@ -53,10 +68,11 @@ export const useCrewReservationFixtureSession = (input: { settledManifest, snapshotMissing, } = input; - const preparationStatus = usePrepareCrewReservationConversation( + const preparation = usePrepareCrewReservationConversation( clientPromise, enabled, ); + const preparationStatus = preparation.status; useEffect(() => { if ( @@ -94,7 +110,7 @@ export const useCrewReservationFixtureSession = (input: { currentWorkpiece, preparationStatus, settlementStatus, - transportReady: !enabled || preparationStatus.state === "ready", + transportClientPromise: preparation.clientPromise, transportUnavailableReason: preparationStatus.state === "failed" ? preparationStatus.error diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts index a8348381255..075545ea8e6 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-flue-chat-history.ts @@ -28,17 +28,28 @@ export type FlueHistorySnapshot = FlueConversationState & { const projectPetrinautMessages = ( conversation: FlueConversationState, clientToolNames: ReadonlySet, + mapClientToolInput: + | ((input: { + readonly input: unknown; + readonly toolName: string; + }) => unknown) + | undefined, ): PetrinautAiMessage[] => // The host owns this narrowing: its configured client-tool catalog is the // same catalog Petrinaut's message type exposes. snapshotToUiMessages(conversation, { clientToolNames, + ...(mapClientToolInput === undefined ? {} : { mapClientToolInput }), }) as PetrinautAiMessage[]; export const useFlueChatHistory = ( clientPromise: Promise | null, conversationId: string, clientToolNames: ReadonlySet = brunchClientToolNames, + mapClientToolInput?: (input: { + readonly input: unknown; + readonly toolName: string; + }) => unknown, ): { readonly error: Error | undefined; readonly latestSettlement: FlueConversationSettlement | undefined; @@ -118,7 +129,11 @@ export const useFlueChatHistory = ( ? absent ? [] : undefined - : projectPetrinautMessages(conversation, clientToolNames), + : projectPetrinautMessages( + conversation, + clientToolNames, + mapClientToolInput, + ), phase: observation?.phase, ready, refresh, diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.test.ts index d0d2bdc91c6..1d71f49b9b8 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.test.ts @@ -22,10 +22,13 @@ test("reports preparation failure without rejecting the shared client", async () usePrepareCrewReservationConversation(clientPromise, true), ); - await waitFor(() => expect(result.current.state).toBe("failed")); - expect(result.current).toEqual({ + await waitFor(() => expect(result.current.status.state).toBe("failed")); + expect(result.current.status).toEqual({ state: "failed", error: "Provider authentication failed", }); await expect(clientPromise).resolves.toBe(client); + await expect(result.current.clientPromise).rejects.toThrow( + "Provider authentication failed", + ); }); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.ts index cba89b08b3c..6b66fa2de3a 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-prepare-crew-reservation-conversation.ts @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { prepareCrewReservationConversation } from "./prepare-crew-reservation-conversation"; @@ -11,27 +11,39 @@ export type CrewReservationPreparationStatus = export const usePrepareCrewReservationConversation = ( clientPromise: Promise | null, enabled: boolean, -): CrewReservationPreparationStatus => { +): { + readonly clientPromise: Promise | null; + readonly status: CrewReservationPreparationStatus; +} => { + const preparedClientPromise = useMemo(() => { + if (!enabled || clientPromise === null) return clientPromise; + return clientPromise.then(async (client) => { + await prepareCrewReservationConversation(client); + return client; + }); + }, [clientPromise, enabled]); const [observed, setObserved] = useState<{ readonly clientPromise: Promise; readonly status: CrewReservationPreparationStatus; }>(); useEffect(() => { - if (!enabled || clientPromise === null) return; + if (!enabled || preparedClientPromise === null) return; let cancelled = false; const prepare = async (): Promise => { try { - const client = await clientPromise; - await prepareCrewReservationConversation(client); + await preparedClientPromise; if (!cancelled) { - setObserved({ clientPromise, status: { state: "ready" } }); + setObserved({ + clientPromise: preparedClientPromise, + status: { state: "ready" }, + }); } } catch (error) { if (cancelled) return; setObserved({ - clientPromise, + clientPromise: preparedClientPromise, status: { state: "failed", error: @@ -46,10 +58,12 @@ export const usePrepareCrewReservationConversation = ( return () => { cancelled = true; }; - }, [clientPromise, enabled]); + }, [enabled, preparedClientPromise]); - if (!enabled) return { state: "idle" }; - return observed?.clientPromise === clientPromise - ? observed.status - : { state: "preparing" }; + const status: CrewReservationPreparationStatus = !enabled + ? { state: "idle" } + : observed?.clientPromise === preparedClientPromise + ? observed.status + : { state: "preparing" }; + return { clientPromise: preparedClientPromise, status }; }; diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts index 42e5f49f57c..78c4b1f606b 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/tools/petrinaut-construction.ts @@ -2,7 +2,10 @@ import { defineTool } from "@flue/runtime"; import * as v from "valibot"; import { AWAITING_CLIENT } from "@hashintel/brunch-agent/client-tools"; -import { petrinautAiTools } from "@hashintel/petrinaut-core/ai"; +import { + normalizePetrinautAiToolInput, + petrinautAiTools, +} from "@hashintel/petrinaut-core/ai"; export const PETRINAUT_CONSTRUCTION_TOOL_NAMES = [ "getLatestNetDefinition", @@ -52,15 +55,22 @@ const canonicalInputFor = (toolName: PetrinautConstructionToolName) => { return { description: [ canonicalTool.description, + ...(toolName === "addArc" + ? [ + "A finite numeric-string weight is normalized to a number before canonical validation.", + ] + : []), "Canonical Petrinaut input JSON Schema:", JSON.stringify(jsonSchema), ].join("\n"), schema: v.pipe( v.looseObject({}), v.rawTransform((context) => { - const parsed = canonicalTool.inputSchema.safeParse( + const normalizedInput = normalizePetrinautAiToolInput( + toolName, context.dataset.value, ); + const parsed = canonicalTool.inputSchema.safeParse(normalizedInput); if (parsed.success) return parsed.data; for (const issue of parsed.error.issues) { diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts index 95bd7df500d..ce2da8f9260 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts @@ -87,6 +87,19 @@ describe("Petrinaut construction tools", () => { ); }); + test("normalizes a finite provider numeric-string arc weight", () => { + const addArc = toolByName("addArc"); + const result = v.parse(addArc.input!, { + transitionId: "transition", + arcDirection: "input", + placeId: "place", + weight: "1", + type: "standard", + }); + + expect(result).toMatchObject({ weight: 1 }); + }); + test("retains nested values in canonical validation paths", () => { const addType = toolByName("addType"); const invalidElement = { diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts index d6160023d9d..573dd5d2647 100644 --- a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts @@ -38,6 +38,10 @@ export interface ClientToolResult { export interface FlueChatTransportOptions { readonly client: FlueClient; readonly clientToolNames: ReadonlySet; + readonly mapClientToolInput?: (input: { + readonly input: unknown; + readonly toolName: string; + }) => unknown; readonly onAdmission?: (event: { readonly admission: AgentSendResult; readonly kind: "client-tool-result" | "user"; @@ -210,6 +214,7 @@ const streamSubmission = ( const projector = createFlueUiStream({ submissionId: admission.submissionId, clientToolNames: options.clientToolNames, + mapClientToolInput: options.mapClientToolInput, write, }); diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/transcript.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/transcript.ts index 089fc3dd4bc..49ca746eb7a 100644 --- a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/transcript.ts +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/transcript.ts @@ -19,6 +19,10 @@ export type UiHistoryMessage = Omit< export interface SnapshotToUiMessagesOptions { readonly clientToolNames: ReadonlySet; + readonly mapClientToolInput?: (input: { + readonly input: unknown; + readonly toolName: string; + }) => unknown; } const unhandledConversationPart = (part: never): never => { @@ -71,17 +75,24 @@ const clientToolResultsFrom = ( const toolPartFrom = ( part: Extract, - clientToolNames: ReadonlySet, + options: SnapshotToUiMessagesOptions, clientOutputs: ReadonlyMap, ): UiMessagePart => { - const isClientTool = clientToolNames.has(part.toolName); + const isClientTool = options.clientToolNames.has(part.toolName); const hasClientOutput = clientOutputs.has(part.toolCallId); + const input = + isClientTool && options.mapClientToolInput !== undefined + ? options.mapClientToolInput({ + input: part.input, + toolName: part.toolName, + }) + : part.input; if (part.state === "output-error") { return { type: `tool-${part.toolName}`, toolCallId: part.toolCallId, state: "output-error", - input: part.input, + input, errorText: part.errorText, ...(isClientTool ? {} : { providerExecuted: true }), }; @@ -91,7 +102,7 @@ const toolPartFrom = ( type: `tool-${part.toolName}`, toolCallId: part.toolCallId, state: "input-available", - input: part.input, + input, }; } const output = isClientTool @@ -104,7 +115,7 @@ const toolPartFrom = ( type: `tool-${part.toolName}`, toolCallId: part.toolCallId, state: "output-available", - input: part.input, + input, output, ...(isClientTool ? {} : { providerExecuted: true }), }; @@ -113,7 +124,7 @@ const toolPartFrom = ( type: `tool-${part.toolName}`, toolCallId: part.toolCallId, state: "input-available", - input: part.input, + input, ...(isClientTool ? {} : { providerExecuted: true }), }; }; @@ -134,7 +145,7 @@ const partsFrom = ( continue; } if (part.type === "dynamic-tool") { - parts.push(toolPartFrom(part, options.clientToolNames, clientOutputs)); + parts.push(toolPartFrom(part, options, clientOutputs)); continue; } if (part.type === "file") { diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/ui-stream.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/ui-stream.ts index 7270be320b2..a24f3398868 100644 --- a/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/ui-stream.ts +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/ui-stream.ts @@ -4,6 +4,10 @@ import type { UIMessageChunk } from "ai"; export interface FlueUiStreamOptions { readonly submissionId: AgentSendResult["submissionId"]; readonly clientToolNames: ReadonlySet; + readonly mapClientToolInput?: (input: { + readonly input: unknown; + readonly toolName: string; + }) => unknown; readonly write: (chunk: UIMessageChunk) => void; } @@ -129,7 +133,13 @@ export const createFlueUiStream = ( type: "tool-input-available", toolCallId: chunk.toolCallId, toolName: chunk.toolName, - input: chunk.input, + input: + isClientTool && options.mapClientToolInput !== undefined + ? options.mapClientToolInput({ + input: chunk.input, + toolName: chunk.toolName, + }) + : chunk.input, ...(isClientTool ? {} : { providerExecuted: true }), }); return; diff --git a/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/ui-stream.test.ts b/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/ui-stream.test.ts index c567fcd9b38..ce905e9dce1 100644 --- a/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/ui-stream.test.ts +++ b/libs/@hashintel/brunch-agent/packages/transport-aisdk/test/ui-stream.test.ts @@ -118,3 +118,37 @@ test("ignores observation catch-up chunks in a submission stream", () => { "finish", ]); }); + +test("maps client-tool input before exposing it to the AI SDK", () => { + const written: UIMessageChunk[] = []; + const projector = createFlueUiStream({ + submissionId: "submission-1", + clientToolNames: new Set(["addArc"]), + mapClientToolInput: ({ input }) => ({ ...(input as object), weight: 1 }), + write: (chunk) => written.push(chunk), + }); + projector.accept({ + type: "message-started", + conversationId: "conversation-1", + messageId: "message-1", + submissionId: "submission-1", + turnId: "turn-1", + position: position(0), + }); + projector.accept({ + type: "tool-input", + conversationId: "conversation-1", + messageId: "message-1", + toolCallId: "call-1", + toolName: "addArc", + input: { weight: "1" }, + position: position(1), + }); + + expect(written).toContainEqual({ + type: "tool-input-available", + toolCallId: "call-1", + toolName: "addArc", + input: { weight: 1 }, + }); +}); diff --git a/libs/@hashintel/petrinaut-core/src/ai.test.ts b/libs/@hashintel/petrinaut-core/src/ai.test.ts index 26f38c743e1..124bed1dfb1 100644 --- a/libs/@hashintel/petrinaut-core/src/ai.test.ts +++ b/libs/@hashintel/petrinaut-core/src/ai.test.ts @@ -5,6 +5,7 @@ import { aiCommandActionInputSchemas, createPetrinautAiWritableCallbacks, getLatestNetDefinitionToolName, + normalizePetrinautAiToolInput, petrinautAiPrompt, petrinautAiToolInputSchemas, petrinautAiTools, @@ -46,6 +47,21 @@ describe("Petrinaut AI core exports", () => { expect(petrinautAiTools).toHaveProperty("applyAutoLayout"); }); + test("normalizes structured addArc values from text-oriented providers", () => { + expect( + normalizePetrinautAiToolInput("addArc", { + transitionId: "transition", + arcDirection: "input", + weight: "1", + type: "standard", + endpoint: '{"kind":"place","placeId":"place"}', + }), + ).toMatchObject({ + weight: 1, + endpoint: { kind: "place", placeId: "place" }, + }); + }); + test("latest net definition tool documents extension settings", () => { expect( petrinautAiTools[getLatestNetDefinitionToolName].description, diff --git a/libs/@hashintel/petrinaut-core/src/ai.ts b/libs/@hashintel/petrinaut-core/src/ai.ts index 2e3f1bc5397..eb33fc43b3b 100644 --- a/libs/@hashintel/petrinaut-core/src/ai.ts +++ b/libs/@hashintel/petrinaut-core/src/ai.ts @@ -213,6 +213,35 @@ export type PetrinautAiToolInput = z.input< (typeof petrinautAiTools)[Name]["inputSchema"] >; +const isRecord = (value: unknown): value is Record => + typeof value === "object" && value !== null; + +/** + * Normalize the narrow structured values that text-oriented providers may + * serialize before applying the canonical Petrinaut tool schema. + */ +export const normalizePetrinautAiToolInput = ( + toolName: PetrinautAiToolName, + input: unknown, +): unknown => { + if (toolName !== "addArc" || !isRecord(input)) return input; + let normalized = input; + + if (typeof normalized.weight === "string") { + const weight = Number(normalized.weight); + if (Number.isFinite(weight)) normalized = { ...normalized, weight }; + } + if (typeof normalized.endpoint === "string") { + try { + const endpoint: unknown = JSON.parse(normalized.endpoint); + if (isRecord(endpoint)) normalized = { ...normalized, endpoint }; + } catch { + // Canonical validation reports the original malformed endpoint. + } + } + return normalized; +}; + /** * Writable tool callbacks exposed to the AI: every mutation, plus the subset * of commands registered in {@link aiCommandActionInputSchemas}. Read-only From 019323128015ac933148ffa0bb4c837c15c1954e Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 10:15:33 +0200 Subject: [PATCH 08/31] Retain Mission 6 outer browser witness Co-authored-by: Cursor --- .../SHA256SUMS | 20 + .../call-result-correlation.json | 51 +++ .../cold-reader-gate.md | 36 ++ .../cold-reader-records.json | 39 ++ .../definition-after.json | 98 +++++ .../definition-before.json | 93 +++++ .../definition-tab-b.json | 98 +++++ .../flue-snapshot-after.json | 321 ++++++++++++++++ .../flue-snapshot-before.json | 113 ++++++ .../flue-snapshot-tab-b.json | 360 ++++++++++++++++++ .../latest-workpiece.md | 41 ++ .../prepared-workpiece.md | 22 ++ .../route-evidence.json | 7 + .../screenshot-tab-a-after.png | Bin 0 -> 142872 bytes .../screenshot-tab-a-before.png | Bin 0 -> 71412 bytes .../screenshot-tab-b-after.png | Bin 0 -> 153210 bytes .../settled-manifest-after.json | 25 ++ .../settled-manifest-before.json | 25 ++ .../settled-manifest-tab-b.json | 25 ++ .../tab-b-correlation.json | 18 + .../witness.md | 90 +++++ .../fe-1575-resumable-workpiece-petrinaut.md | 70 ++-- 22 files changed, 1517 insertions(+), 35 deletions(-) create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/call-result-correlation.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/cold-reader-gate.md create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/cold-reader-records.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-after.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-before.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-tab-b.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-after.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-before.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-tab-b.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/latest-workpiece.md create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/prepared-workpiece.md create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/route-evidence.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-a-after.png create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-a-before.png create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-b-after.png create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-after.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-before.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-tab-b.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/tab-b-correlation.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/witness.md diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS new file mode 100644 index 00000000000..f44908b86b0 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS @@ -0,0 +1,20 @@ +6c3a075636a5df23667c58c4ca005cc7da6b1927e13bfc54939f5e4416e5059f call-result-correlation.json +1d37d87803edd25905098bc957a1557ea7250a243b689c62c1d58ebc463135d0 cold-reader-gate.md +e5393930c436fac7bcb5f30b610ca4d28174a027f0b3fe8eab0045076379ce29 cold-reader-records.json +c17ae80cc22939f0af6c2675f6bcc20b025b17a5b7bfb9e8029813bcef9ad736 definition-after.json +0ec2b0c9bb82787602c359b41e6c1663001f8e42425ad2ab7f84ac019944766b definition-before.json +c17ae80cc22939f0af6c2675f6bcc20b025b17a5b7bfb9e8029813bcef9ad736 definition-tab-b.json +4fe368ef206e71e63173c1876ac9ca54e8b0d0971066be74dae5f78d4b612b0a flue-snapshot-after.json +ea20487150d8a329f4c2a6e0ac32e22de39d0d655646581ad2c56768a3591d1a flue-snapshot-before.json +7aaa993b395bc4ac84625fb2f472645ba13428bc39faac1f0f4ba948bfb3d9f5 flue-snapshot-tab-b.json +0f04053f623e488c522a3cca06bf34593004379dab0f0e551b26a355d87b1049 latest-workpiece.md +2859b2c9c756dd67589df04cdae498f63affffe0d65ca7f9ec6971b81eabfe94 prepared-workpiece.md +cfb79c8f52fc8f1758b1a61f67e520c67a31d2f19f561017899d0724b776100a route-evidence.json +a9bd4a4a18f52ebd5c0f0e9c7c5d80b1c37e85823bfa6a03bd9c1d329b4b4267 screenshot-tab-a-after.png +eaf49081a6ab7acba746f337fdb85e3829d473818dc7c96f83a40acd3cb6f383 screenshot-tab-a-before.png +d39ea91fc69fa049af169c6ebcfe1a09c5b085d350d5eb6f9020c31095549943 screenshot-tab-b-after.png +caf83c79b2526587794faf4ed8c59c0d3f4bb9ed88e3d547679efe429197797c settled-manifest-after.json +5b302df73ccd6ac0cec777c9e4ade15ac7318dca7023ed79e3bceaa0604c3ec0 settled-manifest-before.json +caf83c79b2526587794faf4ed8c59c0d3f4bb9ed88e3d547679efe429197797c settled-manifest-tab-b.json +08afa5150f33b8b19641118524880eca9b13f4e7a94a55eca7b76775cfa30770 tab-b-correlation.json +935fa33c714b6441622cb1c50f2ff5e7f8e56c434a5365f5857c2eb6a1ffd830 witness.md diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/call-result-correlation.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/call-result-correlation.json new file mode 100644 index 00000000000..bdc346ad17c --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/call-result-correlation.json @@ -0,0 +1,51 @@ +{ + "calls": [ + { + "messageId": "entry_01M1NQGD1NRR36CBAX78EA666J", + "submissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2", + "toolCallId": "toolu_01KLHzRE7gbPbFfPaXe3RTry", + "state": "output-available", + "input": { + "transitionId": "start-final-inspection", + "arcDirection": "input", + "placeId": "dispatch-crew-available", + "weight": "1", + "type": "standard" + } + } + ], + "results": [ + { + "toolCallId": "toolu_01KLHzRE7gbPbFfPaXe3RTry", + "toolName": "addArc", + "output": { + "title": "Added input arc", + "detail": "Dispatch crew available <-> Start final inspection", + "target": { + "kind": "selection", + "item": { + "type": "arc", + "id": "$A_place:dispatch-crew-available___start-final-inspection" + } + }, + "applied": true + } + }, + { + "toolCallId": "toolu_01KLHzRE7gbPbFfPaXe3RTry", + "toolName": "addArc", + "output": { + "title": "Added input arc", + "detail": "Dispatch crew available <-> Start final inspection", + "target": { + "kind": "selection", + "item": { + "type": "arc", + "id": "$A_place:dispatch-crew-available___start-final-inspection" + } + }, + "applied": true + } + } + ] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/cold-reader-gate.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/cold-reader-gate.md new file mode 100644 index 00000000000..1d00d3e13f8 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/cold-reader-gate.md @@ -0,0 +1,36 @@ +# Mission 6 cold-reader gate + +Reviewer qualification: a human who did not watch the implementation or outer +witness. Do not give the reviewer `witness.md`, screenshots, implementation +files, or this mission's expected conclusions. + +Give the reviewer only: + +- [prepared-workpiece.md](prepared-workpiece.md) +- [latest-workpiece.md](latest-workpiece.md) +- [cold-reader-records.json](cold-reader-records.json) + +Ask for a written response to these questions: + +1. Who authored each workpiece revision, and what in the supplied Flue records + establishes that attribution? +2. What exact dispatch-crew quantity or resource policy is recorded? +3. What operation reserves the crew, and what operation returns it? +4. List every unresolved timing, failure, and recovery point. +5. What behavioral execution or operational-provenance claims, if any, can be + made from these materials alone? + +Acceptance requires the human response to: + +- attribute revision zero to test preparation, not the model; +- attribute the later assistant record to model production; +- recover the exactly-one-crew policy and the intended reservation/return; +- preserve every timing, failure, and recovery unknown; and +- avoid inferring behavioral execution or capture provenance. + +Record the reviewer's identity, date, verbatim response, and explicit +accept/reject decision below only after the review occurs. + +## Human verdict + +Pending. diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/cold-reader-records.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/cold-reader-records.json new file mode 100644 index 00000000000..a5efc6ff2eb --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/cold-reader-records.json @@ -0,0 +1,39 @@ +{ + "preparedRecord": { + "id": "entry_direct_c3ViX2lrX2YyNDkzOWJlYmI4NDFmZmUxNDY5YTdmM2E0YTA2OTE1", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "signal": { + "tagName": "prepared-fixture", + "attributes": { + "fixtureId": "crew-reservation-v1", + "authorship": "test-authored", + "claimBoundary": "prepared-not-model-produced" + } + }, + "parts": [ + { + "type": "text", + "text": "Fixture authorship: test-authored preparation for Mission 6.\nNon-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.\n\n```runbook-ir\n# Final inspection and dispatch workpiece\n\n## Purpose and posture\nMaintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection reserves the sole available dispatch crew.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.\n\n## Current Petrinaut correspondence\nThe prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n## Explicit unknowns\nInspection and sign-off timing, failure modes, and recovery behavior remain unresolved.\n\n## Claim boundary\nThis prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.\n```", + "state": "done" + } + ] + }, + "revisedRecord": { + "id": "entry_01M1NQGRAKWG69MWYMPYTCFXCZ", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715", + "turnId": "turn_01M1NQGQH38A3MMGGEWKN4VCDP", + "parts": [ + { + "type": "text", + "text": "**Verification successful.** The `start-final-inspection` transition now contains the corrected input arcs:\n```json\n\"inputArcs\":[\n {\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"},\n {\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}\n]\n```\n\nThe resource constraint is now satisfied: firing `start-final-inspection` requires both a ready batch AND an available crew token. The `sign-off` transition releases that crew back to `dispatch-crew-available`.\n\n---\n\n## Revised workpiece (runbook-ir)\n\n```runbook-ir\n# Final inspection and dispatch workpiece — Revised\n\n## Purpose and posture\nModel the batch path from final inspection to dispatch readiness with explicit crew resource management. This revision adds the missing crew-consumption arc to enforce the resource constraint.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Starting final inspection requires both a ready batch AND the sole available dispatch crew.\n- Starting final inspection consumes that crew token.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available. Starting final inspection consumes that one available crew; sign-off returns it. No transition fires without sufficient tokens in all input places.\n\n## Petrinaut correspondence\nThe net contains four places:\n- `batch-ready`: batches awaiting final inspection\n- `under-final-inspection`: batches currently in inspection\n- `ready-for-dispatch`: batches cleared for dispatch\n- `dispatch-crew-available`: crew availability (1 token when free)\n\nTransitions:\n- `start-final-inspection`: requires 1 token from batch-ready AND 1 token from dispatch-crew-available; produces 1 token to under-final-inspection\n- `sign-off`: requires 1 token from under-final-inspection; produces 1 token to ready-for-dispatch AND 1 token to dispatch-crew-available\n\nThe missing standard weight-1 input arc from `dispatch-crew-available` to `start-final-inspection` has been **added and verified** in the live Petrinaut definition.\n\n## Explicit unknowns\n- Inspection timing: duration, stochasticity, or determinism remain unresolved\n- Sign-off timing: duration, stochasticity, or determinism remain unresolved\n- Failure modes: whether inspection can fail, halt, or reject a batch\n- Recovery behavior: how failures or rejections affect batch state or crew availability\n\n## Claim boundary\nThis workpiece and the corrected net establish only:\n- The crew-consumption constraint at start of inspection\n- The crew-release at sign-off completion\n- Token flow from ready batch through inspection to dispatch readiness\n\nThis is test-authored diagnostic material for the narrow final-inspection–to-dispatch path. It does not establish capture provenance, behavioral execution, failure handling, full process projection, or integration with upstream or downstream operations.\n```\n\nThe correction is complete and verified in the live Petrinaut definition.", + "state": "done" + } + ] + } +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-after.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-after.json new file mode 100644 index 00000000000..c92ed16c454 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-after.json @@ -0,0 +1,98 @@ +{ + "places": [ + { + "id": "batch-ready", + "name": "Batch ready", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 80, + "y": 100 + }, + { + "id": "under-final-inspection", + "name": "Under final inspection", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 100 + }, + { + "id": "ready-for-dispatch", + "name": "Ready for dispatch", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 760, + "y": 100 + }, + { + "id": "dispatch-crew-available", + "name": "Dispatch crew available", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 360 + } + ], + "transitions": [ + { + "id": "start-final-inspection", + "name": "Start final inspection", + "inputArcs": [ + { + "placeId": "batch-ready", + "weight": 1, + "type": "standard" + }, + { + "type": "standard", + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "outputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 250, + "y": 100 + }, + { + "id": "sign-off", + "name": "Sign-off", + "inputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1, + "type": "standard" + } + ], + "outputArcs": [ + { + "placeId": "ready-for-dispatch", + "weight": 1 + }, + { + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 590, + "y": 100 + } + ], + "types": [], + "differentialEquations": [], + "parameters": [] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-before.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-before.json new file mode 100644 index 00000000000..5803556bfe8 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-before.json @@ -0,0 +1,93 @@ +{ + "places": [ + { + "id": "batch-ready", + "name": "Batch ready", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 80, + "y": 100 + }, + { + "id": "under-final-inspection", + "name": "Under final inspection", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 100 + }, + { + "id": "ready-for-dispatch", + "name": "Ready for dispatch", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 760, + "y": 100 + }, + { + "id": "dispatch-crew-available", + "name": "Dispatch crew available", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 360 + } + ], + "transitions": [ + { + "id": "start-final-inspection", + "name": "Start final inspection", + "inputArcs": [ + { + "placeId": "batch-ready", + "type": "standard", + "weight": 1 + } + ], + "outputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 250, + "y": 100 + }, + { + "id": "sign-off", + "name": "Sign-off", + "inputArcs": [ + { + "placeId": "under-final-inspection", + "type": "standard", + "weight": 1 + } + ], + "outputArcs": [ + { + "placeId": "ready-for-dispatch", + "weight": 1 + }, + { + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 590, + "y": 100 + } + ], + "types": [], + "parameters": [], + "differentialEquations": [] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-tab-b.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-tab-b.json new file mode 100644 index 00000000000..c92ed16c454 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/definition-tab-b.json @@ -0,0 +1,98 @@ +{ + "places": [ + { + "id": "batch-ready", + "name": "Batch ready", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 80, + "y": 100 + }, + { + "id": "under-final-inspection", + "name": "Under final inspection", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 100 + }, + { + "id": "ready-for-dispatch", + "name": "Ready for dispatch", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 760, + "y": 100 + }, + { + "id": "dispatch-crew-available", + "name": "Dispatch crew available", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 360 + } + ], + "transitions": [ + { + "id": "start-final-inspection", + "name": "Start final inspection", + "inputArcs": [ + { + "placeId": "batch-ready", + "weight": 1, + "type": "standard" + }, + { + "type": "standard", + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "outputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 250, + "y": 100 + }, + { + "id": "sign-off", + "name": "Sign-off", + "inputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1, + "type": "standard" + } + ], + "outputArcs": [ + { + "placeId": "ready-for-dispatch", + "weight": 1 + }, + { + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 590, + "y": 100 + } + ], + "types": [], + "differentialEquations": [], + "parameters": [] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-after.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-after.json new file mode 100644 index 00000000000..ba4e176112e --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-after.json @@ -0,0 +1,321 @@ +{ + "v": 1, + "conversationId": "conv_01M1NQEXM3CAPPTXM33ZE1YSRG", + "offset": "0000000000000000_0000000000000108", + "messages": [ + { + "id": "entry_direct_c3ViX2lrX2YyNDkzOWJlYmI4NDFmZmUxNDY5YTdmM2E0YTA2OTE1", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "signal": { + "tagName": "prepared-fixture", + "attributes": { + "fixtureId": "crew-reservation-v1", + "authorship": "test-authored", + "claimBoundary": "prepared-not-model-produced" + } + }, + "parts": [ + { + "type": "text", + "text": "Fixture authorship: test-authored preparation for Mission 6.\nNon-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.\n\n```runbook-ir\n# Final inspection and dispatch workpiece\n\n## Purpose and posture\nMaintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection reserves the sole available dispatch crew.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.\n\n## Current Petrinaut correspondence\nThe prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n## Explicit unknowns\nInspection and sign-off timing, failure modes, and recovery behavior remain unresolved.\n\n## Claim boundary\nThis prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.\n```", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQEYF9W60J2JVDYB2BJXK1", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "turnId": "turn_01M1NQEXM7MHJ94PF52Q54VAY4", + "parts": [ + { + "type": "reasoning", + "text": "The user has provided a prepared-fixture for SDCPN modelling work. This is test-authored material that is:\n- Part of a Mission 6 exercise\n- Focused on a narrow batch path from final inspection to dispatch readiness\n- Aimed at testing one evidence-backed correction against the live Petrinaut document\n- Not model-produced evidence, not a capture-backed provenance, not proof of automatic full-net projection\n\nThe operational account describes:\n1. A batch that is ready enters final inspection\n2. Final inspection reserves the sole available dispatch crew\n3. Sign-off releases that crew and makes the batch ready for dispatch\n\nThe key policy: Exactly one dispatch crew is available. Starting final inspection consumes it; sign-off returns it.\n\nThe current state: The prepared non-empty net contains the batch path and the crew return from sign-off, but deliberately LACKS the standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\".\n\nThe purpose is to test one evidence-backed correction against the live Petrinaut document.\n\nMy role here is:\n1. First, activate the sdcpn-modelling skill since this is a process-modelling task\n2. Understand the current state of the Petrinaut net\n3. Help verify the operational account against the net\n4. Work with the user to identify and potentially implement the missing arc correction\n5. Maintain the workpiece with clear documentation of what is known, what is missing, and what has been tested\n\nLet me start by activating the skill and getting the current net state.", + "state": "done" + }, + { + "type": "text", + "text": "I'll help you with this prepared-fixture exercise. Let me start by activating the SDCPN modelling skill and then retrieving the current state of the Petrinaut net to understand what we're working with.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "activate_skill", + "toolCallId": "toolu_01WQaZveys8joHtboYvGQiuA", + "state": "output-available", + "input": { + "name": "sdcpn-modelling" + }, + "output": "Run the skill named \"sdcpn-modelling\".\n\n\n# Capability-aware lifecycle\n\nUse one conceptual lifecycle: orient, elicit or revise, maintain the workpiece, construct when supported, check, and deliver. The current conversation may expose only one branch of that lifecycle. Do not claim that an unavailable transition occurred.\n\n## Select the runtime branch\n\n### Interactive elicitation or revision\n\nInterview in the person's operational vocabulary. Activate the `elicitation` skill and read `references/profile.md` before substantive questions or revision. Read `templates/workpiece.md` when creating or materially revising the shared workpiece. Construct only when the mounted capabilities actually permit construction in this conversation.\n\n### Construct-only execution\n\nUse the supplied workpiece as the complete modelling input. Do not interview. Read `references/pn-construction.md` and `references/checks.md`, then use the mounted construction tools. If a consequential workpiece gap prevents faithful construction, report the gap and the smallest question a later interactive elicitation must answer; do not ask it or invent an answer in this conversation.\n\n## Procedure\n\n### Orient\n\nEstablish enough purpose and context to select one focused next action: the intended question or decision, audience, boundary, horizon, accuracy need, and available time. Orientation need not settle every concern before elicitation begins.\n\n### Elicit or revise\n\nFor a new account, follow one concrete case and re-evaluate the active gap after each useful answer. For an existing account, first locate the disputed or changed material and its consequence for the objective. Use the `elicitation` skill's universal guidance and `references/profile.md` for detailed operations and coverage; do not turn their register order into question order.\n\n### Maintain the workpiece\n\nTreat the workpiece as the recoverable account construction will consume. Update it after a useful stretch rather than waiting until the end. Preserve unrelated material unless new evidence affects it.\n\nWhenever the workpiece changes substantially, emit the full current document in a fenced block whose language tag is exactly `runbook-ir`. Emit it again before construction and before workpiece-only delivery. A delta or prose promise is not a recoverable workpiece.\n\n### Construct\n\nConstruct only from the current workpiece. Read `references/pn-construction.md` and `references/checks.md` before beginning. Use mounted Petrinaut tools for every net change and inspect the resulting definition rather than emitting free-form net JSON. If the required tools are absent, limit the result to the workpiece and construction-ready notes.\n\nConstruction may infer a representation from recorded operational meaning; it may not invent operational facts. Record construction inferences, approximations, defaults, and target losses in the workpiece.\n\n### Check and deliver\n\nApply `references/checks.md` whenever construction is prepared or attempted. Deliver the current workpiece in every branch. Deliver a net only when the mounted tool path has produced and checked one. State what the result can support, what remains open, what was assumed or simplified, and what the target or current tools could not represent.\n\nAn explicit stop opens no new topic. In an interactive conversation, emit the best current workpiece and any already-checked net with limitations visible. In construct-only execution, report a blocking gap rather than opening an interview.\n\n## Resource discipline\n\nRead resources directly from this skill's advertised resource list, using the exact `/.flue/packaged-skills/...` path shown in the activation briefing; the relative name is a label only. Do not treat Markdown links as includes, follow references recursively, or read construction material merely to frame ordinary interview questions.\n\n\nSupporting skill resources are available but are not loaded into context unless needed:\n\n- references/checks.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/checks.md\n- references/pn-construction.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/pn-construction.md\n- references/profile.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/profile.md\n- templates/workpiece.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/templates/workpiece.md\n", + "durationMs": 3 + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_01FjSrPHir7RNkmV1PUpZ1qu", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 3 + }, + { + "type": "reasoning", + "text": "The skill is activated. The net definition call shows `{\"awaiting\":\"client\"}` which means the browser needs to fetch it. Let me wait a moment for that result to come through via the client-tool-result signal, or I should ask the user about the current state. \n\nActually, I should ping first to confirm the server is in the loop, then proceed to understand what we have.", + "state": "done" + }, + { + "type": "text", + "text": "Let me confirm the server connection and then retrieve the current net definition:", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "ping", + "toolCallId": "toolu_01NpMVdLYpu7PeSDCfJqjwqA", + "state": "output-available", + "input": { + "note": "Confirming server ready for crew-reservation-v1 prepared-fixture work" + }, + "output": { + "ok": true, + "note": "Confirming server ready for crew-reservation-v1 prepared-fixture work" + }, + "durationMs": 1 + }, + { + "type": "reasoning", + "text": "Good, the server is ready. Now I should wait for the net definition from the browser. The getLatestNetDefinition returned `{\"awaiting\":\"client\"}` which means it's waiting for a client tool result. I should describe what I'm going to do next and wait for that result.", + "state": "done" + }, + { + "type": "text", + "text": "Good. Now let me work with the prepared-fixture material you've provided. \n\n## Understanding the prepared fixture\n\nYou've provided a **test-authored diagnostic workpiece** focused on the **final inspection → dispatch path** with one specific correction to test:\n\n**Operational account:**\n- A batch ready for dispatch enters final inspection\n- Starting final inspection *reserves* the single available dispatch crew\n- Sign-off *releases* that crew and marks the batch ready for dispatch\n\n**Current net state:**\n- Contains the batch path and the crew return from sign-off\n- **Deliberately omits** the weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\" \n\n**Purpose:** Test one evidence-backed correction against the live Petrinaut document.\n\n---\n\n## Next step\n\nThe Petrinaut net definition is being retrieved. Once I see the current structure, I can:\n\n1. **Verify** the operational account against what's in the net\n2. **Identify** the missing arc precisely \n3. **Test the correction** by adding that arc and confirming it satisfies the resource constraint (exactly one crew consumed at start, returned at sign-off)\n\nI'm waiting for the live net definition to come through. What I'll be looking for:\n- The places representing the batch states (ready, in-inspection, ready-for-dispatch)\n- The places for crew availability\n- The transitions for \"Start final inspection\" and \"Sign-off\"\n- Which arcs are already present and which are missing\n\nDoes this match your intention for this exercise?", + "state": "done" + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2I3YTI3NGI3YzI4MjVkNGMwOTE0ZGE0NDBlMjQxY2I2", + "role": "user", + "purpose": "user", + "display": "visible", + "submissionId": "sub_ik_b7a274b7c2825d4c0914da440e241cb6", + "parts": [ + { + "type": "text", + "text": "Confirmed: final inspection uses the single dispatch crew and sign-off releases it; timing, failure, and recovery remain unknown. Read the live Petrinaut definition, add the missing standard weight-1 input arc from Dispatch crew available to Start final inspection, verify it, and emit the full revised runbook-ir workpiece.", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQGAVZ00RTNPHG4MM610XE", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_b7a274b7c2825d4c0914da440e241cb6", + "turnId": "turn_01M1NQGA4WJ01NC2MS1JJB0QWJ", + "parts": [ + { + "type": "reasoning", + "text": "The user has confirmed the operational intent and is asking me to:\n1. Read the live Petrinaut definition\n2. Add the missing standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\"\n3. Verify it\n4. Emit the full revised runbook-ir workpiece\n\nI need to call getLatestNetDefinition again to get the actual net definition since the previous call returned {\"awaiting\":\"client\"}.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_01BqoDEZeq7HTqu3S8p6ZLA6", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2RkMmViN2JlMjE5ODA5OThiODlhZTlhOWRhMDg1ZmIy", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_01BqoDEZeq7HTqu3S8p6ZLA6" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_01BqoDEZeq7HTqu3S8p6ZLA6\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQGD1NRR36CBAX78EA666J", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2", + "turnId": "turn_01M1NQGC2ZFFFC5MFXN2949H93", + "parts": [ + { + "type": "reasoning", + "text": "Good! Now I have the live Petrinaut definition. Let me analyze it:\n\n**Current places:**\n1. `batch-ready` - batch waiting to enter inspection\n2. `under-final-inspection` - batch in inspection\n3. `ready-for-dispatch` - batch ready for dispatch (output state)\n4. `dispatch-crew-available` - represents availability of the single dispatch crew\n\n**Current transitions:**\n1. `start-final-inspection` - takes 1 batch from `batch-ready`, outputs 1 to `under-final-inspection`\n - Input arcs: `batch-ready` (weight 1, standard)\n - Output arcs: `under-final-inspection` (weight 1)\n\n2. `sign-off` - takes 1 batch from `under-final-inspection`, outputs 1 to `ready-for-dispatch` AND 1 to `dispatch-crew-available`\n - Input arcs: `under-final-inspection` (weight 1, standard)\n - Output arcs: `ready-for-dispatch` (weight 1), `dispatch-crew-available` (weight 1)\n\n**What's missing:**\nThe `start-final-inspection` transition is missing an input arc from `dispatch-crew-available`. When a batch starts final inspection, it should consume one crew token.\n\nAccording to the prepared fixture, this should be:\n- Arc direction: **input**\n- Source place: `dispatch-crew-available`\n- Weight: 1\n- Type: standard\n\nSo I need to add an input arc to `start-final-inspection` with:\n- placeId: `dispatch-crew-available`\n- weight: 1\n- type: `standard`\n\nLet me use the `addArc` function to add this arc.", + "state": "done" + }, + { + "type": "text", + "text": "Perfect. I can see the live net structure. Let me analyze it:\n\n**Current structure:**\n- **Places:** Batch-ready → Under-final-inspection → Ready-for-dispatch, plus Dispatch-crew-available\n- **start-final-inspection transition:** Currently has only one input arc (from batch-ready)\n- **sign-off transition:** Takes batch from inspection and outputs both the batch (to ready-for-dispatch) AND returns 1 crew token to dispatch-crew-available\n\n**Missing element:** The `start-final-inspection` transition lacks the input arc from `dispatch-crew-available`. This means the model currently allows inspection to begin without consuming the crew resource—violating the \"exactly one crew reserved\" constraint.\n\nNow I'll add the missing standard weight-1 input arc from `dispatch-crew-available` to `start-final-inspection`:", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "addArc", + "toolCallId": "toolu_01KLHzRE7gbPbFfPaXe3RTry", + "state": "output-available", + "input": { + "transitionId": "start-final-inspection", + "arcDirection": "input", + "placeId": "dispatch-crew-available", + "weight": "1", + "type": "standard" + }, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrXzAwOGZhNmQ3MzU0NzQ5YTFjYjNmNjc0MTg0ZTdjYjFi", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_008fa6d7354749a1cb3f674184e7cb1b", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_01BqoDEZeq7HTqu3S8p6ZLA6,toolu_01KLHzRE7gbPbFfPaXe3RTry" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_01BqoDEZeq7HTqu3S8p6ZLA6\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}},{\"toolCallId\":\"toolu_01KLHzRE7gbPbFfPaXe3RTry\",\"toolName\":\"addArc\",\"output\":{\"title\":\"Added input arc\",\"detail\":\"Dispatch crew available <-> Start final inspection\",\"target\":{\"kind\":\"selection\",\"item\":{\"type\":\"arc\",\"id\":\"$A_place:dispatch-crew-available___start-final-inspection\"}},\"applied\":true}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQGMV82KXETG8X23QZHPM3", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_008fa6d7354749a1cb3f674184e7cb1b", + "turnId": "turn_01M1NQGKXT0H69NP5JFRYQJ2J7", + "parts": [ + { + "type": "reasoning", + "text": "Good! The arc has been added successfully. Let me verify by checking the live definition again to confirm the arc is now present in the start-final-inspection transition.\n\nLooking at the addArc output, it says \"Applied: true\" and created an arc with ID \"$A_place:dispatch-crew-available___start-final-inspection\". This is the confirmation.\n\nHowever, I notice that the getLatestNetDefinition result that came back still shows the old structure—the start-final-inspection transition still shows only one inputArc (from batch-ready). This might be a timing issue in how the results came back, or the definition might not have refreshed yet.\n\nLet me read the live definition one more time to verify the arc was actually applied and is visible in the current state.", + "state": "done" + }, + { + "type": "text", + "text": "Excellent! The arc addition was successful: `\"applied\":true`. Let me verify the updated net definition:", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_01LuBH9HSYSzvkCMq5E3PN57", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrXzZkYmMxODdlNGU3Mjc5M2I3NTM5YzAyMzg3ZDA0NzE1", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_01BqoDEZeq7HTqu3S8p6ZLA6,toolu_01KLHzRE7gbPbFfPaXe3RTry,toolu_01LuBH9HSYSzvkCMq5E3PN57" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_01BqoDEZeq7HTqu3S8p6ZLA6\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}},{\"toolCallId\":\"toolu_01KLHzRE7gbPbFfPaXe3RTry\",\"toolName\":\"addArc\",\"output\":{\"title\":\"Added input arc\",\"detail\":\"Dispatch crew available <-> Start final inspection\",\"target\":{\"kind\":\"selection\",\"item\":{\"type\":\"arc\",\"id\":\"$A_place:dispatch-crew-available___start-final-inspection\"}},\"applied\":true}},{\"toolCallId\":\"toolu_01LuBH9HSYSzvkCMq5E3PN57\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"},{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQGRAKWG69MWYMPYTCFXCZ", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715", + "turnId": "turn_01M1NQGQH38A3MMGGEWKN4VCDP", + "parts": [ + { + "type": "reasoning", + "text": "Perfect! The verification confirms the arc has been successfully added. Looking at the final definition:\n\nThe `start-final-inspection` transition now has two input arcs:\n1. `{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}`\n2. `{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}`\n\nThis means:\n- Starting final inspection requires 1 token from \"batch-ready\" AND 1 token from \"dispatch-crew-available\"\n- It produces 1 token to \"under-final-inspection\"\n- The sign-off transition consumes the batch from inspection and returns 1 crew token\n\nThis satisfies the operational constraint: exactly one dispatch crew is consumed when inspection begins and released when sign-off completes.\n\nNow I need to emit the full revised runbook-ir workpiece as requested. I should update the prepared fixture material with:\n1. The operational account (confirmed)\n2. The current Petrinaut correspondence (UPDATED - the missing arc has been added)\n3. Explicit unknowns (unchanged)\n4. The claim boundary (adjusted to reflect what this correction establishes)", + "state": "done" + }, + { + "type": "text", + "text": "**Verification successful.** The `start-final-inspection` transition now contains the corrected input arcs:\n```json\n\"inputArcs\":[\n {\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"},\n {\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}\n]\n```\n\nThe resource constraint is now satisfied: firing `start-final-inspection` requires both a ready batch AND an available crew token. The `sign-off` transition releases that crew back to `dispatch-crew-available`.\n\n---\n\n## Revised workpiece (runbook-ir)\n\n```runbook-ir\n# Final inspection and dispatch workpiece — Revised\n\n## Purpose and posture\nModel the batch path from final inspection to dispatch readiness with explicit crew resource management. This revision adds the missing crew-consumption arc to enforce the resource constraint.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Starting final inspection requires both a ready batch AND the sole available dispatch crew.\n- Starting final inspection consumes that crew token.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available. Starting final inspection consumes that one available crew; sign-off returns it. No transition fires without sufficient tokens in all input places.\n\n## Petrinaut correspondence\nThe net contains four places:\n- `batch-ready`: batches awaiting final inspection\n- `under-final-inspection`: batches currently in inspection\n- `ready-for-dispatch`: batches cleared for dispatch\n- `dispatch-crew-available`: crew availability (1 token when free)\n\nTransitions:\n- `start-final-inspection`: requires 1 token from batch-ready AND 1 token from dispatch-crew-available; produces 1 token to under-final-inspection\n- `sign-off`: requires 1 token from under-final-inspection; produces 1 token to ready-for-dispatch AND 1 token to dispatch-crew-available\n\nThe missing standard weight-1 input arc from `dispatch-crew-available` to `start-final-inspection` has been **added and verified** in the live Petrinaut definition.\n\n## Explicit unknowns\n- Inspection timing: duration, stochasticity, or determinism remain unresolved\n- Sign-off timing: duration, stochasticity, or determinism remain unresolved\n- Failure modes: whether inspection can fail, halt, or reject a batch\n- Recovery behavior: how failures or rejections affect batch state or crew availability\n\n## Claim boundary\nThis workpiece and the corrected net establish only:\n- The crew-consumption constraint at start of inspection\n- The crew-release at sign-off completion\n- Token flow from ready batch through inspection to dispatch readiness\n\nThis is test-authored diagnostic material for the narrow final-inspection–to-dispatch path. It does not establish capture provenance, behavioral execution, failure handling, full process projection, or integration with upstream or downstream operations.\n```\n\nThe correction is complete and verified in the live Petrinaut definition.", + "state": "done" + } + ] + } + ], + "settlements": [ + { + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915" + }, + { + "submissionId": "sub_ik_b7a274b7c2825d4c0914da440e241cb6", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_b7a274b7c2825d4c0914da440e241cb6" + }, + { + "submissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2" + }, + { + "submissionId": "sub_ik_008fa6d7354749a1cb3f674184e7cb1b", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_008fa6d7354749a1cb3f674184e7cb1b" + }, + { + "submissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715" + } + ], + "incarnation": "inc_01M1NQEXM24JHNYN40Q8RA5DH5" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-before.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-before.json new file mode 100644 index 00000000000..a584f125feb --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-before.json @@ -0,0 +1,113 @@ +{ + "v": 1, + "conversationId": "conv_01M1NQEXM3CAPPTXM33ZE1YSRG", + "offset": "0000000000000000_0000000000000043", + "messages": [ + { + "id": "entry_direct_c3ViX2lrX2YyNDkzOWJlYmI4NDFmZmUxNDY5YTdmM2E0YTA2OTE1", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "signal": { + "tagName": "prepared-fixture", + "attributes": { + "fixtureId": "crew-reservation-v1", + "authorship": "test-authored", + "claimBoundary": "prepared-not-model-produced" + } + }, + "parts": [ + { + "type": "text", + "text": "Fixture authorship: test-authored preparation for Mission 6.\nNon-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.\n\n```runbook-ir\n# Final inspection and dispatch workpiece\n\n## Purpose and posture\nMaintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection reserves the sole available dispatch crew.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.\n\n## Current Petrinaut correspondence\nThe prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n## Explicit unknowns\nInspection and sign-off timing, failure modes, and recovery behavior remain unresolved.\n\n## Claim boundary\nThis prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.\n```", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQEYF9W60J2JVDYB2BJXK1", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "turnId": "turn_01M1NQEXM7MHJ94PF52Q54VAY4", + "parts": [ + { + "type": "reasoning", + "text": "The user has provided a prepared-fixture for SDCPN modelling work. This is test-authored material that is:\n- Part of a Mission 6 exercise\n- Focused on a narrow batch path from final inspection to dispatch readiness\n- Aimed at testing one evidence-backed correction against the live Petrinaut document\n- Not model-produced evidence, not a capture-backed provenance, not proof of automatic full-net projection\n\nThe operational account describes:\n1. A batch that is ready enters final inspection\n2. Final inspection reserves the sole available dispatch crew\n3. Sign-off releases that crew and makes the batch ready for dispatch\n\nThe key policy: Exactly one dispatch crew is available. Starting final inspection consumes it; sign-off returns it.\n\nThe current state: The prepared non-empty net contains the batch path and the crew return from sign-off, but deliberately LACKS the standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\".\n\nThe purpose is to test one evidence-backed correction against the live Petrinaut document.\n\nMy role here is:\n1. First, activate the sdcpn-modelling skill since this is a process-modelling task\n2. Understand the current state of the Petrinaut net\n3. Help verify the operational account against the net\n4. Work with the user to identify and potentially implement the missing arc correction\n5. Maintain the workpiece with clear documentation of what is known, what is missing, and what has been tested\n\nLet me start by activating the skill and getting the current net state.", + "state": "done" + }, + { + "type": "text", + "text": "I'll help you with this prepared-fixture exercise. Let me start by activating the SDCPN modelling skill and then retrieving the current state of the Petrinaut net to understand what we're working with.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "activate_skill", + "toolCallId": "toolu_01WQaZveys8joHtboYvGQiuA", + "state": "output-available", + "input": { + "name": "sdcpn-modelling" + }, + "output": "Run the skill named \"sdcpn-modelling\".\n\n\n# Capability-aware lifecycle\n\nUse one conceptual lifecycle: orient, elicit or revise, maintain the workpiece, construct when supported, check, and deliver. The current conversation may expose only one branch of that lifecycle. Do not claim that an unavailable transition occurred.\n\n## Select the runtime branch\n\n### Interactive elicitation or revision\n\nInterview in the person's operational vocabulary. Activate the `elicitation` skill and read `references/profile.md` before substantive questions or revision. Read `templates/workpiece.md` when creating or materially revising the shared workpiece. Construct only when the mounted capabilities actually permit construction in this conversation.\n\n### Construct-only execution\n\nUse the supplied workpiece as the complete modelling input. Do not interview. Read `references/pn-construction.md` and `references/checks.md`, then use the mounted construction tools. If a consequential workpiece gap prevents faithful construction, report the gap and the smallest question a later interactive elicitation must answer; do not ask it or invent an answer in this conversation.\n\n## Procedure\n\n### Orient\n\nEstablish enough purpose and context to select one focused next action: the intended question or decision, audience, boundary, horizon, accuracy need, and available time. Orientation need not settle every concern before elicitation begins.\n\n### Elicit or revise\n\nFor a new account, follow one concrete case and re-evaluate the active gap after each useful answer. For an existing account, first locate the disputed or changed material and its consequence for the objective. Use the `elicitation` skill's universal guidance and `references/profile.md` for detailed operations and coverage; do not turn their register order into question order.\n\n### Maintain the workpiece\n\nTreat the workpiece as the recoverable account construction will consume. Update it after a useful stretch rather than waiting until the end. Preserve unrelated material unless new evidence affects it.\n\nWhenever the workpiece changes substantially, emit the full current document in a fenced block whose language tag is exactly `runbook-ir`. Emit it again before construction and before workpiece-only delivery. A delta or prose promise is not a recoverable workpiece.\n\n### Construct\n\nConstruct only from the current workpiece. Read `references/pn-construction.md` and `references/checks.md` before beginning. Use mounted Petrinaut tools for every net change and inspect the resulting definition rather than emitting free-form net JSON. If the required tools are absent, limit the result to the workpiece and construction-ready notes.\n\nConstruction may infer a representation from recorded operational meaning; it may not invent operational facts. Record construction inferences, approximations, defaults, and target losses in the workpiece.\n\n### Check and deliver\n\nApply `references/checks.md` whenever construction is prepared or attempted. Deliver the current workpiece in every branch. Deliver a net only when the mounted tool path has produced and checked one. State what the result can support, what remains open, what was assumed or simplified, and what the target or current tools could not represent.\n\nAn explicit stop opens no new topic. In an interactive conversation, emit the best current workpiece and any already-checked net with limitations visible. In construct-only execution, report a blocking gap rather than opening an interview.\n\n## Resource discipline\n\nRead resources directly from this skill's advertised resource list, using the exact `/.flue/packaged-skills/...` path shown in the activation briefing; the relative name is a label only. Do not treat Markdown links as includes, follow references recursively, or read construction material merely to frame ordinary interview questions.\n\n\nSupporting skill resources are available but are not loaded into context unless needed:\n\n- references/checks.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/checks.md\n- references/pn-construction.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/pn-construction.md\n- references/profile.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/profile.md\n- templates/workpiece.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/templates/workpiece.md\n", + "durationMs": 3 + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_01FjSrPHir7RNkmV1PUpZ1qu", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 3 + }, + { + "type": "reasoning", + "text": "The skill is activated. The net definition call shows `{\"awaiting\":\"client\"}` which means the browser needs to fetch it. Let me wait a moment for that result to come through via the client-tool-result signal, or I should ask the user about the current state. \n\nActually, I should ping first to confirm the server is in the loop, then proceed to understand what we have.", + "state": "done" + }, + { + "type": "text", + "text": "Let me confirm the server connection and then retrieve the current net definition:", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "ping", + "toolCallId": "toolu_01NpMVdLYpu7PeSDCfJqjwqA", + "state": "output-available", + "input": { + "note": "Confirming server ready for crew-reservation-v1 prepared-fixture work" + }, + "output": { + "ok": true, + "note": "Confirming server ready for crew-reservation-v1 prepared-fixture work" + }, + "durationMs": 1 + }, + { + "type": "reasoning", + "text": "Good, the server is ready. Now I should wait for the net definition from the browser. The getLatestNetDefinition returned `{\"awaiting\":\"client\"}` which means it's waiting for a client tool result. I should describe what I'm going to do next and wait for that result.", + "state": "done" + }, + { + "type": "text", + "text": "Good. Now let me work with the prepared-fixture material you've provided. \n\n## Understanding the prepared fixture\n\nYou've provided a **test-authored diagnostic workpiece** focused on the **final inspection → dispatch path** with one specific correction to test:\n\n**Operational account:**\n- A batch ready for dispatch enters final inspection\n- Starting final inspection *reserves* the single available dispatch crew\n- Sign-off *releases* that crew and marks the batch ready for dispatch\n\n**Current net state:**\n- Contains the batch path and the crew return from sign-off\n- **Deliberately omits** the weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\" \n\n**Purpose:** Test one evidence-backed correction against the live Petrinaut document.\n\n---\n\n## Next step\n\nThe Petrinaut net definition is being retrieved. Once I see the current structure, I can:\n\n1. **Verify** the operational account against what's in the net\n2. **Identify** the missing arc precisely \n3. **Test the correction** by adding that arc and confirming it satisfies the resource constraint (exactly one crew consumed at start, returned at sign-off)\n\nI'm waiting for the live net definition to come through. What I'll be looking for:\n- The places representing the batch states (ready, in-inspection, ready-for-dispatch)\n- The places for crew availability\n- The transitions for \"Start final inspection\" and \"Sign-off\"\n- Which arcs are already present and which are missing\n\nDoes this match your intention for this exercise?", + "state": "done" + } + ] + } + ], + "settlements": [ + { + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915" + } + ], + "incarnation": "inc_01M1NQEXM24JHNYN40Q8RA5DH5" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-tab-b.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-tab-b.json new file mode 100644 index 00000000000..4cb95e7516d --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/flue-snapshot-tab-b.json @@ -0,0 +1,360 @@ +{ + "v": 1, + "conversationId": "conv_01M1NQEXM3CAPPTXM33ZE1YSRG", + "offset": "0000000000000000_0000000000000123", + "messages": [ + { + "id": "entry_direct_c3ViX2lrX2YyNDkzOWJlYmI4NDFmZmUxNDY5YTdmM2E0YTA2OTE1", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "signal": { + "tagName": "prepared-fixture", + "attributes": { + "fixtureId": "crew-reservation-v1", + "authorship": "test-authored", + "claimBoundary": "prepared-not-model-produced" + } + }, + "parts": [ + { + "type": "text", + "text": "Fixture authorship: test-authored preparation for Mission 6.\nNon-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.\n\n```runbook-ir\n# Final inspection and dispatch workpiece\n\n## Purpose and posture\nMaintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection reserves the sole available dispatch crew.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.\n\n## Current Petrinaut correspondence\nThe prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n## Explicit unknowns\nInspection and sign-off timing, failure modes, and recovery behavior remain unresolved.\n\n## Claim boundary\nThis prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.\n```", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQEYF9W60J2JVDYB2BJXK1", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "turnId": "turn_01M1NQEXM7MHJ94PF52Q54VAY4", + "parts": [ + { + "type": "reasoning", + "text": "The user has provided a prepared-fixture for SDCPN modelling work. This is test-authored material that is:\n- Part of a Mission 6 exercise\n- Focused on a narrow batch path from final inspection to dispatch readiness\n- Aimed at testing one evidence-backed correction against the live Petrinaut document\n- Not model-produced evidence, not a capture-backed provenance, not proof of automatic full-net projection\n\nThe operational account describes:\n1. A batch that is ready enters final inspection\n2. Final inspection reserves the sole available dispatch crew\n3. Sign-off releases that crew and makes the batch ready for dispatch\n\nThe key policy: Exactly one dispatch crew is available. Starting final inspection consumes it; sign-off returns it.\n\nThe current state: The prepared non-empty net contains the batch path and the crew return from sign-off, but deliberately LACKS the standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\".\n\nThe purpose is to test one evidence-backed correction against the live Petrinaut document.\n\nMy role here is:\n1. First, activate the sdcpn-modelling skill since this is a process-modelling task\n2. Understand the current state of the Petrinaut net\n3. Help verify the operational account against the net\n4. Work with the user to identify and potentially implement the missing arc correction\n5. Maintain the workpiece with clear documentation of what is known, what is missing, and what has been tested\n\nLet me start by activating the skill and getting the current net state.", + "state": "done" + }, + { + "type": "text", + "text": "I'll help you with this prepared-fixture exercise. Let me start by activating the SDCPN modelling skill and then retrieving the current state of the Petrinaut net to understand what we're working with.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "activate_skill", + "toolCallId": "toolu_01WQaZveys8joHtboYvGQiuA", + "state": "output-available", + "input": { + "name": "sdcpn-modelling" + }, + "output": "Run the skill named \"sdcpn-modelling\".\n\n\n# Capability-aware lifecycle\n\nUse one conceptual lifecycle: orient, elicit or revise, maintain the workpiece, construct when supported, check, and deliver. The current conversation may expose only one branch of that lifecycle. Do not claim that an unavailable transition occurred.\n\n## Select the runtime branch\n\n### Interactive elicitation or revision\n\nInterview in the person's operational vocabulary. Activate the `elicitation` skill and read `references/profile.md` before substantive questions or revision. Read `templates/workpiece.md` when creating or materially revising the shared workpiece. Construct only when the mounted capabilities actually permit construction in this conversation.\n\n### Construct-only execution\n\nUse the supplied workpiece as the complete modelling input. Do not interview. Read `references/pn-construction.md` and `references/checks.md`, then use the mounted construction tools. If a consequential workpiece gap prevents faithful construction, report the gap and the smallest question a later interactive elicitation must answer; do not ask it or invent an answer in this conversation.\n\n## Procedure\n\n### Orient\n\nEstablish enough purpose and context to select one focused next action: the intended question or decision, audience, boundary, horizon, accuracy need, and available time. Orientation need not settle every concern before elicitation begins.\n\n### Elicit or revise\n\nFor a new account, follow one concrete case and re-evaluate the active gap after each useful answer. For an existing account, first locate the disputed or changed material and its consequence for the objective. Use the `elicitation` skill's universal guidance and `references/profile.md` for detailed operations and coverage; do not turn their register order into question order.\n\n### Maintain the workpiece\n\nTreat the workpiece as the recoverable account construction will consume. Update it after a useful stretch rather than waiting until the end. Preserve unrelated material unless new evidence affects it.\n\nWhenever the workpiece changes substantially, emit the full current document in a fenced block whose language tag is exactly `runbook-ir`. Emit it again before construction and before workpiece-only delivery. A delta or prose promise is not a recoverable workpiece.\n\n### Construct\n\nConstruct only from the current workpiece. Read `references/pn-construction.md` and `references/checks.md` before beginning. Use mounted Petrinaut tools for every net change and inspect the resulting definition rather than emitting free-form net JSON. If the required tools are absent, limit the result to the workpiece and construction-ready notes.\n\nConstruction may infer a representation from recorded operational meaning; it may not invent operational facts. Record construction inferences, approximations, defaults, and target losses in the workpiece.\n\n### Check and deliver\n\nApply `references/checks.md` whenever construction is prepared or attempted. Deliver the current workpiece in every branch. Deliver a net only when the mounted tool path has produced and checked one. State what the result can support, what remains open, what was assumed or simplified, and what the target or current tools could not represent.\n\nAn explicit stop opens no new topic. In an interactive conversation, emit the best current workpiece and any already-checked net with limitations visible. In construct-only execution, report a blocking gap rather than opening an interview.\n\n## Resource discipline\n\nRead resources directly from this skill's advertised resource list, using the exact `/.flue/packaged-skills/...` path shown in the activation briefing; the relative name is a label only. Do not treat Markdown links as includes, follow references recursively, or read construction material merely to frame ordinary interview questions.\n\n\nSupporting skill resources are available but are not loaded into context unless needed:\n\n- references/checks.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/checks.md\n- references/pn-construction.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/pn-construction.md\n- references/profile.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/profile.md\n- templates/workpiece.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/templates/workpiece.md\n", + "durationMs": 3 + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_01FjSrPHir7RNkmV1PUpZ1qu", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 3 + }, + { + "type": "reasoning", + "text": "The skill is activated. The net definition call shows `{\"awaiting\":\"client\"}` which means the browser needs to fetch it. Let me wait a moment for that result to come through via the client-tool-result signal, or I should ask the user about the current state. \n\nActually, I should ping first to confirm the server is in the loop, then proceed to understand what we have.", + "state": "done" + }, + { + "type": "text", + "text": "Let me confirm the server connection and then retrieve the current net definition:", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "ping", + "toolCallId": "toolu_01NpMVdLYpu7PeSDCfJqjwqA", + "state": "output-available", + "input": { + "note": "Confirming server ready for crew-reservation-v1 prepared-fixture work" + }, + "output": { + "ok": true, + "note": "Confirming server ready for crew-reservation-v1 prepared-fixture work" + }, + "durationMs": 1 + }, + { + "type": "reasoning", + "text": "Good, the server is ready. Now I should wait for the net definition from the browser. The getLatestNetDefinition returned `{\"awaiting\":\"client\"}` which means it's waiting for a client tool result. I should describe what I'm going to do next and wait for that result.", + "state": "done" + }, + { + "type": "text", + "text": "Good. Now let me work with the prepared-fixture material you've provided. \n\n## Understanding the prepared fixture\n\nYou've provided a **test-authored diagnostic workpiece** focused on the **final inspection → dispatch path** with one specific correction to test:\n\n**Operational account:**\n- A batch ready for dispatch enters final inspection\n- Starting final inspection *reserves* the single available dispatch crew\n- Sign-off *releases* that crew and marks the batch ready for dispatch\n\n**Current net state:**\n- Contains the batch path and the crew return from sign-off\n- **Deliberately omits** the weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\" \n\n**Purpose:** Test one evidence-backed correction against the live Petrinaut document.\n\n---\n\n## Next step\n\nThe Petrinaut net definition is being retrieved. Once I see the current structure, I can:\n\n1. **Verify** the operational account against what's in the net\n2. **Identify** the missing arc precisely \n3. **Test the correction** by adding that arc and confirming it satisfies the resource constraint (exactly one crew consumed at start, returned at sign-off)\n\nI'm waiting for the live net definition to come through. What I'll be looking for:\n- The places representing the batch states (ready, in-inspection, ready-for-dispatch)\n- The places for crew availability\n- The transitions for \"Start final inspection\" and \"Sign-off\"\n- Which arcs are already present and which are missing\n\nDoes this match your intention for this exercise?", + "state": "done" + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2I3YTI3NGI3YzI4MjVkNGMwOTE0ZGE0NDBlMjQxY2I2", + "role": "user", + "purpose": "user", + "display": "visible", + "submissionId": "sub_ik_b7a274b7c2825d4c0914da440e241cb6", + "parts": [ + { + "type": "text", + "text": "Confirmed: final inspection uses the single dispatch crew and sign-off releases it; timing, failure, and recovery remain unknown. Read the live Petrinaut definition, add the missing standard weight-1 input arc from Dispatch crew available to Start final inspection, verify it, and emit the full revised runbook-ir workpiece.", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQGAVZ00RTNPHG4MM610XE", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_b7a274b7c2825d4c0914da440e241cb6", + "turnId": "turn_01M1NQGA4WJ01NC2MS1JJB0QWJ", + "parts": [ + { + "type": "reasoning", + "text": "The user has confirmed the operational intent and is asking me to:\n1. Read the live Petrinaut definition\n2. Add the missing standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\"\n3. Verify it\n4. Emit the full revised runbook-ir workpiece\n\nI need to call getLatestNetDefinition again to get the actual net definition since the previous call returned {\"awaiting\":\"client\"}.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_01BqoDEZeq7HTqu3S8p6ZLA6", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2RkMmViN2JlMjE5ODA5OThiODlhZTlhOWRhMDg1ZmIy", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_01BqoDEZeq7HTqu3S8p6ZLA6" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_01BqoDEZeq7HTqu3S8p6ZLA6\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQGD1NRR36CBAX78EA666J", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2", + "turnId": "turn_01M1NQGC2ZFFFC5MFXN2949H93", + "parts": [ + { + "type": "reasoning", + "text": "Good! Now I have the live Petrinaut definition. Let me analyze it:\n\n**Current places:**\n1. `batch-ready` - batch waiting to enter inspection\n2. `under-final-inspection` - batch in inspection\n3. `ready-for-dispatch` - batch ready for dispatch (output state)\n4. `dispatch-crew-available` - represents availability of the single dispatch crew\n\n**Current transitions:**\n1. `start-final-inspection` - takes 1 batch from `batch-ready`, outputs 1 to `under-final-inspection`\n - Input arcs: `batch-ready` (weight 1, standard)\n - Output arcs: `under-final-inspection` (weight 1)\n\n2. `sign-off` - takes 1 batch from `under-final-inspection`, outputs 1 to `ready-for-dispatch` AND 1 to `dispatch-crew-available`\n - Input arcs: `under-final-inspection` (weight 1, standard)\n - Output arcs: `ready-for-dispatch` (weight 1), `dispatch-crew-available` (weight 1)\n\n**What's missing:**\nThe `start-final-inspection` transition is missing an input arc from `dispatch-crew-available`. When a batch starts final inspection, it should consume one crew token.\n\nAccording to the prepared fixture, this should be:\n- Arc direction: **input**\n- Source place: `dispatch-crew-available`\n- Weight: 1\n- Type: standard\n\nSo I need to add an input arc to `start-final-inspection` with:\n- placeId: `dispatch-crew-available`\n- weight: 1\n- type: `standard`\n\nLet me use the `addArc` function to add this arc.", + "state": "done" + }, + { + "type": "text", + "text": "Perfect. I can see the live net structure. Let me analyze it:\n\n**Current structure:**\n- **Places:** Batch-ready → Under-final-inspection → Ready-for-dispatch, plus Dispatch-crew-available\n- **start-final-inspection transition:** Currently has only one input arc (from batch-ready)\n- **sign-off transition:** Takes batch from inspection and outputs both the batch (to ready-for-dispatch) AND returns 1 crew token to dispatch-crew-available\n\n**Missing element:** The `start-final-inspection` transition lacks the input arc from `dispatch-crew-available`. This means the model currently allows inspection to begin without consuming the crew resource—violating the \"exactly one crew reserved\" constraint.\n\nNow I'll add the missing standard weight-1 input arc from `dispatch-crew-available` to `start-final-inspection`:", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "addArc", + "toolCallId": "toolu_01KLHzRE7gbPbFfPaXe3RTry", + "state": "output-available", + "input": { + "transitionId": "start-final-inspection", + "arcDirection": "input", + "placeId": "dispatch-crew-available", + "weight": "1", + "type": "standard" + }, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrXzAwOGZhNmQ3MzU0NzQ5YTFjYjNmNjc0MTg0ZTdjYjFi", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_008fa6d7354749a1cb3f674184e7cb1b", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_01BqoDEZeq7HTqu3S8p6ZLA6,toolu_01KLHzRE7gbPbFfPaXe3RTry" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_01BqoDEZeq7HTqu3S8p6ZLA6\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}},{\"toolCallId\":\"toolu_01KLHzRE7gbPbFfPaXe3RTry\",\"toolName\":\"addArc\",\"output\":{\"title\":\"Added input arc\",\"detail\":\"Dispatch crew available <-> Start final inspection\",\"target\":{\"kind\":\"selection\",\"item\":{\"type\":\"arc\",\"id\":\"$A_place:dispatch-crew-available___start-final-inspection\"}},\"applied\":true}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQGMV82KXETG8X23QZHPM3", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_008fa6d7354749a1cb3f674184e7cb1b", + "turnId": "turn_01M1NQGKXT0H69NP5JFRYQJ2J7", + "parts": [ + { + "type": "reasoning", + "text": "Good! The arc has been added successfully. Let me verify by checking the live definition again to confirm the arc is now present in the start-final-inspection transition.\n\nLooking at the addArc output, it says \"Applied: true\" and created an arc with ID \"$A_place:dispatch-crew-available___start-final-inspection\". This is the confirmation.\n\nHowever, I notice that the getLatestNetDefinition result that came back still shows the old structure—the start-final-inspection transition still shows only one inputArc (from batch-ready). This might be a timing issue in how the results came back, or the definition might not have refreshed yet.\n\nLet me read the live definition one more time to verify the arc was actually applied and is visible in the current state.", + "state": "done" + }, + { + "type": "text", + "text": "Excellent! The arc addition was successful: `\"applied\":true`. Let me verify the updated net definition:", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_01LuBH9HSYSzvkCMq5E3PN57", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrXzZkYmMxODdlNGU3Mjc5M2I3NTM5YzAyMzg3ZDA0NzE1", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_01BqoDEZeq7HTqu3S8p6ZLA6,toolu_01KLHzRE7gbPbFfPaXe3RTry,toolu_01LuBH9HSYSzvkCMq5E3PN57" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_01BqoDEZeq7HTqu3S8p6ZLA6\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}},{\"toolCallId\":\"toolu_01KLHzRE7gbPbFfPaXe3RTry\",\"toolName\":\"addArc\",\"output\":{\"title\":\"Added input arc\",\"detail\":\"Dispatch crew available <-> Start final inspection\",\"target\":{\"kind\":\"selection\",\"item\":{\"type\":\"arc\",\"id\":\"$A_place:dispatch-crew-available___start-final-inspection\"}},\"applied\":true}},{\"toolCallId\":\"toolu_01LuBH9HSYSzvkCMq5E3PN57\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"},{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQGRAKWG69MWYMPYTCFXCZ", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715", + "turnId": "turn_01M1NQGQH38A3MMGGEWKN4VCDP", + "parts": [ + { + "type": "reasoning", + "text": "Perfect! The verification confirms the arc has been successfully added. Looking at the final definition:\n\nThe `start-final-inspection` transition now has two input arcs:\n1. `{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}`\n2. `{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}`\n\nThis means:\n- Starting final inspection requires 1 token from \"batch-ready\" AND 1 token from \"dispatch-crew-available\"\n- It produces 1 token to \"under-final-inspection\"\n- The sign-off transition consumes the batch from inspection and returns 1 crew token\n\nThis satisfies the operational constraint: exactly one dispatch crew is consumed when inspection begins and released when sign-off completes.\n\nNow I need to emit the full revised runbook-ir workpiece as requested. I should update the prepared fixture material with:\n1. The operational account (confirmed)\n2. The current Petrinaut correspondence (UPDATED - the missing arc has been added)\n3. Explicit unknowns (unchanged)\n4. The claim boundary (adjusted to reflect what this correction establishes)", + "state": "done" + }, + { + "type": "text", + "text": "**Verification successful.** The `start-final-inspection` transition now contains the corrected input arcs:\n```json\n\"inputArcs\":[\n {\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"},\n {\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}\n]\n```\n\nThe resource constraint is now satisfied: firing `start-final-inspection` requires both a ready batch AND an available crew token. The `sign-off` transition releases that crew back to `dispatch-crew-available`.\n\n---\n\n## Revised workpiece (runbook-ir)\n\n```runbook-ir\n# Final inspection and dispatch workpiece — Revised\n\n## Purpose and posture\nModel the batch path from final inspection to dispatch readiness with explicit crew resource management. This revision adds the missing crew-consumption arc to enforce the resource constraint.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Starting final inspection requires both a ready batch AND the sole available dispatch crew.\n- Starting final inspection consumes that crew token.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available. Starting final inspection consumes that one available crew; sign-off returns it. No transition fires without sufficient tokens in all input places.\n\n## Petrinaut correspondence\nThe net contains four places:\n- `batch-ready`: batches awaiting final inspection\n- `under-final-inspection`: batches currently in inspection\n- `ready-for-dispatch`: batches cleared for dispatch\n- `dispatch-crew-available`: crew availability (1 token when free)\n\nTransitions:\n- `start-final-inspection`: requires 1 token from batch-ready AND 1 token from dispatch-crew-available; produces 1 token to under-final-inspection\n- `sign-off`: requires 1 token from under-final-inspection; produces 1 token to ready-for-dispatch AND 1 token to dispatch-crew-available\n\nThe missing standard weight-1 input arc from `dispatch-crew-available` to `start-final-inspection` has been **added and verified** in the live Petrinaut definition.\n\n## Explicit unknowns\n- Inspection timing: duration, stochasticity, or determinism remain unresolved\n- Sign-off timing: duration, stochasticity, or determinism remain unresolved\n- Failure modes: whether inspection can fail, halt, or reject a batch\n- Recovery behavior: how failures or rejections affect batch state or crew availability\n\n## Claim boundary\nThis workpiece and the corrected net establish only:\n- The crew-consumption constraint at start of inspection\n- The crew-release at sign-off completion\n- Token flow from ready batch through inspection to dispatch readiness\n\nThis is test-authored diagnostic material for the narrow final-inspection–to-dispatch path. It does not establish capture provenance, behavioral execution, failure handling, full process projection, or integration with upstream or downstream operations.\n```\n\nThe correction is complete and verified in the live Petrinaut definition.", + "state": "done" + } + ] + }, + { + "id": "entry_direct_c3ViX2lrXzg4NDFkMzZmMWUyZTRiYTlmMzk4NTJiZTU0ZDJlMTc0", + "role": "user", + "purpose": "user", + "display": "visible", + "submissionId": "sub_ik_8841d36f1e2e4ba9f39852be54d2e174", + "parts": [ + { + "type": "text", + "text": "From the resumed workpiece, list the unresolved timing, failure, and recovery questions. Do not change the Petrinaut net.", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NQJG7GRPC479PRF826T6F3", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_8841d36f1e2e4ba9f39852be54d2e174", + "turnId": "turn_01M1NQJFBBXYRZE472GFGHQF4K", + "parts": [ + { + "type": "reasoning", + "text": "The user wants me to extract and list the unresolved questions from the \"Explicit unknowns\" and \"Claim boundary\" sections of the workpiece I just delivered. They explicitly don't want me to change the Petrinaut net, just to articulate the open questions.\n\nLet me pull out the specific questions that remain unresolved:\n\nFrom \"Explicit unknowns\":\n1. Inspection timing: duration, stochasticity, or determinism remain unresolved\n2. Sign-off timing: duration, stochasticity, or determinism remain unresolved\n3. Failure modes: whether inspection can fail, halt, or reject a batch\n4. Recovery behavior: how failures or rejections affect batch state or crew availability\n\nI should unpack these into concrete questions that would need answering in a real operational investigation.", + "state": "done" + }, + { + "type": "text", + "text": "## Unresolved questions from the workpiece\n\n### Inspection timing\n1. How long does final inspection take—is it a fixed duration or variable?\n2. If variable, what distribution describes inspection duration (exponential, log-normal, empirical)?\n3. Does inspection timing depend on batch characteristics (size, composition, prior history)?\n4. Is inspection deterministic or does it include randomness?\n\n### Sign-off timing\n1. How long does sign-off take after inspection completes—is it immediate, fixed, or variable?\n2. If variable, what distribution describes sign-off duration?\n3. Does sign-off timing depend on inspection outcome or batch properties?\n4. Is sign-off deterministic or does it include randomness?\n\n### Failure modes\n1. Can a batch fail final inspection? If so, what triggers failure?\n2. Can inspection halt or pause without completing (e.g., awaiting additional information)?\n3. Can a batch be rejected at sign-off after passing inspection?\n4. Can the crew become unavailable during inspection (unavoidable absence, equipment failure, reassignment)?\n\n### Recovery behavior\n1. If a batch fails inspection, where does it go—back to ready, to a separate rework queue, or discarded?\n2. If a batch fails, does the crew become available immediately or does recovery consume crew time?\n3. If inspection halts mid-process, does the crew remain locked or become available?\n4. If rejected at sign-off, does the batch cycle back through inspection or follow a different path?\n5. If the crew becomes unavailable mid-inspection, what happens to the batch and the crew state?\n\nThese questions determine whether timing needs stochastic transitions, whether the batch path branches on failure, and how crew availability and batch state interact under exceptions. The current net cannot represent any of these behaviors.", + "state": "done" + } + ] + } + ], + "settlements": [ + { + "submissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915" + }, + { + "submissionId": "sub_ik_b7a274b7c2825d4c0914da440e241cb6", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_b7a274b7c2825d4c0914da440e241cb6" + }, + { + "submissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_dd2eb7be21980998b89ae9a9da085fb2" + }, + { + "submissionId": "sub_ik_008fa6d7354749a1cb3f674184e7cb1b", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_008fa6d7354749a1cb3f674184e7cb1b" + }, + { + "submissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715" + }, + { + "submissionId": "sub_ik_8841d36f1e2e4ba9f39852be54d2e174", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_8841d36f1e2e4ba9f39852be54d2e174" + } + ], + "incarnation": "inc_01M1NQEXM24JHNYN40Q8RA5DH5" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/latest-workpiece.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/latest-workpiece.md new file mode 100644 index 00000000000..596a87eb77c --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/latest-workpiece.md @@ -0,0 +1,41 @@ +# Final inspection and dispatch workpiece — Revised + +## Purpose and posture +Model the batch path from final inspection to dispatch readiness with explicit crew resource management. This revision adds the missing crew-consumption arc to enforce the resource constraint. + +## Operational account +- A batch that is ready enters final inspection. +- Starting final inspection requires both a ready batch AND the sole available dispatch crew. +- Starting final inspection consumes that crew token. +- Sign-off releases that crew and makes the batch ready for dispatch. + +## Quantity and resource policy +Exactly one dispatch crew is available. Starting final inspection consumes that one available crew; sign-off returns it. No transition fires without sufficient tokens in all input places. + +## Petrinaut correspondence +The net contains four places: +- `batch-ready`: batches awaiting final inspection +- `under-final-inspection`: batches currently in inspection +- `ready-for-dispatch`: batches cleared for dispatch +- `dispatch-crew-available`: crew availability (1 token when free) + +Transitions: +- `start-final-inspection`: requires 1 token from batch-ready AND 1 token from dispatch-crew-available; produces 1 token to under-final-inspection +- `sign-off`: requires 1 token from under-final-inspection; produces 1 token to ready-for-dispatch AND 1 token to dispatch-crew-available + +The missing standard weight-1 input arc from `dispatch-crew-available` to `start-final-inspection` has been **added and verified** in the live Petrinaut definition. + +## Explicit unknowns +- Inspection timing: duration, stochasticity, or determinism remain unresolved +- Sign-off timing: duration, stochasticity, or determinism remain unresolved +- Failure modes: whether inspection can fail, halt, or reject a batch +- Recovery behavior: how failures or rejections affect batch state or crew availability + +## Claim boundary +This workpiece and the corrected net establish only: +- The crew-consumption constraint at start of inspection +- The crew-release at sign-off completion +- Token flow from ready batch through inspection to dispatch readiness + +This is test-authored diagnostic material for the narrow final-inspection–to-dispatch path. It does not establish capture provenance, behavioral execution, failure handling, full process projection, or integration with upstream or downstream operations. + diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/prepared-workpiece.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/prepared-workpiece.md new file mode 100644 index 00000000000..9e99beae10e --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/prepared-workpiece.md @@ -0,0 +1,22 @@ +# Final inspection and dispatch workpiece + +## Purpose and posture +Maintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document. + +## Operational account +- A batch that is ready enters final inspection. +- Final inspection reserves the sole available dispatch crew. +- Sign-off releases that crew and makes the batch ready for dispatch. + +## Quantity and resource policy +Exactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it. + +## Current Petrinaut correspondence +The prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`. + +## Explicit unknowns +Inspection and sign-off timing, failure modes, and recovery behavior remain unresolved. + +## Claim boundary +This prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality. + diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/route-evidence.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/route-evidence.json new file mode 100644 index 00000000000..da12d3d008a --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/route-evidence.json @@ -0,0 +1,7 @@ +{ + "origin": "http://127.0.0.1:4915", + "historyRoute": "/agents/chat/?view=history", + "status": 200, + "retainedAuthorizationHeaders": false, + "retainedProviderPayloads": false +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-a-after.png b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-a-after.png new file mode 100644 index 0000000000000000000000000000000000000000..0f42bfeaebf28d6cb26c8b26d5946534853c76b0 GIT binary patch literal 142872 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�aI_jA~Xm^Bd>#SmHNjp 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 AAOHXW literal 0 HcmV?d00001 diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-a-before.png b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-a-before.png new file mode 100644 index 0000000000000000000000000000000000000000..142e160b12bfd58af0790f4c4a93f16852b1493b GIT binary patch literal 71412 zcmd43bySsG_%%v*cXxx7G)R|7gMf%22nvW2BHhxRBA^l?snP<{A&nr?BHe;?N_@}O zbI$ks?zsQmaqqZeFo1L1y!+j2Ju#m-=XxV_wbk%(XmF5_knpdoE9)a6p~J5zgIFl= zL!MCs83~C9>AJFlp~uUOSD1InRDO4GHXvOO81z>2+G?OI)F4JyiRVy3&*lD%krPDr zHauW|S`TflVT?&Zk&}&RNL@$$f>50Cx7=1@uer

EEmzrOc<`668>{ri{9-mfoG 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
XfO>c>ly9m$X&#AH%)SaB% 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 E1Muu|SO5S3 literal 0 HcmV?d00001 diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-b-after.png b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/screenshot-tab-b-after.png new file mode 100644 index 0000000000000000000000000000000000000000..5527acbca57f235f725ae6ec2162b5a83105f26b GIT binary patch literal 153210 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�BP{S(m+9zTh58ogF`uv?S&;yoDP@FZ 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 T6ivYIAZe)RDpxDoMEw5%mJ=)g literal 0 HcmV?d00001 diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-after.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-after.json new file mode 100644 index 00000000000..cd937a8620a --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-after.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "fixtureId": "crew-reservation-v1", + "revision": 1, + "settledAt": "2026-09-04T08:10:58.162Z", + "conversation": { + "logicalId": "mission-6-crew-reservation-conversation-v1", + "canonicalId": "conv_01M1NQEXM3CAPPTXM33ZE1YSRG", + "offset": "0000000000000000_0000000000000108" + }, + "latestWorkpiece": { + "authorship": "model-produced", + "contentSha256": "785135be03f8cbe9156b835f34d463bf7111fc109dd90dbe9db55955670c050e", + "sourceKind": "assistant", + "sourceMessageId": "entry_01M1NQGRAKWG69MWYMPYTCFXCZ", + "sourceMessageSha256": "5c5645d0f63c9792ece099228cbc021e117853108a1501c0cc230334eb2a6af8", + "sourceSubmissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715" + }, + "document": { + "id": "mission-6-crew-reservation-document-v1", + "sha256": "3c47961d02296c00131644d1aea0dac16a017f470a66aea919fcf324a2bc9e37", + "targetArc": "present" + }, + "manifestId": "a00f05964afc87b1ef34b50c96711232ac44c5b60eb6e8ce60a540af3b5dab49" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-before.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-before.json new file mode 100644 index 00000000000..48e8013a09f --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-before.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "fixtureId": "crew-reservation-v1", + "revision": 0, + "settledAt": "2026-09-04T08:10:01.220Z", + "conversation": { + "logicalId": "mission-6-crew-reservation-conversation-v1", + "canonicalId": "conv_01M1NQEXM3CAPPTXM33ZE1YSRG", + "offset": "0000000000000000_0000000000000043" + }, + "latestWorkpiece": { + "authorship": "test-authored", + "contentSha256": "1cc7a1b5d961f9f6327b458cf8292703ced5627fe26ee3f7b878f6375e51501a", + "sourceKind": "prepared-signal", + "sourceMessageId": "entry_direct_c3ViX2lrX2YyNDkzOWJlYmI4NDFmZmUxNDY5YTdmM2E0YTA2OTE1", + "sourceMessageSha256": "05003ea859f0658266d92b24eeaca0103aa75d2c4a3ec4eddaffe606b6775fc6", + "sourceSubmissionId": "sub_ik_f24939bebb841ffe1469a7f3a4a06915" + }, + "document": { + "id": "mission-6-crew-reservation-document-v1", + "sha256": "8dfa723b8dabadad790d2552de8e191e4227b07fe6c4d4e9d8e2d365e6ec4abd", + "targetArc": "absent" + }, + "manifestId": "fef5b371de498d5c2e6bb0456878c21aeb05a0f68957cde4a859f194b5122fab" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-tab-b.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-tab-b.json new file mode 100644 index 00000000000..cd937a8620a --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/settled-manifest-tab-b.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "fixtureId": "crew-reservation-v1", + "revision": 1, + "settledAt": "2026-09-04T08:10:58.162Z", + "conversation": { + "logicalId": "mission-6-crew-reservation-conversation-v1", + "canonicalId": "conv_01M1NQEXM3CAPPTXM33ZE1YSRG", + "offset": "0000000000000000_0000000000000108" + }, + "latestWorkpiece": { + "authorship": "model-produced", + "contentSha256": "785135be03f8cbe9156b835f34d463bf7111fc109dd90dbe9db55955670c050e", + "sourceKind": "assistant", + "sourceMessageId": "entry_01M1NQGRAKWG69MWYMPYTCFXCZ", + "sourceMessageSha256": "5c5645d0f63c9792ece099228cbc021e117853108a1501c0cc230334eb2a6af8", + "sourceSubmissionId": "sub_ik_6dbc187e4e72793b7539c02387d04715" + }, + "document": { + "id": "mission-6-crew-reservation-document-v1", + "sha256": "3c47961d02296c00131644d1aea0dac16a017f470a66aea919fcf324a2bc9e37", + "targetArc": "present" + }, + "manifestId": "a00f05964afc87b1ef34b50c96711232ac44c5b60eb6e8ce60a540af3b5dab49" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/tab-b-correlation.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/tab-b-correlation.json new file mode 100644 index 00000000000..d5c02471672 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/tab-b-correlation.json @@ -0,0 +1,18 @@ +{ + "conversationId": "conv_01M1NQEXM3CAPPTXM33ZE1YSRG", + "offset": "0000000000000000_0000000000000123", + "manifestId": "a00f05964afc87b1ef34b50c96711232ac44c5b60eb6e8ce60a540af3b5dab49", + "documentSha256": "3c47961d02296c00131644d1aea0dac16a017f470a66aea919fcf324a2bc9e37", + "workpieceSha256": "785135be03f8cbe9156b835f34d463bf7111fc109dd90dbe9db55955670c050e", + "preparedSourceCount": 1, + "addArcCallCount": 1, + "followUp": { + "submissionId": "sub_ik_8841d36f1e2e4ba9f39852be54d2e174", + "responseMessageId": "entry_01M1NQJG7GRPC479PRF826T6F3", + "settlement": { + "submissionId": "sub_ik_8841d36f1e2e4ba9f39852be54d2e174", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_8841d36f1e2e4ba9f39852be54d2e174" + } + } +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/witness.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/witness.md new file mode 100644 index 00000000000..87c7d8d2fc5 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/witness.md @@ -0,0 +1,90 @@ +# FE-1575 outer browser witness — 2026-09-04 + +## Scope + +This is the retained outer mechanical witness for Mission 6 at commit +`ace2968`. It used a clean browser principal in one Playwright context, the +stable `crew-reservation-v1` fixture route, the local Brunch Flue mount, and a +real configured provider credential. Credentials, authorization headers, the +browser principal, the Flue instance route component, and provider request +payloads are not retained. + +The provider serialized the `addArc` weight as `"1"`. The witnessed build +normalized that finite numeric string at the Petrinaut tool boundary before +canonical validation and browser execution. The retained raw Flue snapshot +preserves the provider-supplied input; the resulting Petrinaut definition +preserves the canonical numeric weight `1`. + +## Protocol and result + +1. Started `yarn dev:brunch` after loading `.env.local` without printing it. +2. Cleared browser local storage, opened + `http://127.0.0.1:4915/?brunch-fixture=crew-reservation-v1`, and waited for + settled revision zero. +3. Retained the before Flue snapshot, canonical definition, runtime manifest, + and Tab A screenshot. +4. Submitted one confirmation/construction turn: + + > Confirmed: final inspection uses the single dispatch crew and sign-off + > releases it; timing, failure, and recovery remain unknown. Read the live + > Petrinaut definition, add the missing standard weight-1 input arc from + > Dispatch crew available to Start final inspection, verify it, and emit + > the full revised runbook-ir workpiece. + +5. Observed one `addArc` call and one correlated successful client-tool result: + `toolu_01KLHzRE7gbPbFfPaXe3RTry`. +6. Verified that the only semantic definition delta was one standard, + weight-1 input arc from `dispatch-crew-available` to + `start-final-inspection`. +7. Observed runtime manifest revision 1 selecting the model-produced workpiece + and changed document, with target arc `present`. +8. Opened Tab B in the same browser context. It selected the same manifest, + workpiece hash, document hash, and canonical conversation, with exactly one + prepared source and one `addArc` call. +9. Submitted a non-mutating follow-up in Tab B: + + > From the resumed workpiece, list the unresolved timing, failure, and + > recovery questions. Do not change the Petrinaut net. + +10. Observed completed submission + `sub_ik_8841d36f1e2e4ba9f39852be54d2e174` and correlated response message + `entry_01M1NQJG7GRPC479PRF826T6F3`. The document and settled manifest were + unchanged. + +## Retained identities and invariants + +- Canonical conversation: `conv_01M1NQEXM3CAPPTXM33ZE1YSRG` +- Settled manifest revision: `1` +- Settled manifest ID: + `a00f05964afc87b1ef34b50c96711232ac44c5b60eb6e8ce60a540af3b5dab49` +- Prepared source count after Tab B: `1` +- `addArc` call count after Tab B: `1` +- Tab B follow-up outcome: `completed` +- `definition-after.json` and `definition-tab-b.json` have the same SHA-256. +- `settled-manifest-after.json` and `settled-manifest-tab-b.json` have the same + SHA-256. + +## Artifacts + +- Before state: [Flue](flue-snapshot-before.json), + [definition](definition-before.json), + [manifest](settled-manifest-before.json), + [screenshot](screenshot-tab-a-before.png) +- Settled Tab A state: [Flue](flue-snapshot-after.json), + [definition](definition-after.json), + [manifest](settled-manifest-after.json), + [call/result correlation](call-result-correlation.json), + [screenshot](screenshot-tab-a-after.png) +- Tab B continuation: [Flue](flue-snapshot-tab-b.json), + [definition](definition-tab-b.json), + [manifest](settled-manifest-tab-b.json), + [correlation](tab-b-correlation.json), + [screenshot](screenshot-tab-b-after.png) +- Semantic inputs: [prepared workpiece](prepared-workpiece.md), + [latest workpiece](latest-workpiece.md) +- Redacted route observation: [route evidence](route-evidence.json) +- Integrity: [SHA256SUMS](SHA256SUMS) + +This witness proves the bounded browser protocol above. It does not establish +capture provenance, timing behavior, failure/recovery behavior, simulation +validity, or broad automatic projection quality. diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md index 145b4bc08cf..6b215ab5147 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md @@ -17,51 +17,51 @@ Focused tests cover: - rejected and duplicate/no-op canonical browser mutations; - exact prepared and revised document structure; - history, workpiece, mutation-result, and document mismatch refusal; and -- retention of the prior runtime manifest while partial state remains visible. +- content-addressed selection of the prior coherent document revision while a + partial mirrored value remains inspectable. The affected Brunch, transport, plugin, Petrinaut, and website builds, type -checks, and lint checks passed on 2026-09-03. The app-wide lint checks retain +checks, and lint checks passed on 2026-09-04. The app-wide lint checks retain pre-existing warning-only findings; no persona suite was run. -## Live browser attempt and blocker +## Live two-tab browser witness -The local `yarn dev:brunch` stack served the mounted agent at -`/agents/chat/:instanceId` and the Petrinaut fixture at: +The successful 2026-09-04 witness is retained in +[fe-1575-outer-browser-witness-2026-09-04](fe-1575-outer-browser-witness-2026-09-04/witness.md). +It used the local `yarn dev:brunch` stack, one clean Playwright browser +context, the mounted `/agents/chat/:instanceId` route, a real configured +provider credential, and the stable fixture URL: ```text http://127.0.0.1:4915/?brunch-fixture=crew-reservation-v1 ``` -The browser opened the non-empty prepared document and created canonical Flue -conversation `conv_01M1KZ1Z32SJ0800V94ZE59ENR`. Snapshot offset -`0000000000000000_0000000000000006` contained exactly one tagged -`prepared-fixture` dispatch record under submission -`sub_ik_b224f8e328e14cfa803c63d06376e5e9`, preserving the test-authored Markdown -body and claim-boundary attributes. - -That submission settled as `failed` because the configured Anthropic -credential returned HTTP 401 `authentication_error: invalid x-api-key`. -Consequently: - -- no model-behavior claim was made; -- no typed confirmation, client-tool mutation, or Tab B continuation was - attempted; -- the runtime settled manifest remained `null`; and -- the visible fixture status refused settlement as `history-unavailable` - instead of blessing the prepared document alone. - -This is an authentication/environment blocker on the outer witness, not -evidence that the selected provider-visible schema or Flue carrier cannot -faithfully carry the mutation. It is not a passing two-tab witness. No success -screenshot was retained. - -## Remaining external checks - -After a valid provider credential is supplied, rerun the demo script to retain -the successful before/after Flue snapshots, canonical definitions, runtime -manifest, call/result IDs, and Tab A/Tab B screenshots. Cold-reader semantic -adjudication and the product-manager demo remain separate human-harness checks; -they were not replaced with persona testing here. +The clean run created canonical conversation +`conv_01M1NQEXM3CAPPTXM33ZE1YSRG` and exactly one tagged prepared source. Tab A +advanced from settled revision zero with the target arc absent to revision 1 +with a model-produced workpiece and the target arc present. It retained one +`addArc` call and one correlated successful result, +`toolu_01KLHzRE7gbPbFfPaXe3RTry`. Mechanical comparison found exactly one +semantic document change: a standard weight-1 input arc from +`dispatch-crew-available` to `start-final-inspection`. + +Tab B reopened the same manifest, workpiece hash, document hash, and canonical +conversation. It submitted a non-mutating follow-up and received completed +correlated response `entry_01M1NQJG7GRPC479PRF826T6F3` without another prepared +source or `addArc` call. The post-Tab-A and Tab-B definitions and manifests +have identical hashes. + +The provider serialized the arc weight as `"1"`. The witnessed implementation +normalizes that finite numeric string before canonical server and browser +validation; the raw Flue snapshot retains the supplied representation while +the canonical Petrinaut definition contains numeric weight `1`. The earlier +HTTP 401 remains historical authentication/environment evidence only, not a +carrier/schema conclusion. + +## Remaining human checks + +Cold-reader semantic adjudication and the product-manager demo remain separate +human gates. They have not been replaced with persona or agent testing. ### Cold-reader handoff From 7cc35a81e1ef1b78f146b8d59eee63bc2c0a0d7a Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 10:47:08 +0200 Subject: [PATCH 09/31] Simplify Mission 6 settlement coordination --- .../use-crew-reservation-settled-manifest.ts | 37 ++++++++----------- libs/@hashintel/brunch-agent/MISSION.md | 2 +- 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts index 003cca50400..510dd78d5f4 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/use-crew-reservation-settled-manifest.ts @@ -1,5 +1,5 @@ import { useLocalStorage } from "@mantine/hooks"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useState } from "react"; import { crewReservationSettledManifestStorageKey, @@ -69,17 +69,8 @@ export const useCrewReservationSettlement = (input: { } = input; const [observedStatus, setObservedStatus] = useState({ state: "preparing" }); - const manifestRef = useRef(settledManifest); - const observationIdRef = useRef(0); - const queueRef = useRef(Promise.resolve()); useEffect(() => { - manifestRef.current = settledManifest; - }, [settledManifest]); - - useEffect(() => { - const observationId = observationIdRef.current + 1; - observationIdRef.current = observationId; if ( !enabled || historyError !== undefined || @@ -89,22 +80,19 @@ export const useCrewReservationSettlement = (input: { return; } + let cancelled = false; const definitionSnapshot = structuredClone(definition); - const historySnapshot = history; - queueRef.current = queueRef.current.then(async () => { - if (observationId !== observationIdRef.current) return; + const settle = async (): Promise => { let result: CrewReservationSettlementResult; try { result = await settleCrewReservationManifest({ definition: definitionSnapshot, - history: historySnapshot, - ...(manifestRef.current === null - ? {} - : { previous: manifestRef.current }), + history, + ...(settledManifest === null ? {} : { previous: settledManifest }), settledAt: new Date().toISOString(), }); } catch (error) { - if (observationId === observationIdRef.current) { + if (!cancelled) { setObservedStatus({ state: "refused", reason: "settlement-failed", @@ -116,7 +104,7 @@ export const useCrewReservationSettlement = (input: { } return; } - if (observationId !== observationIdRef.current) return; + if (cancelled) return; if (result.status === "refused") { setObservedStatus({ state: "refused", @@ -128,12 +116,16 @@ export const useCrewReservationSettlement = (input: { result.manifest.document.sha256, definitionSnapshot, ); - if (result.manifest.manifestId !== manifestRef.current?.manifestId) { - manifestRef.current = result.manifest; + if (result.manifest.manifestId !== settledManifest?.manifestId) { setSettledManifest(result.manifest); } setObservedStatus({ state: "settled" }); - }); + }; + void settle(); + + return () => { + cancelled = true; + }; }, [ definition, enabled, @@ -141,6 +133,7 @@ export const useCrewReservationSettlement = (input: { historyError, persistCoherentSnapshot, setSettledManifest, + settledManifest, ]); const status: CrewReservationSettlementStatus = !enabled diff --git a/libs/@hashintel/brunch-agent/MISSION.md b/libs/@hashintel/brunch-agent/MISSION.md index fd903deff39..843d4d55ed4 100644 --- a/libs/@hashintel/brunch-agent/MISSION.md +++ b/libs/@hashintel/brunch-agent/MISSION.md @@ -2,7 +2,7 @@ ## Status -**Live on `ln/fe-1575-resumable-workpiece-petrinaut` from 2026-09-03.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) is in progress. This authority cut is committed separately before product or evaluation implementation begins. It was recut on restack the same day to carry the product-manager litmus adopted in [`MISSION.next.md`](MISSION.next.md#current-authority-and-accepted-spine) after the first cut: completion is the readiness gate below, not the first green two-tab pass. The owner subsequently accepted the probe-backed prepared-history semantics under [Accepted fixture and boundary crossings](#accepted-fixture-and-boundary-crossings), then corrected this mission to consume Mission 5's one-route browser Flue transport, automatic localStorage persistence, a runtime settled manifest, visible preparation language, and an actual Tab B continuation. Each authority amendment lands separately before dependent implementation. The 2026-09-04 Mission 5 human witness also made faithful transcript resume load-bearing here: per-message typed/Voice provenance disappeared after reload, and a stopped assistant entry returned as ordinary truncated content. The owner deferred both defects to this mission rather than expanding Mission 5. +**Live on `ln/fe-1575-resumable-workpiece-petrinaut`.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) remains in progress. The implementation and outer mechanical witness are complete; cold-reader semantic adjudication and the product-manager demo remain the final acceptance gates. See the [retained implementation and witness evidence](docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md). ## Imperative From 0f42a698169e5a8c13152863d000922c5ebac801 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 10:48:18 +0200 Subject: [PATCH 10/31] Normalize Mission 6 witness workpiece files --- .../fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS | 4 ++-- .../latest-workpiece.md | 1 - .../prepared-workpiece.md | 1 - 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS index f44908b86b0..1d9c9bd912c 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/SHA256SUMS @@ -7,8 +7,8 @@ c17ae80cc22939f0af6c2675f6bcc20b025b17a5b7bfb9e8029813bcef9ad736 definition-tab 4fe368ef206e71e63173c1876ac9ca54e8b0d0971066be74dae5f78d4b612b0a flue-snapshot-after.json ea20487150d8a329f4c2a6e0ac32e22de39d0d655646581ad2c56768a3591d1a flue-snapshot-before.json 7aaa993b395bc4ac84625fb2f472645ba13428bc39faac1f0f4ba948bfb3d9f5 flue-snapshot-tab-b.json -0f04053f623e488c522a3cca06bf34593004379dab0f0e551b26a355d87b1049 latest-workpiece.md -2859b2c9c756dd67589df04cdae498f63affffe0d65ca7f9ec6971b81eabfe94 prepared-workpiece.md +a384aa803085d3ff350a347e18080503a78305f87eb5d91eec1ad1141b941eb3 latest-workpiece.md +17f99f53f8cf93285a7344f5e9687d94e5f59011e6895ce11a9722fde2e77511 prepared-workpiece.md cfb79c8f52fc8f1758b1a61f67e520c67a31d2f19f561017899d0724b776100a route-evidence.json a9bd4a4a18f52ebd5c0f0e9c7c5d80b1c37e85823bfa6a03bd9c1d329b4b4267 screenshot-tab-a-after.png eaf49081a6ab7acba746f337fdb85e3829d473818dc7c96f83a40acd3cb6f383 screenshot-tab-a-before.png diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/latest-workpiece.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/latest-workpiece.md index 596a87eb77c..be2a95f9fc4 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/latest-workpiece.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/latest-workpiece.md @@ -38,4 +38,3 @@ This workpiece and the corrected net establish only: - Token flow from ready batch through inspection to dispatch readiness This is test-authored diagnostic material for the narrow final-inspection–to-dispatch path. It does not establish capture provenance, behavioral execution, failure handling, full process projection, or integration with upstream or downstream operations. - diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/prepared-workpiece.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/prepared-workpiece.md index 9e99beae10e..fa01def8c11 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/prepared-workpiece.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04/prepared-workpiece.md @@ -19,4 +19,3 @@ Inspection and sign-off timing, failure modes, and recovery behavior remain unre ## Claim boundary This prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality. - From caeced4dd19c7545707b4778d2918324a86541f1 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 10:55:15 +0200 Subject: [PATCH 11/31] Validate Mission 6 coherent bundle inputs --- .changeset/resumable-petrinaut-workpiece.md | 1 + apps/petrinaut-website/package.json | 1 + .../crew-reservation-settled-manifest.ts | 31 ++-- .../resolve-crew-reservation-bundle.test.ts | 149 +++++++++++------- .../resolve-crew-reservation-bundle.ts | 48 +++++- .../packages/plugin-sdcpn/src/flue.ts | 2 +- libs/@hashintel/petrinaut-core/src/ai.test.ts | 8 +- libs/@hashintel/petrinaut-core/src/ai.ts | 8 - yarn.lock | 1 + 9 files changed, 154 insertions(+), 95 deletions(-) diff --git a/.changeset/resumable-petrinaut-workpiece.md b/.changeset/resumable-petrinaut-workpiece.md index 40e8ffd20ae..4387d484672 100644 --- a/.changeset/resumable-petrinaut-workpiece.md +++ b/.changeset/resumable-petrinaut-workpiece.md @@ -1,5 +1,6 @@ --- "@hashintel/petrinaut": patch +"@hashintel/petrinaut-core": patch --- Report duplicate AI mutations as no-ops so hosts can distinguish an applied document change from diff --git a/apps/petrinaut-website/package.json b/apps/petrinaut-website/package.json index 2f9314e4ce9..d90b45168e0 100644 --- a/apps/petrinaut-website/package.json +++ b/apps/petrinaut-website/package.json @@ -27,6 +27,7 @@ "@hashintel/petrinaut-core": "workspace:*", "@local/petrinaut-optimizer-client": "workspace:*", "@mantine/hooks": "8.3.5", + "@noble/hashes": "2.0.1", "@pandacss/dev": "1.11.1", "@sentry/react": "10.64.0", "@tanstack/react-router": "1.170.31", diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts index d94d5111314..b157dfef5a5 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/crew-reservation-settled-manifest.ts @@ -1,3 +1,6 @@ +import { sha256 as sha256Bytes } from "@noble/hashes/sha2.js"; +import { bytesToHex } from "@noble/hashes/utils.js"; + import { clientToolHistoryFrom } from "@hashintel/brunch-agent-transport-aisdk"; import { selectRunbookWorkpiece } from "@hashintel/brunch-agent/workpiece"; import { isSDCPNEqual, type SDCPN } from "@hashintel/petrinaut-core"; @@ -130,17 +133,8 @@ const hasOneCorrelatedTargetMutation = ( return correlatedTargetCallIds.size === 1; }; -const sha256 = async (value: string): Promise => { - const digest = await globalThis.crypto.subtle.digest( - "SHA-256", - new TextEncoder().encode(value), - ); - return asSha256Digest( - [...new Uint8Array(digest)] - .map((byte) => byte.toString(16).padStart(2, "0")) - .join(""), - ); -}; +export const sha256Digest = (value: string): Sha256Digest => + asSha256Digest(bytesToHex(sha256Bytes(new TextEncoder().encode(value)))); export const hasCrewReservationTargetArc = (definition: SDCPN): boolean => { const transition = definition.transitions.find( @@ -214,14 +208,13 @@ export const settleCrewReservationManifest = async (input: { }; } - const [contentSha256, documentSha256, sourceMessageSha256] = - await Promise.all([ - sha256(workpiece.content), - sha256(JSON.stringify(input.definition)), - sha256(JSON.stringify(workpiece.sourceMessage)), - ]); + const contentSha256 = sha256Digest(workpiece.content); + const documentSha256 = sha256Digest(JSON.stringify(input.definition)); + const sourceMessageSha256 = sha256Digest( + JSON.stringify(workpiece.sourceMessage), + ); if (workpiece.authorship === "test-authored") { - const preparedDocumentSha256 = await sha256( + const preparedDocumentSha256 = sha256Digest( JSON.stringify(preparedCrewReservationNet), ); if ( @@ -276,7 +269,7 @@ export const settleCrewReservationManifest = async (input: { status: "settled", manifest: { ...withoutId, - manifestId: asManifestId(await sha256(JSON.stringify(withoutId))), + manifestId: asManifestId(sha256Digest(JSON.stringify(withoutId))), }, }; }; diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts index 169ad433863..7da06ba9129 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test } from "vitest"; import { + latestRunbookIrBlock, preparedWorkpieceAuthorship, preparedWorkpieceClaimBoundary, preparedWorkpieceSignalTag, @@ -12,7 +13,7 @@ import { asFlueMessageId, asFlueSubmissionId, asManifestId, - asSha256Digest, + sha256Digest, type CrewReservationSettledManifest, } from "./crew-reservation-settled-manifest"; import { @@ -27,8 +28,30 @@ import { workpieceForCrewReservationBundle, } from "./resolve-crew-reservation-bundle"; +import type { CrewReservationHistory } from "./crew-reservation-history"; import type { SDCPNInLocalStorage } from "./use-local-storage-sdcpns"; +const preparedMessage = { + id: "prepared-message", + role: "system", + purpose: "dispatch", + submissionId: "prepare-submission", + signal: { + tagName: preparedWorkpieceSignalTag, + attributes: { + fixtureId: crewReservationFixtureId, + authorship: preparedWorkpieceAuthorship, + claimBoundary: preparedWorkpieceClaimBoundary, + }, + }, + parts: [{ type: "text", text: preparedCrewReservationWorkpiece }], +} as const; + +const preparedContent = latestRunbookIrBlock(preparedCrewReservationWorkpiece); +if (preparedContent === undefined) { + throw new Error("The prepared fixture has no runbook-ir workpiece."); +} + const manifest: CrewReservationSettledManifest = { version: 1, fixtureId: crewReservationFixtureId, @@ -42,16 +65,16 @@ const manifest: CrewReservationSettledManifest = { }, document: { id: crewReservationDocumentId, - sha256: asSha256Digest("coherent-hash"), + sha256: sha256Digest(JSON.stringify(preparedCrewReservationNet)), targetArc: "absent", }, latestWorkpiece: { authorship: "test-authored", - contentSha256: asSha256Digest("content"), + contentSha256: sha256Digest(preparedContent), sourceKind: "prepared-signal", - sourceMessageId: asFlueMessageId("prepared-message"), - sourceMessageSha256: asSha256Digest("message"), - sourceSubmissionId: asFlueSubmissionId("prepare-submission"), + sourceMessageId: asFlueMessageId(preparedMessage.id), + sourceMessageSha256: sha256Digest(JSON.stringify(preparedMessage)), + sourceSubmissionId: asFlueSubmissionId(preparedMessage.submissionId), }, }; @@ -62,8 +85,28 @@ const fallbackDocument: SDCPNInLocalStorage = { lastUpdated: "1970-01-01T00:00:00.000Z", }; +const history: CrewReservationHistory = { + conversationId: "canonical", + offset: "3", + settlements: [], + messages: [ + preparedMessage, + { + id: "newer-message", + role: "assistant", + purpose: "assistant", + parts: [ + { + type: "text", + text: "```runbook-ir\n# Unsettled newer workpiece\n```", + }, + ], + }, + ], +}; + describe("resolveCrewReservationBundle", () => { - test("selects the content-addressed coherent document over a partial mirror", () => { + test("selects a coherent document whose content matches the manifest digest", () => { const partialDefinition = structuredClone(preparedCrewReservationNet); const firstPlace = partialDefinition.places.at(0); if (firstPlace === undefined) { @@ -78,7 +121,7 @@ describe("resolveCrewReservationBundle", () => { ...fallbackDocument, sdcpn: partialDefinition, coherentSnapshots: { - "coherent-hash": preparedCrewReservationNet, + [manifest.document.sha256]: preparedCrewReservationNet, }, }, }); @@ -88,62 +131,62 @@ describe("resolveCrewReservationBundle", () => { preparedCrewReservationNet, ); expect(selection.selectedDocument.sdcpn).not.toEqual(partialDefinition); - expect(selection.observedDocument.sdcpn).toEqual(partialDefinition); }); - test("keeps a missing snapshot diagnosable without inventing a revision", () => { + test("refuses a snapshot stored under a digest that its content does not match", () => { + const corruptedSnapshot = structuredClone(preparedCrewReservationNet); + const firstPlace = corruptedSnapshot.places.at(0); + if (firstPlace === undefined) { + throw new Error("The prepared fixture has no places."); + } + firstPlace.name = "Corrupted snapshot"; + const selection = resolveCrewReservationBundle({ fallbackDocument, manifest, - storedDocument: fallbackDocument, + storedDocument: { + ...fallbackDocument, + coherentSnapshots: { + [manifest.document.sha256]: corruptedSnapshot, + }, + }, }); - expect(selection).toEqual({ - observedDocument: fallbackDocument, + expect(selection.snapshotMissing).toBe(true); + expect(selection.selectedDocument.sdcpn).toEqual(fallbackDocument.sdcpn); + expect(selection.selectedDocument.sdcpn).not.toEqual(corruptedSnapshot); + }); + + test("keeps a missing snapshot diagnosable without inventing a revision", () => { + expect( + resolveCrewReservationBundle({ + fallbackDocument, + manifest, + storedDocument: fallbackDocument, + }), + ).toEqual({ selectedDocument: fallbackDocument, snapshotMissing: true, }); }); }); -test("selects the workpiece source named by the settled manifest", () => { - const newerWorkpiece = "```runbook-ir\n# Unsettled newer workpiece\n```"; - expect( - workpieceForCrewReservationBundle( - { - conversationId: "canonical", - offset: "3", - settlements: [], - messages: [ - { - id: "prepared-message", - role: "system", - purpose: "dispatch", - submissionId: "prepare-submission", - signal: { - tagName: preparedWorkpieceSignalTag, - attributes: { - fixtureId: crewReservationFixtureId, - authorship: preparedWorkpieceAuthorship, - claimBoundary: preparedWorkpieceClaimBoundary, - }, - }, - parts: [ - { - type: "text", - text: preparedCrewReservationWorkpiece, - }, - ], - }, - { - id: "newer-message", - role: "assistant", - purpose: "assistant", - parts: [{ type: "text", text: newerWorkpiece }], - }, - ], - }, - manifest, - ), - ).toContain("# Final inspection and dispatch workpiece"); +describe("workpieceForCrewReservationBundle", () => { + test("selects the source whose content and record match the manifest hashes", () => { + expect(workpieceForCrewReservationBundle(history, manifest)).toContain( + "# Final inspection and dispatch workpiece", + ); + }); + + test("refuses a selected source whose manifest hash does not match", () => { + expect( + workpieceForCrewReservationBundle(history, { + ...manifest, + latestWorkpiece: { + ...manifest.latestWorkpiece, + sourceMessageSha256: sha256Digest("mismatched source"), + }, + }), + ).toBeUndefined(); + }); }); diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.ts b/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.ts index 065568d3320..9a601aa517a 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.ts +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/resolve-crew-reservation-bundle.ts @@ -3,12 +3,15 @@ import { selectRunbookWorkpiece, } from "@hashintel/brunch-agent/workpiece"; +import { + sha256Digest, + type CrewReservationSettledManifest, +} from "./crew-reservation-settled-manifest"; + import type { CrewReservationHistory } from "./crew-reservation-history"; -import type { CrewReservationSettledManifest } from "./crew-reservation-settled-manifest"; import type { SDCPNInLocalStorage } from "./use-local-storage-sdcpns"; export interface CrewReservationBundleSelection { - readonly observedDocument: SDCPNInLocalStorage; readonly selectedDocument: SDCPNInLocalStorage; readonly snapshotMissing: boolean; } @@ -21,7 +24,6 @@ export const resolveCrewReservationBundle = (input: { const liveDocument = input.storedDocument ?? input.fallbackDocument; if (input.manifest === null) { return { - observedDocument: liveDocument, selectedDocument: liveDocument, snapshotMissing: false, }; @@ -29,16 +31,18 @@ export const resolveCrewReservationBundle = (input: { const coherentDefinition = liveDocument.coherentSnapshots?.[input.manifest.document.sha256]; - if (coherentDefinition === undefined) { + if ( + coherentDefinition === undefined || + sha256Digest(JSON.stringify(coherentDefinition)) !== + input.manifest.document.sha256 + ) { return { - observedDocument: liveDocument, selectedDocument: liveDocument, snapshotMissing: true, }; } return { - observedDocument: liveDocument, selectedDocument: { ...liveDocument, sdcpn: coherentDefinition, @@ -54,13 +58,41 @@ export const workpieceForCrewReservationBundle = ( if (history === undefined) return undefined; if (manifest === null) return selectRunbookWorkpiece(history)?.content; - const selectedMessage = history.messages.find( + const selectedMessageIndex = history.messages.findIndex( ({ id }) => id === manifest.latestWorkpiece.sourceMessageId, ); + if (selectedMessageIndex === -1) return undefined; + const selectedMessage = history.messages[selectedMessageIndex]; if (selectedMessage === undefined) return undefined; - return latestRunbookIrBlock( + + const content = latestRunbookIrBlock( selectedMessage.parts .flatMap((part) => (part.type === "text" ? [part.text] : [])) .join("\n"), ); + if ( + content === undefined || + sha256Digest(content) !== manifest.latestWorkpiece.contentSha256 || + sha256Digest(JSON.stringify(selectedMessage)) !== + manifest.latestWorkpiece.sourceMessageSha256 + ) { + return undefined; + } + + const selectedWorkpiece = selectRunbookWorkpiece({ + ...history, + messages: history.messages.slice(0, selectedMessageIndex + 1), + }); + if ( + selectedWorkpiece?.sourceMessageId !== + manifest.latestWorkpiece.sourceMessageId || + selectedWorkpiece.sourceSubmissionId !== + manifest.latestWorkpiece.sourceSubmissionId || + selectedWorkpiece.authorship !== manifest.latestWorkpiece.authorship || + selectedWorkpiece.sourceKind !== manifest.latestWorkpiece.sourceKind + ) { + return undefined; + } + + return content; }; diff --git a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts index 6afa49c5ef0..06705585906 100644 --- a/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts +++ b/libs/@hashintel/brunch-agent/packages/plugin-sdcpn/src/flue.ts @@ -56,7 +56,7 @@ This is a construct-only headless conversation. Use only the supplied runbook IR } else if (initialData?.mode === validatedFixtureMutationMode) { useInstruction( ` -This is a visibly labelled prepared-fixture conversation. Treat its tagged prepared runbook-ir dispatch as test-authored revision zero, maintain the full Markdown workpiece in later responses, preserve explicit unknowns, and do not relabel prepared material as model-produced. Use only the mounted canonical Petrinaut read and least arc mutation when confirmed evidence calls for that change. Read the live document before mutating it, report rejected or no-op outcomes honestly, and do not construct unrelated net content. +This is a visibly labelled prepared-fixture conversation. Treat its tagged prepared runbook-ir dispatch as test-authored revision zero, maintain the full Markdown workpiece in later responses, preserve explicit unknowns, and do not relabel prepared material as model-produced. Every later assistant-authored workpiece is model-produced: label that revision accordingly and do not copy revision zero's claim that the current revision is test-authored. Use only the mounted canonical Petrinaut read and least arc mutation when confirmed evidence calls for that change. Read the live document before mutating it, report rejected or no-op outcomes honestly, and do not construct unrelated net content. `.replace(/^\s+|\s+$/gu, ""), ); for (const fixtureTool of petrinautFixtureTools) { diff --git a/libs/@hashintel/petrinaut-core/src/ai.test.ts b/libs/@hashintel/petrinaut-core/src/ai.test.ts index 124bed1dfb1..06f9ac185f0 100644 --- a/libs/@hashintel/petrinaut-core/src/ai.test.ts +++ b/libs/@hashintel/petrinaut-core/src/ai.test.ts @@ -47,19 +47,15 @@ describe("Petrinaut AI core exports", () => { expect(petrinautAiTools).toHaveProperty("applyAutoLayout"); }); - test("normalizes structured addArc values from text-oriented providers", () => { + test("normalizes an addArc weight serialized as text", () => { expect( normalizePetrinautAiToolInput("addArc", { transitionId: "transition", arcDirection: "input", weight: "1", type: "standard", - endpoint: '{"kind":"place","placeId":"place"}', }), - ).toMatchObject({ - weight: 1, - endpoint: { kind: "place", placeId: "place" }, - }); + ).toMatchObject({ weight: 1 }); }); test("latest net definition tool documents extension settings", () => { diff --git a/libs/@hashintel/petrinaut-core/src/ai.ts b/libs/@hashintel/petrinaut-core/src/ai.ts index eb33fc43b3b..686ebbaf6b5 100644 --- a/libs/@hashintel/petrinaut-core/src/ai.ts +++ b/libs/@hashintel/petrinaut-core/src/ai.ts @@ -231,14 +231,6 @@ export const normalizePetrinautAiToolInput = ( const weight = Number(normalized.weight); if (Number.isFinite(weight)) normalized = { ...normalized, weight }; } - if (typeof normalized.endpoint === "string") { - try { - const endpoint: unknown = JSON.parse(normalized.endpoint); - if (isRecord(endpoint)) normalized = { ...normalized, endpoint }; - } catch { - // Canonical validation reports the original malformed endpoint. - } - } return normalized; }; diff --git a/yarn.lock b/yarn.lock index e49cd51704c..cc5c5c0c50e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -949,6 +949,7 @@ __metadata: "@hashintel/petrinaut-core": "workspace:*" "@local/petrinaut-optimizer-client": "workspace:*" "@mantine/hooks": "npm:8.3.5" + "@noble/hashes": "npm:2.0.1" "@pandacss/dev": "npm:1.11.1" "@sentry/react": "npm:10.64.0" "@tanstack/react-router": "npm:1.170.31" From 3a5390444d8174370acd556ae9df7d44c9ea04ab Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 11:19:03 +0200 Subject: [PATCH 12/31] Replace the Mission 6 outer witness with honest authorship evidence --- .../SHA256SUMS | 21 ++ .../call-result-correlation.json | 84 +++++ .../cold-reader-gate.md | 31 ++ .../cold-reader-records.json | 46 +++ .../definition-after.json | 98 ++++++ .../definition-before.json | 93 +++++ .../definition-tab-b.json | 98 ++++++ .../flue-snapshot-after.json | 287 +++++++++++++++ .../flue-snapshot-before.json | 89 +++++ .../flue-snapshot-tab-b.json | 326 ++++++++++++++++++ .../latest-workpiece.md | 45 +++ .../prepared-workpiece.md | 21 ++ .../route-evidence.json | 6 + .../run-metadata.json | 8 + .../screenshot-tab-a-after.png | Bin 0 -> 150019 bytes .../screenshot-tab-a-before.png | Bin 0 -> 88123 bytes .../screenshot-tab-b-after.png | Bin 0 -> 169940 bytes .../settled-manifest-after.json | 25 ++ .../settled-manifest-before.json | 25 ++ .../settled-manifest-tab-b.json | 25 ++ .../tab-b-correlation.json | 21 ++ .../witness.md | 48 +++ .../fe-1575-resumable-workpiece-petrinaut.md | 34 +- 23 files changed, 1405 insertions(+), 26 deletions(-) create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/SHA256SUMS create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/call-result-correlation.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-gate.md create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-records.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-after.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-before.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-tab-b.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-after.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-before.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-tab-b.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/latest-workpiece.md create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/prepared-workpiece.md create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/route-evidence.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/run-metadata.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/screenshot-tab-a-after.png create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/screenshot-tab-a-before.png create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/screenshot-tab-b-after.png create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/settled-manifest-after.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/settled-manifest-before.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/settled-manifest-tab-b.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/tab-b-correlation.json create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/witness.md diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/SHA256SUMS b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/SHA256SUMS new file mode 100644 index 00000000000..f97c0ae270f --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/SHA256SUMS @@ -0,0 +1,21 @@ +6807ecb0e76a2e90193281fb48c3c5c69158f45e04ad55055b75600533fce367 call-result-correlation.json +183ea07ea977ed9a121da7a38f04cdb165d87533ba94de0034d85c07a4efa5db cold-reader-gate.md +c6c49657c8b40f552a4d829f8089027ac4538cff1fe0e5f1f0f58c533138748e cold-reader-records.json +c17ae80cc22939f0af6c2675f6bcc20b025b17a5b7bfb9e8029813bcef9ad736 definition-after.json +0ec2b0c9bb82787602c359b41e6c1663001f8e42425ad2ab7f84ac019944766b definition-before.json +c17ae80cc22939f0af6c2675f6bcc20b025b17a5b7bfb9e8029813bcef9ad736 definition-tab-b.json +64d50737a22eed36ca5d5605a414ba80d30c5bc776e6d2a0d90b454ecd2b7d9b flue-snapshot-after.json +1a8ed1a7463511807bc2f6b796a272bcc279b412fc4306701b9a12b7f9d15f81 flue-snapshot-before.json +b05b8def1ff005df8131f6a486c2f9f68d5e41455c2732fe83d36187dc28e824 flue-snapshot-tab-b.json +6df15e3e1f95a1df9bb0567a84e6808abfebcd089e9b2c0d95b5d3c39b0412f1 latest-workpiece.md +17f99f53f8cf93285a7344f5e9687d94e5f59011e6895ce11a9722fde2e77511 prepared-workpiece.md +9f7148397ddde657157199428147971cbde59a751d8ffc13e5ce9624b74e6bf7 route-evidence.json +9ac14c680bbf962e528fb18826737a61174a3e42aaaeab85745fee2aa923d7ec run-metadata.json +8d5c9ccde97fa2058ba12adf9b37ab911ed02b24ffa4f8175a3633b3d6a42c25 screenshot-tab-a-after.png +ae6811c466fa0f918dc74166f155ad0239ffe37b1ce9c7d27beec5d1ed92a72d screenshot-tab-a-before.png +772ad1314906a2fc67f34b1ca5ccf7c179c8b76751a03b1a3544b7ce289d756d screenshot-tab-b-after.png +ec0af35e2018e72dfb2b10df4be944bdb645c649dcda66685d868c1d33d71f60 settled-manifest-after.json +a29c4a8d3453298285e1b210eb816a2a5636587ecb3fe367a8646d3c02da4e86 settled-manifest-before.json +ec0af35e2018e72dfb2b10df4be944bdb645c649dcda66685d868c1d33d71f60 settled-manifest-tab-b.json +ac10a63dc246af73c123ca81fb24ba1d5b680ff33d21efda930156a36f16e02a tab-b-correlation.json +d5d8211d376ccb334879c52bc7fff6360696c3166ca8903695d99bbe0b75d26d witness.md diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/call-result-correlation.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/call-result-correlation.json new file mode 100644 index 00000000000..04bad3673e9 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/call-result-correlation.json @@ -0,0 +1,84 @@ +{ + "calls": [ + { + "messageId": "entry_01M1NV6ARKVMJTM74GVBKS6VW4", + "submissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb", + "toolCallId": "toolu_01BQukCZTAhJ64VNE7oC1CWG", + "state": "output-available", + "rawInput": { + "transitionId": "start-final-inspection", + "arcDirection": "input", + "placeId": "dispatch-crew-available", + "weight": "1", + "type": "standard" + }, + "parsedInput": { + "transitionId": "start-final-inspection", + "arcDirection": "input", + "placeId": "dispatch-crew-available", + "weight": 1, + "type": "standard" + } + } + ], + "resultDeliveries": [ + { + "messageId": "entry_direct_c3ViX2lrX2FmOWNjY2IxZTk1NzI5ZjkyNDk0NDA2NTE0NTE3Y2Nl", + "submissionId": "sub_ik_af9cccb1e95729f92494406514517cce", + "result": { + "toolCallId": "toolu_01BQukCZTAhJ64VNE7oC1CWG", + "toolName": "addArc", + "output": { + "title": "Added input arc", + "detail": "Dispatch crew available <-> Start final inspection", + "target": { + "kind": "selection", + "item": { + "type": "arc", + "id": "$A_place:dispatch-crew-available___start-final-inspection" + } + }, + "applied": true + } + } + }, + { + "messageId": "entry_direct_c3ViX2lrX2Q3OTdiNGM2MDUzZTVkMGExNDRlYzE1NDdhMjJlMGNh", + "submissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca", + "result": { + "toolCallId": "toolu_01BQukCZTAhJ64VNE7oC1CWG", + "toolName": "addArc", + "output": { + "title": "Added input arc", + "detail": "Dispatch crew available <-> Start final inspection", + "target": { + "kind": "selection", + "item": { + "type": "arc", + "id": "$A_place:dispatch-crew-available___start-final-inspection" + } + }, + "applied": true + } + } + } + ], + "uniqueResults": [ + { + "toolCallId": "toolu_01BQukCZTAhJ64VNE7oC1CWG", + "toolName": "addArc", + "output": { + "title": "Added input arc", + "detail": "Dispatch crew available <-> Start final inspection", + "target": { + "kind": "selection", + "item": { + "type": "arc", + "id": "$A_place:dispatch-crew-available___start-final-inspection" + } + }, + "applied": true + } + } + ] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-gate.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-gate.md new file mode 100644 index 00000000000..eb90497ed0e --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-gate.md @@ -0,0 +1,31 @@ +# Mission 6 cold-reader gate + +Reviewer qualification: a human who did not watch the implementation or outer witness. Do not give the reviewer `witness.md`, screenshots, implementation files, or this mission's expected conclusions. + +Give the reviewer only: + +- [prepared-workpiece.md](prepared-workpiece.md) +- [latest-workpiece.md](latest-workpiece.md) +- [cold-reader-records.json](cold-reader-records.json) + +Ask for a written response to these questions: + +1. Who authored each workpiece revision, and what in the supplied Flue records establishes that attribution? +2. What exact dispatch-crew quantity or resource policy is recorded? +3. What operation reserves the crew, and what operation returns it? +4. List every unresolved timing, failure, and recovery point. +5. What behavioral execution or operational-provenance claims, if any, can be made from these materials alone? + +Acceptance requires the human response to: + +- attribute revision zero to test preparation, not the model; +- attribute the later assistant record to model production; +- recover the exactly-one-crew policy and the intended reservation/return; +- preserve every timing, failure, and recovery unknown; and +- avoid inferring behavioral execution or capture provenance. + +Record the reviewer's identity, date, verbatim response, and explicit accept/reject decision below only after the review occurs. + +## Human verdict + +Pending. diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-records.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-records.json new file mode 100644 index 00000000000..75fd835682f --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-records.json @@ -0,0 +1,46 @@ +{ + "records": [ + { + "id": "entry_direct_c3ViX2lrXzI4ODYzMWVhYWQ3OThjYzY5MDcwZTMzMTNlOTUxYmNi", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "signal": { + "tagName": "prepared-fixture", + "attributes": { + "fixtureId": "crew-reservation-v1", + "authorship": "test-authored", + "claimBoundary": "prepared-not-model-produced" + } + }, + "parts": [ + { + "type": "text", + "text": "Fixture authorship: test-authored preparation for Mission 6.\nNon-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.\n\n```runbook-ir\n# Final inspection and dispatch workpiece\n\n## Purpose and posture\nMaintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection reserves the sole available dispatch crew.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.\n\n## Current Petrinaut correspondence\nThe prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n## Explicit unknowns\nInspection and sign-off timing, failure modes, and recovery behavior remain unresolved.\n\n## Claim boundary\nThis prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.\n```", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV6M4SBXB2WA46SM1B8QM3", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca", + "turnId": "turn_01M1NV6KB8F7QJTRYHX0WT8AG5", + "parts": [ + { + "type": "reasoning", + "text": "Good! The arc has been successfully added. Looking at the final net definition, I can confirm:\n\n1. The arc was added successfully: `addArc` returned `\"applied\":true` with detail \"Dispatch crew available <-> Start final inspection\"\n\n2. In the final `getLatestNetDefinition` result, I can see that the `start-final-inspection` transition now has TWO input arcs:\n - `{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}`\n - `{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1\"}`\n\nThis confirms the missing arc from `Dispatch crew available` (weight 1, standard type) to `Start final inspection` is now in place.\n\nThe net structure is now:\n- **Places**: batch-ready, under-final-inspection, ready-for-dispatch, dispatch-crew-available\n- **Transitions**:\n - `start-final-inspection`: Takes a batch from batch-ready AND a crew token from dispatch-crew-available, produces under-final-inspection\n - `sign-off`: Takes under-final-inspection, produces both ready-for-dispatch AND returns dispatch-crew-available (crew token)\n\nThis correctly models the resource constraint: the single dispatch crew is reserved during inspection (consumed by start-final-inspection) and released at sign-off (produced by sign-off).\n\nNow I need to emit the revised runbook-ir workpiece, marking the revision as model-produced from test-authored revision zero.", + "state": "done" + }, + { + "type": "text", + "text": "✓ **Arc added successfully.** The Petrinaut tool confirms: `\"applied\":true` with detail \"Dispatch crew available ↔ Start final inspection\".\n\n**Verification of revised net structure:**\n- `Start final inspection` transition now has two standard input arcs (weight 1 each):\n 1. From `Batch ready` (original)\n 2. From `Dispatch crew available` (added, evidence-backed correction)\n- `Sign-off` transition correctly returns the crew token to `Dispatch crew available` (weight 1, output arc)\n\nThis enforces the resource constraint: the single dispatch crew is consumed when final inspection begins and restored at sign-off.\n\n---\n\n## Revised Workpiece (Model-Produced from Test-Authored Revision Zero)\n\n```runbook-ir\n# Final inspection and dispatch batch path\n\n## Purpose and posture\nModel the narrow batch path from final inspection to dispatch readiness with single-crew resource constraint. This revision incorporates the evidence-backed correction of the missing crew-availability input arc.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection requires and reserves the sole available dispatch crew.\n- Sign-off releases that crew and marks the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this system. Starting final inspection consumes that one available crew token; sign-off returns it. At most one batch can be under final inspection at a time because the sole crew is needed and cannot be in two places simultaneously.\n\n## Net structure (model-produced)\n**Places:**\n- `Batch ready`: batches waiting for inspection\n- `Under final inspection`: batches currently being inspected\n- `Ready for dispatch`: batches completed and awaiting dispatch\n- `Dispatch crew available`: availability token for the single crew (capacity 1)\n\n**Transitions:**\n- `Start final inspection`: consumes 1 batch token from `Batch ready` AND 1 crew token from `Dispatch crew available`; produces 1 token in `Under final inspection`\n- `Sign-off`: consumes 1 token from `Under final inspection`; produces 1 token each in `Ready for dispatch` and `Dispatch crew available` (returns the crew)\n\n**Arcs:**\n- `Batch ready` → `Start final inspection` (standard, weight 1) — original\n- `Dispatch crew available` → `Start final inspection` (standard, weight 1) — added in revision\n- `Start final inspection` → `Under final inspection` (standard, weight 1) — original\n- `Under final inspection` → `Sign-off` (standard, weight 1) — original\n- `Sign-off` → `Ready for dispatch` (standard, weight 1) — original\n- `Sign-off` → `Dispatch crew available` (standard, weight 1) — original\n\n## Explicit unknowns\n- Inspection and sign-off timing and duration\n- Failure modes, defect outcomes, and recovery behavior\n- Initial batch population and crew availability state\n- Repeat or recycling scenarios\n\n## Revision record\n**Revision 0** (test-authored): Prepared fixture identified missing standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n**Revision 1** (model-produced): Arc added via Petrinaut `addArc` tool and verified in net definition. Crew-availability constraint now enforced at net semantics level.\n\n## Claim boundary\nThis revision is model-produced evidence of arc correction applied to the test-authored source. It does not establish timing behavior, failure recovery, execution performance, or projection beyond this narrow batch-crew-inspection path.\n```", + "state": "done" + } + ] + } + ] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-after.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-after.json new file mode 100644 index 00000000000..c92ed16c454 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-after.json @@ -0,0 +1,98 @@ +{ + "places": [ + { + "id": "batch-ready", + "name": "Batch ready", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 80, + "y": 100 + }, + { + "id": "under-final-inspection", + "name": "Under final inspection", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 100 + }, + { + "id": "ready-for-dispatch", + "name": "Ready for dispatch", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 760, + "y": 100 + }, + { + "id": "dispatch-crew-available", + "name": "Dispatch crew available", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 360 + } + ], + "transitions": [ + { + "id": "start-final-inspection", + "name": "Start final inspection", + "inputArcs": [ + { + "placeId": "batch-ready", + "weight": 1, + "type": "standard" + }, + { + "type": "standard", + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "outputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 250, + "y": 100 + }, + { + "id": "sign-off", + "name": "Sign-off", + "inputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1, + "type": "standard" + } + ], + "outputArcs": [ + { + "placeId": "ready-for-dispatch", + "weight": 1 + }, + { + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 590, + "y": 100 + } + ], + "types": [], + "differentialEquations": [], + "parameters": [] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-before.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-before.json new file mode 100644 index 00000000000..5803556bfe8 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-before.json @@ -0,0 +1,93 @@ +{ + "places": [ + { + "id": "batch-ready", + "name": "Batch ready", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 80, + "y": 100 + }, + { + "id": "under-final-inspection", + "name": "Under final inspection", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 100 + }, + { + "id": "ready-for-dispatch", + "name": "Ready for dispatch", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 760, + "y": 100 + }, + { + "id": "dispatch-crew-available", + "name": "Dispatch crew available", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 360 + } + ], + "transitions": [ + { + "id": "start-final-inspection", + "name": "Start final inspection", + "inputArcs": [ + { + "placeId": "batch-ready", + "type": "standard", + "weight": 1 + } + ], + "outputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 250, + "y": 100 + }, + { + "id": "sign-off", + "name": "Sign-off", + "inputArcs": [ + { + "placeId": "under-final-inspection", + "type": "standard", + "weight": 1 + } + ], + "outputArcs": [ + { + "placeId": "ready-for-dispatch", + "weight": 1 + }, + { + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 590, + "y": 100 + } + ], + "types": [], + "parameters": [], + "differentialEquations": [] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-tab-b.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-tab-b.json new file mode 100644 index 00000000000..c92ed16c454 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/definition-tab-b.json @@ -0,0 +1,98 @@ +{ + "places": [ + { + "id": "batch-ready", + "name": "Batch ready", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 80, + "y": 100 + }, + { + "id": "under-final-inspection", + "name": "Under final inspection", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 100 + }, + { + "id": "ready-for-dispatch", + "name": "Ready for dispatch", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 760, + "y": 100 + }, + { + "id": "dispatch-crew-available", + "name": "Dispatch crew available", + "colorId": null, + "dynamicsEnabled": false, + "differentialEquationId": null, + "x": 420, + "y": 360 + } + ], + "transitions": [ + { + "id": "start-final-inspection", + "name": "Start final inspection", + "inputArcs": [ + { + "placeId": "batch-ready", + "weight": 1, + "type": "standard" + }, + { + "type": "standard", + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "outputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 250, + "y": 100 + }, + { + "id": "sign-off", + "name": "Sign-off", + "inputArcs": [ + { + "placeId": "under-final-inspection", + "weight": 1, + "type": "standard" + } + ], + "outputArcs": [ + { + "placeId": "ready-for-dispatch", + "weight": 1 + }, + { + "placeId": "dispatch-crew-available", + "weight": 1 + } + ], + "lambdaType": "predicate", + "lambdaCode": "", + "transitionKernelCode": "", + "x": 590, + "y": 100 + } + ], + "types": [], + "differentialEquations": [], + "parameters": [] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-after.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-after.json new file mode 100644 index 00000000000..b35e84df234 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-after.json @@ -0,0 +1,287 @@ +{ + "v": 1, + "conversationId": "conv_01M1NV5WZETMYEGGMFXNYDSTRS", + "offset": "0000000000000000_0000000000000092", + "messages": [ + { + "id": "entry_direct_c3ViX2lrXzI4ODYzMWVhYWQ3OThjYzY5MDcwZTMzMTNlOTUxYmNi", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "signal": { + "tagName": "prepared-fixture", + "attributes": { + "fixtureId": "crew-reservation-v1", + "authorship": "test-authored", + "claimBoundary": "prepared-not-model-produced" + } + }, + "parts": [ + { + "type": "text", + "text": "Fixture authorship: test-authored preparation for Mission 6.\nNon-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.\n\n```runbook-ir\n# Final inspection and dispatch workpiece\n\n## Purpose and posture\nMaintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection reserves the sole available dispatch crew.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.\n\n## Current Petrinaut correspondence\nThe prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n## Explicit unknowns\nInspection and sign-off timing, failure modes, and recovery behavior remain unresolved.\n\n## Claim boundary\nThis prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.\n```", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV5XQCBVP3FC4JW5FH1WZJ", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "turnId": "turn_01M1NV5WZH2J0S74S1Q24556EP", + "parts": [ + { + "type": "reasoning", + "text": "This is a prepared fixture for a conversation about operational process modeling using SDCPN (stochastic dynamic coloured Petri nets) in Petrinaut. Let me understand what's being presented:\n\nThe fixture describes a batch processing system with final inspection and dispatch:\n- Batches enter final inspection when ready\n- Final inspection reserves the sole available dispatch crew\n- Sign-off releases the crew and marks the batch as ready for dispatch\n- There's exactly one dispatch crew available\n\nThe fixture notes that the current Petrinaut document has a deliberate gap: it's missing the standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\".\n\nThe task seems to be to:\n1. Maintain this narrow batch path from final inspection to dispatch readiness\n2. Test one evidence-backed correction against the live Petrinaut document\n3. This means likely adding that missing arc\n\nThe explicit unknowns are:\n- Inspection and sign-off timing\n- Failure modes and recovery behavior\n\nThis is a test-authored diagnostic material, not model-produced evidence.\n\nBefore I proceed, I should:\n1. Activate the `sdcpn-modelling` skill since this is about SDCPN modeling\n2. Get the current Petrinaut net definition to see what we're working with\n3. Understand the current state and the specific correction needed\n\nLet me start by activating the skill and getting the current net state.", + "state": "done" + }, + { + "type": "text", + "text": "I'll help you maintain and test this final inspection and dispatch workpiece. Let me start by activating the SDCPN modelling skill and examining the current Petrinaut net definition.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "activate_skill", + "toolCallId": "toolu_01Y9HuAi2cvi16UD9bTvcvfS", + "state": "output-available", + "input": { + "name": "sdcpn-modelling" + }, + "output": "Run the skill named \"sdcpn-modelling\".\n\n\n# Capability-aware lifecycle\n\nUse one conceptual lifecycle: orient, elicit or revise, maintain the workpiece, construct when supported, check, and deliver. The current conversation may expose only one branch of that lifecycle. Do not claim that an unavailable transition occurred.\n\n## Select the runtime branch\n\n### Interactive elicitation or revision\n\nInterview in the person's operational vocabulary. Activate the `elicitation` skill and read `references/profile.md` before substantive questions or revision. Read `templates/workpiece.md` when creating or materially revising the shared workpiece. Construct only when the mounted capabilities actually permit construction in this conversation.\n\n### Construct-only execution\n\nUse the supplied workpiece as the complete modelling input. Do not interview. Read `references/pn-construction.md` and `references/checks.md`, then use the mounted construction tools. If a consequential workpiece gap prevents faithful construction, report the gap and the smallest question a later interactive elicitation must answer; do not ask it or invent an answer in this conversation.\n\n## Procedure\n\n### Orient\n\nEstablish enough purpose and context to select one focused next action: the intended question or decision, audience, boundary, horizon, accuracy need, and available time. Orientation need not settle every concern before elicitation begins.\n\n### Elicit or revise\n\nFor a new account, follow one concrete case and re-evaluate the active gap after each useful answer. For an existing account, first locate the disputed or changed material and its consequence for the objective. Use the `elicitation` skill's universal guidance and `references/profile.md` for detailed operations and coverage; do not turn their register order into question order.\n\n### Maintain the workpiece\n\nTreat the workpiece as the recoverable account construction will consume. Update it after a useful stretch rather than waiting until the end. Preserve unrelated material unless new evidence affects it.\n\nWhenever the workpiece changes substantially, emit the full current document in a fenced block whose language tag is exactly `runbook-ir`. Emit it again before construction and before workpiece-only delivery. A delta or prose promise is not a recoverable workpiece.\n\n### Construct\n\nConstruct only from the current workpiece. Read `references/pn-construction.md` and `references/checks.md` before beginning. Use mounted Petrinaut tools for every net change and inspect the resulting definition rather than emitting free-form net JSON. If the required tools are absent, limit the result to the workpiece and construction-ready notes.\n\nConstruction may infer a representation from recorded operational meaning; it may not invent operational facts. Record construction inferences, approximations, defaults, and target losses in the workpiece.\n\n### Check and deliver\n\nApply `references/checks.md` whenever construction is prepared or attempted. Deliver the current workpiece in every branch. Deliver a net only when the mounted tool path has produced and checked one. State what the result can support, what remains open, what was assumed or simplified, and what the target or current tools could not represent.\n\nAn explicit stop opens no new topic. In an interactive conversation, emit the best current workpiece and any already-checked net with limitations visible. In construct-only execution, report a blocking gap rather than opening an interview.\n\n## Resource discipline\n\nRead resources directly from this skill's advertised resource list, using the exact `/.flue/packaged-skills/...` path shown in the activation briefing; the relative name is a label only. Do not treat Markdown links as includes, follow references recursively, or read construction material merely to frame ordinary interview questions.\n\n\nSupporting skill resources are available but are not loaded into context unless needed:\n\n- references/checks.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/checks.md\n- references/pn-construction.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/pn-construction.md\n- references/profile.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/profile.md\n- templates/workpiece.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/templates/workpiece.md\n", + "durationMs": 1 + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_018ayLcg31aA5nZjvPe3VLEz", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 1 + }, + { + "type": "reasoning", + "text": "The getLatestNetDefinition returned awaiting client signal, meaning the client needs to load the current document. I should wait for that and then proceed. But let me think about what to do next.\n\nThe skill has been activated successfully. Now I need to:\n1. Wait for the net definition from the client\n2. Read the workpiece template to understand how to structure the workpiece\n3. Understand the current gaps and what needs to be corrected\n\nBased on the prepared fixture, the key issue is:\n- The current Petrinaut document is missing the weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\"\n- This is a deliberate gap that we need to test correcting\n\nLet me wait for the client signal and then proceed with getting the live document and understanding what needs to be corrected.", + "state": "done" + }, + { + "type": "text", + "text": "The skill is now active. I'm awaiting the current Petrinaut net definition from the client. Once that arrives, I'll examine the current state and identify the specific gap mentioned in the fixture—the missing input arc from `Dispatch crew available` to `Start final inspection`—and we can verify the evidence-backed correction.\n\nThe fixture establishes a clear scope:\n- **Operational focus**: The narrow batch path from final inspection through dispatch readiness\n- **Resource constraint**: Exactly one dispatch crew available, reserved during inspection, returned at sign-off\n- **Known gap**: Missing standard weight-1 arc from crew availability to the start of inspection\n- **Boundary**: Timing, failure modes, and recovery are explicitly unresolved\n\nI'm ready to proceed once the net definition loads. What would you like to examine or correct first?", + "state": "done" + } + ] + }, + { + "id": "entry_direct_c3ViX2lrXzIzMzcwMWRlZDcxMDVkNWQ0M2M0YjhhZTI1MTRlYzhi", + "role": "user", + "purpose": "user", + "display": "visible", + "submissionId": "sub_ik_233701ded7105d5d43c4b8ae2514ec8b", + "parts": [ + { + "type": "text", + "text": "Confirmed: final inspection uses the single dispatch crew and sign-off releases it; timing, failure, and recovery remain unknown. Read the live Petrinaut definition, add the missing standard weight-1 input arc from Dispatch crew available to Start final inspection, verify it, and emit the full revised runbook-ir workpiece. In that revised workpiece, identify the revision itself as model-produced from test-authored revision zero; do not call the revised workpiece test-authored.", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV68Q36Q2ZMVFVMR3A2J1D", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_233701ded7105d5d43c4b8ae2514ec8b", + "turnId": "turn_01M1NV67W787NJDB98B4DVTMA1", + "parts": [ + { + "type": "reasoning", + "text": "The user wants me to:\n1. Read the live Petrinaut net definition\n2. Add the missing standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\"\n3. Verify the change\n4. Emit the full revised runbook-ir workpiece\n5. Label the revised workpiece as model-produced from test-authored revision zero (not test-authored itself)\n\nLet me start by reading the live definition, then adding the arc, then verifying it, and finally emitting the revised workpiece.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_016Jkt4shRUg8hmtq6YyfcFB", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 1 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2EzOGIxMTMzYjdjN2M2NWJmOGYwNzgxNGQyM2JjYmNi", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_016Jkt4shRUg8hmtq6YyfcFB" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_016Jkt4shRUg8hmtq6YyfcFB\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV6ARKVMJTM74GVBKS6VW4", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb", + "turnId": "turn_01M1NV6A1766CSNYQR9H1HEBKH", + "parts": [ + { + "type": "reasoning", + "text": "The net definition has been loaded. Let me analyze the current state:\n\n**Current state:**\n- Places:\n - `batch-ready`: Batch waiting for final inspection\n - `under-final-inspection`: Batch undergoing final inspection\n - `ready-for-dispatch`: Batch ready for dispatch\n - `dispatch-crew-available`: Dispatch crew available (resource)\n\n- Transitions:\n - `start-final-inspection`: Takes a batch from `batch-ready` to `under-final-inspection`. It has one input arc from `batch-ready` with weight 1.\n - `sign-off`: Takes a batch from `under-final-inspection` to `ready-for-dispatch` and returns the crew to `dispatch-crew-available`. Has input arc from `under-final-inspection` (weight 1) and output arcs to both `ready-for-dispatch` and `dispatch-crew-available`.\n\n**The missing arc:**\nThe fixture states that the missing arc is: standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\nCurrently, `start-final-inspection` only has one input arc from `batch-ready`. It needs an additional input arc from `dispatch-crew-available` with weight 1 and type \"standard\".\n\n**What needs to happen:**\n1. Add an input arc to the `start-final-inspection` transition from the `dispatch-crew-available` place with weight 1 and type \"standard\"\n2. Verify the result\n3. Emit the full revised workpiece with the identification that this is model-produced from test-authored revision zero\n\nLet me use the addArc function to add this arc.\n\nThe parameters for addArc based on the schema:\n- transitionId: \"start-final-inspection\"\n- arcDirection: \"input\"\n- placeId: \"dispatch-crew-available\" (since we're using the legacy shorthand)\n- weight: 1\n- type: \"standard\"\n- targetSubnetId omitted, since this operates on the root net", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "addArc", + "toolCallId": "toolu_01BQukCZTAhJ64VNE7oC1CWG", + "state": "output-available", + "input": { + "transitionId": "start-final-inspection", + "arcDirection": "input", + "placeId": "dispatch-crew-available", + "weight": "1", + "type": "standard" + }, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2FmOWNjY2IxZTk1NzI5ZjkyNDk0NDA2NTE0NTE3Y2Nl", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_af9cccb1e95729f92494406514517cce", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_016Jkt4shRUg8hmtq6YyfcFB,toolu_01BQukCZTAhJ64VNE7oC1CWG" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_016Jkt4shRUg8hmtq6YyfcFB\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}},{\"toolCallId\":\"toolu_01BQukCZTAhJ64VNE7oC1CWG\",\"toolName\":\"addArc\",\"output\":{\"title\":\"Added input arc\",\"detail\":\"Dispatch crew available <-> Start final inspection\",\"target\":{\"kind\":\"selection\",\"item\":{\"type\":\"arc\",\"id\":\"$A_place:dispatch-crew-available___start-final-inspection\"}},\"applied\":true}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV6HRWJHSZ3QD2V8RZEWV3", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_af9cccb1e95729f92494406514517cce", + "turnId": "turn_01M1NV6GV7Q0BAMD0S09EEAY1E", + "parts": [ + { + "type": "reasoning", + "text": "Good! The arc has been added successfully. The tool output shows:\n- \"Applied: true\" - the arc was successfully added\n- Detail: \"Dispatch crew available <-> Start final inspection\"\n- The arc ID is \"$A_place:dispatch-crew-available___start-final-inspection\"\n\nNow I need to read the live net definition again to verify the change was applied correctly, then emit the revised workpiece with the full Markdown document showing the state of the net with the arc now in place.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_017Ze5BnyBGXdaw7DJSGxZQb", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2Q3OTdiNGM2MDUzZTVkMGExNDRlYzE1NDdhMjJlMGNh", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_016Jkt4shRUg8hmtq6YyfcFB,toolu_01BQukCZTAhJ64VNE7oC1CWG,toolu_017Ze5BnyBGXdaw7DJSGxZQb" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_016Jkt4shRUg8hmtq6YyfcFB\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}},{\"toolCallId\":\"toolu_01BQukCZTAhJ64VNE7oC1CWG\",\"toolName\":\"addArc\",\"output\":{\"title\":\"Added input arc\",\"detail\":\"Dispatch crew available <-> Start final inspection\",\"target\":{\"kind\":\"selection\",\"item\":{\"type\":\"arc\",\"id\":\"$A_place:dispatch-crew-available___start-final-inspection\"}},\"applied\":true}},{\"toolCallId\":\"toolu_017Ze5BnyBGXdaw7DJSGxZQb\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"},{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV6M4SBXB2WA46SM1B8QM3", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca", + "turnId": "turn_01M1NV6KB8F7QJTRYHX0WT8AG5", + "parts": [ + { + "type": "reasoning", + "text": "Good! The arc has been successfully added. Looking at the final net definition, I can confirm:\n\n1. The arc was added successfully: `addArc` returned `\"applied\":true` with detail \"Dispatch crew available <-> Start final inspection\"\n\n2. In the final `getLatestNetDefinition` result, I can see that the `start-final-inspection` transition now has TWO input arcs:\n - `{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}`\n - `{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1\"}`\n\nThis confirms the missing arc from `Dispatch crew available` (weight 1, standard type) to `Start final inspection` is now in place.\n\nThe net structure is now:\n- **Places**: batch-ready, under-final-inspection, ready-for-dispatch, dispatch-crew-available\n- **Transitions**:\n - `start-final-inspection`: Takes a batch from batch-ready AND a crew token from dispatch-crew-available, produces under-final-inspection\n - `sign-off`: Takes under-final-inspection, produces both ready-for-dispatch AND returns dispatch-crew-available (crew token)\n\nThis correctly models the resource constraint: the single dispatch crew is reserved during inspection (consumed by start-final-inspection) and released at sign-off (produced by sign-off).\n\nNow I need to emit the revised runbook-ir workpiece, marking the revision as model-produced from test-authored revision zero.", + "state": "done" + }, + { + "type": "text", + "text": "✓ **Arc added successfully.** The Petrinaut tool confirms: `\"applied\":true` with detail \"Dispatch crew available ↔ Start final inspection\".\n\n**Verification of revised net structure:**\n- `Start final inspection` transition now has two standard input arcs (weight 1 each):\n 1. From `Batch ready` (original)\n 2. From `Dispatch crew available` (added, evidence-backed correction)\n- `Sign-off` transition correctly returns the crew token to `Dispatch crew available` (weight 1, output arc)\n\nThis enforces the resource constraint: the single dispatch crew is consumed when final inspection begins and restored at sign-off.\n\n---\n\n## Revised Workpiece (Model-Produced from Test-Authored Revision Zero)\n\n```runbook-ir\n# Final inspection and dispatch batch path\n\n## Purpose and posture\nModel the narrow batch path from final inspection to dispatch readiness with single-crew resource constraint. This revision incorporates the evidence-backed correction of the missing crew-availability input arc.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection requires and reserves the sole available dispatch crew.\n- Sign-off releases that crew and marks the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this system. Starting final inspection consumes that one available crew token; sign-off returns it. At most one batch can be under final inspection at a time because the sole crew is needed and cannot be in two places simultaneously.\n\n## Net structure (model-produced)\n**Places:**\n- `Batch ready`: batches waiting for inspection\n- `Under final inspection`: batches currently being inspected\n- `Ready for dispatch`: batches completed and awaiting dispatch\n- `Dispatch crew available`: availability token for the single crew (capacity 1)\n\n**Transitions:**\n- `Start final inspection`: consumes 1 batch token from `Batch ready` AND 1 crew token from `Dispatch crew available`; produces 1 token in `Under final inspection`\n- `Sign-off`: consumes 1 token from `Under final inspection`; produces 1 token each in `Ready for dispatch` and `Dispatch crew available` (returns the crew)\n\n**Arcs:**\n- `Batch ready` → `Start final inspection` (standard, weight 1) — original\n- `Dispatch crew available` → `Start final inspection` (standard, weight 1) — added in revision\n- `Start final inspection` → `Under final inspection` (standard, weight 1) — original\n- `Under final inspection` → `Sign-off` (standard, weight 1) — original\n- `Sign-off` → `Ready for dispatch` (standard, weight 1) — original\n- `Sign-off` → `Dispatch crew available` (standard, weight 1) — original\n\n## Explicit unknowns\n- Inspection and sign-off timing and duration\n- Failure modes, defect outcomes, and recovery behavior\n- Initial batch population and crew availability state\n- Repeat or recycling scenarios\n\n## Revision record\n**Revision 0** (test-authored): Prepared fixture identified missing standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n**Revision 1** (model-produced): Arc added via Petrinaut `addArc` tool and verified in net definition. Crew-availability constraint now enforced at net semantics level.\n\n## Claim boundary\nThis revision is model-produced evidence of arc correction applied to the test-authored source. It does not establish timing behavior, failure recovery, execution performance, or projection beyond this narrow batch-crew-inspection path.\n```", + "state": "done" + } + ] + } + ], + "settlements": [ + { + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_288631eaad798cc69070e3313e951bcb" + }, + { + "submissionId": "sub_ik_233701ded7105d5d43c4b8ae2514ec8b", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_233701ded7105d5d43c4b8ae2514ec8b" + }, + { + "submissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb" + }, + { + "submissionId": "sub_ik_af9cccb1e95729f92494406514517cce", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_af9cccb1e95729f92494406514517cce" + }, + { + "submissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca" + } + ], + "incarnation": "inc_01M1NV5WZD6VQ76Z7C3JJRFFBA" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-before.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-before.json new file mode 100644 index 00000000000..ab6482d39be --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-before.json @@ -0,0 +1,89 @@ +{ + "v": 1, + "conversationId": "conv_01M1NV5WZETMYEGGMFXNYDSTRS", + "offset": "0000000000000000_0000000000000032", + "messages": [ + { + "id": "entry_direct_c3ViX2lrXzI4ODYzMWVhYWQ3OThjYzY5MDcwZTMzMTNlOTUxYmNi", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "signal": { + "tagName": "prepared-fixture", + "attributes": { + "fixtureId": "crew-reservation-v1", + "authorship": "test-authored", + "claimBoundary": "prepared-not-model-produced" + } + }, + "parts": [ + { + "type": "text", + "text": "Fixture authorship: test-authored preparation for Mission 6.\nNon-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.\n\n```runbook-ir\n# Final inspection and dispatch workpiece\n\n## Purpose and posture\nMaintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection reserves the sole available dispatch crew.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.\n\n## Current Petrinaut correspondence\nThe prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n## Explicit unknowns\nInspection and sign-off timing, failure modes, and recovery behavior remain unresolved.\n\n## Claim boundary\nThis prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.\n```", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV5XQCBVP3FC4JW5FH1WZJ", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "turnId": "turn_01M1NV5WZH2J0S74S1Q24556EP", + "parts": [ + { + "type": "reasoning", + "text": "This is a prepared fixture for a conversation about operational process modeling using SDCPN (stochastic dynamic coloured Petri nets) in Petrinaut. Let me understand what's being presented:\n\nThe fixture describes a batch processing system with final inspection and dispatch:\n- Batches enter final inspection when ready\n- Final inspection reserves the sole available dispatch crew\n- Sign-off releases the crew and marks the batch as ready for dispatch\n- There's exactly one dispatch crew available\n\nThe fixture notes that the current Petrinaut document has a deliberate gap: it's missing the standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\".\n\nThe task seems to be to:\n1. Maintain this narrow batch path from final inspection to dispatch readiness\n2. Test one evidence-backed correction against the live Petrinaut document\n3. This means likely adding that missing arc\n\nThe explicit unknowns are:\n- Inspection and sign-off timing\n- Failure modes and recovery behavior\n\nThis is a test-authored diagnostic material, not model-produced evidence.\n\nBefore I proceed, I should:\n1. Activate the `sdcpn-modelling` skill since this is about SDCPN modeling\n2. Get the current Petrinaut net definition to see what we're working with\n3. Understand the current state and the specific correction needed\n\nLet me start by activating the skill and getting the current net state.", + "state": "done" + }, + { + "type": "text", + "text": "I'll help you maintain and test this final inspection and dispatch workpiece. Let me start by activating the SDCPN modelling skill and examining the current Petrinaut net definition.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "activate_skill", + "toolCallId": "toolu_01Y9HuAi2cvi16UD9bTvcvfS", + "state": "output-available", + "input": { + "name": "sdcpn-modelling" + }, + "output": "Run the skill named \"sdcpn-modelling\".\n\n\n# Capability-aware lifecycle\n\nUse one conceptual lifecycle: orient, elicit or revise, maintain the workpiece, construct when supported, check, and deliver. The current conversation may expose only one branch of that lifecycle. Do not claim that an unavailable transition occurred.\n\n## Select the runtime branch\n\n### Interactive elicitation or revision\n\nInterview in the person's operational vocabulary. Activate the `elicitation` skill and read `references/profile.md` before substantive questions or revision. Read `templates/workpiece.md` when creating or materially revising the shared workpiece. Construct only when the mounted capabilities actually permit construction in this conversation.\n\n### Construct-only execution\n\nUse the supplied workpiece as the complete modelling input. Do not interview. Read `references/pn-construction.md` and `references/checks.md`, then use the mounted construction tools. If a consequential workpiece gap prevents faithful construction, report the gap and the smallest question a later interactive elicitation must answer; do not ask it or invent an answer in this conversation.\n\n## Procedure\n\n### Orient\n\nEstablish enough purpose and context to select one focused next action: the intended question or decision, audience, boundary, horizon, accuracy need, and available time. Orientation need not settle every concern before elicitation begins.\n\n### Elicit or revise\n\nFor a new account, follow one concrete case and re-evaluate the active gap after each useful answer. For an existing account, first locate the disputed or changed material and its consequence for the objective. Use the `elicitation` skill's universal guidance and `references/profile.md` for detailed operations and coverage; do not turn their register order into question order.\n\n### Maintain the workpiece\n\nTreat the workpiece as the recoverable account construction will consume. Update it after a useful stretch rather than waiting until the end. Preserve unrelated material unless new evidence affects it.\n\nWhenever the workpiece changes substantially, emit the full current document in a fenced block whose language tag is exactly `runbook-ir`. Emit it again before construction and before workpiece-only delivery. A delta or prose promise is not a recoverable workpiece.\n\n### Construct\n\nConstruct only from the current workpiece. Read `references/pn-construction.md` and `references/checks.md` before beginning. Use mounted Petrinaut tools for every net change and inspect the resulting definition rather than emitting free-form net JSON. If the required tools are absent, limit the result to the workpiece and construction-ready notes.\n\nConstruction may infer a representation from recorded operational meaning; it may not invent operational facts. Record construction inferences, approximations, defaults, and target losses in the workpiece.\n\n### Check and deliver\n\nApply `references/checks.md` whenever construction is prepared or attempted. Deliver the current workpiece in every branch. Deliver a net only when the mounted tool path has produced and checked one. State what the result can support, what remains open, what was assumed or simplified, and what the target or current tools could not represent.\n\nAn explicit stop opens no new topic. In an interactive conversation, emit the best current workpiece and any already-checked net with limitations visible. In construct-only execution, report a blocking gap rather than opening an interview.\n\n## Resource discipline\n\nRead resources directly from this skill's advertised resource list, using the exact `/.flue/packaged-skills/...` path shown in the activation briefing; the relative name is a label only. Do not treat Markdown links as includes, follow references recursively, or read construction material merely to frame ordinary interview questions.\n\n\nSupporting skill resources are available but are not loaded into context unless needed:\n\n- references/checks.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/checks.md\n- references/pn-construction.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/pn-construction.md\n- references/profile.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/profile.md\n- templates/workpiece.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/templates/workpiece.md\n", + "durationMs": 1 + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_018ayLcg31aA5nZjvPe3VLEz", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 1 + }, + { + "type": "reasoning", + "text": "The getLatestNetDefinition returned awaiting client signal, meaning the client needs to load the current document. I should wait for that and then proceed. But let me think about what to do next.\n\nThe skill has been activated successfully. Now I need to:\n1. Wait for the net definition from the client\n2. Read the workpiece template to understand how to structure the workpiece\n3. Understand the current gaps and what needs to be corrected\n\nBased on the prepared fixture, the key issue is:\n- The current Petrinaut document is missing the weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\"\n- This is a deliberate gap that we need to test correcting\n\nLet me wait for the client signal and then proceed with getting the live document and understanding what needs to be corrected.", + "state": "done" + }, + { + "type": "text", + "text": "The skill is now active. I'm awaiting the current Petrinaut net definition from the client. Once that arrives, I'll examine the current state and identify the specific gap mentioned in the fixture—the missing input arc from `Dispatch crew available` to `Start final inspection`—and we can verify the evidence-backed correction.\n\nThe fixture establishes a clear scope:\n- **Operational focus**: The narrow batch path from final inspection through dispatch readiness\n- **Resource constraint**: Exactly one dispatch crew available, reserved during inspection, returned at sign-off\n- **Known gap**: Missing standard weight-1 arc from crew availability to the start of inspection\n- **Boundary**: Timing, failure modes, and recovery are explicitly unresolved\n\nI'm ready to proceed once the net definition loads. What would you like to examine or correct first?", + "state": "done" + } + ] + } + ], + "settlements": [ + { + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_288631eaad798cc69070e3313e951bcb" + } + ], + "incarnation": "inc_01M1NV5WZD6VQ76Z7C3JJRFFBA" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-tab-b.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-tab-b.json new file mode 100644 index 00000000000..c0f8e5b5153 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-tab-b.json @@ -0,0 +1,326 @@ +{ + "v": 1, + "conversationId": "conv_01M1NV5WZETMYEGGMFXNYDSTRS", + "offset": "0000000000000000_0000000000000110", + "messages": [ + { + "id": "entry_direct_c3ViX2lrXzI4ODYzMWVhYWQ3OThjYzY5MDcwZTMzMTNlOTUxYmNi", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "signal": { + "tagName": "prepared-fixture", + "attributes": { + "fixtureId": "crew-reservation-v1", + "authorship": "test-authored", + "claimBoundary": "prepared-not-model-produced" + } + }, + "parts": [ + { + "type": "text", + "text": "Fixture authorship: test-authored preparation for Mission 6.\nNon-claims: not a Mission 4 candidate, not model-produced evidence, not capture-backed provenance, and not proof of automatic full-net projection.\n\n```runbook-ir\n# Final inspection and dispatch workpiece\n\n## Purpose and posture\nMaintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection reserves the sole available dispatch crew.\n- Sign-off releases that crew and makes the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it.\n\n## Current Petrinaut correspondence\nThe prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n## Explicit unknowns\nInspection and sign-off timing, failure modes, and recovery behavior remain unresolved.\n\n## Claim boundary\nThis prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality.\n```", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV5XQCBVP3FC4JW5FH1WZJ", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "turnId": "turn_01M1NV5WZH2J0S74S1Q24556EP", + "parts": [ + { + "type": "reasoning", + "text": "This is a prepared fixture for a conversation about operational process modeling using SDCPN (stochastic dynamic coloured Petri nets) in Petrinaut. Let me understand what's being presented:\n\nThe fixture describes a batch processing system with final inspection and dispatch:\n- Batches enter final inspection when ready\n- Final inspection reserves the sole available dispatch crew\n- Sign-off releases the crew and marks the batch as ready for dispatch\n- There's exactly one dispatch crew available\n\nThe fixture notes that the current Petrinaut document has a deliberate gap: it's missing the standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\".\n\nThe task seems to be to:\n1. Maintain this narrow batch path from final inspection to dispatch readiness\n2. Test one evidence-backed correction against the live Petrinaut document\n3. This means likely adding that missing arc\n\nThe explicit unknowns are:\n- Inspection and sign-off timing\n- Failure modes and recovery behavior\n\nThis is a test-authored diagnostic material, not model-produced evidence.\n\nBefore I proceed, I should:\n1. Activate the `sdcpn-modelling` skill since this is about SDCPN modeling\n2. Get the current Petrinaut net definition to see what we're working with\n3. Understand the current state and the specific correction needed\n\nLet me start by activating the skill and getting the current net state.", + "state": "done" + }, + { + "type": "text", + "text": "I'll help you maintain and test this final inspection and dispatch workpiece. Let me start by activating the SDCPN modelling skill and examining the current Petrinaut net definition.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "activate_skill", + "toolCallId": "toolu_01Y9HuAi2cvi16UD9bTvcvfS", + "state": "output-available", + "input": { + "name": "sdcpn-modelling" + }, + "output": "Run the skill named \"sdcpn-modelling\".\n\n\n# Capability-aware lifecycle\n\nUse one conceptual lifecycle: orient, elicit or revise, maintain the workpiece, construct when supported, check, and deliver. The current conversation may expose only one branch of that lifecycle. Do not claim that an unavailable transition occurred.\n\n## Select the runtime branch\n\n### Interactive elicitation or revision\n\nInterview in the person's operational vocabulary. Activate the `elicitation` skill and read `references/profile.md` before substantive questions or revision. Read `templates/workpiece.md` when creating or materially revising the shared workpiece. Construct only when the mounted capabilities actually permit construction in this conversation.\n\n### Construct-only execution\n\nUse the supplied workpiece as the complete modelling input. Do not interview. Read `references/pn-construction.md` and `references/checks.md`, then use the mounted construction tools. If a consequential workpiece gap prevents faithful construction, report the gap and the smallest question a later interactive elicitation must answer; do not ask it or invent an answer in this conversation.\n\n## Procedure\n\n### Orient\n\nEstablish enough purpose and context to select one focused next action: the intended question or decision, audience, boundary, horizon, accuracy need, and available time. Orientation need not settle every concern before elicitation begins.\n\n### Elicit or revise\n\nFor a new account, follow one concrete case and re-evaluate the active gap after each useful answer. For an existing account, first locate the disputed or changed material and its consequence for the objective. Use the `elicitation` skill's universal guidance and `references/profile.md` for detailed operations and coverage; do not turn their register order into question order.\n\n### Maintain the workpiece\n\nTreat the workpiece as the recoverable account construction will consume. Update it after a useful stretch rather than waiting until the end. Preserve unrelated material unless new evidence affects it.\n\nWhenever the workpiece changes substantially, emit the full current document in a fenced block whose language tag is exactly `runbook-ir`. Emit it again before construction and before workpiece-only delivery. A delta or prose promise is not a recoverable workpiece.\n\n### Construct\n\nConstruct only from the current workpiece. Read `references/pn-construction.md` and `references/checks.md` before beginning. Use mounted Petrinaut tools for every net change and inspect the resulting definition rather than emitting free-form net JSON. If the required tools are absent, limit the result to the workpiece and construction-ready notes.\n\nConstruction may infer a representation from recorded operational meaning; it may not invent operational facts. Record construction inferences, approximations, defaults, and target losses in the workpiece.\n\n### Check and deliver\n\nApply `references/checks.md` whenever construction is prepared or attempted. Deliver the current workpiece in every branch. Deliver a net only when the mounted tool path has produced and checked one. State what the result can support, what remains open, what was assumed or simplified, and what the target or current tools could not represent.\n\nAn explicit stop opens no new topic. In an interactive conversation, emit the best current workpiece and any already-checked net with limitations visible. In construct-only execution, report a blocking gap rather than opening an interview.\n\n## Resource discipline\n\nRead resources directly from this skill's advertised resource list, using the exact `/.flue/packaged-skills/...` path shown in the activation briefing; the relative name is a label only. Do not treat Markdown links as includes, follow references recursively, or read construction material merely to frame ordinary interview questions.\n\n\nSupporting skill resources are available but are not loaded into context unless needed:\n\n- references/checks.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/checks.md\n- references/pn-construction.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/pn-construction.md\n- references/profile.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/references/profile.md\n- templates/workpiece.md → read_skill_resource /.flue/packaged-skills/skill%3Asdcpn-modelling%3A99a447ec4bcbf6c0/templates/workpiece.md\n", + "durationMs": 1 + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_018ayLcg31aA5nZjvPe3VLEz", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 1 + }, + { + "type": "reasoning", + "text": "The getLatestNetDefinition returned awaiting client signal, meaning the client needs to load the current document. I should wait for that and then proceed. But let me think about what to do next.\n\nThe skill has been activated successfully. Now I need to:\n1. Wait for the net definition from the client\n2. Read the workpiece template to understand how to structure the workpiece\n3. Understand the current gaps and what needs to be corrected\n\nBased on the prepared fixture, the key issue is:\n- The current Petrinaut document is missing the weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\"\n- This is a deliberate gap that we need to test correcting\n\nLet me wait for the client signal and then proceed with getting the live document and understanding what needs to be corrected.", + "state": "done" + }, + { + "type": "text", + "text": "The skill is now active. I'm awaiting the current Petrinaut net definition from the client. Once that arrives, I'll examine the current state and identify the specific gap mentioned in the fixture—the missing input arc from `Dispatch crew available` to `Start final inspection`—and we can verify the evidence-backed correction.\n\nThe fixture establishes a clear scope:\n- **Operational focus**: The narrow batch path from final inspection through dispatch readiness\n- **Resource constraint**: Exactly one dispatch crew available, reserved during inspection, returned at sign-off\n- **Known gap**: Missing standard weight-1 arc from crew availability to the start of inspection\n- **Boundary**: Timing, failure modes, and recovery are explicitly unresolved\n\nI'm ready to proceed once the net definition loads. What would you like to examine or correct first?", + "state": "done" + } + ] + }, + { + "id": "entry_direct_c3ViX2lrXzIzMzcwMWRlZDcxMDVkNWQ0M2M0YjhhZTI1MTRlYzhi", + "role": "user", + "purpose": "user", + "display": "visible", + "submissionId": "sub_ik_233701ded7105d5d43c4b8ae2514ec8b", + "parts": [ + { + "type": "text", + "text": "Confirmed: final inspection uses the single dispatch crew and sign-off releases it; timing, failure, and recovery remain unknown. Read the live Petrinaut definition, add the missing standard weight-1 input arc from Dispatch crew available to Start final inspection, verify it, and emit the full revised runbook-ir workpiece. In that revised workpiece, identify the revision itself as model-produced from test-authored revision zero; do not call the revised workpiece test-authored.", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV68Q36Q2ZMVFVMR3A2J1D", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_233701ded7105d5d43c4b8ae2514ec8b", + "turnId": "turn_01M1NV67W787NJDB98B4DVTMA1", + "parts": [ + { + "type": "reasoning", + "text": "The user wants me to:\n1. Read the live Petrinaut net definition\n2. Add the missing standard weight-1 input arc from \"Dispatch crew available\" to \"Start final inspection\"\n3. Verify the change\n4. Emit the full revised runbook-ir workpiece\n5. Label the revised workpiece as model-produced from test-authored revision zero (not test-authored itself)\n\nLet me start by reading the live definition, then adding the arc, then verifying it, and finally emitting the revised workpiece.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_016Jkt4shRUg8hmtq6YyfcFB", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 1 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2EzOGIxMTMzYjdjN2M2NWJmOGYwNzgxNGQyM2JjYmNi", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_016Jkt4shRUg8hmtq6YyfcFB" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_016Jkt4shRUg8hmtq6YyfcFB\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV6ARKVMJTM74GVBKS6VW4", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb", + "turnId": "turn_01M1NV6A1766CSNYQR9H1HEBKH", + "parts": [ + { + "type": "reasoning", + "text": "The net definition has been loaded. Let me analyze the current state:\n\n**Current state:**\n- Places:\n - `batch-ready`: Batch waiting for final inspection\n - `under-final-inspection`: Batch undergoing final inspection\n - `ready-for-dispatch`: Batch ready for dispatch\n - `dispatch-crew-available`: Dispatch crew available (resource)\n\n- Transitions:\n - `start-final-inspection`: Takes a batch from `batch-ready` to `under-final-inspection`. It has one input arc from `batch-ready` with weight 1.\n - `sign-off`: Takes a batch from `under-final-inspection` to `ready-for-dispatch` and returns the crew to `dispatch-crew-available`. Has input arc from `under-final-inspection` (weight 1) and output arcs to both `ready-for-dispatch` and `dispatch-crew-available`.\n\n**The missing arc:**\nThe fixture states that the missing arc is: standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\nCurrently, `start-final-inspection` only has one input arc from `batch-ready`. It needs an additional input arc from `dispatch-crew-available` with weight 1 and type \"standard\".\n\n**What needs to happen:**\n1. Add an input arc to the `start-final-inspection` transition from the `dispatch-crew-available` place with weight 1 and type \"standard\"\n2. Verify the result\n3. Emit the full revised workpiece with the identification that this is model-produced from test-authored revision zero\n\nLet me use the addArc function to add this arc.\n\nThe parameters for addArc based on the schema:\n- transitionId: \"start-final-inspection\"\n- arcDirection: \"input\"\n- placeId: \"dispatch-crew-available\" (since we're using the legacy shorthand)\n- weight: 1\n- type: \"standard\"\n- targetSubnetId omitted, since this operates on the root net", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "addArc", + "toolCallId": "toolu_01BQukCZTAhJ64VNE7oC1CWG", + "state": "output-available", + "input": { + "transitionId": "start-final-inspection", + "arcDirection": "input", + "placeId": "dispatch-crew-available", + "weight": "1", + "type": "standard" + }, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2FmOWNjY2IxZTk1NzI5ZjkyNDk0NDA2NTE0NTE3Y2Nl", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_af9cccb1e95729f92494406514517cce", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_016Jkt4shRUg8hmtq6YyfcFB,toolu_01BQukCZTAhJ64VNE7oC1CWG" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_016Jkt4shRUg8hmtq6YyfcFB\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}},{\"toolCallId\":\"toolu_01BQukCZTAhJ64VNE7oC1CWG\",\"toolName\":\"addArc\",\"output\":{\"title\":\"Added input arc\",\"detail\":\"Dispatch crew available <-> Start final inspection\",\"target\":{\"kind\":\"selection\",\"item\":{\"type\":\"arc\",\"id\":\"$A_place:dispatch-crew-available___start-final-inspection\"}},\"applied\":true}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV6HRWJHSZ3QD2V8RZEWV3", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_af9cccb1e95729f92494406514517cce", + "turnId": "turn_01M1NV6GV7Q0BAMD0S09EEAY1E", + "parts": [ + { + "type": "reasoning", + "text": "Good! The arc has been added successfully. The tool output shows:\n- \"Applied: true\" - the arc was successfully added\n- Detail: \"Dispatch crew available <-> Start final inspection\"\n- The arc ID is \"$A_place:dispatch-crew-available___start-final-inspection\"\n\nNow I need to read the live net definition again to verify the change was applied correctly, then emit the revised workpiece with the full Markdown document showing the state of the net with the arc now in place.", + "state": "done" + }, + { + "type": "dynamic-tool", + "toolName": "getLatestNetDefinition", + "toolCallId": "toolu_017Ze5BnyBGXdaw7DJSGxZQb", + "state": "output-available", + "input": {}, + "output": { + "awaiting": "client" + }, + "durationMs": 0 + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2Q3OTdiNGM2MDUzZTVkMGExNDRlYzE1NDdhMjJlMGNh", + "role": "system", + "purpose": "dispatch", + "display": "diagnostic", + "submissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca", + "signal": { + "tagName": "client-tool-result", + "attributes": { + "toolCallIds": "toolu_016Jkt4shRUg8hmtq6YyfcFB,toolu_01BQukCZTAhJ64VNE7oC1CWG,toolu_017Ze5BnyBGXdaw7DJSGxZQb" + } + }, + "parts": [ + { + "type": "text", + "text": "[{\"toolCallId\":\"toolu_016Jkt4shRUg8hmtq6YyfcFB\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}},{\"toolCallId\":\"toolu_01BQukCZTAhJ64VNE7oC1CWG\",\"toolName\":\"addArc\",\"output\":{\"title\":\"Added input arc\",\"detail\":\"Dispatch crew available <-> Start final inspection\",\"target\":{\"kind\":\"selection\",\"item\":{\"type\":\"arc\",\"id\":\"$A_place:dispatch-crew-available___start-final-inspection\"}},\"applied\":true}},{\"toolCallId\":\"toolu_017Ze5BnyBGXdaw7DJSGxZQb\",\"toolName\":\"getLatestNetDefinition\",\"output\":{\"title\":\"Prepared final inspection and dispatch\",\"definition\":{\"places\":[{\"id\":\"batch-ready\",\"name\":\"Batch ready\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":80,\"y\":100},{\"id\":\"under-final-inspection\",\"name\":\"Under final inspection\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":100},{\"id\":\"ready-for-dispatch\",\"name\":\"Ready for dispatch\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":760,\"y\":100},{\"id\":\"dispatch-crew-available\",\"name\":\"Dispatch crew available\",\"colorId\":null,\"dynamicsEnabled\":false,\"differentialEquationId\":null,\"x\":420,\"y\":360}],\"transitions\":[{\"id\":\"start-final-inspection\",\"name\":\"Start final inspection\",\"inputArcs\":[{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"},{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"outputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":250,\"y\":100},{\"id\":\"sign-off\",\"name\":\"Sign-off\",\"inputArcs\":[{\"placeId\":\"under-final-inspection\",\"weight\":1,\"type\":\"standard\"}],\"outputArcs\":[{\"placeId\":\"ready-for-dispatch\",\"weight\":1},{\"placeId\":\"dispatch-crew-available\",\"weight\":1}],\"lambdaType\":\"predicate\",\"lambdaCode\":\"\",\"transitionKernelCode\":\"\",\"x\":590,\"y\":100}],\"types\":[],\"differentialEquations\":[],\"parameters\":[]},\"extensions\":{\"colors\":true,\"stochasticity\":true,\"dynamics\":true,\"parameters\":true,\"subnets\":true}}}]", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV6M4SBXB2WA46SM1B8QM3", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca", + "turnId": "turn_01M1NV6KB8F7QJTRYHX0WT8AG5", + "parts": [ + { + "type": "reasoning", + "text": "Good! The arc has been successfully added. Looking at the final net definition, I can confirm:\n\n1. The arc was added successfully: `addArc` returned `\"applied\":true` with detail \"Dispatch crew available <-> Start final inspection\"\n\n2. In the final `getLatestNetDefinition` result, I can see that the `start-final-inspection` transition now has TWO input arcs:\n - `{\"placeId\":\"batch-ready\",\"weight\":1,\"type\":\"standard\"}`\n - `{\"type\":\"standard\",\"placeId\":\"dispatch-crew-available\",\"weight\":1\"}`\n\nThis confirms the missing arc from `Dispatch crew available` (weight 1, standard type) to `Start final inspection` is now in place.\n\nThe net structure is now:\n- **Places**: batch-ready, under-final-inspection, ready-for-dispatch, dispatch-crew-available\n- **Transitions**:\n - `start-final-inspection`: Takes a batch from batch-ready AND a crew token from dispatch-crew-available, produces under-final-inspection\n - `sign-off`: Takes under-final-inspection, produces both ready-for-dispatch AND returns dispatch-crew-available (crew token)\n\nThis correctly models the resource constraint: the single dispatch crew is reserved during inspection (consumed by start-final-inspection) and released at sign-off (produced by sign-off).\n\nNow I need to emit the revised runbook-ir workpiece, marking the revision as model-produced from test-authored revision zero.", + "state": "done" + }, + { + "type": "text", + "text": "✓ **Arc added successfully.** The Petrinaut tool confirms: `\"applied\":true` with detail \"Dispatch crew available ↔ Start final inspection\".\n\n**Verification of revised net structure:**\n- `Start final inspection` transition now has two standard input arcs (weight 1 each):\n 1. From `Batch ready` (original)\n 2. From `Dispatch crew available` (added, evidence-backed correction)\n- `Sign-off` transition correctly returns the crew token to `Dispatch crew available` (weight 1, output arc)\n\nThis enforces the resource constraint: the single dispatch crew is consumed when final inspection begins and restored at sign-off.\n\n---\n\n## Revised Workpiece (Model-Produced from Test-Authored Revision Zero)\n\n```runbook-ir\n# Final inspection and dispatch batch path\n\n## Purpose and posture\nModel the narrow batch path from final inspection to dispatch readiness with single-crew resource constraint. This revision incorporates the evidence-backed correction of the missing crew-availability input arc.\n\n## Operational account\n- A batch that is ready enters final inspection.\n- Final inspection requires and reserves the sole available dispatch crew.\n- Sign-off releases that crew and marks the batch ready for dispatch.\n\n## Quantity and resource policy\nExactly one dispatch crew is available in this system. Starting final inspection consumes that one available crew token; sign-off returns it. At most one batch can be under final inspection at a time because the sole crew is needed and cannot be in two places simultaneously.\n\n## Net structure (model-produced)\n**Places:**\n- `Batch ready`: batches waiting for inspection\n- `Under final inspection`: batches currently being inspected\n- `Ready for dispatch`: batches completed and awaiting dispatch\n- `Dispatch crew available`: availability token for the single crew (capacity 1)\n\n**Transitions:**\n- `Start final inspection`: consumes 1 batch token from `Batch ready` AND 1 crew token from `Dispatch crew available`; produces 1 token in `Under final inspection`\n- `Sign-off`: consumes 1 token from `Under final inspection`; produces 1 token each in `Ready for dispatch` and `Dispatch crew available` (returns the crew)\n\n**Arcs:**\n- `Batch ready` → `Start final inspection` (standard, weight 1) — original\n- `Dispatch crew available` → `Start final inspection` (standard, weight 1) — added in revision\n- `Start final inspection` → `Under final inspection` (standard, weight 1) — original\n- `Under final inspection` → `Sign-off` (standard, weight 1) — original\n- `Sign-off` → `Ready for dispatch` (standard, weight 1) — original\n- `Sign-off` → `Dispatch crew available` (standard, weight 1) — original\n\n## Explicit unknowns\n- Inspection and sign-off timing and duration\n- Failure modes, defect outcomes, and recovery behavior\n- Initial batch population and crew availability state\n- Repeat or recycling scenarios\n\n## Revision record\n**Revision 0** (test-authored): Prepared fixture identified missing standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`.\n\n**Revision 1** (model-produced): Arc added via Petrinaut `addArc` tool and verified in net definition. Crew-availability constraint now enforced at net semantics level.\n\n## Claim boundary\nThis revision is model-produced evidence of arc correction applied to the test-authored source. It does not establish timing behavior, failure recovery, execution performance, or projection beyond this narrow batch-crew-inspection path.\n```", + "state": "done" + } + ] + }, + { + "id": "entry_direct_c3ViX2lrX2IyZjk2ZmQ2MmI4MGE2ZGNmOTgwMzI5YWQ2MWY3MGU5", + "role": "user", + "purpose": "user", + "display": "visible", + "submissionId": "sub_ik_b2f96fd62b80a6dcf980329ad61f70e9", + "parts": [ + { + "type": "text", + "text": "From the resumed workpiece, list the unresolved timing, failure, and recovery questions. Do not change the Petrinaut net.", + "state": "done" + } + ] + }, + { + "id": "entry_01M1NV73Z110CY393GEB8T02SH", + "role": "assistant", + "purpose": "assistant", + "display": "visible", + "submissionId": "sub_ik_b2f96fd62b80a6dcf980329ad61f70e9", + "turnId": "turn_01M1NV7343YW19DZKMTGEDCWTF", + "parts": [ + { + "type": "reasoning", + "text": "The user is asking me to list the unresolved timing, failure, and recovery questions from the workpiece I just provided. They explicitly say not to change the Petrinaut net, so this is purely an analytical question about what remains open in the model.\n\nLet me look at the \"Explicit unknowns\" section I provided:\n- Inspection and sign-off timing and duration\n- Failure modes, defect outcomes, and recovery behavior\n- Initial batch population and crew availability state\n- Repeat or recycling scenarios\n\nBut the user wants me to be more specific about the timing, failure, and recovery questions. I should expand these into actual concrete questions that would need to be answered to make the model complete. Let me think about what operational questions are unresolved:\n\n**Timing questions:**\n- How long does final inspection take?\n- How long does sign-off take?\n- Are inspection and sign-off separate durations or combined?\n- Can inspection occur in parallel for multiple batches if crew were available?\n\n**Failure questions:**\n- What happens if a batch fails inspection?\n- Can inspection fail entirely or does sign-off always succeed?\n- Are there defect categories (reject, rework, accept)?\n- Does a failed batch consume the crew resource?\n\n**Recovery questions:**\n- If a batch fails inspection, where does it go? (Back to ready? To a separate fail queue? Removed entirely?)\n- Does failed inspection release the crew immediately, or after some remediation?\n- Can a reworked batch re-enter the inspection process?\n- What is the relationship between failed batches and crew availability?\n\nLet me provide a structured list of these unresolved questions organized by category.", + "state": "done" + }, + { + "type": "text", + "text": "## Unresolved Timing, Failure, and Recovery Questions\n\n### Timing\n1. **Inspection duration**: What is the stochastic or deterministic duration of the final inspection phase (from \"Start final inspection\" to \"Sign-off\")?\n2. **Sign-off duration**: Does \"Sign-off\" occur instantaneously, or does it have its own duration separate from inspection?\n3. **Crew engagement horizon**: Is the crew occupied only during the inspection phase, or does it remain engaged during batches' time in \"Ready for dispatch\"?\n4. **Parallel inspection capacity**: If additional crews became available, could multiple batches be inspected concurrently, or is there a single-batch constraint in the process?\n\n### Failure and Defect Outcomes\n1. **Inspection failure mode**: Can a batch fail inspection? If so, under what conditions?\n2. **Failure rate**: Is there a known or modeled probability that inspection produces a defect or rejection?\n3. **Defect categories**: Are there multiple outcomes (accept, reject, rework required)? If so, what distinguishes them?\n4. **Sign-off contingency**: Can sign-off always succeed after inspection, or can sign-off itself reject a batch?\n5. **Scrap or return**: What happens to batches that fail? Are they removed from the system, returned to \"Batch ready,\" sent to a separate rework queue, or diverted elsewhere?\n\n### Recovery and Rework Behavior\n1. **Failed batch crew release**: When a batch fails inspection, is the crew released immediately, or must it complete additional work before returning to availability?\n2. **Rework entry point**: If a batch requires rework, does it re-enter \"Batch ready,\" or is there a separate rework-staging place?\n3. **Rework limit**: Is there a maximum number of rework cycles, or can a batch cycle indefinitely?\n4. **Crew allocation to rework**: Does rework use the same dispatch crew, a different crew, or no dedicated crew?\n5. **Initial state**: How many batches start in \"Batch ready\" and how is \"Dispatch crew available\" initialized (1 token, or variable)?", + "state": "done" + } + ] + } + ], + "settlements": [ + { + "submissionId": "sub_ik_288631eaad798cc69070e3313e951bcb", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_288631eaad798cc69070e3313e951bcb" + }, + { + "submissionId": "sub_ik_233701ded7105d5d43c4b8ae2514ec8b", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_233701ded7105d5d43c4b8ae2514ec8b" + }, + { + "submissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_a38b1133b7c7c65bf8f07814d23bcbcb" + }, + { + "submissionId": "sub_ik_af9cccb1e95729f92494406514517cce", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_af9cccb1e95729f92494406514517cce" + }, + { + "submissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_d797b4c6053e5d0a144ec1547a22e0ca" + }, + { + "submissionId": "sub_ik_b2f96fd62b80a6dcf980329ad61f70e9", + "outcome": "completed", + "answeredBySubmissionId": "sub_ik_b2f96fd62b80a6dcf980329ad61f70e9" + } + ], + "incarnation": "inc_01M1NV5WZD6VQ76Z7C3JJRFFBA" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/latest-workpiece.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/latest-workpiece.md new file mode 100644 index 00000000000..4c89055d2b5 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/latest-workpiece.md @@ -0,0 +1,45 @@ +# Final inspection and dispatch batch path + +## Purpose and posture +Model the narrow batch path from final inspection to dispatch readiness with single-crew resource constraint. This revision incorporates the evidence-backed correction of the missing crew-availability input arc. + +## Operational account +- A batch that is ready enters final inspection. +- Final inspection requires and reserves the sole available dispatch crew. +- Sign-off releases that crew and marks the batch ready for dispatch. + +## Quantity and resource policy +Exactly one dispatch crew is available in this system. Starting final inspection consumes that one available crew token; sign-off returns it. At most one batch can be under final inspection at a time because the sole crew is needed and cannot be in two places simultaneously. + +## Net structure (model-produced) +**Places:** +- `Batch ready`: batches waiting for inspection +- `Under final inspection`: batches currently being inspected +- `Ready for dispatch`: batches completed and awaiting dispatch +- `Dispatch crew available`: availability token for the single crew (capacity 1) + +**Transitions:** +- `Start final inspection`: consumes 1 batch token from `Batch ready` AND 1 crew token from `Dispatch crew available`; produces 1 token in `Under final inspection` +- `Sign-off`: consumes 1 token from `Under final inspection`; produces 1 token each in `Ready for dispatch` and `Dispatch crew available` (returns the crew) + +**Arcs:** +- `Batch ready` → `Start final inspection` (standard, weight 1) — original +- `Dispatch crew available` → `Start final inspection` (standard, weight 1) — added in revision +- `Start final inspection` → `Under final inspection` (standard, weight 1) — original +- `Under final inspection` → `Sign-off` (standard, weight 1) — original +- `Sign-off` → `Ready for dispatch` (standard, weight 1) — original +- `Sign-off` → `Dispatch crew available` (standard, weight 1) — original + +## Explicit unknowns +- Inspection and sign-off timing and duration +- Failure modes, defect outcomes, and recovery behavior +- Initial batch population and crew availability state +- Repeat or recycling scenarios + +## Revision record +**Revision 0** (test-authored): Prepared fixture identified missing standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`. + +**Revision 1** (model-produced): Arc added via Petrinaut `addArc` tool and verified in net definition. Crew-availability constraint now enforced at net semantics level. + +## Claim boundary +This revision is model-produced evidence of arc correction applied to the test-authored source. It does not establish timing behavior, failure recovery, execution performance, or projection beyond this narrow batch-crew-inspection path. diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/prepared-workpiece.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/prepared-workpiece.md new file mode 100644 index 00000000000..fa01def8c11 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/prepared-workpiece.md @@ -0,0 +1,21 @@ +# Final inspection and dispatch workpiece + +## Purpose and posture +Maintain the narrow batch path from final inspection to dispatch readiness and test one evidence-backed correction against the live Petrinaut document. + +## Operational account +- A batch that is ready enters final inspection. +- Final inspection reserves the sole available dispatch crew. +- Sign-off releases that crew and makes the batch ready for dispatch. + +## Quantity and resource policy +Exactly one dispatch crew is available in this fixture. Starting final inspection consumes that one available crew; sign-off returns it. + +## Current Petrinaut correspondence +The prepared non-empty net contains the batch path and the crew return from sign-off. It deliberately lacks the standard weight-1 input arc from `Dispatch crew available` to `Start final inspection`. + +## Explicit unknowns +Inspection and sign-off timing, failure modes, and recovery behavior remain unresolved. + +## Claim boundary +This prepared revision is test-authored diagnostic material. It is not model-produced evidence and does not establish capture provenance, behavioral execution, or broad projection quality. diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/route-evidence.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/route-evidence.json new file mode 100644 index 00000000000..85b3c90305b --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/route-evidence.json @@ -0,0 +1,6 @@ +{ + "fixtureUrl": "http://127.0.0.1:4915/?brunch-fixture=crew-reservation-v1", + "mountedRoute": "/agents/chat/", + "sameMountedInstanceAcrossTabs": true, + "browserErrors": [] +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/run-metadata.json b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/run-metadata.json new file mode 100644 index 00000000000..28615dac8f1 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/run-metadata.json @@ -0,0 +1,8 @@ +{ + "implementationCommit": "8ef9cd967d", + "prompt": "Confirmed: final inspection uses the single dispatch crew and sign-off releases it; timing, failure, and recovery remain unknown. Read the live Petrinaut definition, add the missing standard weight-1 input arc from Dispatch crew available to Start final inspection, verify it, and emit the full revised runbook-ir workpiece. In that revised workpiece, identify the revision itself as model-produced from test-authored revision zero; do not call the revised workpiece test-authored.", + "followup": "From the resumed workpiece, list the unresolved timing, failure, and recovery questions. Do not change the Petrinaut net.", + "beforeOffset": "0000000000000000_0000000000000032", + "afterOffset": "0000000000000000_0000000000000092", + "tabBOffset": "0000000000000000_0000000000000110" +} diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/screenshot-tab-a-after.png b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/screenshot-tab-a-after.png new file mode 100644 index 0000000000000000000000000000000000000000..4e06ff085e777cd4ed93e4fb18946c84718b6c7d GIT binary patch literal 150019 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°?%Rp zjH`yOVl&KQ$@f109Nmf(erjvsV=B;^*~!}zcKUJQ2>2B7MJS32zoFkDM4N>$yoh~p zv%T?NCKQ6B1p@b(KM8}b014Ty6+nE%9P7vXbWtpVsdWLmI2K*Kh5r9Q{fiO(>HN%L z#h%@~)M2<`=3yoZKQilO+zpNIMxbt2Lp;JGd#SZveD98zGUUuox@xE?+1b0@%(Fw$ zG3A9r6l-)(L=A_o6)tSS8ttv~CS?(xe*@Y^^JkBq;L<~-s6s?t4@r_>g;&FYhiz9a zTb#c-=C?FVdVD=0G;Hu*kv;ugP)U3qIk6_o%=?(`^3ssAK=szjt5xTrH@AkXjO;}o zg&T9%l77UXYzRP|bDFL4^|yDJrLTTT!H8ov{bk7Xg#b#PG}q4bI|U}JpCOc(IxGL{ zGaN4Yug|d2OZfgfvz7pGv$J*(L9Ol&(9fsKP4=z@3Y%6-2@tc1H)P^6GTd_0IkS8r zZX+s3F`YMW|4I0af=f>AR`y^I2my)}XueDwtc9+~$5A7u+4EoxO#&eTx-O3S59lJp zfp0)<8#*$=u=d?+8P}~-s82dIw4i7hac#fSqrh+eVy10X2V2FFwH@+~Lz)jk$9+Fb z^gYy%KxBYwJsk#_pr8WY0)Cffgh|f$A((!SFTTx;b=2A_Jj6#dVD%^RG2}sW9XpX! zIqXkW>6x^ll`D?}K&`v0i*H~A0uim#W~SIg0|PqAeuCzrliBGe$0UHXTj;;OU3+Z+ zOB@LJL{i?3X~*nq{?c8UcONzcz&x066OrSUt{5qtYt&rad}}L8zDZ$V znbgW01_D{QmnV$Zb`uOIc|Y4j<(uPmE6vKKMwhmYD!s~MFs~z~*C-`%nY=pkSR0@y zx5HAYJRa|7WQd$WTV*Om$OJm0vWSC3Kl61LzHrDNJyw}Z4mnCzq&6}0L`h^tBv~pBdD84+8}WMwYzur%v5vWn=3*6`_!)BOiyc zelP-8Cb>ViS*g8(Y+bZ3kO}pn#^;*XV|^pT0+eCT2wGFHF0!I$c5+zx3vh27d@Nmw!6#z!`Qx0o=LyC$4p3^Q1d`g&rl>K zYOb^RScXFnky<4Vm3nFKoC3|j`cIQ?C$w@pH3jCF#@rpjm^U88Mae_v8u!NEE-=LG zWlGR&f3?%s_%aRna>IXNe_HimqY}LqoY-YLq7!VLc35nsw#=F$UO3xmiKK;E_){vC z$1U7hdH?<6s_iRD>_H_JUu>%&M-*6n_L zX$1h^$GXL(5*GoM{f858qxKryhnI?JW=!egX5<-ComH&(>w#w2nXS0dmCoO$m*tIh zh{Q}Q&%IwhS_hb43G<(Vd)eM==^%3%NWK$@E!|YVfxI?aW%yCdG%w$BqmEqCwi(950xpxxpH6nd z7>|-vgk}qAJwd-DUe+gYZ^7%V;SQUHPvBS*VC%GYSVhd! zb4UaM{Ze7f9YQ>Eo_m<21>y+kH$F^ek6T_^+MIj~18?@&+pK|34k^raY!?P zmmcv2kJu>?*b_n?H6qB@ z*{vi=!QK5Bz-6!+#!c_hJ)fh(}>OHwN2A>W{p@Dskz1+2WH zFj&5s7$X1*^M{c?h@6-33rH2%$1F=ys5#+TdmO)8LGniDb1W6jO@E!gq0ToBfZ-{% z1qKH^AR4Tg+lXu+;HUUmSTK%=B@>Fj3m`GS)b7QE$ri-SXV9m!5F{s@gBTwL1ts}F zZx-}+tn`E$L6@DH0RE=Z%EJm!J2UY#w6r5*Bw_XQZm*76aZf=+KQ^fo=ZkVy>l zrFV8Xk21t$AV3|^>859Y0({aC>lwcC&9;MFA98kNzn#kyV-dF*v__ch@qUGo7A*$C zMPDPZqNlmDFFri&q^+BK#&B*?nK{ji(bSxjI@zrLB>xWC4Uh%jA-{xZ{%+E7e3UXM z?Cb#>|5|4c0Xwj@nKtj>hHR`7yX7U*hd~J8AyT;Zpu#hIS6GPzCtFg*0}wl|dd34m z5#}&@d-H*5IfU`01goQ zP$+fRKo`rw;m{t6sVDjTx!m@gFN=`S*VP^!;ElH?J4|xMDT&=*sXu%62h;#8^jVsp z{JhP~%!CFCBOP2m$TiH{ffVH#$Y7h2K!~6%ov>ICUfsD|bXQo|;Ga!eKm7YDyrJJ< zJ^}G*DBFgI_h3Svg(YZP^%6Dx|FXmnn_5S8{}V8~MDG;}>6Pom;0Y@y8fAjK#zlSx zhW3}fUn)oojh$*?K!!1ln4^MIE8)ZM+pH<#15jLLp`UL5c%%8FcX+e|!NKop6>A`u z86|)#U-2$vPT-kQnVr+3{rGmANrAkn7p34wMX0lI&Z#h%Lj?K=MrGaf+Oag z3xq~CB7b|N*|#bWB+2)~2S8N;O~6hc$?Ka2je486;&8Up4|7;$p{O04tl-y6@kM;V zR|q%c>FMb_jDG>nlH;tgFklWB@eN4;8OPFtB(GRMg6x$#Y!h%nUjeAVHr?R4L-|0< zp75Qr3F|H7V`_f(QRk}ybI{Mma<77V0kYt=dZpdn1#*1Q%Hy3zaOtK|_W|9vUlBNg zEL;|P3b-w83&IgYY_zyB$yz_;Tb|O0)j3c5{GM7UJK6_7=Q(6foo~;6*aKD&F*E=o za5i&}RXD_cd$s||SYg~S>YWD7Xd+YcT2;B0iTrwW2^e({#^}1ACL(%@_6xYM&(lBd z-Bdw?g3RPM_@^O|b^|S!N`~*RsR?)}3fKmrRt1n%`_F?fNkyGk<1%ab#`Vn%@6tKx))bItq1n#5~tF{yUYz%1z^Ir&uvI8PSR$0;W-*01H@pJvp z`g;Fmo0Ys(s;T`$t@(M=%e|qwyV0pnR+tsKZF&<5VWUD+J}WqBLb?$tUcfSfAiAtW z3_R9gZAqP))oqIZ9wo|Z+-4|9z+GD7cSJ!r?~j;E+`hq2V2 z@SR0Jgc@SvK0j2=BvrYo~EiVeHaEzQEVdOs+MBY)T z6R+RdXy?)`)q(9l1%;7h5?z4^6ue!w0PpY1v(Zn#{O2BQ{+4mAV$g0<@&&CVP0>gp>Tb167k3>r6gT`Dtnb`Wco*H-RaI3mU*Yr}`tuZ6GTmi&E5(u7OK|nlRB*Y^_k%oi~ z>I#*cFfjtww`M8az^}lj2Pj%n^){n{-wE?i9EAM zVN8j2#5_c0@NWd3oj?2Y^QPtl+J2#^r=S`F%p8XcA+Wz3e;e%n;i{*|R+2_adp+^U zYkP{93Bw-aRc*j!Ep*n(UibdF0t+aAHxi}1sC$k3bho9&z;MFz%&f^hnR}k}2?tL{ zXsBtWVM+O%mqts3mC6SaJoD3q#d6bT(Q7e^OE}MN--Sk3AGGzTrT~nB5}+#pPoagL z6+|6xV?6Zs(U$umznPzC1Oz87bjW6042k<*EU^vaa_$ix0w+JK|efgq61k>yXKzLI^VcqmA zk5wfvt9Y(ttl;| zF8Pg!qUeOv_dJ>E5!mK6OV2Ig436>{S2%c3ph%ch5Qpqo2SEs#={<@9oV1#u0%n@- zUK}3eIyoQTQk=hse8O{15ATE3S8})T4K#fuOArh3Nydfj8zMB3inDi`FoocX9TAaT zb_Tc_;W`lJnj?SoDqjr4Q8ty!VSu@U>JdfP{Uj!@OD0-ELF>_zs&obtX{VR<=N_2q zZ3ief!cds+zY0Z3zvk)%IUepG{~u3p8J5-hybaSWjZ)HGQUW5~AT0_aDIkr~-Q6i5 z(j^MgNJ+PZh$xM8NH>VUJNN!Q|M$y2_6HBawbnJ)%sFR_V?O~33;VwrD_3!|XY0e& zF-XRMUZ*0`39f#};j;Q-92e z0_Di>-t`5t5P`%wlD{2TlOaS32sPJCu;TxKTM=EhhBYFngW(gl@;vk^;kohz$;#cVFZlWSiKWZy>Mg{fi6!`}5zwb`hi_6B?BRrUY^ira4tFYV$Z|Ltp z3OfnaU%egV-i`6oTSY(KV^0XXZ=luEPVIGEjd&si8kM<4d@^#ET0seary%qzi~CCZ zufYPZe4ckYyaQ!|Wob8%mCw!Euy*}&xlBblhnp6PV;^P!dl5RXH*j#Y;nT{umP4f-a=Cp_GLsHgL{fS+5 zXvI>38Er3&U*&!B9~f{OSPG4!k@P)lm3P3=?bhBTmM{DFcJ1>ov*I0fjTRuWnWtad zTu0^RORj#NhARYGftI6@hsWO$g}fawExy(79$yqrd*}Br8)vvDVixkP8-J)~i%}TH3QP^|d%v?b1md{XG)V3Mv^@X^ z^E!PuVvN-Rm=pp@zi1b!oI5>0`=H7JSGQ$MfXVF8(7$(PI4>z2|A>C%6dF1cI8sJd zvnY>e);HLoK8KL>KgC^hI?<-?Gx2ubZZp_;edAz`X@<3>IP{p_Udn8ZkyFAhkRo8tl< zZNeJ)GDpkF2`1G;!5ubGt3rsjk51$fx*@4BNulOVQt&Z^+WN^E&|CI(!x8x zR5UnOU?Bbc>NgE`l0^9s|xF zoGd)kAuYMi*zf|Zq0dG?wi?&7YgD2iQXk|>Ce~s3z2LRvCn*Nu8v=#Vfac;P@UOZu zMI(Whk3!t={ZduThG%d&_xN=S)GLeE{{u15FW9J~9fMAaf;Sy^U0lI=y?gINI!+iao%Y9Y(Sh7eY5GMHdTn(SIYmWx za1uG%0KSL){Fg=*N?!kqvL~gf4{nT=!b8Htw|*|4cm*nVz;zGU{Xjzg0}(bcJzjbm z@9iqV-(B5v#!@=344VDKbw@HkcK|o=&lg#kqN;y(wLFD2O)!zYLMerTP`HRz`Z$se zNqqV3CcMOD0u%G!-@d&9gkHpz7MNAt-1F1Gev~D!w~c&c2Odr}hDCU$F=^?6uY3ke zEHa1Gom?Tt9pmhKZ%i;_f7UkGB`M)-953w{o*dnMN-as1@laR&Rp_HVqrIJ-q8N*^ z6oM>>EToU^M2~wCr4LS+1=*Q{(o|Ai-Ngoi)j8| zM#LxYWZElAyb+z5K8{Iz=I(JX^yh>{(6Z-10FRm>0TW-jpzSX%IFJ)iCC@g#%Tgqz zH{HUCe z*G!{nEILGY>Ph;FPICMM*6~I6K~V^4@UAHkQq3BFFus4-5*S|(A9I5_#6IVxt!ReD zw*VFf58rmSfsY}X_bXvLP~<#jk#4w+@Af>)l|r_01!Wi3CQO2F3Gf&{HnQ{jN6OEw5_ai*wB64o@bjORX!bhs(Ukp*h`#)`Tnn+f)xn zgb%z*xj#Ass|4HMt^aA2HzunJ<_GFbjL<=wU<8c_yr%8m&Aq+fQ1%ee6SR;pZ$jn2 zpDaZHie6GJL-2fZcA)oq2-w|QaA6W}!AvZh7}oA>=Fa@@LwXCyA&XfrUTQrPB66^| z!>)6;!vsov#TJUl!HU@B$BG69v*1U8NP7a{c;TZL z-0Qb_46LrbAeVjiE=S%1_XF2IDal1>2v19pVZw&f0a$78oS;e7D+j|3?MNhf!(vqm zaS9Q`JoL)ds5%)Odhs*f59rOft-N$rTSa$HII(0h6#tV59CKEjY*qZAf^FYCIM+A3 zZ1O{98ZfAVIP(vTh!IT8>l65mfEOOD!lr|;x`sIT6}EQ3XrRwTOi-}k&R3HV;*Bg*6%zg1Z0;=}A zJ_ZZN6?_`82Ivpqm2rjxMcm-*LZTBGeL_qIwF+ZVAr1>3$Ml(Ov&tWbskuwwIg*26oICoUGh!)sHEr18#Lr z4%5p}`og=J1V|9P+!jEZ{_9ft3j8_je-sY`s5PK!ZvLMtRa8NE4wk5#^zum(-v1$B z_Zc4NqSG5{LVRncz~-=6&+llje{1hvy`EXZ?9H3*m8v)ldUwZo7q0o&r+@ax$Ds28 zbK*B3k7<QX14a0s4U;H%Q zg4|b@7{~@ppJ^y?MBmy8!VvKzA_MWE*Xo~Ru7Hzgqr-Yif&YDYA;$^^2Gnjrb8miz zjt8j*-VSjIysbVRyA}fV2BI?W03tR8XHSO`MPvK)&4R8h0?7K~Dv} znlT)5fC2sYJ1_w%A4#AOwm@p$(qYDc&&8Rlt+w&w?R-E!TM>GO`Id(?+rXDCsYQv~ zg>6rTUR5Vo8RtgvJBJhhuYElw*PfLx^{U_tQH<|q{Bk7Jy*Meu=c{X`av zNRFyAD4<_$AJ%VU;E63-6@_LWfPsAR5;R9}^4V2flhrt zuhud2X)(Ai9m_>wGt_X4a1GXt@R7e!Sw$%Mn^P5f_D)mmBpi%)l~4hW^^nJ9y8uT%lLbJr>B5yjYF9df0+K_c@-f!dH>uZ05YIM`N6f0)~FXAw?K^uyLNk} z@R@EOn(`YsKaNolPX2NiAU~7Nc_|^UW2-q6gSH7)5$^bflBN+zt#w{k_ab{khv=^| zYlU@D%*40=TnGPuaB*;@;ZL;hVw%ULHv%=n1Qfy&rrtN77YhZRL5~G1sVDsZJ4d;! zYz$15640D)u%#DuIYWLJTm$|9L_YZ#I)93&*Mio>^_GUBlTSh{1?V3@vX)QTNr6uTgBw_RAnZM&ov-_Qp+I7P z&=!CJjutMw9nKBn$R|At3JRd3s09?vD*FTjl%M00%+>f54iZrDR)cxfMWDvO%>b?k zZ}`jW;!5uim+~j0-y^YBoq*eG#OyBQpEg&^(0s9qvtR_#Z;I8 z9ffTXJT~=))70_I1MCEC#<8Mr_ubQv4_$rH8x}@sR8G3k8wh2qU|NNln!tf-{`H-GPer!KO;w7eW`X}6!huQDScHi}iMfkF{8$qZ;|N9L8Xk%M zKTq|?@w)m_;#m433+ACzBgk5{oCRauQWz!3tGV`*_Tg@&(W1b-iW^Y{Wz(=jhykc? zQ~Lo)LFC`@w~xSN=@h-*?HJckuT2m)(!dB0gcQ{G&+D+6d)mBUtqKR5gj@b~sXYV; zmEuZIHK$I2P|(gMI4f5@RVidP`%7SGsC6nz;?ovmD<>!S+7-NrqIqHSq7*jZj>wZ8!~N^{!(+Y2 zdZTa&Z{y8q`=mApnM`8i=C2YhGZ^%b2WJrkNPaM6y86ptu`vV-g~w6~$D3Q&qu@(~ zCSZ627jB&0FJW~>6VWdKj?5-RWa1lo#@%Z@50b`I*r=)pE`B{!k`IF64kl0!!E~qy zKPzNhpeQRR+B}Q|%)C5ju4Wq_x@_bUquGCeYlP!xQUHwt#TsKU-R9RPNiMI8OjKUP z97eL2;k~C|;aUzj)|%{2PyecC7SDt4EeyCt)Tfw^mikbC0225m;juU8Irw?I04 zCR6Fn&1n{ZF%X;8g@vnz%RZv6kAirS66qRv5sTaX#_vc z4z79OKAmUzm?%V0b{uvwJ%g5Cmu@Cze-8fIW_#S^5iX<#aOF1Jm(y=nk)3tD3!K90 zr4Nr63*M)Gntpv^Lw;4==AT+N{J1>)4%##3w@0;fU_ggJ( z2RmTdUm*~;-DtSC6koBw+}8KgAb(w2`7l1MIdoN*W7MF!$LaY|QsDec6IT$Bk*k`= z*pGxhXzM?1C++;c{9gCfED43D_vW80xWMgxmidJ`6=j78Q<2Y1ew{s}_1@+id`KJX z*0J=HRXwYb=C)RqS3&wle@V%VI_0N*q(yTwb}f3dmy+(@xm~=F&19Wh9%8TsD%__(@;d&m@da zdS$33`F~hI+<&$6>M>~bDwByg&PUlOX_SV{nk2rinvbF7Rv=Uc1`Qk3SDHy~Gi!Vc zF3-8AdM?J$akic$t6`B&|rn|ne4fvMBzuu{^Pex+NG;WIT ze!ev$TI)?e*^+vnG)kcpqg-E|Cry%1GaMHGrjj)Jt1RX*2Pii2>4{}AUlJJVY|eb9 z?5WHH5*hWId4e8@na;em66QCgmH%8;Uf64oJhb^%(!X`b&*z|4s5zXMA&BuB#>=Ax zXG&0Ryf?fXNB>Ul$Q1VDP6uN@jagN{r5+g>YfN~a=udvW>#c!~E_r0W{_op&vpMGF!w}iLT6336QE2t zuAyXek2quh6|%Uyb0ID5tygO|T>a)IgO1OA7cB?(t%$2z>C0RC_h04C$o~KG{GDrh z$7v;g#*P7Sk<}GTMKjjO#<@P)yC4$2zNJPQF!P^)S z7X#m~5+5a1IhSHsOVp{?>V<#q5*>)yHLYIjFXi$|UuIQ5^Zi)*bAW%CZV-yDdJMQV z&~w*zr2O$Bj}Nepxc{LZ;Z!(_*>xu{B=A2O`7+lAYf!mWe-`_-sw|ztyDIJ4)r;@5A+?si)#c`YCOTI>n2hoqA)y^rL@r+a1_e3dD+KgJG1(rJQe4Htkr&8F^ev~;3)=WYUv*fOYT^p1O zLu0nzIgX>=eTKlKhb~0;6J1lH@^jm+p<8$xV$H4FHQ4Lpe{dMq0mM=G0{@8%THYU* z8RvBB!=Ev~UH5PE#!0E=E7c+O_B*#Ht%WL3k3^QXN`;Q%zhBdNf&rWPkjk^`q;n0m)WSc?J6 z@@gwFmabfyPa3JYW7uSOrHy$y^t{$aDyJ`t*1^U^2n7|D;-(<{mZ-DeiReS;r)lK| z#;pb)l6u75oXND&`_$36jV&x22jAEVOX_@+W!ggHGcUMKxqU^v{A}ylj+JCzR zGn4d5)3tv@Qcb`Lo~(jX9D@@6pC|^L{1Ud3W?kXAlQwtvz4G#=CX}EEHU_1U2TF0W zBc@8S2d z$%+F3ra;ZXTVZnLP9t$SFMPYWi6%oz#`(^eE}!Kz3bl3=5ERfnYK#kARl@S$DMu*u zRB3SfWZ}1P=XSUl&vwSHoIdFT?L#Wm`MQG2{p^415ns%MY?;r92 zA?A&VWIEDEf;ndFsK}_n@G$a?ed0WSZ}ceSw{zLcNA0@2WbE4geJI#(kt{!(l)Yu@ z&A8Y;7C-t>?74x7*Lv*7F|vLDR7yzo(E;~Qcx%1WFH`q<^?Df_YF!Rso+;>ESm}Bn zbO+6!SL>qN>{Y0Y()7$o7tC4xdH}<$d;^#W$bE0z{Y65}^%)*p}s zIIDspCkLR6WY5MnhdEKo>_n6bj;ZL}Z>o7p{OuH{v?AMoNxp;{<4RD+XS2wLi6{61 z?*KhI)meNyajil>KG9V za=Utq6>>#X8CG(Z2a@6U^;!16WW5A0iB<3?T!dm6I!%U;NV8)7sPK_*n-rQpGsQ`! z<&v7#JrxUlwElSSw-jeUhC+zr&q)+p=uIm`${|vh62#dn$|W z7YQ_$diCbJ&VKDADh1trN=jTvbI6@QNk;jAMHIq8a5A235>#I9lUwxzP`AJEi*2V& z*Cti@J(&deDO#U9R#=D1W>Z_Q&|O|yQC4Ut*yK@OaA>hn5-o8%&!W_&+5TR56kZxy zK_kEKq>b?eZIxw4y6LG%JBsp6PEYI#&vSrdpF>twj(JpIy*0qs@cX)||Lvse)&+QQ ziT^JlP1Fp4+Py3#YrtdthMCPHL-jaV#{zcUpqQzHZS3F7EjPw%lN1QHputu?Imq~~ zRifF?O|*26p5`s#w@0A~@?(I2bq*l!s0i^sqyfZNl&3WlW?O-k??a^PV4tDdE{77j z)Uk9P*+AEZPa!HM+jKcE{r=V;%CYRSe!5o6y+Enw8|WJ9i5x_Q-|P1#uOz+eMfTAC zn7LstGm83myqNvO^4f_#6sgNPuk{wC;6hVtC~yOCkgq{A{Wa|#g6#ji_&1niT!Qy= zCAX`K*>)pf9bdOQU{SH;-gg!vPLJ$y3UjQ$0MbDmFU1dUQP!bdr1Ti!-ItH_oUExQ z)z2Rh*e?sa*a245=$|6HS*86y0D)i;$hQ~m^c}MrOevu{&HBy z&ol4yrUGe1Ib2aio^Ynx0{7)R`@I)u$((rdyCz;!w(gr$E*@odyft!-a=zHuDVQ4QXn4qF0bt%bcKhXI_+^LJ;g9dnwd7jut~jET%{~kzd4BaAAM{w)Wa^r z$TzAf?IJD8u(}vMGI0gF*n+RTj#$58%6+hrbWgnCb9XOh_D6(A$_Mw4F;T@`2l`Df zgReWhUue(-i;-ljhgqq*uVhGsJaGh#7F>*}+XFQ3cvldE@C0#lh=H{2s*bSA0oZ6S z*Gq90zhkg!gL&EGa>Hle(wib!CQ+5}&Ye4ZtZqM2vwr)4A#24m{@G)zY|8boUC#;T zaHRsYy!~$8>Bcf}FILdv%WgPdv1c{D6aV3Fhr2y{#ikijzxT4ik(Ca4_ebeW!F^dH z^4rh;?ZJKi8~?`l`+n)6W6J&T^njbc6K(rl)0nXfF6+VkK!BIfAkP3ypt4>Z6`@NI zv1#nR8$)tC$?oRsI^GuMa-^+Tqt6L(mx>Y+u~|r?AL~{YQuGtrek|ubKaK0Q=%YJ4 zE3VJoV~L47ohS6P>G4-wzaEN!ImskO|kk_ir7Qg*g|E zCham*XHhw7NO%W6!MFcft$Nep5vMly@|ftnk4$a;;jk-tNXG^+2Tj_7!5sr^(WTw%#le>Rmi zJBW@_R{M5{dcQTa-YzxZjg^bR#|~%n>1a&v zmEPojMWJLH$jq`nxH;Pr^Xm0LG@>OQxBLCzWaTRG^y1NK{|)DFcaMA@Cm*tjQ- z3|r1(6B5X`C-hXf>}2rQNjzpVRTo+e%3aB{>(2XL1MljPcC9s%W@-<1#;fBNB8IV) z0}iM+5kw}>%6II@*J=K)rCH1ZaWL&I0kILw@gt<}N%$uY);T8!YtBjX&cm!B{o;dr zCbBwiSK|TFTxVl+h5*$Iqul9bW6=AFPhWvC&A@Y5Xu2kI%SXxP1)+1KLNI6>t}*xX zV!4|;*-rBvk5)ATvZ(40jgGe__Ra@>c%R-qWJN-=`d-_rjGw{IbSD}HyW+!k|C1a^^Z4nB&~6GCF^Xzb*zYWvLzAs zuia}o)@HE(T%m*lO)#S#eq^^&GR>)*5<7k#4bp9VN?`{BAT)7sn0imM3Na|Gujuex zI>)8manCw3ubD9N{sb#B;4cTJ9ln1JF5sn~FVJ~4;&FY0Q6FmyJ!&UBc%bm@X`y3& zj-v`ky9TUa6sfk%?8V{tpXaj=p0(m!Icf**7D|{e7+*mXnu9^2N{6r)9?Py}lSTK2KZz4fN}WtW{#asT3rnPj>|024@*rB=;_Kpb6861)UBgTOTrSy4M zX2Tq*ocHa2{S%NhTyPFxnk;k7`ggHJA&^C4ylDu#nOe)Km9KBF&e|v{-MW75JUqKA zLFv6Xt3fd~cReBLm!qo6Mp+K~H+U1BKW9Ll6|x0;CO?oQiA2Iqe}y>=_N*kzE5dCT z!_cJQen;3?W<7uN+8Kr(Ccf7TQsZmz9>z2_9#n5CILV$fs)E%MTb8e2u<|@(j7**; zo3Tiaim@ejr};{qp(+Bk9D{&H z%%mNu@w$ul8m@s4Kuvm)s|zbU_+o12>=8xlCCtm=42%_5JFonsqoVkK-EQ6Rw(^3$ z=oIp57jK}Y2ZHO__9ry(xIZ{+yFoYrpO1e{VeiraHhi@}z#c+$1e<*mrA1H%wi%ab z(i8uM|J&g`-z?#?e40hDBo)G#=uF`cetLOdmHL3}XbclZqc4QcN`SUxrG^+gp8l=i z0g=fR+TgBmXXV07hh@)v7lRIh)le@o`k6uGp?bC$ zm>u%1)7%~)MCf#`X?;TSL~hReBxB4%KIm03WFIWdXJSfp79JbslHr6h$TKcAODXz2 zVl5Njg9{UX0c-5h#u;$G*N5JAS<Gp25~VwJrNGc6HXUR9d#Jn~3uo*3*qxei>;k z+?mumkHN{je%@>F@-%GVHXyf%B|dN`VzS*JyGqyi%D=Bf%5XoL&nk{W0Hfm;@gbNF z%;35tMuXVx1Qtm?@I@sEcD8%0vWlTY;g0h8xs__Lrmgv#j)^EQix zOh3W>8(_nrTekHk$*y*K+DIKD|BgVbF*dWmrZ#`9MokUtMAbET0G1SA<@bqt8w;|l ziY@Z4SiW&P!();m!unj4B9pjnuxSe46f9`roJZ>{k>Z@UIz4WyjuOPBZ%_Z;kyici zcLwAJi!cw9-g@p1!4L;<`oYr<_ZdzVL_T9U>H*!uHMWRMHr~FvLxWIPue9nk{Jqmc z4vdxZx5B3Qr`t<=W)+V@5)V0bDA@6e>Vex*(n?J5mv`j?K22T<9WHR1daU>h>EYrL z-AO#d6>R#YT!2x_WBL(-|MdCL19h9TSyP5gHG;Tx%c;k5(vsz^*eO?`h`TJmE-7X> zpku^SUs+&`*|7+lgc|5>%zm=?}UU*=cimzy|vaM1fwCpE-$;{UnhsTT_5cgewVh0}4Nz}g|rt^D?>64ra#Fu`>4M-TK` zeIBq3!(#uHHkbBHo&;h(TkLoV?|?R#jOt7}RuiWOHC)N^AiFMjlJhZruIY!cs|@4Q zZ8AZ7FaNeBAcs)cYBR4QYLOUdeLrFq5!w8yWrEwz(s*!9p*miCh++-Mnl&9Lz06MK zc4P1)jM8h=o=NNIjQ_qqt@n8Q?k3nA<4{#U5GRSaz8KoD{;LOF* zI=F9;Pfdh(*nrJVH}xx}YL|s}p)bK5yHa;-#C-j8S zC+1#M;2KGjK+@CvWwWbz<^`WIxl~Y>}!XQD&u;>6baTHB4ErD<2CW!7InQkd=)(ZV9vAfX4^p)nktgosy5325yv zl06sbkx^oLt-jSfVG{PBHGN%9A>3#>ts@gMfkTFAV`|4Ym2fmYUBTycu zcZ?3^8Gj(h>pTsjG`kR`_zeZ@0rXwTbO?X6m_PHh>jg)^T$#2_V+e$Gq&{lYh} zyvq`RDS|U9prXL;o9#oSoN)U+XSj9a1L6983e@^?!<%K^FQT_qH=ZYYmcEbZ&AclW$ zPtW4WLY#dgLyG-e6WLlYZ$w&xP6AIN+66W@8?bf?+5BSRJG=pn7@S!UliC5cxkK@$ zTiMCH0D3Mt;zBw8ys!iWO&#zmpi^w>vtW!MzEfO71`SRbgzr)EB=GdhZt-v=Ffj#Y=~BJK8|G5fNJQ z+P>@!ySDB#E~Vk_cd3H3KkEQA26dY=Nls|@c3T}iX`;%4vs3`!td~QUsxg}lr^v1- zKFzgGMz~<6_hp4wQ+WR#*DV!EM4tqFhS)l*h|@WMod7<<>aFkzZPa*(ad`K~C|Utc z=H=li1H||wZ-Ie=@~6Whge`hj4!&%veytU~;@Ccycu4UIE@w??P;Hu|j0$Jr*`vQ= zWl4WJTX;Tg-Z11|b+RVPDnAmU_S`H=+sM4W8r8eZRyhaT_Y&yNU&!Yg9)%@^gCO}J z3_8QH2iSvV_ZYZ8jtuy{f`A{7gBQn^4r9seLD)sF&_2jMXi$7wB2WFn9;a3&?{(_q!JPTTfrYg;ZhCxJ2z{5~f!QPA*~Cz!H`p3GCvq7($p@ z+9e~a>G+~G!9~}OO+gRe=OZMuP5Bo#X0s%XcJ_1vG^TfeHq)sZJ~KHW-Cy+?NP>7p zcuDqQUxCF&%u4+V+;#Z#^BEU&nFQ{Ny3mE2tBz%ex^i>{sdj+{eRmT7Rer9o7 z`hJ#+@>K-Kb^(JJ7;LDOYBrI0gpzOjg2FMsX0P-vQKj4sBHDA1Dz~PvwGrk12?GOM z{WHRbe83EE#Xq-P46k&VxEGR}S?3lsXySKuM@Y7Z1UGE3Pi&5fw(~>2n2wZEi*}3=j?)YZMbo_li^%`=9y+{`1r7BoZ8$1?rv<+XVH=K6CIBGh-?*UC7 zds#XyT6>lp-q>oyR0zHi=X&Bv!1iKB-V0CJMncPyvsR)K{7pNTBt)c4S|B!+kFip} zry`k2D8osxv|RCo7i&9Aa*$!9w>vxF&>Y<#^lgatdLOfuL{A8B7!jP;Z}KJ8nEi6X z*nikEri$w9rtSLVUQp!L71*uzyaSBqH&B-Hv2$r|R`2;Ebjs(GCQestF!Rj(zV1Cs zs-kjUtnk0$T+6kymq*$)>)791lHHh{o4BC+&7H9g*Kqi&!Rh6cI8ATTk!9GBfcu74 z=c9?$cWRdE4$bjw{~#3k-9vkn)QCB*3G(I`0v6&D$XmP!Wth$#Aon46{`jnNuS>z) zUIWj4%p2Ij*37sH@@{|#4P!ehl5L(DSdq7RG$U#S*7f+{R zr25RCTFxd`exL47W);2?$uyl59kJ^jdY!ek1X?a@mB461KdUmsRpk`=G`_d~*tg9! z4y9I;l6U&s#J!U>0+j6Klnkegw7zqMW}=1L>i53buKrFs#q!|t$1$Q`dfuQk^LA^)c-=n3c4O2mCw;>n#Rii zB%HLkR95NkOKBGr4O~6$pj$Xnxq`J!CVtou8!GxPDovq4#Pe=!^DZDx?yrU#eZ9Lu z;mM*4wnmE5J-WnWT%Qug4zK;Rd>phH_`}iyCDj7%NZS#FVfi^dO|z9`3RAh=px~OO z6H^zZ(nQVk$SdpSW#&Op{zc5#my_8=^o}~ySJ7lPzxO}Lic;zO0^8Cf&GR5@@HX!*P?7E zqwR9{p*Pj@enhP6Aq-_^ReWei7yqD};*wlM38%V&IqvM;tJZa0P36$q4X0`>bhC`~ zszGI9^N?snU=|pNK6tCq9yBB6Y6S*Tn?ZJ3 z3i&I@X{92nAMz8J3~(4oVzS!blKHB+9Mdk8xW_mDnN7Jj9pQT*W@uN!n|%=^q;AZJfX#w+3oqXCEVjH-SC5z@e!x zWV|#%_Z&w#(ffEKvGV?DN@pV>CGy)0Y}a?aa4GYlJkB|%Yf#9-l?!NbNiUR~%w)Lt zta=431M;6~v4rDMydWl-|9x-z?sF8+-xnTV?#X<4-AnkzJrt)KX?^LQnQJAiD?bCr zv)KY#A|TS$x*F1Y(5kLD)BPmtwphFClQj1BW?@G(5mvxg?H0CNo$gB7laT#<7uEZAtrnBO23E3aK#K>kr-6$x#=t;r z>X7{z>3)yhs*HIKz_EmQ;h}c3_NAr>sykR40C7CgWra27)v*Fi_;VTW?b>R6sV9tu zw+i4CT_abvp(2#%p7$$29qF_?Y3Lbm& zZ`@~l7=bucSW3HcN=h%V-uy{GyMGUJXJ2F@@I?YUYJSlrSN-X$3f>?5d0&hLG3|%d zUdZaFsdWZ@!P2>7M6O-`9GYhnE60Qu!D0Zgm!q~QoZM}>AUWZ z4fgw2CeKVIzHdRLmAtu-`1jPO^nWL1pT4G%G>Q}lYaig{N{$$Yx6+E~<|spO92Ct) zVWaW*rD1PxZ)e(yu4yE^4VY(zw(;MQsRW09%{jezvS9{|BqNQHu(hUN7Q73~9AAv} zKpj~JW+uNb0Q2C_yTRT!p%?xK5=B~II7e`fp(~Ae4^&_lIYI>1Q+Xb{s)1d7lT%pd zvZ*c71!~NH(3B7Qs=l_fH5;ZFFsIkV3;Y^7rIwWmv}Xz1_Ym%2l?~l`aN6{bu&U*q z$37p-CqL)}Rc+WV_r_9`EtIbufzc;H%56cKd33G7tNgNQ&r(Qn05g7oF}qyBQpsA4 z^fO@E{xB;FIv~(c$9R@pLnbP)S~>?F^*+BQ_DC0sZeUXIir>hyxq1u=_^6uqJ`J#>}L>{k!&_53E zLQGF0fIRx5Rev+CAz~IZC1Jv#T)56%AUan6`gET36991h!y!R*|CYiTxTEN(LNh8a z6@bcKf{2ayn!g&snB~w^qFHFr-P6-^S=W9s0Vdl#*MQ(WkgOsK*`DqjWqBxDjK8qi z_l^Sy*W1bNMq~0z~-mFn&^6Y zN~;NXarvm1=Pa}q<>YY{672$vDa@7tz;LlXCM-~*Ngx8@U#4hhp-8TKJ#G9uW3ASisNtss9e&mtlu~T(+Hdyy9yiGs`E$v!Vx)Dq^ z76c4uFAM)B{8eBe>)4=#w)3YMpq0HD+HX?7-O(yUF=-x+9lmF%pQuVV{5@A1^{%P5 zDEu0%73ng05hB`Cmt-q3Riwy>QP`#zPL26fj(6JRlx<13Y?=WX`YWH|DFx?typFp&n9J?j_`3XZ&XKA>GLYoL^|n``=M$w<$uZxqWG3i8`1m;J# zn*{Gboe+q^#JOuqLkD1`Ajp0JCPay)3jBX*ErZY8Kj5hZ zkVTD0!e31bpl&q$Nb*nyGHHC|xX4Jz*{#E_ zpmYVKN-;Zip_T!?LHGoiAi&T8SPI*ySu0Nlo#yvv`*)GlWA8PLLAeR7F1SA^Kv(Y^ z{!zl`oOc4Qp#^=TBM;n{Nql_Bl#waJ z=%cw9{p0j5;{Qm-vTY%edVBTQDeP4O))*# zBqaNnJ}K>8upo`n2?2;pQC_~oZ*#?fyeBvyju&i`fv7i{i%hL>9kR6a#skJ95dTK; zH9>Jg#42gPy*r%suwI!hHwBY`hUvk*z(u@>mr&c)(s=F`f1Vvm=Uaw&8XFnKY%x!G zd3`;)#=ffuiD>W1*kPd;`sc9CxGzYV4G?NR*dokQv*fcu2SWAgOX4j4K{38=ncjDR zbb`=vUw%y)Xw6v=wfmlrUV%6k;)k9jZr-7hQuppI?|?D8D)~NzaF7WIY~YuRO}oly z_my}ci(M&`h=Wjn8C)BPfxXc`?}MdPM#UHKwQN}QlfWS=H6M5Z@QA9zZ+Uqf`4Vvs zkM~7pvH{xH<`t?tn0WL!ic7Y=X}fW(oe((`ZvKV5-4h zFgMz19qh`27(g8F2uB4rrR+K-gij^-bE{tB7oZ_@g0DA0ooRYbjDXH6AS|h3!<&NN z9FZRkSb(8`EJnho(c)^$Z@YHxKFpn>06#lW9kV$l%rrEJbWT7NMJs{)6nIouQw3Rq z;)hO>zGZ>F2)*Y8d7jJpxPHCEt*($3M!%#b=*&t2;V~_%(X9YFRZ3@tUbUt@dak8Qy$+~g#C0ay`K*Q z7~qvWujdJjbGF~$PivtC zo+ybi-qjQs1zCR&O)#e*-lS5?5X=*J?F>s07er!Ven~PiJJ*Cy4fueybM`*6q&27e zDNjZe(+VT5z0Mo^|~Ap$9%wsCGOWa zt*TJljH6z#u1WdMH?#~&|9K7I9;pEaL$kpMA4dnRm!}12z8+Vbf1ho1N;jUTyBcF7 z{XmFt7nJ?vBXJ>M`zt)^HaGQHcnt^_;oW0z5*2-oqJs$meXkZ8n@*nY_D)USD5mgl zSj+MKLiJLL=?m?-AsaF|CIRV}FYYP8$y=f$)=M4cHqmgtfql=)$tJ)m3Ia^eL@I5174-2q2BKpgsM`via+T|5oQe-W->tGD;_(bf!n{e*S z2$FBn*#E{3==>S#Mc=u?)?!~Ho#X2DSfTP^vaNS0+Sd_6vjbyitO97rSE=2L87`D84-xs?OXhd!MU zGHQ^*hbCwxC4mdUmkQYoW~9iiA?UAU0?%s6E95j+DL=jp4-uOv)s4q3{Ft6j-heqx zdC`&bzE`t;fvWe#v)R30pQtXn-NL=;rv3{C28sXhvl(8SYo;&G0`wX00w1wVb>d_; zyXB=2)9>Pm1Yo1DJWi2qRPYb>&}@oOE!(e<{S)r+xaOsrgN#$i4{gF)O+kD9fQj~J zJo?E>8)oAKT@fzow4;{bo~9Horwbl|_nxo@$JpM@xNNN{8#4l92u5A=utk~T2MM%B z`Dm|M_pB+lx)e`v2wX5A*pS~hm_^}OL1c9DjS+mXS;}iX*zOl3ygB91lhXfTsk+88-0|9QIB3>o=O}RA;zqO( zgRbedcU1hj#*asM5@spb1TgB}tgkcEqov0r(dRtgvlg&ns!mQ*LVp$LtPky3#2o}{ zKA6TyAPb*2&^`bk1$p5^H zHU?ra81Z^bokI?!|MzjEhrMVFf@sE!QRxDczXe8Z%WGj*-tQLu zKD3iy5D}!-7reqdLO#gT^Y_iC&yA^n^1oo~aj76zZLel{WX@13*D{fQ{DC>b^+PjD z$_7{Px5)p;(^o)6wSR5X-Q78KNQnqY3@sgkbQ&nq5=su;rG$cnC|C#xN_T^lC?V2< zC`d|3efxO-@3+=<-L>vjoH^$gdq1^N2jkpVZd{OQCfR>(W7G{74$G^$++%$w75m_o zJb%n4{=$RQV^$BX%3dPIN=N#*1-X`BwO46FMDB}g`3z+172O<*w${LGUU~^_dQs>j zdlutUdMjNmOv1v$RK2NB;%ib1I+EONlazcM_kTx(!d7KY4JN==pMvY2oKuO7ko<|% zOo2)Y;k~SrU#a%1WZttJp^39h^j@e)EVVDI->WL5pQhfo8l2hWvMYGgt)MAu!dH5;WjKPL z-1{kXTuh`7xbzlfhIYSx1a2N-y9Yo(zG6#n@$&yHP;2}BFpx0pN`-QwXK%aGZ|W+4 z>F#DCgWdi0^EaYmMTHEQ$$Xa<;PWcHSqMGTdeHdEHF1U{p160||^#bqFMH=b?5uV7sjag0tWUw)Wi)DAHUn9M`HYUs7 z%im(cz5Vt|l)piXJ>^1`#lsxy;4lkrq%A3Vf4#r5PeXu|IY2iZimIN&m zMUE1^ADZ<7dxool-mhDFrmIvUt>rD_A5wCPm$RBHAd;yd-~@L zYRrV%I3(1gikG!RfIfv{LA7>xwv=r}+(s$P$`r4TEvm9azTXB(LNVzAz@xX!V!pka z!dA^>#b0cgeDC+SU&lhw1XhXKiUb($Jz;R{O5scy)L~o@%kcd!FeCamec;=}Eb6#y zJFTq6Qy3L-P32uZwlNGHxI$4N<$jL+?HgYYJE{O7#s_1+W4sk!ZFOYE0=jJZ`^5;al4^Mhem!V60`rT|l;mX+=mBd#4ES$xCj z@zTc|v!Q=;Ma!Sdx{8JH8L%7mdzvw2CSWZ&{#Q z(tk>8dMjRSNlA@BgY-e>?a0$BE_Cq+5)hxc^|$%Y7i)fE?q#98T#qO2y^m#EvBZDh zIKx&p-hy-vNHqxnP$}Rk@HifHam1QT7o&F}Q&(1ph~2TF09xg2&Fn=c`Uwr_z2ApI zHO*0V2PE0qV~8iMi!vN+Jjv8f9vZB8OlAiP&}Q`~m_vWI51WoN6O0t6nB&s>A zP>(^xDNX9VD7d@jV_f&)WY_JXV3%*X53H4ed+(Dw->7j(6z7>~T=7Zp)gV47?-<53 zTs?(u^;{ryW(>J8dl;R+L=n{CLodxzN&&Zm!UBeMs;c6wdkb)V1sApN#WlYvUH(}U z@wKloLnu04qiNBQmbm6i;q4xP*G4gbj`c$_&Cs-m6zxscC>u-l1VP&|C03CWUKYFkd-8EwcEI*F^IWVIYXc zqIGV9ivuQbq&^$(^1c!&1FLV9reLA%W9hXHFGU8qc$XR3-#j@uVpWuB_tLQJ`gx8{4R*Uj*P7n z!hb?0FJH?i``gqdr%a_fwmEXSE!)&p>1%cV8x-T49yU^4 z>}MaJwY?S}A7oY<&S4b2iiLX%fSzDe1Dl;n^|t#WJ$6n?Uh>_7Kdc*`zItW9=CHQf z5a>;<@z-}hMdh-`$qgDs{6`lu+oY3^@&!K%kZ=&4@M2kpHy;{WJC*lrlO}51^eUQj zo})hYoRA#+i1mZkNPVFr1LYrU^n-5}?LNAGlk6~V1~=ou)6G(;`xg|k()tH(`Qm8)NZN1pcHg*1u3iV&JG&J=& z1lsI%D+8%Q4oV9wiAm>0`;jhyh^XI|6jXt4CaFD`?I^ z#Ux8`gs(1)P;~KJeo`VX!0eG$WwZL~HhbL+SN#oDFMM;-P8x<|~-@{kEd`8>`<4!T^AX-_Dv`=O0S}>dwOES}gW9qFLxlkJ=cdCF`k6XZ*{t(gHHQY;0-;4RA z_hUa@3>;dWDNs)@6BSeO%NSb^JnVXeouV)YkkJCpX0~}M5k1KUB*sPLW^F<=wsLCH zr+_~$7=mvTf$5KVKI0NTb9=2qNc4$8kLkdr0i1F+5CPqzi0K}&NtE+ zg^iHMqj(-sZS+5=h$lubPV$WLJ}|*+<7pXI#Ix>URs6IZKYUTZKI_*U9+T7RPONl8 zuDpiuUj8!U+c2zExmNS6p7LRXNvYP0SH7;s&rJoIh2_aKk(*=ELA{QO;lqgc?kbKObO8d7TITO9#3 z9!yc*TjR~A=PUe^^&=c25A)9sIiG^OyBc@Jz{GvAMEgw-=-YX8D&w`erw@slE(NhT zmdM&xrQpzdiYfFE#zku7@<^n}u@98@0YJ(o@2kyEoX{nbk;I1u){u{Xg>ZP@vpKKR z{mK)T8TY+r!tEUC`=rC6gyP}H>){GZ=H^1(kN-XGbI5qsjgWl>JGBNhBq>T#(m_xR za(BbOjPZL-V77L8fG$cSJ$x@JvS*M1$|z9?sthcE5iP@rPvJ8sC`3a~e%b%jOr&FS z3_1EbYggkL{`MB!TYEtsfDjWarZ>2a1wo6 zL!7?_jG0lFwjCE=Eh|=&$r9N{@&FCvsmr!v=KBXTDg&~|(wa2Z8oj@hjupx<)7y$fPVEGjG=byYLGFqS)$ zmH1lpYS?dOPb^_%411y*Sz@B`Ft?^aEfU_xT*)E&<2pj3|5;H!%dy*s_@6)EffVGy z*31Tg#tWM~WX^3zHAzD0vBNj}j$-*jM8kYlJq&B-b2!`7SMx1_F*+W?lBn9=TBTFN ztxinMwq?|(ZGD7A0tw#%qbyO9uQ)M73llh7<3D9>PV7r`f&8U^+O;jFYT!}nk~&{b zfgxGy6{TlNU(I{Vgz4~}=n1(rd*i@>iTKxO|7)*a0+XauK3KPhS z0Ub1jY&!_%1_;$xZF>`v)L57up#yjUMf&5V@M2C!HyqJ~r;t8x(l`IyLXeI`qYsTv zR^28VPZ|lHOOGcO;pDIJy!8Fw0y~vEFEcM z9Xaft#fmn_XmzBhURKA+$GN5N<>f5rSU*5e*-BP$XOOnB5(bLbgRvi-R@ zHfS5?NH2&Yr?06n793>)6n+;}%R3A(iTM~%M^D?NqF6>4s}ced^8*J*lSHu8oH;bh z;O7esGm6`ZuE|!52@y-21OYAw|L6*_R+Rw>3GKq^%-Mq{nf{xN$mlQN$7q&yr>b0O z^ACCq+**CAAh9O;@|ixH&Ba~_tdYF76`SJ{VPub|`5v}%{-yg28&8anF%k+lvJt8e zG@2NnGvm;VPE4}2ohH%&GfZz^u>HU*_r4x2Ov(Wp}^exU7u(Z zMBq6){ApN|X%I@Ja3`-{U)CX%S!vhk`o_^K$b-MA7QI_Wc&`?nvB_iyzm!^aVA_3> zyK?Ah&|iv5o-;^Oz~u^&2%cK&zaRRwq{5U*9zS zAtA=|{WLl^S1I@&0IHy-ddSx10tM-n#(Q_2*@@pn2H9xZ)IwAXE(j z$^Z^EK52-`ppGD1mW42(I@4aNl4LbArL*ImD-06(4XL>ZFh3`2Rp;vpuxZfm4d5m~ z7hc{SDP~^6zXFrN>+8!z^q2w|C0IeO7$@QE9|japGV6up-|EpXG;etCUbrj}ELu?k z=%PH$d7Tglpc1_R^OYq44u&6c48mNRp6nQEfMYjg)ZeOzZ8K%z7jjL=z!^L zTWIsmUGOezXlUegM0OAMuC)9)Pd2u4;sr7^B(guCy4rjL8H^d+B2>5~8Vl^U zwyeL7pS`ktr|5e)`Y@51dEisYyPM_2J50r9SlPHIqoK}}@{L1JuEu3$qNyp4_c?!p z=pDdsV0-+J54IpTlIa8UVp|$-1-JgbT+qS9=U3y6%0)T>WN+aYrvXg^UGvemjq>$_ zQbY>W?6Z<=96%t;Q?2#cG4^=XFtkXjS}VsT4qUg5;34Y0$+%(FZmV2y2Zr{a|WHSr-Wq7LYdF$30 z_&bgkInQp=afAhLf<42T-}?jxF!cuMt{eCIy|~)Ysd`DR2MDEBa0_!?1l2p0$vv0J^8?n;JuaHMDowk1j>1(0t2yJZmjlg#{q^3?)W z@yWzS`;sm}X%L%8q<^0J>Q>`(4}dMYE(#FEllG>>#m(~rQKZl64#V5527RL5a5H|@ z*xShEZnR$t1x5UJ$cXZ)H2>z2#tO`UQMhG;vz)j#+nk?F{;YT$a_cdEY?4lRN`?4bN6VINE z9QB#T%k1@4anmlc!Er5r3ll*TfpS}rkPlt$k~{CUpdNjY$^nDzP5?aw^R%qy zgq*#Mvrz=%yAu?8W>-HS<9*^cn5@H@!c~J-S_ws45sSsI9$=V&0WOYV>JagLRG`G3 z6cNB>*7XD1I1RU@24ZZ@4m_c-NaRbsT$Or9nD7yH{WAX_;vIoMkotPn)Q40;1-%S& zFK$bzSWmFf72kvIBo+WcKYeKG7WZvM>28K+j5t*1SgR!g!2Z>Wv)17 zFF1vhNabDR(|HSxPW*Y(qfYJNYwL6XCJ@&@5!bhCWcb6q&P)xnU@ zy|ly}KAxP*h-ZQSggTn&6wYJY@C5E2dAmnlO2&c?D%n6If;0DeXoykJjrke+h%!0T47I0@JmIOENx8bm2irZ zmc33FxX@)~D*_DF8`7(5B*^nOv&TWRzvKiuh3v&c(YZiwZ>ca7LVWVOwJ-Lo=B#*1 zy~#Pt)!O!57I3BbpDQmBK1?}o36j_{{xIie5;I*w(JR2i`kD0PX?&^5!mec%@zZ6) zHid75X6GJ~F{VGt;zi>rt$$}7|3Y9ba@J#9N)ZI95$Vs zkHh|k4-JbXp0EG>+^}caB&OWyRy{}1hfefF8lt;Cncx~cb1tL^T|84dVdP&Mql3Oj{h^l2B6cM`wP9q8L!)5uS%0mc zL9TrO4-{K`$7~m3PE5hU9@t;-vEf?zZL{0sO8HpY-yU_eTx2f2d5R|RJ_n* zIG~rO4ytDf&y$%I>SaRH{(T}iG%-s(-8G4@7c*_$)K9SZTE1k}e(}>5S8si8RiFc` zvxIrIQPLPkny1)jbYN6>G#<&#bG0arlD+Sr>}IgPrn#0HaJ7>h?h~<4&meIlbZyYZ zso>at2+H7@_)1}HOO)+>$Aj}@R4{G)O@9x|x4&Mitx6Pq^||A3P|thOdRTYEJ4(5; z?W4L#3bS;yrh2zK(1``r9jfvr-TMhQ9MglM3lgZ@O5`?nLPiAg@IU0SaJ2HO6A{Pk z^Wdw6J@d%86N`)=P5PV>k?YG#+RSI6q@X()^)UTW5BHXzb$J6vQ<@02xuA(MGVmwi z9_S#+LgkD`{9L@U&}j@3pqOBrhcJxK;JG)JIE7327jdeAglNP5%zY4>*zndK|Fme9 ziYLTQ90Lnob|g;w30z~|V$vMAQFH_%;d%U`Cf2y5;T#>wyG`qUIAKp2`X4i9vMnU5 zc1pz&`)U(W4*0;GDCo`p=3U;pJW9aCm|1M@vR{0R31u6t#B^Fh8kO3VBuwKzc~%qK zvm|;o!zWyvjNz1d)P2I}9Fa7QAS%Ak@oH)yc3Jqm1*8WTAB>U7NKqLwJgAs!SbPn< z!k7k0A%?AuAkV*4a;g#f!J8w}HwM)+C}mb#?yr#Th7?jht>?MsbIE&2`;2gXzkl+= z8U-`W!BSzP^T9}?D~oYhT&6;eT%)4%TofIxr3TJKVeuK~b*TWNdO&(pi0ha7aBod2Yky?DW#< zPhayXA>KroFe5~}fmpDCXzy6hIj#u$V713>hB6?t(PnNc5p(F~b@8H(yx7u|+IgTo zA{LyfRK$rM2w=Od)Kh1^;c7ezf>oodPSK2$UM736y}3U19@{yK@ngDLb`NeArS?a& zR4Opux~Q}H7i2T-*UMAM+jeLz=}$5iQkmE8m(}*3#~z;LvK_U99wAcsak(l-pPUK} zIDgHw>jjO)C%ysNTN(ouwP{9MUMbbKj%v?E#v%)~6~Q@(M!MkG7KtY+`~Fud*ejSZ zIO}g2gofK+c-}CF5~vo2#?-NOqLgLrKi&#wNj+c1e{*G5wP2sr;wg%qm6dh6Hev|V zq$*+JKbUmki@OVuna_5gaTUmECGf^g{2vwoYM|SydnoBI*cWP~Axv0T5@{J$^}+^w z7ky6w$>7aBaN#oYRtlb>KUV*l&T!^^=T+0L%&qgWg6xvVMR@16MK>=Ah7OrsG@wRD}AFQ9mmlqeN zxeU}Ue~AM<83-hS53uwtby)-4)Tk)(VKYGGqhwVcUm4JF4#7SD1-0AAi)TdNc}xpJ!o?blR`^O`_&u zk03(GI{uI{sM!e(*(!Wb$aLjt6x3eXjrn!-86@lK4m=$fs9nwpI#WBC?L$-+ZDLif zLft$8&&t-5(mqnO&S6%nk$#}PAkk|k-c%(+$7`{k>$$}+*KX+dM1|V4JTNk(PjW-^ z{mC^m*RHMCX4Qa19;`JnGhjnI6Qab- z=Wxv`=lsO#ES-k7+Djvh0&`0fJ6Dx=7=-wXcb@T3NTp7gI_9|=+wMJz1xepiG9-+B zV(Zjp;1B;2DwmJGim~Amv%5ju+^Vhob6#$oMN{pGt^P9l$J#18F%k1e?>;n0nLA!9 zy5EozGjKL6ihU8N7XnkZT(H}Mmc`ISywOOIgRY!) zIOz1K`HXea2aI1ei0&^)w&TCF}EEl#!)`4WOG`*$H33;JSLFAfK_KG^!Wl5SU zT?#jR)cd=0*@gCLBbE1Dvb~fXljm-|)T7X1eQW$QT8An<@q|TpNUJUeOTpt_$zSff zgA%jn&bmhwL83-KntAF z$oeb;t%n}V)DzMCf*m)q3@Ilh+AML`DAyL@!SqI}^w14m+Rx=k zFV^P03P~(_Ow`%GAU&q>=yyHzrsst?;cq^IxPS@>7b=6+^bCMII5b8D(f@uLT|8l| z#22jY@BJCwq2%Q>{}x9j9uwdk-f)lY75YF%NXSB*Kq5Mgz!PSr%AbLd7sRd+tfhcm zK}YQrN5iMr*8wdYpeIPWThlgZB7Xqx0EhnF(>rYi@RS3%0_I}8g>s2@hTnQpdEvY^ zEdW_>3S_E7SMas}^>x%NXsN~p9ky?P9v@cVnva7@w$8*v-QDph(yWG~IT_-V`Sb8A zI2|0GUy+i4!Uo3B@mNCW9N3ZfW0a5Q!FtE9f&F>^L-WZUh&+UMs;MeC2(um_KF8yo z{T=s|iT7evsB{{z38zQ>QrZ`qgOwlbzA$YGQZt5P9RoR#vI2x~?8C|r(%UL9KxVuT z_d#IG-djSnIhNp~2E$=P48&7(mOHk)r8KlD{_xL1=2$O)(pB$rdoug|13WoGpKo}& zh1#u~HN@sn_jw{Rm(K~T4<%rnW$!}~e?2`id#>ZRz@*N>h)_P>hml+`J`DWCJ59uI z_~#`XkYBfHhIcra3r!v$xLDwcQ^(7(>D*Ss{S`-kay%e*^K!YT2-INKyBcJ>hBOEd~*D zQDRv+MMzqKmA5>Ymylxz*!M;D7{gxRb-)^=77ehY8Bnawjki;;*i|6IPX+Mm z17ILIpi8VTP{7)=ngr;hGqfvFx2y|>c1RqazO85xXa=YgmWhsgccjw`(eki85&xbb zSoVcmW%Jdwv_f$xP2d~K->*mfx_JUiO&L7=SHmZ2;2eeI#EN6Qc?e2N)uDm8S!&1; zq5FCA3FF1uShR^ zfkr=p0n^?S$T|8I;_;f~YS8J=1+=ifXty{#IaNN&LyiM|E;H%m%^w`#Pd^3)WBIdk zV~NvST=HwB~{Fp}=F zJ7fTi1Oll=s9$uZqVC8d_(9J9fVk)?Jl#2SDMOew#(cjHM9%OB`2}3C9!B37*z9pCf0pHVHT;)ork}|jyE5~0ElAnLI?2;>K<+ynPjnEV*mH<-{P}}^p*V5 zZ#+RyECp+Q%Dj=nu7Duz)8v(WLSf!rY=cR?MhIV+8I@b*NejnndWymuy%7>RK@~?B zuyONsXQq0>1}kyiZ`HI_0hkzBpq2LdA5iH_NnP=b$mMa+f@d0cTAw|f?(u?79#Eg< znG|*}M`Nvgm}^+Ij|8-AM?e{JF8Dy1_MiwbrLIS|DFX&qsM2lXuF3};Y(kiVFBH*B znIqQA?4T_1`bAJB=PekaJU9%_pc+UgGqF7lZdcF_1``wzZ?iRCyqG(%-)>U>%-kQV z_PH0Dl~f&c5AuZv{Vy8bJ&Z6zr0An%re9odt2@wMWK#;tHZNF|3^JC2H^lgiMFFx75(O5u7(pQOiW>T$C{=kFR`qY$81fj`v~ilH1UoKQ)*ZN zEr8gmlkcaO8kzos9c!gW+u+oZxKmq@g~s{*+^9Y>eC?txwXo-+$weSQGI<<2GD0Io z%bpQsPf2_LGSK-1NQkVZ#6P3+*M*IX@XX>zbbZJ6J;;ylAp-h5P^cF@ie-87Jtr#Stz8CZ*ReYVjvgv*I|Crg+oe{VrvYXOs0Q z@9Y2AoE`3|CQ1_ZRORS-D90tpD6d>iSRdgyD#k}}a0PCkR<1pmqC#R4Q}!+FrVyj; zqqO`BQH&jUKUil}JJSW#Z|u795>=m#OuwoM3^pNMD=&0?=HTKTf&JPpYhxIYmP=vsH7yDoyS)5ZB&Xw{-TWhCjJbrKKDjG<*SOXa~ zp0aIn%&q`{YIv)sw{0`fVB$PH>LQx(u5i6#dM(wQqDExV^yhaIi%n0}1M9eJONS1r7NxywWf%Hn~Wki3m6N8>Bf^GHvQ^=>jwuT}<~ zMxNgrHSD-iDjC7RXsg8;?<59!t;O^};GKM{rUx>`Sn~)uzAuqgzPrSgp(Jg=t=)4< z<#3PU89x~wWsyij*1e|<5}FH30^5shw|d@{c65zS#Hs&&y4SD&)2QPLEl;U9C;4nO zQL0Rr+B9BI;hy|wxZe>v>sS}npzaxs8^#hW@h853#gA;dy;rtD5tn z-Ir{u4|Vt}Jcyqoq;k!qV$YE7vW*y-7XRqK!dNk!k~n$$dGs~%&DB=gV6vQ3ZzCzLT^!NEl@3y-y>lV>SfY+iB;7)6V`pB?6ubLq{PXpV!2U`Oi}9Xas>t#ra~hhX#W;Ln5{BYE4Y{Wa)7J=1@Tv>es2rG#Q^)eEZ&_e&v&*+X z#Y2ue)lwx%?GPqf45xuwGv>#r$Xsb^5wLDkw0I~2lgMCV?B)LCc1$V{7vcQH!Qi-D zfv(A%c^*f3?#ay@Va{SAr8(6l)7)rZ@4w~JXC_yBpZIzpZ;D`$=>Tsy@8%;FIJM`V zf$Jg_f9K{%z$KK`+2Crt(d_qFl}G$NB-GL8&Kf�%N%v=`6i<*)M14eE9I{fn!o( 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%0DTv$1=^01nC$s$oLc^w*Kb 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 Ac>n+a literal 0 HcmV?d00001 diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/screenshot-tab-a-before.png b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/screenshot-tab-a-before.png new file mode 100644 index 0000000000000000000000000000000000000000..082e16eb0becfae7a07011f3a2a2671c6d13991c GIT binary patch literal 88123 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

Jx#T$tyEhz)g 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 Date: Fri, 4 Sep 2026 11:40:25 +0200 Subject: [PATCH 13/31] M7+ resteering planning --- ...nce-and-tooling-decision-log-2026-09-04.md | 93 +++++ ...y-lineage-independent-review-2026-09-04.md | 392 ++++++++++++++++++ ...venance-by-lineage-mini-spec-2026-09-04.md | 135 ++++++ 3 files changed, 620 insertions(+) create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-independent-review-2026-09-04.md create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md diff --git a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md new file mode 100644 index 00000000000..7638119b3cb --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md @@ -0,0 +1,93 @@ +# Provenance, workpiece, and tooling decision log — 2026-09-04 + +> Design evidence, not execution authority. Compiled on 2026-09-04 from the owner conversation that reviewed the Mission 6 tie-off and the Mission 7 departure point. Every terrain claim below was checked against the checked-out code or the installed Flue 2.0.3 types during that conversation; each entry names what was inspected. Owner-settled items are policy accepted in conversation and must still be promoted into mission authority at the named cut before implementation. Recommendations are the agent's and remain open until the owner accepts them. The projection of this log into a reviewable design is [`provenance-by-lineage-mini-spec-2026-09-04.md`](provenance-by-lineage-mini-spec-2026-09-04.md). + +Legend: **Settled** = owner accepted in conversation. **Recommended** = agent recommendation, not yet accepted. **Open** = fog; a probe is named. + +## A. Mission 6 tie-off + +**A1. Mission 6 deterministic layers are closed; the outer witness was blocked by an environment fault, not a product defect.** Settled as observation. Inspected: `docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md`; the shell's `ANTHROPIC_API_KEY` was the five-character placeholder `dummy`, which explains the recorded HTTP 401. Consequence: the outer two-tab witness, the cold-reader adjudication, and the product-manager demo remain open; the two human gates depend on the outer rerun because the model-produced revision does not yet exist. The Mission 6 builder is performing the rerun in a parallel session (untracked `fe-1575-outer-browser-witness-2026-09-04-r2/` observed in the worktree). + +**A2. Mission 6 stacks on unmerged Mission 5.** Observation. `gt log short` shows `ln/fe-1574-direct-voice-flue` beneath this branch; GitHub PR 9528 is open awaiting review; Mission 5's human Voice witness is unrun per its evidence README. No PR exists yet for FE-1575. Consequence: Mission 6 cannot merge before Mission 5, and its close report needs a PR. + +**A3. The prepared fixture's "Current Petrinaut correspondence" section is fixture-rigging.** Settled. Inspected: `prepared-crew-reservation-fixture.ts` versus `plugin-sdcpn/src/skills/sdcpn-modelling/templates/workpiece.md`; no template heading or skill directive produces such a section. Consequence: the Mission 6 fixture is a viability proof of transport, mutation, and resume, and must not be promoted into the provenance pair. The close report must say so. + +**A4. The fenced-block workpiece source is a Mission 6 contract that Mission 7 will change.** Settled. The Mission 6 close report names the move from fenced `runbook-ir` blocks to an `update_workpiece` tool as a carried change so nobody treats latest-block selection as settled. Mission 6's implementation is not retrofitted mid-tie-off. + +## B. Terrain: what exists between conversation, workpiece, and net + +**B1. Flue history to workpiece revision: exists and is tested.** Inspected: `packages/core/src/workpiece.ts`. The resolver selects the tagged prepared signal or the latest assistant `runbook-ir` block, identified by source message id plus SHA-256. + +**B2. Flue history to capture store: exists as a stub that re-indexes user utterances.** Inspected: `apps/brunch-agent/src/capture/apply-sweep.ts`, `packages/core/src/evidence/capture-store.ts`, `session-log.ts`. One envelope per user entry, excerpt equals the whole utterance, payload `{}`; excerpts resolve to a pointer of session id plus entry ordinal by substring search over an archived copy of history; the store adds an owner key, dedup, and idempotent retry. Everything but the owner key duplicates what Flue history already carries, under a second identity scheme. The store is a JSON file beside the sqlite database (`db-path.ts`). + +**B3. Capture store to workpiece: does not exist.** Inspected: the workpiece template asks for "exact expert wording" as prose beside each claim and never names capture ids, message ids, or ordinals; Markdown has no passage identity. Settled: this is the central unresolved design tension, and it has been deferred as "later" without being stated in the spine. + +**B4. Workpiece to net: one prose sentence in the fixture; no derivation record anywhere.** Inspected: fixture and template as in A3. Settled: a hand-authored derivation fixture, as the Mission 7 draft proposes, is useless and rejected. + +**B5. Workpiece visibility: the workpiece is a black box during a conversation.** Inspected: the `runbook-ir` block streams as a fenced code block inside the assistant message; the only current view is the Mission 6 fixture banner's collapsed `

` element (`prepared-fixture-banner.tsx`). No pane, revision list, or diff exists. + +**B6. Retained persona runs contain no revision series.** Inspected: every run under `docs/evidence/evaluations/` has at most one `runbook-ir` block; `vestera-runbook-headless` emits once at the end; Mission 4 v2 runs stopped before substance. Consequence: the model's revision cadence is unmeasured. + +**B7. Petrinaut elements have no metadata slot; the file wrapper has only `title` and `meta.generator`.** Inspected: `petrinaut-core/src/schemas/entity-schemas.ts` (strict objects), `file-format/types.ts`. + +**B8. Flue offers four typed ways to put something in the canonical log.** Inspected: `@flue/runtime` and `@flue/sdk` 2.0.3 `.d.mts`. Tool call records (input, output, call id; surfaced as tool parts on the assistant message with `turnId` and `submissionId`); `useDataWriter` data parts on the current response; `usePersistentState` `state_write` records, atomic with the tool batch, server-side only, not in `history()`; and signals via external `dispatch()` or `ctx.append` in finish hooks, surfaced as system-role messages with `tagName` and string attributes. There is no arbitrary custom entry and no tool-context `append`. + +**B9. The construction tool schema carrier is still the one Mission 3 falsified.** Inspected: `plugin-sdcpn/src/tools/petrinaut-construction.ts` declares input as `v.looseObject({})` with a `rawTransform` that re-parses against Petrinaut's Zod schema, and pastes the canonical JSON Schema into the description text. Flue accepts Valibot only (`ToolInputSchema = v.GenericSchema`), converts via `@valibot/to-json-schema`, and rejects other Standard Schema vendors by checking `~standard.vendor === "valibot"`. The provider therefore sees an object with no fields. Flat `addArc` can survive on the description; nested `addType.elements` failed nine of nine in Mission 3. The spine already recorded "Flue Standard Schema support or a mechanical shape-preserving conversion" as the accepted next move; neither has been done. + +**B10. Mounted tools today.** Inspected: `chat-agent/agent.ts`, `plugin-sdcpn/src/flue.ts`, `core/src/flue.ts`, `core/src/client-tools.ts`, website `local-storage-demo/`, persona `client-tool-hosts.ts`. Server: `ping`, Flue's `activate_skill`, `readPetrinautDoc` (browser-deferred, all SDCPN conversations), six construction tools (headless mode only), two fixture tools (Mission 6 mode only). Core owns no model-facing tool by stated rule. Client: the Petrinaut panel client-tool host; an `ask` interactive tool and `sweep` result handling that no mounted server tool ever produces; the Voice bridge, which is a transport rather than a tool; persona hosts `none`, `mock`, `real-headless`. The stock Petrinaut assistant exposes about fifty canonical tools. + +## C. Design decisions + +**C1. Provenance is recovered from lineage in the canonical log, not stored in a typed IR, a capture store, or a hand-authored derivation.** Settled in principle. Rationale: the typed comprehensive IR chased a receding horizon and degraded model performance; the structural swing left no seam; both treated provenance as a property of the domain model when it is a property of who changed what, in response to what, when. Every such moment is already recorded in Flue history once workpiece revisions and net mutations are tool calls. + +**C2. The honest shape of a why answer is one creating call, one workpiece passage, one introducing revision, then either a quoted line or a short turn range.** Settled. The owner's correction: tool calls do not occur every turn and workpiece revisions do not occur every turn, so ranges enter at exactly one hop, the last. The verbatim quote check narrows a range to a line where the model quoted the expert. Elements changed several times show introducing and last-changing calls separately. + +**C3. The why tool returns structured ranges; the assistant interprets.** Settled. The user asking "why" implies an assistant interpretation anyway, so the tool never authors prose and never invents a link. It must accept multiple element ids and return potentially several ranges per element. + +**C4. Workpiece updates are tool calls, not fenced blocks in assistant text.** Settled. Tool: `update_workpiece`, input one Markdown string, `durable: true`, validates and hashes, writes the current-revision pointer with `usePersistentState` inside the same tool batch, returns revision and hash. Core owns the tool; plugins own the template. Rationale: structural revision identity (call id), write-time validation, agent access to its own current revision without model echo, lineage shared with mutation calls through `turnId`, and a clean UI split. Caveats recorded: token cost is unchanged and a structured-patch input is the later absorber; a model may call a tool less readily than it emits text, so cadence must be measured either way. + +**C5. The generic lookup is a core `query_workpiece` tool; the element lookup is plugin-owned.** Settled for the split, name provisional. Core knows revisions and history, not Petri nets; it takes a revision pointer or passage locator and returns turn ranges with user text. Plugin-sdcpn owns a `locate_elements`-style lookup because only it knows which calls are mutations and where ids sit in inputs. + +**C6. Net revisions join to workpiece revisions through the client-tool result, not through Petrinaut metadata.** Recommended. The browser returns the post-mutation document hash inside the client-tool result (Mission 6 already computes it for the settled manifest). A document hash no tool result explains is honestly "changed outside the conversation." A file-level pointer in Petrinaut `meta` is deferred until Mission 11 has a real consumer for a self-describing export. + +**C7. The workpiece becomes a visible, revisioned document in its own pane.** Settled. Chat projects `update_workpiece` parts out of assistant messages, leaving a one-line marker; the pane shows current revision, revision list, and diff, driven from Flue history through the Mission 5 transport. Rationale: the chat pane is too small for artifacts; a why answer resolves to a passage the reviewer must be able to see; per-turn emission for the pane is the same behaviour that gives blame its grain. Projection lives in the app or transport layer, not the Petrinaut library. + +**C8. The capture store and sweep earn no place in Mission 7.** Recommended. Flue history already carries message ids and exact text. Owner-key enforcement on evidence reads can be a check at answer time. The store re-enters only if verification strains under compaction or ownership. + +**C9. The `ask` and `sweep` client handling is retired from code.** Settled. Surfaces: the two names in core `client-tools.ts` and the suspended ask contract behind them; the website's ask interactive tool and its test; the sweep filter in the panel transport and the sweep output module; the Voice references in `canonical-speech.ts` and `interview-coverage.ts`. Archived mission records remain the design reference. Vehicle: a subtraction commit under Mission 7 authority. + +**C10. Petrinaut mutation tools are wired into ordinary conversation now, and admission is by evidence rather than by an inherited six-tool subset.** Settled as policy. The owner's judgement: continuing to defer tool wiring is a strategic mistake; the six were an unexamined side-quest set; the skill teaches concepts but not tool use. Terrain supports it: the subset lacks every `update*` and `remove*`, `getNetCompilationErrors`, `addScenario`, `applyAutoLayout`, metrics, subnets, and differential equations. Parity with the stock modeller is still not the goal. Mission 6's live constraint that construction tools stay out of ordinary conversations must be amended at the Mission 7 cut, not in the Mission 6 tie-off. + +**C11. The schema carrier must be fixed before tools are admitted.** Recommended as the first act of the next cut. Options: a mechanical JSON Schema to Valibot interpreter for the subset Petrinaut uses (local, reversible, satisfies "mechanically derived"), or upstream Flue Standard Schema support. Petrinaut's canonical tool descriptions were written for the stock assistant and become useful field-level guidance once the carrier carries fields. + +**C12. The skill must add construction posture, not just concepts.** Settled in principle. Read the definition first, mutate in small steps, check compilation errors, record each decision in Construction notes, call `update_workpiece` before and after construction. + +**C13. Mission 7's release note narrows to the honest framing.** Settled. "Ask why about any element and see the workpiece passage, who prepared it, and the exact conversation line it rests on, or an explicit refusal." Rejected: inventing a longer conversation to make "what the expert actually said" true for prepared elements. + +**C14. Mission 7 names local deployment posture; remote durability returns to Mission 8.** Settled. The owner reports the Postgres persistence move is slow and unresolved for local versus remote; it will not exist for Mission 7, so the sequence lines up with the original numbering. + +**C15. The workpiece passage-identity question is decided by probe, not in a draft.** Recommended. Candidates: heading path (readable, breaks on rename), Markdown anchors (stable, changes the surface), companion manifest (clean Markdown, second-artifact drift). Probe: prepare references for the elements of one real pair, revise one non-semantic line, observe which scheme survives. + +## D. Real honest fixtures through persona interviews + +**D1. Real conversations and real workpieces replace prepared fixtures as the provenance pair.** Settled. The Mission 6 fixture stays a viability proof. Multiple persona runs can proceed in parallel; six cases already exist under `evaluations/cases/`. + +**D2. Persistence during a run is the Flue store; retention is the harness's per-run evidence directory.** Observation. The harness's `--brunch-evidence-dir` already refreshes a canonical `snapshot.json` plus deterministic projections on every settled read. With `update_workpiece`, revisions become tool parts in that snapshot and the harness's workpiece recovery must read tool parts instead of fenced blocks. + +**D3. How a retained real conversation becomes a live fixture is the first fog item of the persona programme.** Open. Options: keep the genuine conversation live in a durable store shipped with the demo; restore retained genuine records into a fresh store through Flue's storage adapter (records are genuine, only relocated, but the adapter's record types are private and the routing doc warns against consuming them); or replay the materialized snapshot as prepared signals, which turns genuine history into a prepared projection and would make the why route fixture-only. Probe: whether Flue 2.0.3 exposes or tolerates a conversation export and restore at the storage boundary. + +**D4. Stop rule: a turn cap as budget plus a Brunch-side completion signal; ledger coverage grades afterwards.** Recommended. Today the turn budget lives only in the launch prompt and the persona is told never to end the interview. Proposed: cap per run (larger than the 6–10 used so far, cost accepted), stop early when Brunch itself declares construction handoff or delivery in its status section, and grade coverage against the hidden oracle ledger after the run rather than using it to stop. + +**D5. Runs go to construction, because the fixture must contain lineage.** Recommended. Sequencing follows: carrier fix and tool admission and `update_workpiece` land before construction runs. An elicitation-only campaign can run earlier to measure revision cadence. + +## E. Consequences for the planning record + +**E1.** State the provenance tension in the spine as an open design decision with C1 as the current hypothesis, the typed IR and hand-authored derivation as rejected with reasons, revision cadence as the named strain, and the visible workpiece as the precondition. + +**E2.** Re-cut the Mission 7 draft: drop the capture-store chain and Mission 2 inherited closure; make the carrier fix, orphan retirement, `update_workpiece`, the workpiece pane, tool admission and teaching, and the persona programme the mission's body; make the why route the last step over real lineage; name local posture. + +**E3.** Adjust the Mission 9 and 10 drafts: they inherit the seam from lineage (revision id equals call id, passage identity per C15, element id, document hash per C6) and no longer assume a derivation fixture or prebuilt pair. + +**E4.** Mission 6 close report: record A3 and A4 plainly, plus the credential cause in A1. + +**E5.** Decision-integrity: every Settled item here is an owner decision expressed in conversation. It becomes authority only when written into the cut `MISSION.md` for Mission 7; this log and the mini spec are neither authority nor a substitute for it. diff --git a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-independent-review-2026-09-04.md b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-independent-review-2026-09-04.md new file mode 100644 index 00000000000..c96ae7fc06e --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-independent-review-2026-09-04.md @@ -0,0 +1,392 @@ +# Independent review of provenance-by-lineage replanning — 2026-09-04 + +> Review evidence, not execution authority. This document evaluates [`provenance-and-tooling-decision-log-2026-09-04.md`](provenance-and-tooling-decision-log-2026-09-04.md) and [`provenance-by-lineage-mini-spec-2026-09-04.md`](provenance-by-lineage-mini-spec-2026-09-04.md) against the checked-out Brunch and Petrinaut code, the installed Flue 2.0.3 documentation and types, the current future mission record, and three independent adversarial reviews. It identifies factual corrections, semantic gaps, and strategic blind spots. It changes no owner-settled policy and authorizes no implementation. + +## Executive verdict + +The replanning is directionally strong. Making the workpiece visible, making revisions first-class tool calls, refusing to turn the capture store into semantic IR, repairing the provider schema carrier before trusting construction, and deriving audit information from the canonical conversation record are all sound moves. + +The central claim is nevertheless overstated. The proposed mechanism establishes **temporal audit lineage**, not yet **motivational or causal provenance**. It can show which workpiece revision was current when an assistant requested a mutation and which conversation context preceded that revision. It cannot deterministically establish that a particular workpiece passage motivated a particular element. Passage selection, element-effect attribution, actor identity, and durable exact evidence each require information or contracts that the described lineage does not contain. + +The defensible near-term claim is: + +> Show the logged assistant mutation request, its later browser outcome, the workpiece revision temporally current for that request, and the intervening authorized conversation context, with explicit warnings where motivation, causal derivation, actor attribution, or exact historical evidence is not established. + +Anything stronger requires reopening C1–C3, C5, C6, C8, C10, C13, and C15 before Mission 7 authority is cut. The proposed Mission 7 also absorbs the central automatic-construction advance currently assigned to Mission 9 and is too large to remain a bounded explainability mission without an explicit recut. + +## Critical semantic gaps + +### 1. “Latest workpiece before mutation” is correlation, not causation + +The decisive unsupported traversal is: + +```text +element id + → mutation call + → latest update_workpiece at or before that call + → the passage in that revision +``` + +The conversation log contains no deterministic relation from a mutation to the passage that motivated it. A workpiece can contain many claims; one call can realize several claims; several mutations can be made while the same multi-topic workpiece is current; and a mutation can arise from formalism constraints, model inference, an external source, or a mistake. A post-construction workpiece update may contain the actual rationale but is excluded by the backward-selection rule. + +The proposed `locate_elements` returns mutation calls and the workpiece revision current at each. The proposed `query_workpiece` begins from a passage locator. No mechanism produces that locator from the mutation. Therefore the mini spec's statement that “every hop is a lookup in the canonical log; nothing is stored elsewhere and nothing is inferred” is false as written: selecting the relevant passage necessarily requires semantic inference or an explicit relation. + +This is not repaired merely by sharing a `turnId`. Shared temporal correlation still does not establish motivation, and the current client-tool result does not in fact share the mutation request's turn, as described below. + +**Required decision:** choose explicitly between: + +1. **Temporal-lineage claim:** report the workpiece revision current for the mutation and a broader conversation range, without saying that one passage motivated the element; or +2. **Small creation-time association:** carry a revision identifier and one or more passage locators with the mutation request or with a thin construction-operation envelope. + +A small creation-time relation is not the comprehensive typed IR previously rejected, and it differs materially from a retrospective hand-authored derivation fixture. If neither is acceptable, the system must return a broader range or refuse rather than invent a point passage. + +### 2. Passage identity and blame are prerequisites, not downstream fog + +The intent promises one workpiece passage, the revision that introduced it, and blame across revisions while passage identity remains undecided. Heading paths fail under rename or movement; exact text fails under edits; ordinary line blame fails under reformatting; anchors remain stable only if their lifecycle is defined; and a companion manifest can drift from the Markdown. + +The proposed C15 probe changes one non-semantic line. That is too weak to establish the promised semantics. It does not test: + +- heading rename or movement; +- passage split or merge; +- paraphrase that preserves meaning; +- deletion and reintroduction; +- a passage accumulating evidence from several non-adjacent periods; +- duplicate quotations or repeated headings; or +- correction, qualification, contextual coexistence, and conflict. + +For split, merge, paraphrase, and reintroduction there may be no unique mechanically discoverable “introducing revision” without explicit successor/predecessor semantics. + +**Required decision:** either define durable passage identifiers and their edit lifecycle before promising blame, or narrow the first claim to revision-local text and refuse cross-revision “introduced by” answers. The passage-identity probe should cover rename, move, paraphrase, split, merge, deletion, and reintroduction, not only a non-semantic line edit. + +### 3. User-turn ranges are not attribution and do not establish “who prepared it” + +The range between two workpiece revisions can contain unrelated statements and can omit older evidence reused in the new revision. A verbatim match proves string occurrence, not endorsement, origin, authority, or causation. A user may quote another person, reject the quoted proposition, or repeat wording supplied by the assistant. Non-verbatim synthesis, declared defaults, formalism constraints, assumptions, external sources, and construction-opened losses require distinct treatment. + +The proposed answer also collapses several different actors: + +- the assistant that authored the workpiece revision; +- the expert whose evidence supports a claim; +- the person who requested construction; +- the browser principal that applied the mutation; +- a later reviewer; and +- the owner or authority that permits canonical change. + +A Flue `role: "user"` is not sufficient actor identity. The release note's promise to show “who prepared it” is therefore unsupported by the described records. + +**Required contract:** represent and report workpiece author, source/evidence actor, mutation actor, requesting principal, and authorization context separately. Conversation ranges may be supporting context; they are not, by themselves, authorship or authority. + +### 4. Element IDs in tool inputs do not establish actual mutation effects + +Seeing an element ID in a mutation input does not prove that the call created or changed that element. Calls can fail, no-op, apply against stale state, affect several entities, create derived entities, delete an entity, replace or recreate an ID, or be successfully applied while their result delivery is lost. Commands such as layout can affect many elements without identifying them individually in the input. + +The current `clientToolHistoryFrom` projection treats results as opaque correlated outputs. It does not establish canonical effect semantics or reconcile conflicting and repeated results. + +**Minimum settled mutation evidence:** + +- mutation call or operation identity; +- target document identity or incarnation; +- expected base document hash; +- applied, no-op, failed, stale, or unknown outcome; +- confirmed post-document hash; +- exact created, updated, deleted, and derived element IDs, or retained canonical pre/post definitions from which those effects are mechanically derived; and +- one authoritative result per call with duplicate-result rules. + +Without this, the honest statement is “the assistant attempted this mutation,” not “this call created this element.” Deleted and recreated elements also need explicit lifecycle semantics; “creating call and last-changing call” is not sufficient when identity can be retired and reused. + +### 5. The browser mutation and workpiece update do not share one atomic boundary + +`update_workpiece` would be a server-side Flue tool. Its `usePersistentState` setter can commit atomically with that server tool's unit of work. Petrinaut mutation executes later in the browser and its result returns as a separate `client-tool-result` system dispatch. The workpiece update and the browser mutation therefore do not share durability or a transaction. + +A workpiece update can settle while a browser mutation fails, times out, applies against stale state, or is manually superseded. A browser mutation can apply while its result is lost. Two tabs or two conversations can target the same document. A later result can arrive after another mutation or hand edit. + +Atomicity across these boundaries is not necessarily required, but observable incomplete states and deterministic reconciliation are. The design should model an operation protocol rather than imply a shared batch: + +```text +mutation requested(callId, documentId, baseDocumentHash, workpieceRevision, intended scope) + → browser outcome(applied | no-op | failed | stale, postDocumentHash, effects) + → reconciled | incomplete | unknown +``` + +This protocol must define retry identity, duplicate delivery, stale-base refusal, lost-result behavior, and what provenance is safe to report for an incomplete or unknown operation. + +### 6. A post-document hash is not an adequate join + +A whole-document SHA-256 is a content fingerprint, not a mutation lineage record. It does not identify the pre-state, the transition, the actor, or the affected elements. Identical hashes can recur after revert and reapply. A hand edit followed by a logged mutation can yield a post-hash that appears “explained” by the tool result even though the resulting document includes an outside-conversation change. Serialization changes or a missing client-tool result can produce the opposite false classification. + +Consequently, “a document hash that no tool result explains is changed outside the conversation” is too strong. The safe classification is “not attributable from the recorded transitions.” Reliable attribution needs at least document identity, expected base hash, serialized operation order, result hash, operation ID, and confirmed effects. + +After an unexplained transition, the system should refuse provenance for the affected state—or for the entire document when no trustworthy diff can isolate the effects—and begin a new explicitly imported external revision if lineage is to continue. + +## Critical durability and access gaps + +### 7. Flue's supported history projection does not preserve exact lineage across compaction + +The design conflates Flue's append-only canonical storage with the public `history()` projection. Flue's underlying `ConversationStreamStore` is an ordered append-only canonical record, but its record types are not the supported application read surface. Brunch reads `createFlueClient(...).history()`, which returns a materialized conversation snapshot. + +Flue 2.0.3 explicitly compacts older messages into a summary while retaining only recent history verbatim. After compaction, the supported materialized history may no longer contain: + +- exact old user lines; +- old `update_workpiece` inputs; +- old mutation tool parts and results; +- the full workpiece revision series; or +- the exact text needed for quote verification. + +Brunch's current Flue history reader consumes only `snapshot.messages`; it has no supported access to the private pre-compaction records. This breaks the exact-line answer, workpiece revision pane, passage blame, and mutation lookup at once. + +C8 therefore understates the re-entry condition for independent retention. Compaction is already a known behavior, not merely hypothetical future strain. + +**Required decision:** either scope Mission 7 explicitly to uncompacted local conversations and visibly refuse once required evidence has compacted, or retain an immutable, authorized, compaction-independent lineage projection before compaction. That projection need not resurrect the current one-envelope-per-user-utterance capture design, but some stable retained evidence is required for the longer Mission 9 and Mission 10 story. + +Retention, export, audit, revocation, and migration are additional reasons a canonical operational conversation store may not be sufficient as the product's evidentiary archive. + +### 8. `query_workpiece` and `locate_elements` have no specified executable history-access boundary + +The ownership split is conceptually plausible but omits the runtime boundary. Inside a Flue agent there is no history hook. The supported read path is `createFlueClient(...).history()`, which requires a host-resolved conversation URL and transport. The current Brunch architecture deliberately places this absorption in the binding and app layer. + +Therefore “core knows revisions and history” is not currently true as an executable capability. A core server tool cannot silently self-HTTP without host composition, and a plugin-owned server tool cannot inspect Flue history without acquiring a substrate dependency or an injected history service. + +**Recommended boundary:** + +- core owns pure formalism-independent workpiece revision and query semantics; +- plugin-sdcpn owns interpretation of Petrinaut mutation names, inputs, outputs, and element effects; +- the binding/app owns authorized acquisition of the Flue materialized history or retained lineage projection; and +- the app composes the model-facing query tool from those capabilities. + +Whether there is one composed why tool or two model-facing tools should follow the minimum useful product interaction; package ownership does not require exposing package seams to the model. + +### 9. The proposed persistent-state pointer does not give the model the current workpiece + +The proposed state contains only `{ callId, sha256, revision }`. It contains no Markdown, and `usePersistentState` values are server-side; they are not automatically shown to the model. The statement that “the next render reads the current pointer without the model echoing it” does not explain how the model obtains the current workpiece content. + +Reading the content back from `history()` reintroduces the unavailable-history and compaction problems. A pointer alone also cannot validate or recover the current document after old tool parts disappear from the materialized projection. + +**Required mechanism:** persist the current Markdown with the pointer, or provide a retrieval capability backed by a compaction-independent store. The design must also distinguish generic core validation from plugin-specific validation. Core can check non-empty Markdown and generic size/integrity constraints, but it cannot validate conformance to the SDCPN workpiece template without plugin participation. + +### 10. Authorization, disclosure, retention, and untrusted-history handling are absent + +Returning coarse ranges “with the user text” can expose unrelated material and supplies old conversation content to the model as untrusted input. Answer-time equality with one owner key is insufficient for: + +- a second authorized reviewer; +- partial disclosure; +- revocation; +- restored fixtures; +- cross-conversation document access; +- a document whose owner changes; +- sensitive or deleted evidence; and +- later Mission 10 authority distinctions. + +The lineage must bind principal or actor identity, conversation identity or incarnation, document identity, and authorization context. Restoring or relocating a fixture must preserve those identities or explicitly establish replacements. Reads must fail without leaking the existence or content of unauthorized evidence. + +Retrieved conversation text should be treated as untrusted evidence rather than fresh instructions. The why operation should return only the smallest authorized range necessary for the answer and preserve a clear boundary between quoted evidence and model-authored interpretation. + +## Factual corrections to the mini spec and decision log + +### 11. The depicted client-tool turn topology is incorrect + +The mini spec depicts a user message, assistant response, mutation request, and mutation result as sharing one `turnId`. In current Flue history: + +- user messages commonly carry a `submissionId` but no `turnId`; +- the assistant mutation request carries the model turn's `turnId`; +- the construction tool's immediate Flue output is only `{ awaiting: "client" }` and terminates that response; +- the browser's actual output arrives later in a separate `client-tool-result` system dispatch under another submission; and +- the assistant continuation has a new model turn. + +Correlation is by `toolCallId`, plus submission and record order where needed—not by assigning the same `turnId` to the original user message and later browser result. Conversation-range resolution must join user deliveries, assistant turns, client-result signals, and continuations through their actual submission/order semantics. + +The retained Mission 6 witness also shows cumulative client-tool-result signals that repeat earlier call IDs. The lineage reader must deduplicate and reconcile by call ID rather than treating every signal occurrence as a new result. + +### 12. Current browser mutation results do not contain `documentSha256` + +The current construction tool settles server-side with `{ awaiting: "client" }`. The retained Mission 6 `addArc` browser result contains title, detail, target, and `applied`, but no document hash. Mission 6 computes the document hash separately in its settled manifest. + +Accordingly, the sentence “the browser returns the post-mutation document SHA-256 inside each client-tool result” describes proposed work, not observed current behavior. The browser result contract, its caller, and the production routing must be changed and tested before C6 exists. + +### 13. `usePersistentState` cannot be called inside the tool's `run` + +Flue hooks must be called while the agent function renders. The implementable pattern is: + +1. call `usePersistentState` during agent render; +2. capture the returned setter in the tool closure; and +3. invoke that setter from the tool callback, where `toolCallId` is available in the tool context. + +The mechanism table's pseudocode is therefore technically wrong or materially ambiguous. It should describe a render-time hook and tool closure, including how the revision number is computed with updater semantics and how the returned revision is kept consistent with the buffered state write. + +### 14. The Petrinaut file-wrapper description is imprecise + +The versioned Petrinaut file wrapper carries more than `title` and `meta.generator`: it also includes `version`, the SDCPN document arrays, and optional generator-version metadata. Runtime entity schemas use strict objects in important places, but the file import schemas are not uniformly strict. + +The narrower conclusion remains sound: there is no currently supported provenance metadata slot on individual elements, and no established file-level provenance field. The documents should state that directly rather than claiming that the wrapper has only two fields or that every relevant file-level object is strict. + +### 15. “Durable tool” does not make the browser side effect exactly once + +`durable: true` can protect the server-side tool attempt and its recorded Flue state effects. It does not make an external browser mutation exactly once. The browser can apply a mutation and lose its result; a retry can encounter changed state; signal admission can be deduplicated while the external side effect has already happened more than once. + +The durability statement must be scoped to the server workpiece tool. Browser mutation idempotency, base-state checking, and unknown outcomes require their own contract. + +## Strategic gaps in the mission sequence + +### 16. The proposed Mission 7 absorbs Mission 9's central product advance + +The recut Mission 7 now includes: + +- provider schema-carrier repair; +- broad ordinary-conversation mutation-tool admission; +- construction teaching; +- `update_workpiece` and persistent revision mechanics; +- a workpiece revision/diff pane; +- retirement of old client-tool surfaces; +- several real persona interviews through construction; +- production of a real constructed net; and +- the final why route over that lineage. + +Mission 9's current release note is that Brunch constructs a recognizable net region itself. If Mission 7's real persona run constructs the provenance pair, that advance has already been crossed. M7 becomes a large multi-front construction, UI, evaluation, persistence, and explainability mission whose user value arrives last, while M9 later repeats the same terrain under a different completion bar. + +**Required recut:** choose explicitly between: + +1. consolidate the real construction and explanation advance, then give the following mission projection breadth, repeat/change behavior, and readiness closure; or +2. make the visible revisioned workpiece a smaller precursor mission, followed by one mission that constructs and explains a real bounded region. + +At minimum, carrier repair plus one canonical production-path mutation should be an early go/no-go tracer before committing to the pane, persona campaign, and whole-net coverage. + +### 17. M7 is not bounded around one coherent visible advance + +Even if one branch may contain several tracer bullets, the proposed M7 has too many independent failure fronts: schema conversion, model tool selection, workpiece cadence, history access, passage identity, browser mutation effects, new UI, fixture restoration, persona quality, and reviewer usefulness. Several can invalidate the architecture after substantial unrelated implementation has landed. + +The first working line should answer the disputed semantic question with the least mechanism: one genuine conversation, at least two distinguishable workpiece passages, at least two mutations, one failed or no-op mutation, one correction, and one hand edit. If the why resolver cannot distinguish those cases without guessing, the architecture should stop before whole-net breadth. + +### 18. Fixture restoration is unresolved but lies on the critical path + +The mini spec accurately marks a `???` between a genuine persona run and a live demo fixture. Keeping a dev store, importing private Flue records, and replaying a materialized snapshot each make a different product claim. Replaying signals creates a prepared projection rather than preserving the original live lineage. + +Running several paid persona construction campaigns before proving that one minimal genuine conversation can be exported or retained, relocated, reopened, authorized, and queried risks producing evidence that cannot power the demo. + +**Recommended order:** run the export/restore/reopen probe on one tiny genuine conversation before the broader persona programme. Record whether the product fixture is a retained live store, a supported relocation of genuine records, or an honestly labelled prepared projection. + +### 19. Broad canonical-tool admission contradicts the stated restraint + +The mini spec says to admit Petrinaut's canonical mutation, query, and command tools by default and scope down only after observed misbehavior, while saying stock-modeller parity remains a non-goal. That is parity-first admission in practice. It also conflicts with the current Mission 9 record's rejection of broad tool parity and risks a large provider tool-definition cost, selection ambiguity, inappropriate commands, and a much larger failure surface before any scenario requires metrics, subnets, differential equations, scenarios, removals, and layout together. + +Rejecting the inherited arbitrary six-tool subset does not require admitting everything. Replace it with a **scenario-derived canonical subset**, mechanically generated from Petrinaut's authority, and expand it when the selected scenario or observed failure requires another mutation class. Measure schema size, prompt-cache effects, tool-selection behavior, latency, correction behavior, and provider errors before making a broad bundle the ordinary default. + +### 20. The completion criterion remains underdefined + +“Any element” and “consequential element” lack a mechanical inventory rule. The old M7 draft at least required a frozen element inventory and explicit supported or unsupported dispositions. That obligation should survive the mechanism change. + +Before a run is graded, freeze: + +- the selected document and workpiece revisions; +- the element inventory; +- the rule distinguishing consequential elements from presentation-only artifacts; +- expected supported, partially supported, externally changed, and refused dispositions; and +- what happens to deleted or recreated elements. + +Without this, whole-net completion can be gamed by excluding difficult elements after the fact. + +### 21. Migration and rollback are missing + +The plan changes persisted workpiece representation from fenced assistant text to tool parts and state, changes ordinary-conversation tool admission, removes `ask` and `sweep` handling, and changes the lineage expected by future missions. Existing conversations and retained runs contain only the old representation. Rollback after new state records and new tool calls is unspecified. + +A migration matrix should cover: + +- old history with new code; +- new history with rolled-back code; +- conversations containing both fenced and tool revisions; +- mixed-version browser and server; +- Mission 6 fixture mode; +- retained evidence restoration; and +- tool-manifest rollback. + +Given the prototype posture, a permanent compatibility layer is not warranted, but the transition crosses persisted data and separately deployed browser/server boundaries. An additive introduction with a bounded dual-read period may therefore be the least safe mechanism. The bridge should have an explicit removal gate. + +### 22. Deployment ordering is inconsistent + +C14 moves remote durability back to Mission 8, but current Mission 9 and Mission 10 drafts still require deployed or replacement-safe inherited state. Historical Mission 8 stopped before remote deployment, and no new executable M8 is yet scheduled. This leaves later missions either blocked on an unscheduled dependency or tempted to silently weaken “deployed.” + +Choose explicitly between: + +- scheduling a real Mission 8 persistence/deployment mission before the first remote claim; or +- making M9 and M10 explicitly local-product missions and naming a pre-M11 remote release gate. + +“Locally run panel,” “locally verified application image,” and “remote replacement-safe service” must remain distinct claims. + +### 23. Consumer discovery may be too late + +Deferring self-describing export and optimization-consumer discovery until Mission 11 risks choosing an M9 region and M10 correction that do not exercise the scenario, parameter, metric, executable, or behavioral semantics Chris and Yannis actually need. Mission 11 could then become an unexpectedly large rebuild rather than a handoff. + +Do lightweight, non-binding consumer discovery before selecting the M9 region: one optimization question, minimum scenario and parameter semantics, expected execution boundary, required outputs, and minimum credibility checks. Keep implementation in M11, but use the real consumer to select a representative proving case and decide whether file-level provenance is load-bearing earlier. + +### 24. Semantic and behavioral proof is too visual until the optimization handoff + +A visually plausible, parser-valid SDCPN can still have incorrect enabling, resource conservation, timing, scenarios, or stochastic behavior. Human semantic review is necessary but insufficient for operational behavior. + +When selecting the first meaningful generated region, require at least one executable discriminator derived from the workpiece—for example resource reservation and release, reachability, token conservation, or one scenario outcome—and carry it unchanged through the reviewer-revision mission. This need not become broad simulation coverage; it should be the cheapest check capable of catching a plausible but behaviorally wrong projection. + +## Items that should be reopened before Mission 7 authority + +### Reopen C1–C3: lineage and the honest why answer + +Decide whether the product promises temporal audit context or causal provenance. If causal provenance remains the intent, identify the smallest explicit mutation-to-passage relation and separate authorship, evidence, rationale, and authority. + +### Reopen C5: lookup ownership and execution + +Keep semantic package ownership, but assign supported Flue history acquisition, authorization, and tool composition to the binding/app boundary. Decide whether the model needs two tools or one composed why operation based on interaction quality rather than package topology. + +### Reopen C6: hash-only net/workpiece join + +Replace the post-hash-only proposal with a transition and effect contract, or narrow the claim to unattributed state correlation. + +### Reopen C8: excluding capture or another retained evidence projection + +Known Flue compaction already threatens exact evidence and revision recovery. Decide the uncompacted limitation or the minimal compaction-independent retention mechanism before promising exact historical lines. + +### Reopen C10: full-bundle default admission + +Retire the inherited arbitrary six, but choose a scenario-derived canonical subset and expand from observed need rather than mounting near-parity by default. + +### Reopen C13: release wording + +“Who prepared it” and “the exact conversation line it rests on” exceed the represented identity and causality. Narrow the release note until actor identity, evidence retention, and causal association are established. + +### Reopen C15: passage identity + +Treat passage identity as a prerequisite to point-passage provenance and blame. Strengthen the probe to semantic edits, or defer blame and report only revision-local text. + +### Reopen D1, D3, and D5: real fixtures and construction sequencing + +Prove one genuine conversation can become an authorized live fixture before the persona campaign, and resolve whether construction in M7 intentionally consumes M9's visible advance. + +## Recommended next sequence + +1. **Adjudicate the product claim.** Decide causal provenance versus temporal audit lineage and amend the release wording accordingly. +2. **Build one adversarial tracer on paper or in the smallest executable harness.** Use one conversation with two workpiece passages, two mutations, one failed or no-op mutation, one correction, and one hand edit. Require deterministic answers or explicit refusals. +3. **Correct the Flue topology model.** Represent user delivery, assistant mutation request, later client-result signal, continuation, duplicate result delivery, and server-state writes using their real identities. +4. **Define the minimum mutation transition/effect record.** Include document identity, base state, outcome, post state, affected elements, and unknown-result behavior. +5. **Force compaction.** Verify which exact user text, workpiece revisions, and tool records remain available through the supported public surface; choose an explicit limitation or retained projection. +6. **Export or retain and reopen the tracer conversation.** Exercise authorization and why resolution after relocation or restart before launching paid persona breadth. +7. **Probe passage identity under semantic edits.** Include rename, move, paraphrase, split, merge, deletion, and reintroduction. +8. **Repair the provider schema carrier for the smallest scenario-derived mutation subset.** Prove one real nested call before broad admission. +9. **Re-cut the mission topology from the observed results.** Explicitly resolve the M7/M9 overlap, deployment order, migration boundary, and consumer-driven proving scenario. +10. **Only then run the broader persona construction campaign.** Freeze the consequential-element inventory and behavioral oracle before grading. + +## Evidence consulted + +- [`provenance-and-tooling-decision-log-2026-09-04.md`](provenance-and-tooling-decision-log-2026-09-04.md) +- [`provenance-by-lineage-mini-spec-2026-09-04.md`](provenance-by-lineage-mini-spec-2026-09-04.md) +- [`../../../MISSION.next.md`](../../../MISSION.next.md) +- [`../../mission-drafts/7-capture-backed-review.md`](../../mission-drafts/7-capture-backed-review.md) +- [`../../mission-drafts/9-traceable-projection.md`](../../mission-drafts/9-traceable-projection.md) +- [`../../mission-drafts/10-bounded-reviewer-revision.md`](../../mission-drafts/10-bounded-reviewer-revision.md) +- [`../../specs/petrinaut-batched-construction-tools.md`](../../specs/petrinaut-batched-construction-tools.md) +- [`../../../packages/core/src/workpiece.ts`](../../../packages/core/src/workpiece.ts) +- [`../../../packages/plugin-sdcpn/src/flue.ts`](../../../packages/plugin-sdcpn/src/flue.ts) +- [`../../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts`](../../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts) +- [`../../../packages/binding-flue/src/history-reader.ts`](../../../packages/binding-flue/src/history-reader.ts) +- [`../../../packages/transport-aisdk/src/client-tool-history.ts`](../../../packages/transport-aisdk/src/client-tool-history.ts) +- [`../../../../../../apps/brunch-agent/src/agents/chat-agent/agent.ts`](../../../../../../apps/brunch-agent/src/agents/chat-agent/agent.ts) +- [`../implementations/fe-1575-outer-browser-witness-2026-09-04-r2/witness.md`](../implementations/fe-1575-outer-browser-witness-2026-09-04-r2/witness.md) +- Installed Flue 2.0.3 documentation for agent hooks, public conversation history, compaction, streaming, and conversation persistence under `node_modules/@flue/runtime/docs/` and `node_modules/@flue/sdk/docs/` +- Petrinaut canonical AI, action, entity, and file-format schemas under `libs/@hashintel/petrinaut-core/src/` + +## Review disposition + +The design should not be discarded. Its useful core is a first-class revisioned workpiece plus mutation-call audit history. The correction is to stop calling temporal adjacency a complete provenance relation, then add only the smallest identities, effects, retention, and authorization contracts that the real why answer requires. The mission sequence should be recut after those disputed seams are probed, not before. diff --git a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md new file mode 100644 index 00000000000..259beb1dc6e --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md @@ -0,0 +1,135 @@ +# Provenance by lineage — mini spec for review, 2026-09-04 + +> Design evidence, not execution authority. This document projects the [decision log of 2026-09-04](provenance-and-tooling-decision-log-2026-09-04.md) into one reviewable statement of intent, design, and consequences for the Brunch mission spine. It is written for an independent reviewer who has not seen the originating conversation. Entry references such as C4 point into the log. Nothing here may be implemented until it is re-evaluated and cut into a live `MISSION.md`; the intended vehicle is the Mission 7 cut. + +## 1. Intent + +Brunch must be able to say, for any consequential element of a Petri net it helped build, where that element came from: the workpiece passage that motivated it, the revision that introduced the passage, and the conversation turns behind that revision, or an honest refusal. It must do this without a comprehensive typed domain model, without a second conversation log, and without anyone hand-authoring links. + +Two earlier approaches failed in opposite directions. A comprehensive typed intermediate representation tried to make provenance a property of the domain model; the typology receded as it grew and the model worked worse with it. The structural Markdown workpiece that replaced it is legible and cheap but has no seam to either the conversation or the net, and provenance was deferred as "later" without the tension being named in the planning record (B3). + +The resolving observation: provenance is not a domain fact. It is who changed what, in response to what, when. Three actors know a link at the moment it is created, and each moment is already recorded in Flue's append-only canonical log once the artifacts they produce are tool calls (C1). + +## 2. The lineage model + +```text +turn N: user says X (user message, turnId T) + └─ assistant response (assistant message, turnId T) + ├─ text + ├─ tool call update_workpiece { markdown } revision R, identity = call id + ├─ tool result { revision, sha256 } + ├─ tool call addArc { ... } net mutation, same turnId + └─ tool result { ..., documentSha256 } net revision, same turnId + state_write workpiece = { callId, sha256, revision } same batch, same durability +``` + +Resolution walks backwards from an element and is a point at every hop but the last: + +```text +element id + → mutation call that created it, and calls that changed it point(s) + → latest update_workpiece at or before that call point + → the passage in that revision point + → blame: the revision that introduced the passage point + → user turns between that revision and the previous one RANGE + └─ narrowed to one line where the passage quotes the expert verbatim +``` + +The honest why answer is therefore: one creating call, one workpiece passage, one introducing revision, and then either a quoted line or a short turn range (C2). The range is where workpiece cadence is coarser than turn cadence. Elements changed several times report introducing and last-changing calls separately. Every hop is a lookup in the canonical log; nothing is stored elsewhere and nothing is inferred. + +What the model does: it calls the tools and interprets structured ranges in prose. What it may not do: author a link, reread the transcript as provenance, or explain an element the tools mark unsupported (C3). + +## 3. Mechanisms + +### 3.1 `update_workpiece` (core, server-side) — C4 + +| Aspect | Decision | +| --- | --- | +| Input | one Markdown string, the full current workpiece | +| Run | validate non-empty and well-formed; SHA-256; `usePersistentState('workpiece', { callId, sha256, revision })`; return `{ revision, sha256 }` | +| Durability | `durable: true`, so an interrupted call replays rather than settling unknown | +| Ownership | core owns the tool because the mechanism is formalism-independent; plugins own the template | +| Replaces | the fenced `runbook-ir` block in assistant text; the prepared-signal route stays for test-authored revision zero | + +Why a tool rather than a fenced block: the revision identity is a call id instead of a regex over prose; the tool can refuse a truncated document; the next render reads the current pointer without the model echoing it; mutations and revisions share `turnId`; the UI can project the part into its own pane. Costs acknowledged: the full document still crosses the wire each revision, and a model may call a tool less readily than it emits text. A structured-patch input is the later absorber for token cost; cadence must be measured for either shape (B6). + +### 3.2 `query_workpiece` (core) and `locate_elements` (plugin-sdcpn) — C5 + +`query_workpiece` takes a revision pointer or a passage locator and returns the turn ranges behind it with the user text, plus verbatim-quote matches where the passage quotes. `locate_elements` takes element ids and returns, per id, the mutation calls with their turn ids and document hashes, and the workpiece revision current at each. The split follows knowledge: core knows revisions and history; only the plugin knows which calls are mutations and where ids sit in inputs. Names are provisional. + +### 3.3 Net revision identity through the client-tool result — C6 + +The browser returns the post-mutation document SHA-256 inside each client-tool result. Mission 6 already computes this hash for its settled manifest. A document hash that no tool result explains is reported as "changed outside the conversation." Petrinaut's schema is not extended: elements are strict objects with no metadata slot and the file wrapper carries only `title` and a generator (B7). A file-level provenance pointer in `meta` is deferred until Mission 11 has a consumer for a self-describing export. + +### 3.4 The visible workpiece — C7 + +The chat rendering projects `update_workpiece` parts out of assistant messages and leaves a one-line "workpiece updated" marker. A pane in the Petrinaut Brunch panel shows the current revision, the revision list, and a diff between any two, all derived from Flue history through the Mission 5 transport. The why answer renders into the same pane because it resolves to a passage the reviewer must see. This projection lives in the app or transport layer, not in the Petrinaut library. The pane is the surface every later provenance and revision mission assumes and none has built; it is also the product-manager-visible advance in its own right. + +### 3.5 Schema carrier repair — B9, C11 + +Precondition for admitting any tool beyond the flat ones. Flue accepts Valibot schemas only and rejects other Standard Schema vendors; the construction factory therefore declares an empty loose object and pastes Petrinaut's JSON Schema into the description. Fix by a mechanical JSON Schema to Valibot interpreter covering the subset Petrinaut uses (objects, strings, numbers, enums, arrays, nullable, optional, unions), or by upstream Flue Standard Schema support. The local interpreter is derived rather than hand-copied and is reversible if upstream support arrives. + +### 3.6 Tool admission and teaching — C10, C12 + +Petrinaut's canonical mutation, query, and command tools are admitted to ordinary SDCPN conversations, mechanically from Petrinaut's AI tool bundle, and scoped down only from observed misbehaviour. The inherited six-tool subset is retired as a product surface. The skill gains construction posture: read the definition first, mutate in small steps, check compilation errors, record decisions in Construction notes, call `update_workpiece` before and after construction. Parity with the stock modeller remains a non-goal; the change is the direction of the default. + +### 3.7 Subtraction — C8, C9 + +Retired from code under Mission 7 authority: the `ask` and `sweep` names in core, the suspended ask contract, the website ask interactive tool and test, the sweep filter and output module in the panel transport, and the two Voice references. The capture store and sweep are not consumed by Mission 7; the store re-enters only if answer-time verification strains under compaction or ownership. + +## 4. Tool inventory after this design + +| Tool | Owner | Executes | Status | +| --- | --- | --- | --- | +| `ping` | app | server | keep, diagnostic | +| `activate_skill` | Flue | server | keep | +| `readPetrinautDoc` | plugin-sdcpn | browser | keep | +| Petrinaut canonical bundle | plugin-sdcpn, derived | browser | admit to ordinary conversation after 3.5 | +| `update_workpiece` | core | server | new | +| `query_workpiece` | core | server | new | +| `locate_elements` | plugin-sdcpn | server | new | +| `ask`, `sweep` client handling | core, website | browser | retire | +| six-tool and two-tool subsets | plugin-sdcpn | browser | retire as product surfaces; Mission 6 fixture mode stays until Mission 6 archives | + +## 5. Real honest fixtures — D1 to D5 + +The provenance pair is a real conversation with a real revisioned workpiece and a real constructed net, produced by persona interviews against the production agent. The Mission 6 prepared fixture remains a viability proof and is not promoted (A3). + +```text +persona run (Pi harness, production ChatAgent, real-headless host) + → Flue store holds the genuine conversation, revisions, mutations + → harness retains snapshot.json + projections per settled read + → grade coverage against the hidden oracle ledger afterwards + → ??? → live fixture the demo opens (D3, open) +``` + +Settled: run several cases in parallel; six cases exist. Recommended: a turn cap larger than the 6–10 used so far as budget, early stop when Brunch itself declares construction handoff or delivery, ledger coverage as the post-hoc grade rather than the stop rule (D4); runs go to construction so the fixture contains lineage, which sequences the carrier fix and tool admission before the construction campaign, with an earlier elicitation-only campaign to measure revision cadence (D5). + +Open: how a retained genuine conversation becomes a live fixture in a fresh store. Keeping the dev store as shipped data, restoring genuine records through Flue's storage adapter, and replaying the snapshot as prepared signals each have a named cost in D3; the first probe is whether Flue 2.0.3 tolerates export and restore at its storage boundary. + +## 6. What this changes in the mission spine + +1. **Name the tension.** The spine states provenance-by-lineage as the current hypothesis, the typed IR and hand-authored derivation as rejected with reasons, revision cadence as the named strain, and the visible workpiece as the precondition (E1). +2. **Re-cut Mission 7.** Body: carrier fix, orphan retirement, `update_workpiece`, workpiece pane, tool admission and teaching, persona programme to construction. Last step: the why route over real lineage. Release note narrowed to the honest framing (C13). Local posture; remote durability to Mission 8 (C14). Capture-store chain and Mission 2 inherited closure dropped (E2). +3. **Adjust Missions 9 and 10.** They inherit the seam from lineage: revision id equals call id, passage identity per the probe in C15, stable element ids, document hash per C6. They no longer assume a derivation fixture or a prebuilt pair (E3). +4. **Mission 6 close report.** Record the fixture-rigging admission, the carried fenced-block-to-tool change, and the credential cause of the blocked witness (E4). +5. **Authority.** Every settled item is an owner decision expressed in conversation. It becomes authority only when written into the cut Mission 7 `MISSION.md`, with Mission 6's construction-tool constraint amended there and not in the Mission 6 tie-off (E5). + +## 7. Fog-line + +- Revision cadence: whether the model calls `update_workpiece` often enough for blame to have grain; unmeasured (B6). +- Passage identity: heading path, Markdown anchor, or companion manifest; decided by the probe in C15. +- Carrier repair route: local interpreter versus upstream Flue support (3.5). +- Fixture materialization from a genuine conversation (D3). +- Token cost of full-document emission on long interviews, and when a structured patch earns its place. +- Which canonical tools misbehave at the provider boundary once the carrier carries fields; only observed failure scopes admission down. +- Whether the why answer over a real pair is useful to a reviewer, not merely correct; a human judges, per the Mission 7 draft's existing risk row. + +## 8. Questions for the independent reviewer + +1. Is provenance-by-lineage a sufficient answer to the stated intent, or does it smuggle an assumption the log did not check? +2. Is the tool split in 3.2 the right ownership boundary, or should one tool serve both lookups? +3. Is returning the document hash in the client-tool result an adequate join between net and workpiece revisions, given hand edits in Petrinaut? +4. Does anything in sections 3 and 4 reintroduce a mechanism the spine's rejected-mechanisms list has already refused? +5. Is the persona programme's stop rule and fixture-materialization plan honest about what a "real" fixture is? +6. Which settled items should be re-opened before they enter the Mission 7 authority, and why? From 570d5418c61ceed76312065cf672967658a4bfc6 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 12:00:37 +0200 Subject: [PATCH 14/31] M7+ resteering draft 2 --- ...nce-and-tooling-decision-log-2026-09-04.md | 36 ++++ ...venance-by-lineage-mini-spec-2026-09-04.md | 191 +++++++++++------- 2 files changed, 149 insertions(+), 78 deletions(-) diff --git a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md index 7638119b3cb..a3fe414761d 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md @@ -91,3 +91,39 @@ Legend: **Settled** = owner accepted in conversation. **Recommended** = agent re **E4.** Mission 6 close report: record A3 and A4 plainly, plus the credential cause in A1. **E5.** Decision-integrity: every Settled item here is an owner decision expressed in conversation. It becomes authority only when written into the cut `MISSION.md` for Mission 7; this log and the mini spec are neither authority nor a substitute for it. + +## F. Dispositions after the independent review (same day) + +The [independent review](provenance-by-lineage-independent-review-2026-09-04.md) was read in full and its terrain claims re-checked before these dispositions. Review item numbers are cited as R1 to R24. Entries here supersede the C, D, and E entries they name; the earlier entries stay as history. + +**F1. R11 confirmed from the Mission 6 r2 witness: the turn topology in C4 and the mini spec was wrong.** Inspected: `fe-1575-outer-browser-witness-2026-09-04-r2/flue-snapshot-tab-b.json`. User messages carry a submission id and no turn id; the mutation request sits in one assistant turn; the browser result arrives as a separate `client-tool-result` system dispatch under a new submission; the continuation is a new turn; cumulative result signals repeat earlier call ids (one call id appears three times). Consequence: correlation is by tool call id plus submission order, never by a shared `turnId`, and the lineage reader deduplicates results by call id. + +**F2. R13 confirmed from Flue's hook rules: hooks throw outside render, setters throw during render.** Inspected: `@flue/runtime/docs/reference/agent-hooks-api.md`, "Rendering and the rules of hooks"; `ToolContext` carries `toolCallId`. Consequence: `update_workpiece` captures the `usePersistentState` setter at render and calls it from `run`; revision numbering uses the updater form. + +**F3. R12, R14, R15 accepted.** The document hash in client-tool results is proposed work, not current behaviour; the Petrinaut wrapper carries version, the document arrays, title, and optional generator metadata, with no element-level or file-level provenance slot; `durable: true` protects only the server tool attempt, never the browser side effect. + +**F4. R7 is plausible and unverified by either party; it is the first probe.** Flue folds older history into a summary for the model, keeping 8000 recent tokens verbatim by default. Whether the public `history()` projection also drops folded messages is not stated in the installed docs; the database guide says reconnecting clients rebuild from the full stream. Probe: set `keepRecentTokens` low, run past threshold, read `history()`, and check whether old `update_workpiece` inputs, mutation parts, and user lines survive. C8's re-entry condition for independent retention is this probe's negative result. + +**F5. R1 to R3 accepted; the claim narrows and gains a declared basis.** Settled by the owner. "Latest revision before the mutation" is temporal adjacency and selects no passage. The constructor declares its basis when it constructs: one or more passage locators plus a one-line rationale carried with each mutation request. This is the actor who knows, at the moment they know; it types nothing about the domain and is not a retrospective hand-authored derivation. Where the basis is absent the answer degrades to the temporal range and says so. Workpiece author, evidence actor, requesting principal, and mutation actor are reported separately; a Flue `user` role is not actor identity. Supersedes the "nothing is inferred" wording in C1 to C3 and narrows C13 further. + +**F6. R2 accepted: passage identity is a prerequisite.** The C15 probe must cover rename, move, paraphrase, split, merge, deletion, and reintroduction. If no scheme survives, the first claim is revision-local text with no cross-revision "introduced by." + +**F7. R4 to R6 accepted: a mutation transition record replaces the hash-only join.** Per call: document identity, expected base hash, outcome (applied, no-op, failed, stale, unknown), confirmed post hash, affected element ids or retained pre and post definitions, one authoritative result per call with a duplicate rule. A transition no record explains is "not attributable from recorded transitions," and provenance for the affected state is refused until an explicit external revision is imported. Supersedes C6. + +**F8. R5 accepted: workpiece update and browser mutation are separate boundaries.** An operation protocol with requested, outcome, and reconciled or incomplete or unknown states replaces any implied shared batch. Retry identity, duplicate delivery, stale-base refusal, and lost-result behaviour are part of that protocol. + +**F9. R8 accepted: executable boundary for lookups.** Core owns formalism-independent revision and query semantics; plugin-sdcpn owns mutation names, inputs, outputs, and effects; binding and app own authorized acquisition of Flue history (the in-process fetch pattern the capture sweep already uses) and compose the model-facing tool. One or two model-facing tools follows interaction quality, not package seams. Supersedes the executable reading of C5. + +**F10. R9 accepted: persistent state holds the current Markdown, not only a pointer.** State is reduced from the record stream at render, independent of the model's context, so the current workpiece is always available to the agent regardless of compaction. Core validates non-empty and size; template conformance is plugin participation. Revision history still depends on F4. + +**F11. R10 accepted as a named limit.** Mission 7 states a single-principal local authorization limit and treats retrieved conversation text as untrusted evidence returned in the smallest range needed; the broader contract is deferred with that owner. + +**F12. R16 and R17: consolidate.** Settled by the owner. Construction and explanation ship in one mission; the following mission takes projection breadth, repeat and changed-input behaviour, and readiness closure. The owner's stated reason: resist the regression to thin tracers; build fully connected parts and real test beds rather than partial coverage with caveats. The reviewer's minimal adversarial tracer is the first act inside that mission: one genuine conversation, two distinguishable passages, two mutations, one no-op or failed mutation, one correction, one hand edit; deterministic answers or explicit refusals before breadth. Supersedes E2 and E3. + +**F13. R19: scenario-derived subset, enumerated now.** Settled by the owner with the condition that it must not become a deferral. The subset is derived mechanically from Petrinaut's AI tool bundle by the document entity classes the six persona cases exercise, surveyed on 2026-09-04 across `evaluations/cases/*` and `evaluations/oracles/*`: every case needs places, transitions, arcs, and scenarios (initial state); most name colours or token attributes and stochastic timing; industrial gas names parameters; vestera names metrics; data-centre thermal and pharma cold chain name temperature dynamics, so differential equations; only vestera mentions hierarchy, so subnets and component instances are excluded until a case needs them. Initial subset: add, update, and remove for places, transitions, arcs (including weight and type), types and type elements, parameters, scenarios, metrics, and differential equations; plus `getLatestNetDefinition`, `getNetCompilationErrors`, `applyAutoLayout`, and `setNetTitle`. Position updates are excluded because layout covers them. Expansion is by observed need with the case named. The six-tool and two-tool subsets are retired as product surfaces once Mission 6 archives. Supersedes C10. + +**F14. R18 accepted: fixture materialization before any paid campaign.** Export or retain, relocate, reopen, authorize, and query one tiny genuine conversation first, and record whether the product fixture is a retained live store, a supported relocation of genuine records, or an honestly labelled prepared projection. + +**F15. R20 to R24 accepted as additions.** Freeze the element inventory and consequential rule before grading; write the migration matrix (old history with new code, new history with old code, mixed revisions, mixed browser and server versions, Mission 6 fixture mode, retained evidence, tool manifest) with an explicit removal gate for any dual-read bridge; resolve deployment ordering explicitly rather than weakening "deployed"; do lightweight consumer discovery with Chris and Yannis before choosing the construction region; require one executable behavioural discriminator derived from the workpiece alongside human semantic review. + +**F16. Next sequence, merged.** (1) Adjudicate the claim as F5. (2) Paper adversarial tracer per F12. (3) Probes: compaction on `history()` (F4), export and reopen (F14), passage identity under semantic edits (F6), carrier repair for one real nested mutation from the F13 subset. (4) Correct the Flue topology model (F1) and define the transition record (F7) and operation protocol (F8). (5) Re-cut the mission topology from observed results (F12). (6) Then the persona construction campaign with frozen inventory and behavioural oracle (F15). diff --git a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md index 259beb1dc6e..de71a6aad98 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md @@ -1,135 +1,170 @@ -# Provenance by lineage — mini spec for review, 2026-09-04 +# Provenance by lineage with declared basis — mini spec, 2026-09-04 (revised) -> Design evidence, not execution authority. This document projects the [decision log of 2026-09-04](provenance-and-tooling-decision-log-2026-09-04.md) into one reviewable statement of intent, design, and consequences for the Brunch mission spine. It is written for an independent reviewer who has not seen the originating conversation. Entry references such as C4 point into the log. Nothing here may be implemented until it is re-evaluated and cut into a live `MISSION.md`; the intended vehicle is the Mission 7 cut. +> Design evidence, not execution authority. This document projects the [decision log of 2026-09-04](provenance-and-tooling-decision-log-2026-09-04.md), including its post-review dispositions (F1 to F16), into one reviewable statement of intent, design, and consequences for the Brunch mission spine. It was revised the same day after the [independent review](provenance-by-lineage-independent-review-2026-09-04.md); the revision corrects the turn topology, the hook pattern, and the claim strength, adds the declared basis, the mutation transition record, and the operation protocol, consolidates the construction and explanation missions, and enumerates the scenario-derived tool subset. Nothing here may be implemented until it is re-evaluated and cut into a live `MISSION.md`. ## 1. Intent -Brunch must be able to say, for any consequential element of a Petri net it helped build, where that element came from: the workpiece passage that motivated it, the revision that introduced the passage, and the conversation turns behind that revision, or an honest refusal. It must do this without a comprehensive typed domain model, without a second conversation log, and without anyone hand-authoring links. +Brunch must be able to say, for any consequential element of a Petri net it helped build, what it rests on: the workpiece passage the constructor declared as its basis, the revision that carried that passage, the conversation context behind that revision, and who did what, or an honest refusal. It must do this without a comprehensive typed domain model, without a second conversation log, and without anyone hand-authoring links after the fact. -Two earlier approaches failed in opposite directions. A comprehensive typed intermediate representation tried to make provenance a property of the domain model; the typology receded as it grew and the model worked worse with it. The structural Markdown workpiece that replaced it is legible and cheap but has no seam to either the conversation or the net, and provenance was deferred as "later" without the tension being named in the planning record (B3). +Two earlier approaches failed in opposite directions. A comprehensive typed intermediate representation tried to make provenance a property of the domain model; the typology receded as it grew and the model worked worse with it. The structural Markdown workpiece that replaced it is legible and cheap but has no seam to either the conversation or the net, and provenance was deferred without the tension being named in the planning record. -The resolving observation: provenance is not a domain fact. It is who changed what, in response to what, when. Three actors know a link at the moment it is created, and each moment is already recorded in Flue's append-only canonical log once the artifacts they produce are tool calls (C1). +The resolving observation, as corrected by review: provenance has two parts. **Lineage** is who changed what, in response to what, when; it is recoverable from Flue's append-only log once workpiece revisions and net mutations are tool calls. **Basis** is why an element exists; it is not in the log unless the actor who knows declares it at the moment they know. The design therefore combines recovered lineage with a declared basis, and says plainly which of the two any given answer rests on (F5). -## 2. The lineage model +## 2. The lineage model, as the log actually records it ```text -turn N: user says X (user message, turnId T) - └─ assistant response (assistant message, turnId T) - ├─ text - ├─ tool call update_workpiece { markdown } revision R, identity = call id - ├─ tool result { revision, sha256 } - ├─ tool call addArc { ... } net mutation, same turnId - └─ tool result { ..., documentSha256 } net revision, same turnId - state_write workpiece = { callId, sha256, revision } same batch, same durability +submission S1 user message (submissionId S1, no turnId) + assistant turn T1 (turnId T1) + ├─ update_workpiece {markdown} revision R, identity = callId + ├─ tool result {revision, sha256} + └─ addArc {…, basis} request; server output = awaiting client + state_write workpiece = {callId, sha256, revision, markdown} +submission S2 system dispatch client-tool-result [{toolCallId, output}] (may repeat earlier ids) + assistant turn T2 continuation ``` -Resolution walks backwards from an element and is a point at every hop but the last: +Correlation is by `toolCallId` plus submission order; a shared turn id between the request and the browser result does not exist (F1). The lineage reader deduplicates cumulative result signals by call id. + +Resolution walks from an element: ```text element id - → mutation call that created it, and calls that changed it point(s) - → latest update_workpiece at or before that call point - → the passage in that revision point - → blame: the revision that introduced the passage point - → user turns between that revision and the previous one RANGE - └─ narrowed to one line where the passage quotes the expert verbatim + → mutation transition records naming it (created, changed, deleted; F7) + → the declared basis on the creating request passage locator(s) + rationale (F5) + ├─ present: the passage in the revision current at that request + └─ absent: the revision current at that request, and a temporal range, marked as such + → the conversation context behind that revision turns between it and the previous revision + └─ verbatim quote where the passage quotes; reported as string occurrence, not endorsement + → actors reported separately: workpiece author, evidence actor, requesting principal, mutation actor ``` -The honest why answer is therefore: one creating call, one workpiece passage, one introducing revision, and then either a quoted line or a short turn range (C2). The range is where workpiece cadence is coarser than turn cadence. Elements changed several times report introducing and last-changing calls separately. Every hop is a lookup in the canonical log; nothing is stored elsewhere and nothing is inferred. - -What the model does: it calls the tools and interprets structured ranges in prose. What it may not do: author a link, reread the transcript as provenance, or explain an element the tools mark unsupported (C3). +What the model does: it calls the tools and interprets structured results in prose. What it may not do: author a basis after the fact, reread the transcript as provenance, or explain an element the tools mark unsupported or not attributable (C3, F7). ## 3. Mechanisms -### 3.1 `update_workpiece` (core, server-side) — C4 +### 3.1 `update_workpiece` (core, server-side) — C4, F2, F10 | Aspect | Decision | | --- | --- | | Input | one Markdown string, the full current workpiece | -| Run | validate non-empty and well-formed; SHA-256; `usePersistentState('workpiece', { callId, sha256, revision })`; return `{ revision, sha256 }` | -| Durability | `durable: true`, so an interrupted call replays rather than settling unknown | -| Ownership | core owns the tool because the mechanism is formalism-independent; plugins own the template | +| Hook pattern | `usePersistentState('workpiece', …)` called at render; its setter captured in the tool closure; called from `run`, which receives `toolCallId` | +| State value | `{ callId, sha256, revision, markdown }`, written with the updater form so the revision number composes; the Markdown is in state so the agent always has its current workpiece at render regardless of compaction | +| Validation | core checks non-empty and size; template conformance is plugin participation | +| Durability | `durable: true` protects the server tool attempt only | +| Ownership | core owns the tool; plugins own the template | | Replaces | the fenced `runbook-ir` block in assistant text; the prepared-signal route stays for test-authored revision zero | -Why a tool rather than a fenced block: the revision identity is a call id instead of a regex over prose; the tool can refuse a truncated document; the next render reads the current pointer without the model echoing it; mutations and revisions share `turnId`; the UI can project the part into its own pane. Costs acknowledged: the full document still crosses the wire each revision, and a model may call a tool less readily than it emits text. A structured-patch input is the later absorber for token cost; cadence must be measured for either shape (B6). +Costs acknowledged: the full document crosses the wire each revision and is written twice, as tool input and as state; a structured-patch input is the later absorber. A model may call a tool less readily than it emits text; cadence is unmeasured either way (B6). + +### 3.2 Declared basis on mutation requests — F5 + +Every construction request carries `basis`: one or more passage locators into the workpiece revision current at the request, plus a one-line rationale. The plugin strips `basis` before forwarding the canonical input to Petrinaut, so Petrinaut's contract is unchanged, and the full request with basis is retained in the log as the tool-call input. The skill teaches that a mutation without a basis is a mutation the model must justify in Construction notes or not make. Passage locator form is decided by the probe in 3.7. + +### 3.3 Mutation transition record and operation protocol — F7, F8 + +The browser returns, per call: document identity, expected base hash, outcome (applied, no-op, failed, stale, unknown), confirmed post hash, and affected element ids or retained pre and post definitions. One authoritative result per call; a duplicate rule for repeated signals. The workpiece update and the browser mutation are separate boundaries, so the protocol is: + +```text +requested(callId, documentId, baseHash, workpieceRevision, basis) + → outcome(applied | no-op | failed | stale | unknown, postHash, effects) + → reconciled | incomplete | unknown +``` + +A document transition no record explains is "not attributable from recorded transitions"; provenance for the affected state is refused until an explicit external revision is imported. No Petrinaut schema change is needed; the wrapper has no provenance slot and none is added (F3). + +### 3.4 Lookups and their executable boundary — C5, F9 -### 3.2 `query_workpiece` (core) and `locate_elements` (plugin-sdcpn) — C5 +Core owns revision and query semantics. Plugin-sdcpn owns mutation names, inputs, outputs, and effect interpretation. Binding and app own authorized acquisition of Flue history through the in-process fetch pattern the capture sweep already uses, and compose the model-facing tool. Whether the model sees one composed why tool or two follows interaction quality. Retrieved conversation text is untrusted evidence returned in the smallest range needed (F11). -`query_workpiece` takes a revision pointer or a passage locator and returns the turn ranges behind it with the user text, plus verbatim-quote matches where the passage quotes. `locate_elements` takes element ids and returns, per id, the mutation calls with their turn ids and document hashes, and the workpiece revision current at each. The split follows knowledge: core knows revisions and history; only the plugin knows which calls are mutations and where ids sit in inputs. Names are provisional. +### 3.5 The visible workpiece — C7 -### 3.3 Net revision identity through the client-tool result — C6 +Chat projects `update_workpiece` parts out of assistant messages and leaves a one-line marker. A pane in the Petrinaut Brunch panel shows the current revision, the revision list, and a diff, derived from Flue history through the Mission 5 transport. The why answer renders into the same pane. This projection lives in the app or transport layer, not the Petrinaut library. It is the surface every later mission assumes and a product-manager-visible advance in its own right. -The browser returns the post-mutation document SHA-256 inside each client-tool result. Mission 6 already computes this hash for its settled manifest. A document hash that no tool result explains is reported as "changed outside the conversation." Petrinaut's schema is not extended: elements are strict objects with no metadata slot and the file wrapper carries only `title` and a generator (B7). A file-level provenance pointer in `meta` is deferred until Mission 11 has a consumer for a self-describing export. +### 3.6 Schema carrier repair — B9, C11 -### 3.4 The visible workpiece — C7 +Precondition for admitting any nested tool. Flue accepts Valibot only and rejects other Standard Schema vendors; the construction factory declares an empty loose object with the JSON Schema pasted into the description. Fix by a mechanical JSON Schema to Valibot interpreter for the subset Petrinaut uses, or upstream Flue Standard Schema support. Prove one real nested call before broad admission. -The chat rendering projects `update_workpiece` parts out of assistant messages and leaves a one-line "workpiece updated" marker. A pane in the Petrinaut Brunch panel shows the current revision, the revision list, and a diff between any two, all derived from Flue history through the Mission 5 transport. The why answer renders into the same pane because it resolves to a passage the reviewer must see. This projection lives in the app or transport layer, not in the Petrinaut library. The pane is the surface every later provenance and revision mission assumes and none has built; it is also the product-manager-visible advance in its own right. +### 3.7 Passage identity — F6 -### 3.5 Schema carrier repair — B9, C11 +A prerequisite, not fog. Candidates: heading path, Markdown anchor, companion manifest. The probe covers rename, move, paraphrase, split, merge, deletion, and reintroduction on one real workpiece. If no scheme survives, the first claim is revision-local text with no cross-revision "introduced by." -Precondition for admitting any tool beyond the flat ones. Flue accepts Valibot schemas only and rejects other Standard Schema vendors; the construction factory therefore declares an empty loose object and pastes Petrinaut's JSON Schema into the description. Fix by a mechanical JSON Schema to Valibot interpreter covering the subset Petrinaut uses (objects, strings, numbers, enums, arrays, nullable, optional, unions), or by upstream Flue Standard Schema support. The local interpreter is derived rather than hand-copied and is reversible if upstream support arrives. +### 3.8 Scenario-derived tool admission — F13 -### 3.6 Tool admission and teaching — C10, C12 +The inherited six-tool subset is retired. The admitted subset is generated mechanically from Petrinaut's AI tool bundle by the document entity classes the six persona cases exercise, surveyed on 2026-09-04: -Petrinaut's canonical mutation, query, and command tools are admitted to ordinary SDCPN conversations, mechanically from Petrinaut's AI tool bundle, and scoped down only from observed misbehaviour. The inherited six-tool subset is retired as a product surface. The skill gains construction posture: read the definition first, mutate in small steps, check compilation errors, record decisions in Construction notes, call `update_workpiece` before and after construction. Parity with the stock modeller remains a non-goal; the change is the direction of the default. +| Entity class | Case evidence | Admitted operations | +| --- | --- | --- | +| places, transitions, arcs | every case | add, update, remove; arc weight and type | +| scenarios (initial state) | every case | add, update, remove | +| types and type elements | most cases name colours or token attributes | add, update, remove, move element | +| parameters | industrial gas | add, update, remove | +| metrics | vestera | add, update, remove | +| differential equations | data-centre thermal, pharma cold chain | add, update, remove | +| queries and commands | all | `getLatestNetDefinition`, `getNetCompilationErrors`, `applyAutoLayout`, `setNetTitle` | +| excluded for now | only vestera hints at hierarchy | subnets, component instances, position updates | -### 3.7 Subtraction — C8, C9 +Expansion is by observed need with the case named. Admission in ordinary SDCPN conversation is the default; parity with the stock modeller is still not the goal. -Retired from code under Mission 7 authority: the `ask` and `sweep` names in core, the suspended ask contract, the website ask interactive tool and test, the sweep filter and output module in the panel transport, and the two Voice references. The capture store and sweep are not consumed by Mission 7; the store re-enters only if answer-time verification strains under compaction or ownership. +### 3.9 Teaching and subtraction — C9, C12 + +The skill gains construction posture: read the definition first, mutate in small steps with a declared basis, check compilation errors, record decisions in Construction notes, call `update_workpiece` before and after construction. The `ask` and `sweep` client handling is retired from code. The capture store is not consumed; it re-enters only if the compaction probe shows `history()` loses records (F4). ## 4. Tool inventory after this design | Tool | Owner | Executes | Status | | --- | --- | --- | --- | -| `ping` | app | server | keep, diagnostic | -| `activate_skill` | Flue | server | keep | -| `readPetrinautDoc` | plugin-sdcpn | browser | keep | -| Petrinaut canonical bundle | plugin-sdcpn, derived | browser | admit to ordinary conversation after 3.5 | +| `ping`, `activate_skill`, `readPetrinautDoc` | app, Flue, plugin | server, server, browser | keep | +| scenario-derived Petrinaut subset (3.8) | plugin-sdcpn, derived | browser | admit after carrier repair | | `update_workpiece` | core | server | new | -| `query_workpiece` | core | server | new | -| `locate_elements` | plugin-sdcpn | server | new | +| why lookup (one or two model-facing tools) | composed at app from core and plugin | server | new | | `ask`, `sweep` client handling | core, website | browser | retire | -| six-tool and two-tool subsets | plugin-sdcpn | browser | retire as product surfaces; Mission 6 fixture mode stays until Mission 6 archives | +| six-tool and two-tool subsets | plugin-sdcpn | browser | retire once Mission 6 archives | -## 5. Real honest fixtures — D1 to D5 +## 5. Real honest fixtures — D1 to D5, F14, F15 -The provenance pair is a real conversation with a real revisioned workpiece and a real constructed net, produced by persona interviews against the production agent. The Mission 6 prepared fixture remains a viability proof and is not promoted (A3). +The provenance pair is a real conversation with a real revisioned workpiece and a real constructed net, produced by persona interviews against the production agent. The Mission 6 prepared fixture stays a viability proof. ```text -persona run (Pi harness, production ChatAgent, real-headless host) - → Flue store holds the genuine conversation, revisions, mutations - → harness retains snapshot.json + projections per settled read - → grade coverage against the hidden oracle ledger afterwards - → ??? → live fixture the demo opens (D3, open) +probe: one tiny genuine conversation → export or retain → relocate → reopen → authorize → query (F14, first) +then: persona runs (Pi harness, production ChatAgent, real-headless host), several cases in parallel + → Flue store holds conversation, revisions, mutations with basis, transition records + → harness retains snapshot.json + projections per settled read + → frozen element inventory and consequential rule; frozen behavioural discriminator + → grade coverage against the hidden oracle ledger afterwards ``` -Settled: run several cases in parallel; six cases exist. Recommended: a turn cap larger than the 6–10 used so far as budget, early stop when Brunch itself declares construction handoff or delivery, ledger coverage as the post-hoc grade rather than the stop rule (D4); runs go to construction so the fixture contains lineage, which sequences the carrier fix and tool admission before the construction campaign, with an earlier elicitation-only campaign to measure revision cadence (D5). +Stop rule: a turn cap as budget, early stop when Brunch declares construction handoff, ledger coverage as the post-hoc grade (D4). Runs go to construction so the fixture contains lineage and basis (D5). + +## 6. Mission topology — F12 + +Construction and explanation ship in one mission. Its body: carrier repair, orphan retirement, `update_workpiece`, the workpiece pane, scenario-derived tool admission and teaching, declared basis and transition records, the persona programme to construction, and the why route over real lineage. Its first act is the adversarial tracer: one genuine conversation, two distinguishable passages, two mutations, one no-op or failed mutation, one correction, one hand edit, with deterministic answers or explicit refusals before any breadth. The following mission takes projection breadth, repeat and changed-input behaviour, and readiness closure. Reviewer revision follows. Local posture is named; remote durability goes to a scheduled Mission 8 or an explicit pre-handoff release gate, and "locally run," "locally verified image," and "remote replacement-safe" stay distinct claims (F15). -Open: how a retained genuine conversation becomes a live fixture in a fresh store. Keeping the dev store as shipped data, restoring genuine records through Flue's storage adapter, and replaying the snapshot as prepared signals each have a named cost in D3; the first probe is whether Flue 2.0.3 tolerates export and restore at its storage boundary. +Release wording, narrowed (C13, F5): "Ask why about any element and see the passage the constructor declared as its basis, the conversation context behind it, and who did what, or an explicit refusal." Actor identity and causal wording strengthen only as the records do. -## 6. What this changes in the mission spine +## 7. Consequences for the planning record -1. **Name the tension.** The spine states provenance-by-lineage as the current hypothesis, the typed IR and hand-authored derivation as rejected with reasons, revision cadence as the named strain, and the visible workpiece as the precondition (E1). -2. **Re-cut Mission 7.** Body: carrier fix, orphan retirement, `update_workpiece`, workpiece pane, tool admission and teaching, persona programme to construction. Last step: the why route over real lineage. Release note narrowed to the honest framing (C13). Local posture; remote durability to Mission 8 (C14). Capture-store chain and Mission 2 inherited closure dropped (E2). -3. **Adjust Missions 9 and 10.** They inherit the seam from lineage: revision id equals call id, passage identity per the probe in C15, stable element ids, document hash per C6. They no longer assume a derivation fixture or a prebuilt pair (E3). -4. **Mission 6 close report.** Record the fixture-rigging admission, the carried fenced-block-to-tool change, and the credential cause of the blocked witness (E4). -5. **Authority.** Every settled item is an owner decision expressed in conversation. It becomes authority only when written into the cut Mission 7 `MISSION.md`, with Mission 6's construction-tool constraint amended there and not in the Mission 6 tie-off (E5). +1. **Name the tension** in the spine: lineage plus declared basis as the hypothesis; typed IR and hand-authored derivation rejected with reasons; revision cadence, compaction survival, and passage identity as the named strains; the visible workpiece as the precondition. +2. **Re-cut the mission drafts**: one consolidated construction-and-explanation mission replaces the current Mission 7 and the construction half of Mission 9; the remainder of Mission 9 becomes breadth and repeat behaviour; Mission 10 inherits basis, transition records, and passage identity rather than a derivation fixture. +3. **Mission 6 close report**: fixture-rigging admission, the carried fenced-block-to-tool change, the credential cause of the blocked witness. +4. **Migration matrix** with a removal gate for any dual-read bridge (F15). +5. **Consumer discovery** with Chris and Yannis before the construction region is chosen (F15). +6. **Authority**: every settled item becomes authority only when written into the cut `MISSION.md`, with Mission 6's construction-tool constraint amended there. -## 7. Fog-line +## 8. Fog-line and probes, in order -- Revision cadence: whether the model calls `update_workpiece` often enough for blame to have grain; unmeasured (B6). -- Passage identity: heading path, Markdown anchor, or companion manifest; decided by the probe in C15. -- Carrier repair route: local interpreter versus upstream Flue support (3.5). -- Fixture materialization from a genuine conversation (D3). -- Token cost of full-document emission on long interviews, and when a structured patch earns its place. -- Which canonical tools misbehave at the provider boundary once the carrier carries fields; only observed failure scopes admission down. -- Whether the why answer over a real pair is useful to a reviewer, not merely correct; a human judges, per the Mission 7 draft's existing risk row. +1. Compaction: whether `history()` keeps folded messages; set `keepRecentTokens` low, run past threshold, read history (F4). +2. Fixture materialization: export, relocate, reopen, authorize, query one tiny genuine conversation (F14). +3. Passage identity under semantic edits (F6). +4. Carrier repair for one real nested mutation from the 3.8 subset. +5. Revision cadence: whether the model calls `update_workpiece` often enough for revisions to have grain (B6). +6. Basis quality: whether the constructor declares a usable basis unprompted, and how often it is absent. +7. Whether the why answer over a real pair is useful to a reviewer, judged by a human. +8. Token cost of full-document emission, and when a structured patch earns its place. -## 8. Questions for the independent reviewer +## 9. Questions for the next reviewer -1. Is provenance-by-lineage a sufficient answer to the stated intent, or does it smuggle an assumption the log did not check? -2. Is the tool split in 3.2 the right ownership boundary, or should one tool serve both lookups? -3. Is returning the document hash in the client-tool result an adequate join between net and workpiece revisions, given hand edits in Petrinaut? -4. Does anything in sections 3 and 4 reintroduce a mechanism the spine's rejected-mechanisms list has already refused? -5. Is the persona programme's stop rule and fixture-materialization plan honest about what a "real" fixture is? -6. Which settled items should be re-opened before they enter the Mission 7 authority, and why? +1. Does the declared basis reintroduce any rejected mechanism, or does it stay a thin creation-time relation? +2. Is the transition record the minimum that makes "not attributable" decidable? +3. Does the consolidated mission have one coherent visible advance, or does it still have too many independent failure fronts after the adversarial tracer? +4. Is the scenario-derived subset honestly derived from the cases, and is anything in it unearned? +5. Which probes, if negative, should stop the cut rather than reshape it? From fe3046589439415ea85dd133f9e26b624480250b Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 12:16:21 +0200 Subject: [PATCH 15/31] Incorporate the follow-up provenance review into the replanning record Add dispositions G1 to G22 to the decision log, revise the mini spec to its third state with the settled-revision protocol, typed basis, verifiable transition record, document reconciliation, readiness ownership, and probe decision tables, and retain the follow-up review as design evidence. Co-Authored-By: Claude Fable 5.1 --- ...nce-and-tooling-decision-log-2026-09-04.md | 48 +++ ...-by-lineage-follow-up-review-2026-09-04.md | 344 ++++++++++++++++++ ...venance-by-lineage-mini-spec-2026-09-04.md | 206 ++++++----- 3 files changed, 507 insertions(+), 91 deletions(-) create mode 100644 libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-follow-up-review-2026-09-04.md diff --git a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md index a3fe414761d..03bef48fc63 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md @@ -127,3 +127,51 @@ The [independent review](provenance-by-lineage-independent-review-2026-09-04.md) **F15. R20 to R24 accepted as additions.** Freeze the element inventory and consequential rule before grading; write the migration matrix (old history with new code, new history with old code, mixed revisions, mixed browser and server versions, Mission 6 fixture mode, retained evidence, tool manifest) with an explicit removal gate for any dual-read bridge; resolve deployment ordering explicitly rather than weakening "deployed"; do lightweight consumer discovery with Chris and Yannis before choosing the construction region; require one executable behavioural discriminator derived from the workpiece alongside human semantic review. **F16. Next sequence, merged.** (1) Adjudicate the claim as F5. (2) Paper adversarial tracer per F12. (3) Probes: compaction on `history()` (F4), export and reopen (F14), passage identity under semantic edits (F6), carrier repair for one real nested mutation from the F13 subset. (4) Correct the Flue topology model (F1) and define the transition record (F7) and operation protocol (F8). (5) Re-cut the mission topology from observed results (F12). (6) Then the persona construction campaign with frozen inventory and behavioural oracle (F15). + +## G. Dispositions after the follow-up review (same day) + +The [follow-up review](provenance-by-lineage-follow-up-review-2026-09-04.md) items are cited as S1 to S23. Its two Flue contradictions were re-verified against the installed 2.0.3 reference before disposition. Entries here supersede the F entries they name. + +**G1. S1 confirmed: a mixed tool batch does not reliably hand off to the browser.** Inspected: `@flue/runtime/docs/reference/agent-api.md`, `run` contract: "a multi-tool batch ends the turn only when every result in it terminates." The construction tools terminate; a non-terminating `update_workpiece` beside them would keep the turn alive. Consequence: `update_workpiece` and a Petrinaut mutation never share a batch. The revision protocol is: `update_workpiece` settles → the next render exposes the revision id and hash → the mutation request names that revision explicitly → the browser executes. Supersedes the sibling-call diagram in F1 and the spec. + +**G2. S2 accepted: "revision current at the request" is defined only by explicit citation.** A mutation request carries `revisionId` and `sha256` of an already-settled revision. "Latest" and sibling order are not admissible. The tool refuses a request citing an unknown or superseded revision unless the request marks the supersession as intended. + +**G3. S3 accepted: passage to evidence stays temporal unless a revision-time relation is declared.** The hop from a passage to conversation turns is labelled **conversation context temporally associated with the revision**, never "support" or "evidence for," unless `update_workpiece` carries an optional revision-time evidence relation. Decision for the cut: admit the least such relation as an optional field on `update_workpiece`, `evidence: [{ locator, messageIds[], kind }]` where kind is one of elicited, inference, default, formalism-constraint, external, correction, and where a passage carried forward unchanged inherits its prior relation. The adversarial tracer includes a carried-forward passage, non-adjacent evidence, a correction, and multi-source synthesis. Supersedes the unqualified range hop in F5. + +**G4. S4 accepted: a why query reconciles against the live document or labels its staleness.** Every why answer either acquires the current document identity and hash from the browser through the existing client-tool path before answering, or states "as of the last reconciled recorded state" with the hash it last saw. A hand edit after the last recorded transition therefore either surfaces as "not attributable" or is disclosed as unreconciled. + +**G5. S5 accepted: Mission 7 binds one conversation to one document incarnation.** The binding is recorded at fixture creation, checked on every mutation request and why query, and refused on mismatch. Cross-conversation and multi-conversation document access, and a document-scoped durable owner for shared lineage, are carried to the breadth mission with this as their re-entry gate. Inspected: `flue-routing.md` distinguishes per-conversation `usePersistentState` from cross-conversation target-document state. + +**G6. S6 and S7 accepted: actor and time claims narrow to what records carry.** Recorded roles only: "assistant tool call," "local browser executor," "prepared-fixture author (test-authored)," "user message under principal key." Human identity is reported as unknown. "When" means canonical stream order, not wall-clock time, unless a trusted timestamp is added to retained records. Inspected: `apps/brunch-agent/src/conversation/identity.ts` and `src/http/ownership.ts` carry a principal key and conversation id only. Supersedes the actor list in F5. + +**G7. S8 and S9 accepted: basis is typed, settled, and operation-level unless mapped.** Basis on a mutation request is `declared { revisionId, sha256, locators[], rationale, scope }` or `absent { reason }`. The cited revision must have settled. Construction notes are not a substitute for an absent basis. The answer labels the relation **constructor-declared**. The output distinguishes elicited evidence, constructor inference, default, formalism constraint, external source, and construction rationale. Request-level basis is **operation-level**; an actual effect without a specific intended-effect mapping is basis-absent or unanticipated and does not inherit the request's locators. Basis quality is graded for relevance, contradiction, granularity, and omitted dependencies, not presence alone. + +**G8. S10 accepted: four query semantics.** Origin (basis for the identity epoch's creation), current state (applied transitions composing the present definition), change history (all applied changes and corrections), attempt history (failed, no-op, stale, unknown requests, never causes). Element ids are never reused across identity epochs; delete and recreate opens a new epoch. + +**G9. S11 accepted: the transition record is independently verifiable.** Per call: requested base hash; independently observed pre-apply hash; canonical post-apply observation when available; mechanically derived, disjoint `created`, `updated`, `deleted`, `derived` sets; verification that those effects account for the canonical document diff; conflicting duplicate outcomes resolve to `unknown`, never winner-by-arrival; failed, no-op, stale, and unknown calls contribute only attempt history. Supersedes the "ids or definitions" alternative in F7. + +**G10. S12 accepted: external import does not launder.** An external revision records actor or unknown actor, principal, observed parent hash, canonical diff, and import reason. Every imported changed element or field keeps an `external/unsupported` disposition until a later recorded transition replaces it. Import resets continuity; it explains nothing retrospectively. + +**G11. S13 accepted: passage identity is policy first, probe second.** Predeclared invariants: passage ids are never reused after deletion; split and merge record predecessor and successor sets; ambiguous paraphrase refuses continuity; reintroduction starts a new identity unless continuity is declared; a locator resolves to an immutable revision-local span; duplicate headings and quotations are tested; an overbroad span fails basis quality when a materially narrower sufficient span exists. The F6 probe then tests ergonomics and model compliance against this policy. If the policy is too expensive, revision-local text with refused cross-revision claims remains the fallback. + +**G12. S14 accepted: fixture representativeness and on-path acceptance.** Sources are labelled synthetic-persona, internal-human, or customer-derived. Acceptance assertions run through the reopened authorized why operation the product uses; `snapshot.json` and projections are diagnostics only. At least one adversarial fixture includes duplicate wording, rejected quotations, constructor inference, a correction, and unrelated context. + +**G13. S15 accepted: the consequential rule is frozen before the run.** The inventory is generated mechanically from the final canonical document, includes every identity-bearing or behaviour-affecting entity or field the selected claim requires (parameters, scenarios, type elements, arc attributes, expressions, document-level settings, derived entities, identity epochs), receives exactly one disposition per item, and publishes numerator, denominator, and exclusions. + +**G14. S16 accepted: separate safety and utility gates.** Safety: no false attribution and correct required refusals. Utility: a predeclared nonzero proportion of consequential elements yields usable current-state answers, with minimum coverage across the selected entity classes, judged by a blinded reviewer task with a fixed rubric: identify the governing passage, distinguish elicited evidence from constructor inference, understand the current definition and latest correction, and decide whether the answer changes the review judgement. + +**G15. S17 accepted: "scenario-selected operations with canonically derived schemas."** Admission is interpretive; schemas are mechanical. Corrections to F13: "move element" is removed; metrics are conditional, admitted only when the proving scenario names a measurable objective that Petrinaut's `Metric` entity can express, because the Vestera case names scheduling objectives and prohibits invented weights but does not entail executable metrics. Each admitted class cites the case requirement it discharges. Breadth follows the selected proving scenario, not all six cases. + +**G16. S18 accepted: the consolidated mission closes the readiness of its own claim.** Mission 7's contract stratum is named and its identity, failure, durability, basis-quality, current-state, and oracle obligations close inside it. Only breadth first made load-bearing by the following visible advance (repeat, changed input, deletion and retirement, concurrent change, cross-conversation document access, broader schema classes) moves to Mission 9. Supersedes the readiness split wording in F12. The workpiece pane is an internal enabling surface inside Mission 7, not a second release claim. + +**G17. S19 accepted: every probe carries a decision table.** Pass continues under the named claim; partial narrows the claim or changes the mechanism; fail stops the cut or splits predecessor work; re-entry names the evidence to reopen the rejected route. The tables live in the Mission 7 draft. + +**G18. S20 decided: probes run under an initially narrow Mission 7 authority with an owner gate before amendment into construction breadth.** Rejected: a side quest under Mission 6 (Mission 6 is closing and the probes are not residual Mission 6 failures) and a separate probe mission (ceremony without a visible advance). The narrow first authority names the adversarial tracer and the four probes as its throughline; the owner gate is the readiness decision that admits the construction and explanation body. + +**G19. S21 accepted: a planning-content migration matrix accompanies the spine recut.** Every old hypothesis, accepted decision, rejected alternative, oracle gap, deferred item, and readiness obligation maps to exactly one surviving destination; the matrix lives in `MISSION.next.md`. + +**G20. S22 accepted: archive lane distinguished from capture semantics.** Three things are kept apart: capture envelopes and sweep semantics (rejected for Mission 7 provenance); the existing session-log archive in `binding-flue/src/history-reader.ts` and the capture storage contract's archive slot (an existing lane that may be hardened if the compaction probe is negative); and any new immutable lineage projection actually required by compaction, relocation, or authorization. Supersedes the F4 re-entry wording. + +**G21. S23 accepted: Mission 11's readiness is three distinct gates.** Consumer contract acceptance; a working handoff throughline; post-throughline readiness closure sufficient to begin the experiment without reconstruction. Artifact receipt is not an executable witnessed experiment start. + +**G22. Next sequence, merged and final for this replanning.** (1) Recut the planning record with the migration matrix (G19). (2) Cut a narrow Mission 7 authority whose throughline is the adversarial tracer and the four probes with decision tables (G17, G18). (3) On pass, owner gate amends the authority to the construction and explanation body with its own readiness closure (G16). (4) Mission 9 takes breadth; Mission 10 inherits basis, transition records, and passage policy; Mission 11 gains early consumer discovery and three-gate readiness (G21). diff --git a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-follow-up-review-2026-09-04.md b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-follow-up-review-2026-09-04.md new file mode 100644 index 00000000000..6a7bab42d77 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-follow-up-review-2026-09-04.md @@ -0,0 +1,344 @@ +# Follow-up review of provenance-by-lineage replanning — 2026-09-04 + +> Review evidence, not execution authority. This document evaluates the revised [`provenance-and-tooling-decision-log-2026-09-04.md`](provenance-and-tooling-decision-log-2026-09-04.md) and [`provenance-by-lineage-mini-spec-2026-09-04.md`](provenance-by-lineage-mini-spec-2026-09-04.md) after dispositions F1–F16. It focuses on gaps that remain after the first [`independent review`](provenance-by-lineage-independent-review-2026-09-04.md), using checked-out code, installed Flue 2.0.3 documentation, the canonical future-planning record, and three additional adversarial reviews. It changes no owner-settled policy and authorizes no implementation. + +## Executive verdict + +The revised design is materially stronger. First-class workpiece revisions, constructor-declared mutation basis, canonical mutation transition records, explicit refusal under incomplete lineage, schema-carrier repair before construction breadth, and a genuine production-path fixture are sound directions. The revision correctly stopped treating temporal adjacency alone as causal provenance. + +The design is not ready to become Mission 7 authority. Two concrete Flue contradictions make the depicted update-and-mutate path unreliable, and several remaining semantic gaps permit complete-looking lineage to overstate what the records establish. Strategically, the consolidated mission cannot defer readiness closure for its own visible claim, and the required probes currently have neither result-conditioned stop branches nor an unambiguous execution-authority home. + +The most important correction is to treat the design as four distinct contracts: + +1. **Revision protocol:** a workpiece revision settles and becomes addressable before a mutation can cite it. +2. **Provenance semantics:** mutation basis, passage evidence, element origin, current-state history, and actor identity are distinct relations. +3. **Document reconciliation:** the current live Petrinaut state is compared with recorded transitions before provenance is reported. +4. **Mission readiness:** M7 closes the safety and utility obligations required by its own construction-and-explanation claim; only breadth first made load-bearing by the following visible advance moves later. + +## Critical factual and semantic gaps + +### 1. The depicted mixed tool batch will not reliably produce the browser handoff + +The mini spec depicts `update_workpiece` and a Petrinaut mutation as sibling calls in one assistant turn, followed by a separate `client-tool-result` submission: + +```text +assistant turn T1 + ├─ update_workpiece {markdown} + └─ addArc {…, basis} +submission S2 + system dispatch client-tool-result +``` + +The current Petrinaut client tools return `{ awaiting: "client" }` with `terminate: true` in [`packages/plugin-sdcpn/src/tools/petrinaut-construction.ts`](../../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts). The proposed `update_workpiece` specifies `durable: true` but does not specify termination. Flue 2.0.3 documents that a multi-tool batch ends the turn only when every result terminates. A non-terminating workpiece result alongside a terminating browser tool therefore does not guarantee the depicted handoff. + +**Required correction:** prohibit the mixed batch or define termination behavior that preserves the browser handoff. The safer contract is a completed workpiece update followed by mutation in a later render. + +### 2. “Revision current at the request” is undefined when update and mutation are sibling calls + +The mini spec says the mutation basis locates passages in “the workpiece revision current at the request,” while the topology makes the update and mutation siblings. Flue runs calls in one batch in parallel; persistent-state reads are render-time snapshots, writes do not cause a mid-run re-render, and the writes commit with the batch. Assistant-part order is therefore not a dependable state order. + +The mutation cannot reliably regard the sibling `update_workpiece` as current, and a model cannot name the new update call’s generated call ID before the call settles. + +**Required protocol:** + +```text +update_workpiece settles +→ next render exposes revisionId and sha256 +→ mutation request explicitly names that revisionId and sha256 +→ browser mutation executes +``` + +A mutation must cite an already-settled revision explicitly; “latest” or sibling order is insufficient. + +### 3. Declared basis repairs mutation → passage, but passage → evidence remains temporal + +F5 adds the missing mutation-to-passage declaration. The next hop still resolves a passage to “turns between it and the previous revision.” That range does not establish the evidence for a passage that: + +- survives unchanged from an older revision; +- synthesizes several non-adjacent ranges; +- reuses earlier evidence; +- incorporates a correction or qualification; +- records constructor inference, a default, an external source, or a formalism constraint. + +The design can honestly call this range **conversation context temporally associated with the revision**. It cannot call the range support for the passage without another relation. + +**Required decision:** either add the least revision-time passage-to-evidence relation, including multiple and inherited ranges, or consistently label this hop as temporal context rather than evidence or support. The adversarial tracer should include a carried-forward passage, non-adjacent evidence, a correction, and multi-source synthesis. + +### 4. Current-state provenance cannot be checked from history alone + +The adversarial tracer includes one hand edit, and the visible operation asks why an element in the current net exists. A transition history can establish the last reconciled recorded state, but a hand edit after the last recorded mutation leaves no Flue record. The server-side why resolver therefore cannot discover that the current element differs from its last attributable state unless it obtains a fresh observation from the browser. + +**Required decision:** every why query either: + +- acquires and reconciles the live document identity and hash before answering; or +- says explicitly that the answer is “as of the last reconciled recorded state.” + +Without this, a hand-edited element can receive stale but apparently authoritative provenance. + +### 5. Per-conversation workpiece state does not settle target-document ownership + +`usePersistentState` is per conversation. The current workpiece and mutation lineage concern a Petrinaut target document, which may be reopened, copied, reviewed from another conversation, or targeted by more than one conversation owned by the same principal. The design does not define the binding among conversation identity/incarnation, document identity/incarnation, and current workpiece revision. + +The repository’s [`Flue routing guidance`](../../reference/architecture/flue-routing.md) explicitly distinguishes per-conversation state from cross-conversation target-document state. + +**Required decision:** either constrain M7 to an immutable one-conversation ↔ one-document-incarnation binding or place shared current-workpiece and lineage indexes behind a document-scoped durable owner. A single-principal limit does not solve multiple conversations owned by that principal. + +### 6. “Who did what” has no implementable identity source + +The mini spec promises separate workpiece author, evidence actor, requesting principal, and mutation actor. The proposed records do not contain trusted values for those identities: + +- workpiece state contains call ID, hash, revision, and Markdown; +- the transition record contains document/hash/outcome/effects; +- the current client-result envelope contains call ID, tool name, and output; +- Flue message roles are not human identity, and agent-authored metadata is not authenticated identity. + +F11’s single-principal limitation narrows authorization but does not establish who spoke quoted material or which human or browser actor applied a mutation. + +**Required correction:** define the trusted source and persistence rule for each actor field, including restored fixtures, or narrow the release wording to recorded roles such as “assistant tool call” and “local browser executor,” with human identity explicitly unknown. + +### 7. “When” currently means stream order, not wall-clock time + +The intent defines lineage as who changed what, in response to what, when. The supported Flue snapshot and Brunch history projection provide canonical message order, message IDs, submission IDs, and optional turn IDs, but no authenticated operation timestamp. + +**Required correction:** say **in what canonical stream order** unless a trusted timestamp source is added to retained revision and transition records. + +## Provenance quality and Goodhart risks + +### 8. Declared basis can become circular provenance laundering + +The constructor authors both the workpiece and the basis relation. Under the current wording it may decide on a mutation, write a convenient Construction note, cite that note as the mutation’s basis, and present the cycle as provenance. A locator plus one-line rationale proves that the constructor asserted a relation; it does not prove relevance, compatibility, or evidentiary support. + +The escape saying a mutation without basis may be justified in Construction notes compounds the problem. + +**Minimum correction:** + +```text +basis = + | declared { revisionId, locators, rationale, scope } + | absent { reason } +``` + +Additionally: + +- the cited revision must already have settled; +- Construction notes are not a substitute for absent basis; +- the answer visibly labels the relation **constructor-declared**; +- the output distinguishes elicited evidence, constructor inference, default, formalism constraint, external source, and construction rationale; +- basis quality is graded for relevance, contradiction, granularity, and omitted dependencies, not only presence and readability. + +### 9. Request-level basis does not establish element-level basis + +One mutation can affect several explicit or derived elements, while the request carries one undifferentiated set of locators. Assigning every locator to every actual effect overstates provenance for batches, cascaded deletes, layout, generated entities, and unexpected side effects. + +**Required correction:** either carry an intended-effect-to-locator mapping or label the relation as **operation-level basis** only. An actual effect without a specific mapping is basis-absent or unanticipated; it does not inherit all request locators. + +### 10. Origin, current state, change history, and attempt history are conflated + +The resolver privileges the creating request, but after corrections the creation basis may explain an obsolete definition rather than the current element. Delete-and-recreate is more dangerous if an ID is reused. + +Define separate query semantics: + +- **origin:** basis for the identity epoch’s creation; +- **current state:** applied transitions whose effects compose the present definition; +- **change history:** all applied changes and corrections; +- **attempt history:** failed, no-op, stale, and unknown requests, never treated as causes. + +Element IDs must not be silently reused across identity epochs. + +### 11. The transition record permits unverifiable self-report + +The current proposal accepts affected element IDs **or** retained pre/post definitions. The first option lets the browser self-report a favorable affected set without enough evidence to prove that it accounts for the canonical document diff. An expected base hash can also merely echo the request rather than prove which base the browser observed. + +The outcome shape is internally strained as well: an `unknown` outcome cannot always have a confirmed post hash. + +**Safer minimum:** + +- requested base hash; +- independently observed pre-apply hash; +- canonical post-apply observation when available; +- mechanically derived, disjoint `created`, `updated`, `deleted`, and `derived` sets; +- verification that those effects account for the canonical document diff; +- conflicting duplicate outcomes resolve to `unknown`, never winner-by-arrival; +- failed, no-op, stale, and unknown calls contribute only attempt history. + +### 12. External import can wash away unexplained provenance + +The design permits provenance to resume after an explicit external revision is imported. A permissive import could make an unexplained current state the new clean baseline, erasing which elements or fields remain externally sourced. + +**Required correction:** an external revision records actor or unknown actor, principal, observed parent hash, canonical diff, and import reason. Every imported changed element or field retains an `external/unsupported` disposition until a later recorded transition replaces it. Import resets continuity; it does not explain imported content retrospectively. + +### 13. Passage identity is partly policy, not terrain discoverable by probe + +A probe can test whether a locator remains syntactically usable. It cannot decide whether a paraphrase preserves identity. Split, merge, deletion, and reintroduction require explicit lineage policy. An anchor can mechanically survive while denoting materially different meaning, and a whole-section locator can make every basis superficially stable. + +Predeclare the invariants: + +- passage IDs are never reused after deletion; +- split and merge record predecessor and successor sets; +- ambiguous paraphrase refuses continuity; +- reintroduction starts a new identity unless continuity is explicitly declared; +- a locator resolves to an immutable revision-local span; +- duplicate headings and quotations are tested; +- an overbroad span fails basis quality when a materially narrower sufficient span exists. + +If these semantics are too expensive, retain revision-local passage text and refuse cross-revision “introduced by” claims as F6 permits. + +### 14. A genuine fixture can still be unrepresentative or accepted off-path + +A synthetic persona can produce a genuine production-agent run with short, unique wording that makes provenance trivial. That proves the path, not performance on messy human conversation. Acceptance can also drift toward inspecting retained `snapshot.json` projections rather than exercising the reopened authorized product query. + +**Required correction:** + +- label sources as synthetic-persona, internal-human, or customer-derived; +- run acceptance assertions through the same reopened authorized why operation used by the product; +- treat snapshots and projections as diagnostics only; +- include duplicate wording, rejected quotations, constructor inference, correction, and unrelated context in at least one adversarial fixture. + +### 15. The consequential inventory can be gamed after generation + +Freezing the element inventory before grading still permits defining “consequential” after inspecting the generated artifact. Parameters, scenarios, type elements, arc attributes, expressions, document-level settings, derived entities, and deleted/recreated identity epochs can be excluded by a favorable rule. + +**Required correction:** freeze the consequential rule before the run, generate the inventory mechanically from the final canonical document, include every identity-bearing or behavior-affecting entity or field required by the selected claim, and assign exactly one disposition to every inventory item. Publish numerator, denominator, and exclusions. + +### 16. Refusal safety can satisfy the contract while destroying utility + +“Deterministic answer or explicit refusal” is a safety contract. An implementation that refuses every difficult query can satisfy the literal wording while providing no reviewer value. Basis absence has no threshold, and “judged by a human” has no fixed task or rubric. + +Separate two gates: + +1. **Safety:** no false attribution; required refusals are correct. +2. **Utility:** a predeclared nonzero proportion of consequential elements yields usable current-state answers, with minimum coverage across selected entity classes. + +Use a blinded reviewer task and a fixed rubric: can the reviewer identify the governing passage, distinguish elicited evidence from constructor inference, understand the current definition and latest correction, and decide whether the answer changes their review judgment? + +## Tool-admission factual gaps + +### 17. The subset is scenario-selected, not mechanically derived from scenario requirements + +Petrinaut schemas can be mechanically sourced from the canonical AI bundle. The choice of entity classes from natural-language cases is interpretive. The mini spec should say **scenario-selected operations with canonically derived schemas**, not that admission itself is mechanically generated. + +Two concrete discrepancies remain: + +- F13 lists add/update/remove for type elements, while the mini spec additionally admits “move element.” +- F13 says Vestera names metrics, but the Vestera case and oracle describe scheduling objectives and prohibit invented numerical objective weights; they do not clearly require Petrinaut executable `Metric` entities. A natural-language objective does not mechanically entail the formalism’s metric class. + +Remove unearned classes or cite the exact case requirement and Petrinaut operation each class discharges. Tool breadth should follow the selected mission scenario and observed need, even if the later persona programme spans six cases. + +## Strategic mission and planning gaps + +### 18. M7 cannot defer readiness closure for its own visible claim + +F12 says construction and explanation ship together while the following mission takes projection breadth, repeat and changed-input behavior, and readiness closure. This conflicts with [`AGENTS.md`](../../../AGENTS.md): the mission making a visible claim performs its readiness decision and closes the obligations required to trust that claim. A provisional line cannot silently become the following mission’s hardened departure base. + +The consolidated M7 also contains two product-manager-visible advances: the workpiece pane is called an advance in its own right, while construction-and-explanation is the mission release. + +**Required decision:** name M7’s exact contract stratum and close every identity, failure, durability, basis-quality, current-state, and oracle obligation required for its construction-and-explanation claim. Move only breadth first made load-bearing by the following visible advance into M9. + +### 19. The probe sequence lacks result-conditioned stop and reorientation branches + +The mini spec lists compaction, relocation, passage identity, carrier repair, revision cadence, basis quality, reviewer usefulness, and token-cost probes, but F16 orders them and then proceeds toward recutting and the persona campaign. It does not say what each negative result changes. + +Before cutting authority, give every probe a decision table: + +| Result | Consequence | +| --- | --- | +| Pass | Continue under the named claim | +| Partial | Narrow the claim or change the mechanism | +| Fail | Stop the cut or split predecessor work | +| Re-entry | Evidence required to reopen the rejected route | + +At minimum: + +- persistent unusable basis or reviewer-useless why answers stop the explainability claim; +- no supported relocation blocks the retained-live-fixture route and forces an explicitly labelled alternative; +- no passage-continuity policy narrows the release to revision-local text; +- carrier failure produces a crisp upstream blocker rather than a local schema copy; +- sparse revision cadence changes the blame claim or update interaction before persona breadth. + +### 20. F16’s executable probes have no unambiguous authority home + +F16 places probes before mission topology is recut, while the mini spec calls the adversarial tracer the first act inside the consolidated mission. Under the one-live-mission rule, executable probes still need authority. + +Choose explicitly among: + +- a bounded owner-authorized side quest under M6; +- a separate probe mission; +- an initially narrow M7 authority with an owner gate before amendment into construction breadth. + +Do not leave implementation-relevant probes in design evidence with no lawful execution home. + +### 21. The canonical future record still embodies the superseded topology + +The current planning record still says: + +- M7 is capture-backed review over a prepared pair; +- M9 is where automatic projection begins; +- Draft M7 requires a hand-authored derivation fixture; +- Draft M9 inherits a Mission 7 prebuilt pair and retains the obsolete same-turn client-result wording; +- Draft M10 still depends on the old capture/derivation seam. + +F15’s migration matrix concerns runtime and persisted-data compatibility. A separate **planning-content migration matrix** is needed to satisfy the one-authoritative-home and no-silent-loss rules. + +Before promotion, map every old hypothesis, accepted decision, rejected alternative, oracle gap, deferred item, and readiness obligation to exactly one surviving destination. Then update `MISSION.next.md` and drafts atomically, remove consumed drafts under the lifecycle rules, and compare before/after planning content for unexplained loss or duplication. + +### 22. Existing archival machinery is conflated with the rejected capture semantics + +The decision documents often speak of the capture store as though re-entry means reviving one-envelope-per-user semantic capture. The current binding already archives materialized Flue history through [`packages/binding-flue/src/history-reader.ts`](../../../packages/binding-flue/src/history-reader.ts) and the capture storage contract’s session-log archive. If the compaction probe is negative, the least response may be to harden or reposition that existing archive lane rather than revive sweep envelopes or invent a third log. + +The recut should distinguish: + +- capture envelopes and sweep semantics, which are rejected for M7 provenance; +- the existing session-log archive capability; +- any new immutable lineage projection actually required by compaction, relocation, or authorization. + +### 23. Mission 11 still has a circular readiness statement + +Draft M11 says the first accepted handoff is also the completion bar because consumer acceptance is the readiness decision, then says lateral package, transfer, execution, result, credibility, repeatability, access, and retention obligations are enumerated after the handoff works. + +Distinguish: + +1. consumer contract acceptance; +2. working handoff throughline; +3. post-throughline readiness closure sufficient to begin the experiment without reconstruction. + +Consumer enthusiasm or artifact receipt is not the same as an executable witnessed experiment start. + +## Recommended decision sequence before cutting Mission 7 + +1. **Correct the Flue protocol.** Require a settled `update_workpiece` revision before mutation; prohibit ambiguous mixed batching and bind every mutation to an explicit revision ID and hash. +2. **Settle document ownership and reconciliation.** Define conversation ↔ document-incarnation binding, observed pre-state, current-state checks for why queries, and external-import continuity. +3. **Separate provenance relations.** Distinguish operation basis, element basis, passage evidence, origin, current-state changes, attempts, and actor roles or identities. +4. **Define passage identity policy.** State invariants and refusal cases before using edit probes to test ergonomics and model compliance. +5. **Make effects independently verifiable.** Derive canonical effects from observed pre/post state and fail conflicting or unknown outcomes closed. +6. **Narrow tool admission.** Select classes from the actual proving scenario, mechanically source their schemas from Petrinaut, and remove metrics or movement operations unless exact case evidence earns them. +7. **Freeze safety and utility gates.** Predeclare the consequential rule, mechanical inventory, required dispositions, minimum useful coverage, reviewer task, and behavioral discriminator. +8. **Attach stop branches and authority to probes.** Decide where executable probes live and what each result permits, reshapes, or stops. +9. **Define M7’s own readiness stratum.** Do not defer trustworthiness of the construction-and-explanation release to M9. +10. **Perform a lossless planning migration.** Recut `MISSION.next.md` and drafts 7/9/10/11 only after the observed probe results, with one surviving home for every obligation. + +## Evidence consulted + +- [`provenance-and-tooling-decision-log-2026-09-04.md`](provenance-and-tooling-decision-log-2026-09-04.md) +- [`provenance-by-lineage-mini-spec-2026-09-04.md`](provenance-by-lineage-mini-spec-2026-09-04.md) +- [`provenance-by-lineage-independent-review-2026-09-04.md`](provenance-by-lineage-independent-review-2026-09-04.md) +- [`../../../AGENTS.md`](../../../AGENTS.md) +- [`../../../MISSION.next.md`](../../../MISSION.next.md) +- [`../../mission-drafts/7-capture-backed-review.md`](../../mission-drafts/7-capture-backed-review.md) +- [`../../mission-drafts/9-traceable-projection.md`](../../mission-drafts/9-traceable-projection.md) +- [`../../mission-drafts/10-bounded-reviewer-revision.md`](../../mission-drafts/10-bounded-reviewer-revision.md) +- [`../../mission-drafts/11-optimisation-handoff.md`](../../mission-drafts/11-optimisation-handoff.md) +- [`../../reference/architecture/flue-routing.md`](../../reference/architecture/flue-routing.md) +- [`../../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts`](../../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts) +- [`../../../packages/core/src/workpiece.ts`](../../../packages/core/src/workpiece.ts) +- [`../../../packages/core/src/evidence/capture-store.ts`](../../../packages/core/src/evidence/capture-store.ts) +- [`../../../packages/binding-flue/src/history-reader.ts`](../../../packages/binding-flue/src/history-reader.ts) +- [`../../../packages/transport-aisdk/src/client-tool-history.ts`](../../../packages/transport-aisdk/src/client-tool-history.ts) +- [`../../../../../../apps/brunch-agent/src/conversation/identity.ts`](../../../../../../apps/brunch-agent/src/conversation/identity.ts) +- [`../../../../../../apps/brunch-agent/src/http/ownership.ts`](../../../../../../apps/brunch-agent/src/http/ownership.ts) +- installed Flue 2.0.3 documentation under `node_modules/@flue/runtime/docs/reference/`, especially `agent-api.md`, `agent-behavior.md`, `agent-hooks-api.md`, and `streaming-protocol.md` +- Vestera case and oracle under `evaluations/cases/vestera-scheduling/` and `evaluations/oracles/vestera-scheduling/` +- Petrinaut metric schema under `libs/@hashintel/petrinaut-core/src/schemas/metric-schema.ts` + +## Review disposition + +Do not discard the lineage design. Its useful core is a visible revisioned workpiece, constructor-declared relations, and verifiable document transitions over a real production conversation. Before mission authority is cut, make revision ordering explicit, separate declaration from evidence, reconcile against current document state, and define M7’s own safety and utility readiness gates. The next design move should remove ambiguity from the protocol and claim, not add a broader provenance platform. diff --git a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md index de71a6aad98..77d77b740e2 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md @@ -1,170 +1,194 @@ -# Provenance by lineage with declared basis — mini spec, 2026-09-04 (revised) +# Provenance by lineage with declared basis — mini spec, 2026-09-04 (third state) -> Design evidence, not execution authority. This document projects the [decision log of 2026-09-04](provenance-and-tooling-decision-log-2026-09-04.md), including its post-review dispositions (F1 to F16), into one reviewable statement of intent, design, and consequences for the Brunch mission spine. It was revised the same day after the [independent review](provenance-by-lineage-independent-review-2026-09-04.md); the revision corrects the turn topology, the hook pattern, and the claim strength, adds the declared basis, the mutation transition record, and the operation protocol, consolidates the construction and explanation missions, and enumerates the scenario-derived tool subset. Nothing here may be implemented until it is re-evaluated and cut into a live `MISSION.md`. +> Design evidence, not execution authority. This document projects the [decision log of 2026-09-04](provenance-and-tooling-decision-log-2026-09-04.md), including dispositions F1 to F16 and G1 to G22, into one reviewable statement of intent, design, and consequences for the Brunch mission spine. Two review passes shaped it: the [independent review](provenance-by-lineage-independent-review-2026-09-04.md) corrected the turn topology, hook pattern, and claim strength and added the declared basis and transition record; the [follow-up review](provenance-by-lineage-follow-up-review-2026-09-04.md) corrected the revision protocol, separated the provenance relations, added document reconciliation and readiness ownership, and hardened the gates. Nothing here may be implemented until it is re-evaluated and cut into a live `MISSION.md`; the planning projection is the Mission 7 draft. ## 1. Intent -Brunch must be able to say, for any consequential element of a Petri net it helped build, what it rests on: the workpiece passage the constructor declared as its basis, the revision that carried that passage, the conversation context behind that revision, and who did what, or an honest refusal. It must do this without a comprehensive typed domain model, without a second conversation log, and without anyone hand-authoring links after the fact. +Brunch must be able to say, for any consequential element of a Petri net it helped build, what it rests on: the workpiece passage the constructor declared as its basis, the settled revision that carried that passage, the conversation context associated with that revision and, where declared, the evidence relation behind the passage, and the recorded roles that did each thing, or an honest refusal. It must do this without a comprehensive typed domain model, without a second conversation log, and without anyone authoring links after the fact. Two earlier approaches failed in opposite directions. A comprehensive typed intermediate representation tried to make provenance a property of the domain model; the typology receded as it grew and the model worked worse with it. The structural Markdown workpiece that replaced it is legible and cheap but has no seam to either the conversation or the net, and provenance was deferred without the tension being named in the planning record. -The resolving observation, as corrected by review: provenance has two parts. **Lineage** is who changed what, in response to what, when; it is recoverable from Flue's append-only log once workpiece revisions and net mutations are tool calls. **Basis** is why an element exists; it is not in the log unless the actor who knows declares it at the moment they know. The design therefore combines recovered lineage with a declared basis, and says plainly which of the two any given answer rests on (F5). +The corrected resolution treats provenance as four distinct contracts, none of which is inferred from the others: + +1. **Revision protocol.** A workpiece revision settles and becomes addressable before any mutation can cite it. +2. **Provenance semantics.** Mutation basis, passage evidence, element origin, current-state history, attempt history, and recorded actor roles are distinct relations, each with its own source. +3. **Document reconciliation.** The live Petrinaut state is compared with recorded transitions before provenance is reported. +4. **Mission readiness.** The mission making the construction-and-explanation claim closes the safety and utility obligations that claim depends on; only breadth first made load-bearing by the next visible advance moves later. ## 2. The lineage model, as the log actually records it ```text -submission S1 user message (submissionId S1, no turnId) - assistant turn T1 (turnId T1) - ├─ update_workpiece {markdown} revision R, identity = callId - ├─ tool result {revision, sha256} - └─ addArc {…, basis} request; server output = awaiting client - state_write workpiece = {callId, sha256, revision, markdown} -submission S2 system dispatch client-tool-result [{toolCallId, output}] (may repeat earlier ids) - assistant turn T2 continuation +submission S1 user message (submissionId S1, no turnId) + assistant turn T1 + ├─ update_workpiece { markdown, evidence? } revision R: identity = callId, sha256 + └─ tool result { revisionId, sha256, revision } + state_write workpiece = { revisionId, sha256, revision, markdown } +submission S2 user message or continuation + assistant turn T2 (render exposes revision R from state) + └─ addArc { …, basis: declared{ revisionId R, sha256, locators, rationale, scope } } + server output = awaiting client; turn terminates +submission S3 system dispatch client-tool-result [{ toolCallId, output: transition record }] + assistant turn T3 continuation ``` -Correlation is by `toolCallId` plus submission order; a shared turn id between the request and the browser result does not exist (F1). The lineage reader deduplicates cumulative result signals by call id. +Rules the diagram encodes: + +- `update_workpiece` and a Petrinaut mutation never share a tool batch, because a batch ends the turn only when every result terminates and construction tools terminate (G1). +- A mutation cites a settled revision by id and hash; "latest" and sibling order are inadmissible (G2). +- Correlation is by `toolCallId` plus submission order; cumulative result signals repeat earlier ids and are deduplicated (F1). +- "When" means canonical stream order (G6). -Resolution walks from an element: +Resolution from an element, with the relation each hop actually is: ```text element id - → mutation transition records naming it (created, changed, deleted; F7) - → the declared basis on the creating request passage locator(s) + rationale (F5) - ├─ present: the passage in the revision current at that request - └─ absent: the revision current at that request, and a temporal range, marked as such - → the conversation context behind that revision turns between it and the previous revision - └─ verbatim quote where the passage quotes; reported as string occurrence, not endorsement - → actors reported separately: workpiece author, evidence actor, requesting principal, mutation actor + → identity epoch, then transition records naming it origin | current state | change history | attempt history (G8, G9) + → operation-level basis on the creating and changing calls constructor-declared, or absent{reason} (G7) + └─ mapped to this element only if an intended-effect mapping names it; else operation-level only + → the locator's immutable span in the cited settled revision passage (G11) + → declared evidence relation on that revision, if any elicited | inference | default | formalism | external | correction (G3) + └─ otherwise: conversation context temporally associated with the revision, labelled as such + → recorded roles assistant tool call · local browser executor · user under principal · test-authored fixture (G6) + → live document reconciliation current hash matches last reconciled state, or answer is labelled "as of …" (G4) ``` -What the model does: it calls the tools and interprets structured results in prose. What it may not do: author a basis after the fact, reread the transcript as provenance, or explain an element the tools mark unsupported or not attributable (C3, F7). +What the model does: it calls the lookup tools and interprets structured results in prose. What it may not do: author a basis after the fact, promote temporal context to evidence, reread the transcript as provenance, or explain an element the records mark unsupported, not attributable, or external (C3, G7, G10). ## 3. Mechanisms -### 3.1 `update_workpiece` (core, server-side) — C4, F2, F10 +### 3.1 `update_workpiece` (core, server-side) — C4, F2, F10, G1, G3 | Aspect | Decision | | --- | --- | -| Input | one Markdown string, the full current workpiece | -| Hook pattern | `usePersistentState('workpiece', …)` called at render; its setter captured in the tool closure; called from `run`, which receives `toolCallId` | -| State value | `{ callId, sha256, revision, markdown }`, written with the updater form so the revision number composes; the Markdown is in state so the agent always has its current workpiece at render regardless of compaction | -| Validation | core checks non-empty and size; template conformance is plugin participation | -| Durability | `durable: true` protects the server tool attempt only | +| Input | `markdown` (full document) and optional `evidence: [{ locator, messageIds[], kind }]` | +| Hook pattern | `usePersistentState('workpiece', …)` at render; setter captured in the tool closure; called from `run`, which receives `toolCallId` | +| State value | `{ revisionId, sha256, revision, markdown }`, updater form; the Markdown lives in state so the agent has its current workpiece at render regardless of compaction | +| Output | `{ revisionId, sha256, revision }`; the model must use these in later basis declarations | +| Termination | non-terminating; never batched with a terminating construction tool | +| Validation | core: non-empty, size; plugin: template conformance | +| Durability | `durable: true`, server attempt only | | Ownership | core owns the tool; plugins own the template | -| Replaces | the fenced `runbook-ir` block in assistant text; the prepared-signal route stays for test-authored revision zero | -Costs acknowledged: the full document crosses the wire each revision and is written twice, as tool input and as state; a structured-patch input is the later absorber. A model may call a tool less readily than it emits text; cadence is unmeasured either way (B6). +The fenced `runbook-ir` block is retired as the model-produced revision source. The prepared-signal route stays for test-authored revision zero, tagged as such. + +### 3.2 Declared basis on mutation requests — F5, G2, G7 -### 3.2 Declared basis on mutation requests — F5 +```text +basis = + | declared { revisionId, sha256, locators: [span], rationale, scope: operation | { intendedEffects: [{ elementId, locators }] } } + | absent { reason } +``` -Every construction request carries `basis`: one or more passage locators into the workpiece revision current at the request, plus a one-line rationale. The plugin strips `basis` before forwarding the canonical input to Petrinaut, so Petrinaut's contract is unchanged, and the full request with basis is retained in the log as the tool-call input. The skill teaches that a mutation without a basis is a mutation the model must justify in Construction notes or not make. Passage locator form is decided by the probe in 3.7. +The cited revision must have settled and match the current state pointer unless supersession is marked intended. Construction notes are not a substitute for an absent basis. The plugin strips `basis` before forwarding the canonical input to Petrinaut, so Petrinaut's contract is unchanged, and the full request is retained in the log as the tool-call input. Basis quality is graded for relevance, contradiction, granularity, and omitted dependencies. -### 3.3 Mutation transition record and operation protocol — F7, F8 +### 3.3 Mutation transition record and operation protocol — F7, F8, G4, G5, G9, G10 -The browser returns, per call: document identity, expected base hash, outcome (applied, no-op, failed, stale, unknown), confirmed post hash, and affected element ids or retained pre and post definitions. One authoritative result per call; a duplicate rule for repeated signals. The workpiece update and the browser mutation are separate boundaries, so the protocol is: +The browser returns one authoritative transition record per call: ```text -requested(callId, documentId, baseHash, workpieceRevision, basis) - → outcome(applied | no-op | failed | stale | unknown, postHash, effects) - → reconciled | incomplete | unknown +{ toolCallId, documentId, documentIncarnation, + requestedBaseHash, observedPreHash, postHash?, + outcome: applied | no-op | failed | stale | unknown, + effects: { created[], updated[], deleted[], derived[] } disjoint, mechanically derived from pre/post + diffAccounted: boolean } ``` -A document transition no record explains is "not attributable from recorded transitions"; provenance for the affected state is refused until an explicit external revision is imported. No Petrinaut schema change is needed; the wrapper has no provenance slot and none is added (F3). +Protocol: `requested → outcome → reconciled | incomplete | unknown`. Conflicting duplicate outcomes resolve to `unknown`. Failed, no-op, stale, and unknown calls contribute only attempt history. Mission 7 binds one conversation to one document incarnation, recorded at fixture creation and checked on every mutation and why query (G5). A document hash no record explains is "not attributable from recorded transitions"; an external revision may be imported with actor or unknown, principal, parent hash, canonical diff, and reason, and every imported changed element keeps an `external/unsupported` disposition until a later recorded transition replaces it (G10). Every why answer reconciles against the live document hash through the existing client-tool path or labels itself "as of the last reconciled recorded state" (G4). ### 3.4 Lookups and their executable boundary — C5, F9 -Core owns revision and query semantics. Plugin-sdcpn owns mutation names, inputs, outputs, and effect interpretation. Binding and app own authorized acquisition of Flue history through the in-process fetch pattern the capture sweep already uses, and compose the model-facing tool. Whether the model sees one composed why tool or two follows interaction quality. Retrieved conversation text is untrusted evidence returned in the smallest range needed (F11). +Core owns revision and query semantics. Plugin-sdcpn owns mutation names, inputs, outputs, and effect interpretation. Binding and app own authorized acquisition of Flue history through the in-process fetch pattern the capture sweep already uses, and compose the model-facing why operation. One or two model-facing tools follows interaction quality. Retrieved conversation text is untrusted evidence returned in the smallest range needed; the single-principal local limit is stated (F11). -### 3.5 The visible workpiece — C7 +### 3.5 The visible workpiece — C7, G16 -Chat projects `update_workpiece` parts out of assistant messages and leaves a one-line marker. A pane in the Petrinaut Brunch panel shows the current revision, the revision list, and a diff, derived from Flue history through the Mission 5 transport. The why answer renders into the same pane. This projection lives in the app or transport layer, not the Petrinaut library. It is the surface every later mission assumes and a product-manager-visible advance in its own right. +Chat projects `update_workpiece` parts out of assistant messages and leaves a one-line marker. A pane in the Petrinaut Brunch panel shows the current revision, the revision list, and a diff, derived from Flue history through the Mission 5 transport. The why answer renders into the same pane. The projection lives in the app or transport layer, not the Petrinaut library. Inside Mission 7 the pane is an enabling surface for the construction-and-explanation claim, not a second release. ### 3.6 Schema carrier repair — B9, C11 -Precondition for admitting any nested tool. Flue accepts Valibot only and rejects other Standard Schema vendors; the construction factory declares an empty loose object with the JSON Schema pasted into the description. Fix by a mechanical JSON Schema to Valibot interpreter for the subset Petrinaut uses, or upstream Flue Standard Schema support. Prove one real nested call before broad admission. +Precondition for admitting any nested tool. Flue accepts Valibot only and rejects other Standard Schema vendors; the construction factory declares an empty loose object with the JSON Schema pasted into the description. Fix by a mechanical JSON Schema to Valibot interpreter for the subset Petrinaut uses, or upstream Flue Standard Schema support. Prove one real nested call before broad admission. Carrier failure is a crisp upstream blocker, never a local schema copy. -### 3.7 Passage identity — F6 +### 3.7 Passage identity — F6, G11 -A prerequisite, not fog. Candidates: heading path, Markdown anchor, companion manifest. The probe covers rename, move, paraphrase, split, merge, deletion, and reintroduction on one real workpiece. If no scheme survives, the first claim is revision-local text with no cross-revision "introduced by." +Policy first: passage ids are never reused after deletion; split and merge record predecessor and successor sets; ambiguous paraphrase refuses continuity; reintroduction starts a new identity unless continuity is declared; a locator resolves to an immutable revision-local span; duplicate headings and quotations are tested; an overbroad span fails basis quality when a materially narrower sufficient span exists. Then the probe tests ergonomics and model compliance on one real workpiece under rename, move, paraphrase, split, merge, deletion, and reintroduction. Fallback if the policy proves too expensive: revision-local text and refused cross-revision "introduced by" claims. -### 3.8 Scenario-derived tool admission — F13 +### 3.8 Scenario-selected tool admission with canonically derived schemas — F13, G15 -The inherited six-tool subset is retired. The admitted subset is generated mechanically from Petrinaut's AI tool bundle by the document entity classes the six persona cases exercise, surveyed on 2026-09-04: +The inherited six-tool subset is retired. Operations are selected from the proving scenario; their schemas are derived mechanically from Petrinaut's AI tool bundle. The 2026-09-04 survey of the six persona cases gives the candidate set; the cut names the proving scenario and admits only the classes it needs, citing the case requirement each discharges. -| Entity class | Case evidence | Admitted operations | -| --- | --- | --- | -| places, transitions, arcs | every case | add, update, remove; arc weight and type | -| scenarios (initial state) | every case | add, update, remove | -| types and type elements | most cases name colours or token attributes | add, update, remove, move element | -| parameters | industrial gas | add, update, remove | -| metrics | vestera | add, update, remove | -| differential equations | data-centre thermal, pharma cold chain | add, update, remove | -| queries and commands | all | `getLatestNetDefinition`, `getNetCompilationErrors`, `applyAutoLayout`, `setNetTitle` | -| excluded for now | only vestera hints at hierarchy | subnets, component instances, position updates | +| Entity class | Case evidence | Operations (add, update, remove unless noted) | Admission | +| --- | --- | --- | --- | +| places, transitions, arcs | every case | including arc weight and type | default | +| scenarios (initial state) | every case | | default | +| types and type elements | most cases name colours or token attributes | | default when the scenario has typed tokens | +| parameters | industrial gas | | when the scenario names a tunable quantity | +| differential equations | data-centre thermal, pharma cold chain | | when the scenario has continuous dynamics | +| metrics | Vestera names scheduling objectives but forbids invented weights | | only when the scenario names a measurable objective Petrinaut's `Metric` can express | +| queries and commands | all | `getLatestNetDefinition`, `getNetCompilationErrors`, `applyAutoLayout`, `setNetTitle` | default | +| excluded | only Vestera hints at hierarchy | subnets, component instances, position updates, type-element move | until a case needs them | -Expansion is by observed need with the case named. Admission in ordinary SDCPN conversation is the default; parity with the stock modeller is still not the goal. +Expansion is by observed need with the case named. Parity with the stock modeller is not the goal; ending deferral is. -### 3.9 Teaching and subtraction — C9, C12 +### 3.9 Teaching and subtraction — C9, C12, G20 -The skill gains construction posture: read the definition first, mutate in small steps with a declared basis, check compilation errors, record decisions in Construction notes, call `update_workpiece` before and after construction. The `ask` and `sweep` client handling is retired from code. The capture store is not consumed; it re-enters only if the compaction probe shows `history()` loses records (F4). +The skill gains construction posture: read the definition first, call `update_workpiece` and wait for its settled revision, mutate in small steps each citing that revision with a declared basis, check compilation errors, record decisions in Construction notes without treating them as basis, and call `update_workpiece` again after construction. The `ask` and `sweep` client handling is retired from code. Three things stay distinct: capture envelopes and sweep semantics, rejected for Mission 7 provenance; the existing session-log archive lane in `binding-flue`, which may be hardened if the compaction probe is negative; and any new immutable lineage projection required by compaction, relocation, or authorization. ## 4. Tool inventory after this design | Tool | Owner | Executes | Status | | --- | --- | --- | --- | | `ping`, `activate_skill`, `readPetrinautDoc` | app, Flue, plugin | server, server, browser | keep | -| scenario-derived Petrinaut subset (3.8) | plugin-sdcpn, derived | browser | admit after carrier repair | +| scenario-selected Petrinaut operations (3.8) | plugin-sdcpn, schemas derived | browser | admit after carrier repair, per proving scenario | | `update_workpiece` | core | server | new | -| why lookup (one or two model-facing tools) | composed at app from core and plugin | server | new | +| why operation (one or two model-facing tools) | composed at app from core and plugin | server, with a browser read for reconciliation | new | | `ask`, `sweep` client handling | core, website | browser | retire | | six-tool and two-tool subsets | plugin-sdcpn | browser | retire once Mission 6 archives | -## 5. Real honest fixtures — D1 to D5, F14, F15 +## 5. Real honest fixtures — D1 to D5, F14, G12, G13, G14 The provenance pair is a real conversation with a real revisioned workpiece and a real constructed net, produced by persona interviews against the production agent. The Mission 6 prepared fixture stays a viability proof. ```text probe: one tiny genuine conversation → export or retain → relocate → reopen → authorize → query (F14, first) then: persona runs (Pi harness, production ChatAgent, real-headless host), several cases in parallel - → Flue store holds conversation, revisions, mutations with basis, transition records - → harness retains snapshot.json + projections per settled read - → frozen element inventory and consequential rule; frozen behavioural discriminator - → grade coverage against the hidden oracle ledger afterwards + → Flue store holds conversation, settled revisions, mutations with basis, transition records + → harness retains snapshot.json + projections per settled read (diagnostics only) + → consequential rule frozen before the run; inventory generated from the final canonical document + → acceptance assertions run through the reopened authorized why operation the product uses + → safety gate, then utility gate with a blinded reviewer task and fixed rubric ``` -Stop rule: a turn cap as budget, early stop when Brunch declares construction handoff, ledger coverage as the post-hoc grade (D4). Runs go to construction so the fixture contains lineage and basis (D5). +Sources are labelled synthetic-persona, internal-human, or customer-derived. At least one adversarial fixture includes duplicate wording, rejected quotations, constructor inference, a correction, unrelated context, a carried-forward passage, non-adjacent evidence, and multi-source synthesis. Stop rule: a turn cap as budget, early stop when Brunch declares construction handoff, ledger coverage as the post-hoc grade (D4). Runs go to construction so the fixture contains lineage and basis (D5). -## 6. Mission topology — F12 +## 6. Mission topology — F12, G16, G18 -Construction and explanation ship in one mission. Its body: carrier repair, orphan retirement, `update_workpiece`, the workpiece pane, scenario-derived tool admission and teaching, declared basis and transition records, the persona programme to construction, and the why route over real lineage. Its first act is the adversarial tracer: one genuine conversation, two distinguishable passages, two mutations, one no-op or failed mutation, one correction, one hand edit, with deterministic answers or explicit refusals before any breadth. The following mission takes projection breadth, repeat and changed-input behaviour, and readiness closure. Reviewer revision follows. Local posture is named; remote durability goes to a scheduled Mission 8 or an explicit pre-handoff release gate, and "locally run," "locally verified image," and "remote replacement-safe" stay distinct claims (F15). +Construction and explanation ship in one mission, Mission 7, which also closes the readiness of its own claim. Its authority is cut in two steps under one issue and branch: a narrow first authority whose throughline is the adversarial tracer and the four probes with decision tables; then, on pass and owner gate, an amendment admitting the construction-and-explanation body with its readiness gate. Mission 9 takes breadth first made load-bearing by "repeatable": unchanged repeat, changed input, deletion and retirement, concurrent user change, cross-conversation document access, broader schema classes, and the per-action versus batch decision if Mission 7 has not settled it. Mission 10 inherits basis, transition records, passage policy, and identity epochs. Mission 11 gains early consumer discovery and three-gate readiness (G21). Local posture is named; remote durability goes to a scheduled Mission 8 or an explicit pre-handoff release gate, and "locally run," "locally verified image," and "remote replacement-safe" stay distinct claims. -Release wording, narrowed (C13, F5): "Ask why about any element and see the passage the constructor declared as its basis, the conversation context behind it, and who did what, or an explicit refusal." Actor identity and causal wording strengthen only as the records do. +Release wording (C13, F5, G6): "Ask why about any element in a net Brunch built with you, and see the workpiece passage the constructor declared as its basis, the conversation context behind it, and which recorded step did what, or an explicit refusal." Causal and identity wording strengthen only as the records do. -## 7. Consequences for the planning record +## 7. Consequences for the planning record — G19 -1. **Name the tension** in the spine: lineage plus declared basis as the hypothesis; typed IR and hand-authored derivation rejected with reasons; revision cadence, compaction survival, and passage identity as the named strains; the visible workpiece as the precondition. -2. **Re-cut the mission drafts**: one consolidated construction-and-explanation mission replaces the current Mission 7 and the construction half of Mission 9; the remainder of Mission 9 becomes breadth and repeat behaviour; Mission 10 inherits basis, transition records, and passage identity rather than a derivation fixture. -3. **Mission 6 close report**: fixture-rigging admission, the carried fenced-block-to-tool change, the credential cause of the blocked witness. -4. **Migration matrix** with a removal gate for any dual-read bridge (F15). -5. **Consumer discovery** with Chris and Yannis before the construction region is chosen (F15). -6. **Authority**: every settled item becomes authority only when written into the cut `MISSION.md`, with Mission 6's construction-tool constraint amended there. +1. **Name the tension** in the spine: lineage plus declared basis as the hypothesis; typed IR, hand-authored derivation, and temporal adjacency as causation rejected with reasons; revision cadence, compaction survival, passage identity, and basis quality as named strains; the visible workpiece as the precondition. +2. **Recut the drafts**: Mission 7 becomes the consolidated construction-and-explanation mission at cut-level detail; Mission 9 becomes breadth and repeat behaviour; Mission 10 inherits the new seam; Mission 11 gets early consumer discovery and three-gate readiness. +3. **Planning-content migration matrix** in `MISSION.next.md`: one surviving destination per old item. +4. **Mission 6 close report**: fixture-rigging admission, the carried fenced-block-to-tool change, the credential cause of the blocked witness. +5. **Runtime migration matrix** with a removal gate for any dual-read bridge (F15). +6. **Authority**: every settled item becomes authority only when written into the cut Mission 7 `MISSION.md`, with Mission 6's construction-tool constraint amended there. -## 8. Fog-line and probes, in order +## 8. Probes with decision tables — G17 -1. Compaction: whether `history()` keeps folded messages; set `keepRecentTokens` low, run past threshold, read history (F4). -2. Fixture materialization: export, relocate, reopen, authorize, query one tiny genuine conversation (F14). -3. Passage identity under semantic edits (F6). -4. Carrier repair for one real nested mutation from the 3.8 subset. -5. Revision cadence: whether the model calls `update_workpiece` often enough for revisions to have grain (B6). -6. Basis quality: whether the constructor declares a usable basis unprompted, and how often it is absent. -7. Whether the why answer over a real pair is useful to a reviewer, judged by a human. -8. Token cost of full-document emission, and when a structured patch earns its place. +| Probe | Pass | Partial | Fail | Re-entry | +| --- | --- | --- | --- | --- | +| Compaction: does `history()` keep folded `update_workpiece` inputs, mutation parts, and user lines? | Lineage reads from `history()` | Current revision from state; history claims limited to the uncompacted window and disclosed | Harden the existing session-log archive lane into an immutable lineage projection before any exact-line claim | Flue exposes a supported pre-compaction read | +| Fixture materialization: export, relocate, reopen, authorize, query one tiny genuine conversation | Retained live store or supported relocation is the fixture route | Relocation works but identities must be re-bound; record the binding rule | Prepared-projection route only, honestly labelled; the why claim narrows to that projection | Flue adds a supported export or import surface | +| Passage identity under the G11 policy | Locator scheme selected | Some edit classes refuse continuity; refusals become part of the claim | Revision-local text only; no cross-revision "introduced by" | Cheaper anchor lifecycle appears in the workpiece template | +| Carrier repair for one real nested mutation from the proving scenario | Admit the scenario's classes | Flat classes only; nested classes refused with a named blocker | Crisp upstream Flue requirement; no local schema copy | Flue accepts Standard Schema or supplied JSON Schema | +| Revision cadence and basis quality in the adversarial tracer | Blame and basis have grain | Coarser ranges disclosed; skill wording and pane interaction adjusted before breadth | Explainability claim stops at "which revision, which turns"; construction proceeds without the why release | Cadence improves under the revised interaction | +| Reviewer utility under the blinded rubric | Utility gate passes | Coverage below threshold on named classes; scope the claim to passing classes | Explainability release withheld; construction release stands on its own gates | Rubric passes on a later fixture | ## 9. Questions for the next reviewer -1. Does the declared basis reintroduce any rejected mechanism, or does it stay a thin creation-time relation? -2. Is the transition record the minimum that makes "not attributable" decidable? -3. Does the consolidated mission have one coherent visible advance, or does it still have too many independent failure fronts after the adversarial tracer? -4. Is the scenario-derived subset honestly derived from the cases, and is anything in it unearned? -5. Which probes, if negative, should stop the cut rather than reshape it? +1. Does the two-step Mission 7 authority satisfy the one-live-mission rule without becoming a thin tracer by another name? +2. Is the optional revision-time evidence relation on `update_workpiece` the least mechanism that makes passage evidence honest, or does it drift toward assertion cards? +3. Is the transition record now independently verifiable, and does the one-conversation-one-document binding leave Mission 9 a clean re-entry? +4. Is any admitted class in 3.8 unearned by the proving scenario? +5. Which decision-table rows should stop the cut outright rather than narrow the claim? From 87237ee3106fdc7482aa0c9ed4b852d1b35adad1 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 12:28:59 +0200 Subject: [PATCH 16/31] Recut the Brunch mission spine around provenance by lineage with declared basis Rewrite the Mission 7 draft at cut-level detail as the consolidated construct-and-explain mission with a two-step authority, probe decision tables, and a conversion map; recut Mission 9 as repeatable projection breadth over the Mission 7 seam; re-express Missions 10 and 11 over settled revisions, declared basis, and transition records with three-gate readiness for the handoff; and record the provenance relations and tool admission locks plus a lossless planning-content migration matrix in MISSION.next.md. Co-Authored-By: Claude Fable 5.1 --- libs/@hashintel/brunch-agent/MISSION.next.md | 105 +++-- .../10-bounded-reviewer-revision.md | 55 +-- .../mission-drafts/11-optimisation-handoff.md | 18 +- .../mission-drafts/7-capture-backed-review.md | 294 ------------- .../7-explainable-construction.md | 362 ++++++++++++++++ .../mission-drafts/9-traceable-projection.md | 408 ++++++++---------- .../docs/mission-drafts/README.md | 2 +- 7 files changed, 655 insertions(+), 589 deletions(-) delete mode 100644 libs/@hashintel/brunch-agent/docs/mission-drafts/7-capture-backed-review.md create mode 100644 libs/@hashintel/brunch-agent/docs/mission-drafts/7-explainable-construction.md diff --git a/libs/@hashintel/brunch-agent/MISSION.next.md b/libs/@hashintel/brunch-agent/MISSION.next.md index 94a6b746f33..0b2cfe65af1 100644 --- a/libs/@hashintel/brunch-agent/MISSION.next.md +++ b/libs/@hashintel/brunch-agent/MISSION.next.md @@ -4,6 +4,8 @@ This spine and its four linked drafts form one future-planning record. Keep each consequential meaning in one authoritative planning home: shared contracts and unallocated concerns live here; mission-specific detail lives in its draft. A spine pointer is not a second contract. Material omitted from a future cut returns to this record at full fidelity, and the consumed draft is removed. +The record was recut on 2026-09-04 around provenance by lineage with declared basis; the [2026-09-04 migration disposition](#2026-09-04-provenance-replanning-migration-disposition) maps every prior planning item to its surviving home. + ## Current authority and accepted spine Mission 4 closed on this branch by owner adjudication on 2026-09-03. The accepted implementation is the independent core `elicitation` capability, SDCPN job-skill activation, and core/plugin/app responsibility split. The bounded evidence is narrower than the pre-registered campaign claim: Vestera and Data Centre activated correctly before substance, and S3 correctly refrained; S4 preserved the unresolved rule but did not activate elicitation, so the frozen campaign stopped before Industrial Gas. No `3/3` claim or full-run conversation/workpiece candidate exists. The owner judged immediate review-to-elicitation switching a nice-to-have at this boundary and deferred it. See the [closure decision](docs/evidence/decisions/mission-4-closure-and-deferral-2026-09-03.md), [campaign adjudication](docs/evidence/evaluations/mission-4-proof-of-life-v2/final-adjudication.md), and [Voice integration handoff](docs/evidence/implementations/mission-4-voice-integration-handoff.md). The parallel deployment branch's earlier Mission 4 transition remains historical and is not imported as independent acceptance. @@ -12,47 +14,47 @@ A future Mission 4 close-out addendum requires its own issue, branch, PR, and mi Mission 6 is now live on the FE-1575 branch under root [`MISSION.md`](MISSION.md): one deliberately prepared, honestly labelled fixture must join canonical conversation, session history, Markdown workpiece, and Petrinaut document through a browser-backed read/write change and cross-tab resume. Its consumed draft has been removed; its product-manager litmus, demo script, and readiness-gate completion bar live only in that authority. Mission 5 is live on the FE-1574 branch directly beneath this one and owns the direct Voice/Flue transport cut; its full contract lives only in that branch's root `MISSION.md`. Neither tracer requires a Mission 4 full-run candidate. The two were cut as independent siblings, but Mission 5's recut made the browser Flue `ChatTransport` the only door into a Brunch conversation and removed the `/api/chat` path Mission 6 had named as its departure point; the owner therefore corrected Mission 6 to consume Mission 5's landed transport, and this branch now stacks on Mission 5's committed typed-panel transport tracer. -The earlier capture-backed provenance, automatic-projection, revision, and optimisation drafts remain later readiness/product advances. They are renumbered around the historical Mission 8 deployment track rather than forcing the two uncertainty-retiring tracers to inherit its unproved remote boundary. +On 2026-09-04, while Mission 6 was closing, the owner and an agent reviewed the provenance design that Missions 7, 9, and 10 had assumed, and two independent adversarial reviews tested the result. The outcome, recorded in the [decision log](docs/evidence/design/provenance-and-tooling-decision-log-2026-09-04.md), [mini spec](docs/evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md), [independent review](docs/evidence/design/provenance-by-lineage-independent-review-2026-09-04.md), and [follow-up review](docs/evidence/design/provenance-by-lineage-follow-up-review-2026-09-04.md), changed the spine in four ways. Provenance is no longer a capture-envelope and hand-authored derivation seam over a prepared pair; it is recovered lineage in the canonical Flue log (workpiece revisions and net mutations as tool calls) plus a constructor-declared basis carried on each mutation request, with passage evidence, element origin, current state, attempt history, and recorded roles kept as distinct relations. Construction and explanation are consolidated into Mission 7 on a genuine conversation, because lineage exists only when the model actually constructs and because the owner chose fully connected parts over thin tracers; Mission 7 closes the readiness of its own claim and hands only breadth to Mission 9. The prepared Mission 6 fixture is a viability proof and is not promoted; real fixtures come from persona interviews run to construction. Tool admission ends its deferral: the inherited six-tool subset is retired in favour of scenario-selected operations with canonically derived schemas over a repaired provider carrier. These are owner decisions expressed in conversation; they become authority only when the Mission 7 draft is cut. ```text M4 closed — core/plugin elicitation pattern accepted; S4 transition and full-run candidate deferred M4+ optional successor — broader hardening or source promotion only under separate authority M5 live on FE-1574, beneath this branch — direct Voice/Flue turn, canonical streamed reply, cancellation, and reopen M6 live on FE-1575 — conversation → Markdown workpiece → Petrinaut read/write → cross-tab resume over Mission 5's transport -M7 capture-backed review — close selected-pair provenance breadth and visible why/refusal -M8 deployment handoff — historical branch stopped after local application proof, before infrastructure deployment -M9 automatic projection — broaden the proved fixture seam to repeatable traceable projection of one meaningful region -M10 revision — ship bounded authorized reviewer revision and a scoped patch -M11 optimisation — ship an accepted optimisation handoff after its consumer contract exists +M7 construct and explain — one genuine conversation builds and explains one real net region; two-step authority; closes its own readiness +M8 deployment handoff — historical branch stopped after local application proof, before infrastructure deployment; a successor must be scheduled before any remote claim +M9 repeatable projection breadth — unchanged repeat, changed input, retirement, concurrent change, schema classes over the M7 seam +M10 revision — ship bounded authorized reviewer revision and a scoped patch over basis, transition records, and epochs +M11 optimisation — ship an accepted optimisation handoff after its consumer contract exists; early non-binding consumer discovery before M9's region ``` Every numbered product mission after the proof-of-life exception must pass the **product-manager litmus**: a product manager who did not watch the work must be able to notice that the product materially moved forward. Each mission therefore states, in its draft's visible-product-advance section and then in its cut `MISSION.md` imperative, a release-note sentence, a demo script a product manager can run without an engineer, and the thing that was impossible before. Snapshots, manifests, event ledgers, and negative controls are oracles that belong in the evidence sections; they are not the visible advance. A mission is complete at its readiness gate, when the demo script works for the named scenario, not at the first green throughline tracer, which is an internal milestone inside the mission. Live Mission 5 names the Petrinaut Brunch panel's typed and Voice surface over one Flue route, with its litmus stated in the FE-1574 branch's live `MISSION.md`; live Mission 6 names the stable fixture and browser Petrinaut document, with its litmus stated in this branch's [`MISSION.md`](MISSION.md#visible-product-advance); Missions 7, 9, and 10 name the Petrinaut Brunch panel. Because Mission 8 stopped before remote deployment, those panel missions must name the deployment posture available at cut time, and a locally run panel is acceptable for the demo; a product-manager-noticeable claim must never depend on infrastructure that does not exist, while remote durability obligations stay in their readiness gates. Architecture, schema repair, fixtures, evaluation, rehearsal, and spikes may support the advance but cannot be the sole outcome. Parallel work means separate issue, branch, PR, worktree, and mission authority; it never means multiple live missions here. ## Successor mission précis -### M7 — Make the demo net genuinely explainable +### M7 — Construct and explain one real net region from a genuine conversation -Tracker projection: [FE-1573](https://linear.app/hash/issue/FE-1573/explain-one-prepared-petrinaut-net-from-exact-conversation-evidence), advancing stakeholder outcome [FE-1478](https://linear.app/hash/issue/FE-1478/provide-provenance-from-a-generated-net-back-to-the-requirements-graph). +Tracker projection: [FE-1573](https://linear.app/hash/issue/FE-1573/explain-one-prepared-petrinaut-net-from-exact-conversation-evidence), advancing stakeholder outcome [FE-1478](https://linear.app/hash/issue/FE-1478/provide-provenance-from-a-generated-net-back-to-the-requirements-graph); the issue must be re-titled with owner approval before the cut because it still describes the superseded prepared-pair mission. -After M6 proves viability, close exact capture-backed provenance across the selected prepared pair so a reviewer can ask why any consequential visible element exists and receive workpiece meaning, preparation rationale, and exact conversation evidence, or a visible refusal. **Product-manager litmus:** ask why about any element in the demo net and get the original conversation back. Demo: open the prebuilt demo net, pick any element, type its name, read the answer and its quoted evidence; pick the element known to have no support and watch Brunch decline. Previously impossible: nothing connected a net element to what the expert actually said. Complete when every consequential element in the demo net resolves or visibly declines, not when one element resolves; one element is the throughline tracer inside the mission. On 2026-09-03 the one-element cut was judged too small under the litmus and Mission 7 was expanded to the whole demo net rather than folded into Mission 6 or Mission 9; the reasoning is recorded in the [visible product advance](docs/mission-drafts/7-capture-backed-review.md#visible-product-advance). +After M6 proves viability, run a genuine conversation on one proving scenario through the production agent, let Brunch revise the workpiece as first-class tool calls, build one real net region with a declared basis on every mutation, and answer why for every consequential element from recorded lineage, or refuse. **Product-manager litmus:** talk to Brunch about a process, watch it build that part of the net, then ask why any element exists and see the passage Brunch declared as its basis, the conversation behind it, and which recorded step did what. Demo: open the demo conversation and its net, watch the workpiece pane and its revision diff, type any element's name, read the answer; pick the hand-edited element and the basis-less element and watch Brunch refuse honestly. Previously impossible: Brunch had never built a region inside a real conversation, and nothing connected an element to what was said. Complete at the readiness gate, including the why operation's safety and utility gates; the adversarial tracer and the first constructed region are internal milestones. Authority is cut in two steps under one issue: a narrow first authority for the adversarial tracer and four probes with decision tables, then an owner-gated amendment into the construction-and-explanation body. Scope history and the full cut-level contract live in the [draft](docs/mission-drafts/7-explainable-construction.md). -### M9 — Make projection repeatable and traceable +### M9 — Make projection repeatable -Tracker projection: [FE-1438](https://linear.app/hash/issue/FE-1438/project-an-evidence-backed-workpiece-into-a-traceable-live-sdcpn). +Tracker projection: [FE-1438](https://linear.app/hash/issue/FE-1438/project-an-evidence-backed-workpiece-into-a-traceable-live-sdcpn); its description predates the 2026-09-04 recut and must be re-titled with owner approval. -Broaden the viable M6 mutation seam into automatic projection of one meaningful workpiece region, with stable identities and derivations that M7's why route can resolve. Close repeat, changed-input, schema, partial-failure, and semantic-correspondence obligations for the named region rather than a whole-net platform. **Product-manager litmus:** Brunch builds a recognisable part of the net itself from the conversation, and can still explain every piece it built. Demo: from the demo workpiece, ask Brunch to model the named region, watch a non-empty region appear in the panel that matches what was discussed, then ask why about one generated element. Previously impossible: every net in the demo was prebuilt by a person. Provider-schema repair, the transaction probe, and the batching decision are internal to this mission and are not the advance; see the [visible product advance](docs/mission-drafts/9-traceable-projection.md#visible-product-advance). +Over the accepted M7 seam, close what "repeatable" first makes load-bearing: unchanged repeat without duplication or churn, changed input with a bounded impact set, deletion and retirement through identity epochs, concurrent or hand change refused and imported rather than overwritten, cross-conversation document access if the proving scenario needs it, the schema classes the extended region requires, and the per-action versus bounded-batch decision if M7 left it open. **Product-manager litmus:** ask Brunch to model the next part of the process and the net grows without disturbing what was built; ask again and nothing duplicates. Demo: extend the M7 net, repeat the request, change one fact, bring the net up to date, and ask why after the change. Previously impossible: building once was proved; doing it again safely was not. See the [visible product advance](docs/mission-drafts/9-traceable-projection.md#visible-product-advance). The construction half of the former M9 (carrier repair, first nested mutation, first meaningful region, stable ids, positive why) moved into M7 on 2026-09-04. ### M10 — Revise meaning without collateral rebuilding Tracker projection: [FE-1394](https://linear.app/hash/issue/FE-1394/revise-one-traceable-net-region-through-targeted-reviewer-elicitation). -A scenario-authorized reviewer supplies focused new evidence; Brunch preserves prior support, creates an inspectable workpiece revision, and applies a bounded net patch, justified widening, or refusal. **Product-manager litmus:** a second person corrects the model in conversation and only the relevant part of the net changes. Demo: a reviewer challenges one modelled fact in a few turns, sees that region update with the correction attributed to them, sees the rest of the net untouched, and sees Brunch decline a second change it is not entitled to make. Previously impossible: changing the net meant regenerating or hand-editing it. Complete when both the accepted correction and a visible refusal or qualification appear in the same demo; see the [visible product advance](docs/mission-drafts/10-bounded-reviewer-revision.md#visible-product-advance). +A scenario-authorized reviewer supplies focused new evidence; Brunch preserves prior support, creates an inspectable settled workpiece revision that cites the reviewer's message ids, and applies a bounded net patch with declared basis, justified widening, or refusal. Since 2026-09-04 this mission inherits basis, transition records, identity epochs, and the passage policy from M7 and M9 rather than a capture-envelope and derivation seam. **Product-manager litmus:** a second person corrects the model in conversation and only the relevant part of the net changes. Demo: a reviewer challenges one modelled fact in a few turns, sees that region update with the correction attributed to them, sees the rest of the net untouched, and sees Brunch decline a second change it is not entitled to make. Previously impossible: changing the net meant regenerating or hand-editing it. Complete when both the accepted correction and a visible refusal or qualification appear in the same demo; see the [visible product advance](docs/mission-drafts/10-bounded-reviewer-revision.md#visible-product-advance). ### M11 — Hand an accepted model to optimisation Tracker projection: [FE-1503](https://linear.app/hash/issue/FE-1503/hand-one-accepted-sdcpn-to-an-optimisation-experiment). -Only after Chris and Yannis define one concrete consumer contract, broaden the proven path to one selected complete SDCPN and deliver the semantic artifact package in the form they accept. **Product-manager litmus:** Chris and Yannis start an optimisation experiment on a model that came out of Brunch, without asking anyone to reconstruct it. Demo: the handoff package opens in the form they accepted and the experiment begins. Previously impossible: no Brunch output had an external consumer. This mission passes the litmus by construction; see the [visible product advance](docs/mission-drafts/11-optimisation-handoff.md#visible-product-advance). +Only after Chris and Yannis define one concrete consumer contract, broaden the proven path to one selected complete SDCPN and deliver the semantic artifact package in the form they accept. **Product-manager litmus:** Chris and Yannis start an optimisation experiment on a model that came out of Brunch, without asking anyone to reconstruct it. Demo: the handoff package opens in the form they accepted and the experiment begins. Previously impossible: no Brunch output had an external consumer. Since 2026-09-04 the mission has three distinct gates (consumer contract acceptance, working handoff throughline, readiness closure sufficient to begin the experiment) rather than treating the first handoff as completion, and it owes lightweight non-binding consumer discovery before M9 selects its region; see the [visible product advance](docs/mission-drafts/11-optimisation-handoff.md#visible-product-advance). ## FE-1476 product frame @@ -111,9 +113,11 @@ This is an expeditionary posture, not a defensive one. Survey only until the nex ### Evidence, workpiece, capture, and projection -Flue history is the canonical conversation log. Mechanical capture envelopes are immutable, exact-evidence, domain-opaque source records; the foreground Markdown workpiece owns semantic synthesis. Projection consumes the current workpiece. Petrinaut owns canonical net schemas, mutations, parsing, and simulation; Brunch imports or mechanically derives those contracts and never hand-copies their field shapes. +Flue history is the canonical conversation log. The foreground Markdown workpiece owns semantic synthesis and, from Mission 7, its revisions settle only as `update_workpiece` tool calls with revision id, SHA-256, and Markdown persisted in per-conversation state; the fenced `runbook-ir` block is retired for model-produced revisions and the tagged prepared signal is retained only for test-authored material. Projection consumes the current settled workpiece revision. Petrinaut owns canonical net schemas, mutations, parsing, and simulation; Brunch imports or mechanically derives those contracts and never hand-copies their field shapes. + +Mission 2 proved an idempotent model-free sweep: one envelope per user utterance, quote equal to source text, payload `{}`. The production path never invoked capture. On 2026-09-04 capture envelopes and sweep semantics were rejected for provenance: Flue history already carries message ids and exact text, and the store duplicated them under a second identity scheme (decision log C8, G20). Three things stay distinct: those rejected semantics; the existing session-log archive lane in `binding-flue`, which may be hardened only if Mission 7's compaction probe shows `history()` loses folded records; and any new immutable lineage projection actually required by compaction, relocation, or authorization. Task-local JSON is forbidden across any claimed process or task replacement boundary. -Mission 2 proved an idempotent model-free sweep: one envelope per user utterance, quote equal to source text, payload `{}`. The production runbook path still does not invoke capture. Mission 6 may use an explicitly prepared fixture without claiming capture-backed provenance; Mission 7 is the first planned consumer that turns capture into trustworthy product provenance, so capture must become durable before that claim is made. Task-local JSON is forbidden across any claimed process/task replacement boundary. +**Provenance relations lock (2026-09-04).** Lineage and basis are distinct contracts and neither is inferred from the other. Lineage is recovered from the log: settled revisions, mutation requests, and one independently verifiable transition record per browser mutation (requested base hash, observed pre-apply hash, post hash, outcome, disjoint derived effects, diff accounting, conflicting duplicates to unknown). Basis is declared by the constructor on each mutation request as `declared { revisionId, sha256, locators, rationale, scope }` or `absent { reason }`, operation-level unless an intended-effect mapping names elements, and the cited revision must already have settled; a mutation never shares a tool batch with `update_workpiece` and never cites "latest." Passage-to-conversation ranges are conversation context temporally associated with a revision, not evidence, unless `update_workpiece` carried a revision-time evidence relation (`{ locator, messageIds, kind }`). Element ids are never reused across identity epochs, and origin, current state, change history, and attempt history are distinct query semantics. Every why answer reconciles against the live document hash or labels itself "as of the last reconciled state"; external state is imported with dispositions and never laundered. Actors are recorded roles (assistant tool call, local browser executor, user under principal key, test-authored fixture author); human identity is unknown; "when" is canonical stream order. Passage identity is policy before probe: ids never reused after deletion, split and merge record predecessors and successors, ambiguous paraphrase refuses continuity, reintroduction starts a new identity unless declared, locators resolve to immutable revision-local spans. Rejected with reasons: temporal adjacency as causation, hash-only net-to-workpiece joins, provenance pointers in the Petrinaut document, and hand-authored derivation fixtures. Keep these epistemic levels separate: @@ -125,7 +129,9 @@ what projection actually represents Optional SDCPN mapping hints remain advisory, may be absent or plural, identify the prose they concern, and record whether projection accepted, rejected, or deferred them. They neither establish completeness nor copy Petrinaut payloads. -The smallest currently earned provenance seam is current workpiece revision/reference, capture evidence references, net-element ids, and projection rationale. Exact storage and identity shape remain fog for the real tracer. Stable ids must be exercised rather than assumed. Unsupported defaults, stale/partial state, identity churn, repeated projection, and visible partial failure stay explicit. +The smallest planned provenance seam, to be earned by Mission 7, is: settled workpiece revision identity (call id plus SHA-256), passage locator under the passage policy, optional revision-time evidence relation, stable net-element ids with identity epochs, declared basis per mutation request, and the transition record. Storage is the Flue log plus per-conversation state; the compaction probe decides whether an archive lane is needed. Stable ids must be exercised rather than assumed. Unsupported defaults, stale or partial state, identity churn, repeated projection, and visible partial failure stay explicit. + +**Tool admission lock (2026-09-04).** Deferral of Petrinaut tool wiring ended. The inherited six-tool and two-tool subsets are retired as product surfaces once Mission 6 archives. Operations are scenario-selected from the proving case with each class citing the requirement it discharges; their schemas are derived mechanically from Petrinaut's AI tool bundle over a repaired provider carrier (a JSON Schema to Valibot interpreter for the subset Petrinaut uses, or upstream Flue Standard Schema support; never a local copy). The 2026-09-04 case survey and the candidate table live in the mini spec section 3.8. Parity with the stock modeller remains a non-goal; expansion is by observed need with the case named. The `ask` and `sweep` client handling is retired from code under Mission 7 authority; their designs stay in the archives and the structured-question backlog below. Do not add a comprehensive process ontology, graph database, universal subject/predicate/value schema, deterministic capture-to-workpiece reducer, full regeneration engine, or typed completion algebra before observed consumer strain earns one. @@ -220,23 +226,24 @@ These tracks may start only under their own issue, branch, PR, and mission autho | Track | Join gate under the accepted spine | Does not block | | --- | --- | --- | -| Frozen prospective baseline | The closed Mission 4 branch preserves it unchanged and makes no quality-improvement claim; because Mission 4 produced no full-run candidate, a successor may inspect this observed one-invalid/two-valid Mission 3 range only if it explicitly selects and promotes an eligible source | Mission 7's source selection and provenance-suitability decision, or the optional Mission 4 addendum | +| Frozen prospective baseline | The closed Mission 4 branch preserves it unchanged and makes no quality-improvement claim; it is calibration only. Since 2026-09-04 no mission promotes a retained Mission 3 or Mission 4 source; genuine fixtures come from Mission 7's persona programme, labelled synthetic-persona, internal-human, or customer-derived | Mission 7's persona programme, or the optional Mission 4 addendum | | Resumable fixture viability | One prepared fixture crosses conversation → Markdown workpiece → browser Petrinaut read/write → save/reopen | The live Mission 5 Voice transport work | | Inferential observer fold | Decide before Mission 10 whether observed foreground strain earns promotion; otherwise retain phase-boundary synthesis | Missions 4–9 | -| Provider-visible nested schema | Mission 6 tests only the least mutation needed by its meaningful fixture; Mission 9 closes the broader canonical projection classes after a crisp blocker or success | Mission 5 and non-construction Voice work | -| Provenance interaction fixture | Mission 6 establishes minimal fixture identity; freeze the broader derivation fixture before Mission 7 why and Mission 9 automatic projection diverge | Voice work and prepared-fixture viability | +| Provider-visible nested schema | Mission 6 tests only the least mutation needed by its fixture; Mission 7 repairs the carrier and proves one real nested mutation on its proving scenario before admitting classes; Mission 9 closes the classes its extended region adds | Mission 5 and non-construction Voice work | +| Fixture materialization | Mission 7 proves one tiny genuine conversation can be exported or retained, relocated, reopened, authorized, and queried before any paid persona breadth; the probe's branch selects the demo fixture route | Voice work and prepared-fixture viability | +| Compaction survival | Mission 7 forces compaction and reads `history()`; the branch decides whether the existing archive lane is hardened | Everything before Mission 7 | | Host choice/session lifecycle | Mission 5 proves Flue conversation reopen; Mission 6 proves fixture save/reopen over Mission 5's landed browser transport; later host/picker breadth waits for its visible consumer | Mission 5 first, then Mission 6 | -| Optimisation handoff contract | Chris/Yannis accept input/output contract and one fixture before Mission 11 is cut | Missions 4–10 | -| Simulation-backed semantic check | Promote only if cheap and discriminating for the selected revision | First provenance tracer | +| Optimisation handoff contract | Chris/Yannis accept input/output contract and one fixture before Mission 11 is cut; lightweight non-binding discovery happens before Mission 9 selects its region | Missions 4–8 | +| Behavioural discriminator | Mission 7 derives one executable check from the workpiece for its constructed region and carries it unchanged to Missions 9 and 10; broader simulation coverage waits for a discriminating need | The adversarial tracer | -The deliberately provisional shared-interface names remain `EvidenceBackedWorkpieceItem`, `DerivationRecord`, and `NetPatch`. Do not freeze richer names or field catalogs before two tracks genuinely share them. If fixture UI and projection cannot agree on the minimal derivation record, pause parallel work at that seam. +The provisional shared-interface names `EvidenceBackedWorkpieceItem`, `DerivationRecord`, and `NetPatch` were superseded on 2026-09-04: the revision identity, declared basis, transition record, and identity epoch named in the provenance relations lock are the shared seam, and Mission 7 earns their exact shapes. Do not freeze richer names or field catalogs before two missions genuinely share them. ## Detailed provisional clusters Detailed mission-specific boundaries, tracer floors, readiness ratchets, risks, oracles, and stop conditions live only in these four context repositories: -- [Draft Mission 7 — capture-backed review](docs/mission-drafts/7-capture-backed-review.md) -- [Draft Mission 9 — automatic traceable projection](docs/mission-drafts/9-traceable-projection.md) +- [Draft Mission 7 — construct and explain one real net region](docs/mission-drafts/7-explainable-construction.md), written at cut-level detail with a conversion map +- [Draft Mission 9 — repeatable projection breadth](docs/mission-drafts/9-traceable-projection.md) - [Draft Mission 10 — bounded reviewer revision](docs/mission-drafts/10-bounded-reviewer-revision.md) - [Draft Mission 11 — optimisation handoff](docs/mission-drafts/11-optimisation-handoff.md) @@ -290,6 +297,8 @@ Rejected mechanisms re-enter only under their named strain: closed kinds/slots/d The previous typed-map cluster—required fields and unresolved gaps mechanically deriving ask/construct/deliver—remains a recorded hypothesis, not the default. It re-enters only if the workpiece-to-projection tracer or construction-gap return shows that model-assisted judgment cannot reliably name the smallest next question without typed demands. +**2026-09-04 additions.** Passage identity is now a predeclared policy (see the provenance relations lock) tested by Mission 7's probe across rename, move, paraphrase, split, merge, deletion, and reintroduction; if the policy is too expensive the first claim is revision-local text. Revision cadence, unmeasured in every retained run (no retained persona run has more than one `runbook-ir` block), is the named strain for both the visible workpiece pane and blame grain; Mission 7 measures it in the adversarial tracer. Versioned assertion clusters remain the possible response only if the optional evidence relation proves insufficient under observed revision strain. + ### Capture/workpiece seam history and rejected mechanisms Four prior relationships retain distinct evidence: @@ -301,6 +310,8 @@ Four prior relationships retain distinct evidence: The optional offline shadow join runs Mission 2 capture over settled history, assigns temporary workpiece-statement ids, and grades evidence relation, epistemic treatment, lifecycle relation, and projection treatment separately; assumptions never count as evidence support. Measure support coverage, synthesis fan-in, capture utility, context dependence, correction integrity, path sensitivity, and revision link churn. A fold becomes plausible only if order perturbation preserves active meaning without loop latency or requiring elicitor consultation of every fold. FE-1476 supersedes independence only as a sufficient delivery posture; it proves no store fold, merger, live linker, or comprehensive identity system. +**2026-09-04 outcome.** Relationship B, support links only, was superseded rather than implemented: the link from a net element to workpiece meaning is now the constructor's declared basis at construction time, and the link from workpiece meaning to conversation evidence is the optional revision-time evidence relation on `update_workpiece`, with temporal context as the honest fallback. Both are creation-time relations authored by the actor who knows, not retrospective links, and neither is a capture envelope. A, C, and D remain rejected for the reasons above; the shadow join remains an optional offline measurement if basis quality proves poor. + ### Mission 3 split and construction evidence The surviving outcome is intentionally split: **runbook/workpiece path accepted; real-model semantic construction false on the exercised route**. Mission 3 locked one off-canvas PN JSON result, Petrinaut validation, manual load as inspection, and no canvas tools. The frozen prospective control has one invalid runtime member and two valid independently graded workpieces; historical runs are calibration only. @@ -341,6 +352,8 @@ The real proof must cross **model → binding → transport → frontend → cor Do not claim this from a model tool call or rendered widget alone. Exercise all layers, cancellation/topic redirect, replay/resume, correlation, no wake wart, and stock-assistant isolation before promotion. +On 2026-09-04 the owner decided that the orphaned `ask` and `sweep` client handling (core `client-tools.ts` names and the suspended ask contract, the website ask interactive tool and test, the sweep filter and output module in the panel transport, and the Voice references in `canonical-speech.ts` and `interview-coverage.ts`) is retired from code under Mission 7 authority, because no mounted server tool produces either and the MVP demo will not teach them. This section and the Mission 2 and 4 archives remain the design reference; re-entry follows the proof above. + ## Later and opportunistic concerns ### Host/session continuity and compaction @@ -351,7 +364,7 @@ Missions 5 and 6 may each use a fixed Brunch mode. Mission 11 owns only the broa Working session hypothesis: net id discriminates one Flue conversation per principal; save/load resumes it, new net creates another. Today localStorage maps conversation ids by `netId`, while capture keys principal + conversation id. If ids regenerate/collide, rekey. Locked: net id is only a discriminator, not a Brunch target-document ontology. Keep rejected alternatives rejected: “net equals target-document” and sweep into a throwaway store for later splicing. -Before claiming long-running provenance, prove panel/transcript/workpiece recovery across real Flue compaction (`compaction-vs-durable-history` / FE-1386). Current recovery scrapes the last `runbook-ir` fence; summary loss would break it. A short rehearsal may avoid compaction only if the handoff declares uncompacted-history dependence. Compaction is history reconstruction, not projection sequencing; control to compact/show summaries waits for evidence. +Before claiming long-running provenance, prove panel/transcript/workpiece recovery across real Flue compaction (`compaction-vs-durable-history` / FE-1386). Current recovery scrapes the last `runbook-ir` fence; summary loss would break it. Mission 7 replaces that recovery with `update_workpiece` state and runs the compaction probe as one of its four first probes, with a decision table in its draft; a short rehearsal may avoid compaction only if the handoff declares uncompacted-history dependence. Compaction is history reconstruction, not projection sequencing; control to compact/show summaries waits for evidence. ### Voice after the live transport cut @@ -386,6 +399,46 @@ AI SDK 7 `HarnessAgent` is undecided: it is the converse of the current door, re Exploded-view net prototypes belong on Petrinaut website host routes, not `:4321`. If `ChatAgent` leaves the app, put it under `packages//`; the app stays shell. HASH embed remains stock unless explicitly opted in. Historical Conditions 1/2/4/5 remain batch evidence; no TUI, retired SDCPN elicitor, generalized `useElicitation()` runtime, loader, workflow engine, or second model-facing agent. +## 2026-09-04 provenance replanning migration disposition + +This ledger satisfies the one-authoritative-home and no-silent-loss rules for the 2026-09-04 recut. Every planning item in the former Mission 7 draft (`7-capture-backed-review.md`, renamed with history to `7-explainable-construction.md`), the former Mission 9 draft, and the affected spine paragraphs maps to exactly one surviving destination. Nothing was removed without a named home or a recorded rejection with reason. + +| Former item | Surviving home | Disposition and consequence | +| --- | --- | --- | +| M7 visible advance: why over an honest prebuilt pair; whole-net expansion of 2026-09-03 | Draft 7, Visible product advance and Scope history | Superseded: prebuilt pair rejected as fixture-rigging (log A3, B4); construction and explanation consolidated (F12); whole-net completion preserved as the inventory rule (G13). | +| M7 contract stratum: capture envelopes, stable references, prebuilt SDCPN, derivation fixture, resolution operation | Draft 7, Contract stratum; spine provenance relations lock | Envelopes and derivation fixture rejected with reasons (C8, B4, G20); stable references become passage policy plus declared basis; resolution operation becomes the composed why operation. | +| M7 boundary crossings: harness sweep, capture store, prebuilder, `useChat`/`onToolCall` path | Draft 7, Boundary crossings | Sweep and store removed; prebuilder replaced by the constructing model with declared basis; host path retained. | +| M7 proof floor: one element resolves; one broken link refuses | Draft 7, Throughline proof floor Step A | Expanded to the adversarial tracer with eight required features and four probes with decision tables (G17). | +| M7 inherited closure: Mission 2, 3/4, prebuilt honesty, Mission 8 durable capture, product door | Draft 7, Inherited stratum closure | Mission 2 not consumed; Mission 8 local posture; product door consumed via Mission 5. | +| M7 readiness gate list (dispositions, duplicates, replay, cross-owner, negative states, deterministic context, coexistence, latency, compaction) | Draft 7, Readiness gate | Every item retained and re-expressed over lineage and basis; cross-owner narrowed to the single-principal limit (F11) with breadth to Mission 9 (G5). | +| M7 candidate evidence table and ORACLE GAPs | Draft 7, Candidate evidence and oracles | Existing tests re-cited; gaps re-expressed; capture-store tests retained as historical inner evidence only. | +| M7 inputs and joins (upstream source, Mission 2, prebuilt fixture, Mission 8, Petrinaut host, Mission 9 output) | Draft 7, Inputs and joins | Upstream source becomes the persona programme; Mission 2 join dropped with reason; Mission 8 join is local posture. | +| M7 risks table | Draft 7, Risks and assumptions | Rows on unique names, useful excerpts, compaction, model inventing links, and one-pair peer set carried; new rows for cadence, basis, materialization, carrier, effects, binding, representativeness, cost, and gate ordering. | +| M7 constraints: harness owns sweep; envelopes immutable; no observer; no typed ontology; no automatic projection; no transcript fallback; durability matches claim; ownership fails closed; Petrinaut owner; no content telemetry | Draft 7, Accepted constraints | Sweep and envelope items retired with reason; "no automatic projection" inverted because this mission constructs; all others retained. | +| M7 cross-cutting obligations and touched paths | Draft 7, Cross-cutting obligations and Expected touched paths | Retained and re-expressed; capture paths marked for retirement or archive-lane hardening. | +| M7 fog-line (source eligibility, exact range, derivation representation, inventory, names, durable owner, deployed host, compaction, latency, portfolio) | Draft 7, Fog-line and decision tables | Source eligibility replaced by source labelling; derivation representation replaced by basis and transition record; others retained. | +| M7 stop conditions | Draft 7, Stop or reorient | Retained and re-expressed; new stops for mixed batch, uncitable revisions, self-reported effects, id reuse, circular basis. | +| M7 carried evidence and rejected alternatives (Mission 2 pipe, Mission 3, Mission 4, Mission 8 handoff, A–D seam, assertion cards, typed payloads, observer, automatic projection to M9) | Draft 7, Carried evidence; spine capture seam history 2026-09-04 outcome | All retained; B superseded by declared basis; automatic projection now in M7 with breadth to M9. | +| M7 click-to-chat deferral; FE-1476 beats 1–3 framing | Draft 7, Carried evidence | Retained. | +| M9 visible advance: Brunch builds a recognisable region and explains it | Draft 7, Visible product advance | Moved: this is now Mission 7's advance. | +| M9 internal sequencing: carrier repair → single nested tracer → transaction probe → batch decision | Draft 7 (carrier probe, nested tracer); Draft 9 (transaction probe, batch decision) | Split: repair and first nested call in M7; batching decision in M9 unless M7's scenario forces it. | +| M9 contract stratum items: region identity, types, parameters, places/transitions/arcs, stable ids, derivations, rejection/repair, repeat/change, semantic correspondence, durable boundary | Draft 7 (first region, ids, basis, rejection/repair, correspondence); Draft 9 (repeat, change, retirement, concurrent, breadth) | Split by what each visible claim first makes load-bearing (G16). | +| M9 readiness gate list | Draft 9, Readiness gate; Draft 7, Readiness gate | Repeat, change, retirement, concurrent, batch, breadth in Draft 9; schema classes used, provider vs canonical rejection, repair budget, no-op honesty, unsupported defaults, correspondence, partial failure, isolation in Draft 7 for the proving scenario and in Draft 9 for the extension. | +| M9 candidate evidence and ORACLE GAPs | Draft 7 and Draft 9 tables | Split accordingly; existing tests re-cited in both. | +| M9 risks table | Draft 7 and Draft 9 tables | Carrier and conversion rows in Draft 7; repeat, ids, batch, bounded context, recomputation, retirement, discriminator rows in Draft 9. | +| M9 constraints, obligations, touched paths, fog, stops | Draft 9, corresponding sections; Draft 7 where they concern the first region | Retained; "no automatic projection" and "derivation" wording replaced by basis and transition record. | +| M9 carried evidence (Mission 3 fixture and 0-for-9, Standard Schema move, canonical authority, prebuilt-first, rejected ontology list, hints, stable ids, recomputation fog, 46-tool parity, `pn_read`/`pn_edit`, observer, Mission 11 breadth) | Draft 9, Carried evidence | All retained; prebuilt-first replaced by the 2026-09-04 rejection with reason. | +| Spine précis M7 and M9 | Spine, Successor mission précis | Rewritten; scope history preserved in Draft 7. | +| Spine capture paragraph: "Mission 7 turns capture into trustworthy product provenance" | Spine, Evidence, workpiece, capture, and projection | Superseded with reason; archive lane distinction added (G20). | +| Spine "smallest currently earned provenance seam" | Same section | Replaced by the planned seam and the tool admission lock. | +| Spine parallel tracks: provider-visible nested schema (M9 owner), provenance interaction fixture, simulation check; provisional interface names | Spine, Parallel and asynchronous proof tracks | Owners moved to M7; interaction fixture replaced by fixture materialization and compaction rows; names superseded. | +| Spine later concerns: compaction paragraph | Spine, Host/session continuity and compaction | Pointer to M7 probe added; content retained. | +| Spine backlog: capture seam history; workpiece hypotheses; structured questions | Same sections, 2026-09-04 additions | Outcomes appended; nothing removed. | +| Draft 10 sweep, capture ledger, derivation seam, durable capture oracle gap | Draft 10, edited in place | Re-expressed over settled revisions, reviewer message ids, basis, transition records; Mission 2 archive marked historical. | +| Draft 11 circular readiness statement | Draft 11, Throughline proof floor and Readiness ratchet | Three gates; early consumer discovery added (G21, F15). | + +Items added on 2026-09-04 with no former home: the settled-revision protocol, declared basis, revision-time evidence relation, transition record, identity epochs, document reconciliation and binding, recorded roles, passage policy, scenario-selected admission, safety and utility gates, runtime migration matrix, behavioural discriminator, two-step authority, and the probe decision tables. Their authoritative planning home is Draft 7; their rationale is the decision log. + ## Historical 2026-09-02 migration disposition This section preserves the planning split as it was accepted on 2026-09-02. It is historical evidence, not the current draft inventory or numbering authority; the then-current six-draft topology preceded the live Mission 5 cut. At that time, the candidate split had one live authority, one compact spine, four provisional drafts, and no Mission 4 or Mission 8 draft. Its source-to-destination ledger was: diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/10-bounded-reviewer-revision.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/10-bounded-reviewer-revision.md index 87cdb10c326..058fc424168 100644 --- a/libs/@hashintel/brunch-agent/docs/mission-drafts/10-bounded-reviewer-revision.md +++ b/libs/@hashintel/brunch-agent/docs/mission-drafts/10-bounded-reviewer-revision.md @@ -8,16 +8,17 @@ A fresh builder must read these sources before cutting or implementing this cluster: -- [`MISSION.md`](../../MISSION.md) — live Mission 5 Voice authority on this branch; it supplies no Mission 10 execution authority or workpiece candidate. Consume only the source/workpiece pair explicitly selected and promoted by Mission 7 or a predecessor addendum. +- [`MISSION.md`](../../MISSION.md) — the current branch's live authority; it supplies no Mission 10 execution authority or workpiece candidate. Consume only the genuine conversation, settled workpiece revisions, and constructed region accepted by Missions 7 and 9. +- [`7-explainable-construction.md`](7-explainable-construction.md) and [`../evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md`](../evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md) — the 2026-09-04 recut: settled-revision protocol, declared basis, transition records, identity epochs, passage identity policy, document reconciliation, and recorded roles replace the former capture-envelope and derivation-fixture seam this draft once assumed. - [`MISSION.next.md`](../../MISSION.next.md) — compact shared frame, standing locks, and current mission joins. - [`README.md`](README.md) — durable draft authority, lifecycle, conversion, and oracle-gap rules. -- [`docs/mission-archive/2-mechanical-capture-sweep.md`](../mission-archive/2-mechanical-capture-sweep.md) — exact-evidence capture, idempotency, Flue-history authority, and model-free scheduling. +- [`docs/mission-archive/2-mechanical-capture-sweep.md`](../mission-archive/2-mechanical-capture-sweep.md) — exact-evidence capture, idempotency, Flue-history authority, and model-free scheduling. Historical: capture envelopes and sweep semantics are rejected for provenance since 2026-09-04; reviewer evidence is retained as canonical Flue history and cited through the revision-time evidence relation. - [`docs/mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) — accepted workpiece leg and falsified provider-schema construction leg. - [`evaluations/oracles/ir-quality-ruler-v1.md`](../../evaluations/oracles/ir-quality-ruler-v1.md) and [`evaluations/protocols/ir-quality-ruler-v1/cold-ir-reviewer.md`](../../evaluations/protocols/ir-quality-ruler-v1/cold-ir-reviewer.md) — current conservation, grounding, conflict-collapse, and cold-reading criteria; neither is yet a successive-revision oracle. - [`docs/evidence/evaluations/vestera-prospective-baseline-v1/campaign-adjudication.md`](../evidence/evaluations/vestera-prospective-baseline-v1/campaign-adjudication.md) — healthy foreground-turn range, costly whole-workpiece synthesis, and observed correction handling. - [`packages/core/src/prompts/SYSTEM.md`](../../packages/core/src/prompts/SYSTEM.md), [`packages/plugin-sdcpn/src/skills/sdcpn-modelling/SKILL.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/SKILL.md), and [`packages/plugin-sdcpn/src/skills/sdcpn-modelling/templates/workpiece.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/templates/workpiece.md) — current foreground lifecycle and workpiece correction behavior. - [`apps/brunch-agent/test/petrinaut-chat.test.ts`](../../../../../apps/brunch-agent/test/petrinaut-chat.test.ts), [`apps/brunch-agent/test/headless-petrinaut-client.test.ts`](../../../../../apps/brunch-agent/test/headless-petrinaut-client.test.ts), and [`packages/plugin-sdcpn/src/tools/petrinaut-construction.ts`](../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts) — current real door, bounded mutation subset, and its limits. -- [`7-capture-backed-review.md`](7-capture-backed-review.md) and [`9-traceable-projection.md`](9-traceable-projection.md) — provisional inherited artifacts, provenance seam, projection contract, and stable-identity obligations. Re-resolve these joins against accepted close evidence at cut time rather than assuming draft hypotheses landed. +- [`9-traceable-projection.md`](9-traceable-projection.md) — repeat, changed-input, retirement, and impact-boundary semantics this draft inherits. Re-resolve these joins against accepted close evidence at cut time rather than assuming draft hypotheses landed. - Commit `157730cc5a214dd9c543e8d95c7193a219c48aef` on deployment branch `ln/fe-1569-brunch-agent-deployment`, especially `libs/@hashintel/brunch-agent/docs/evidence/implementations/mission-8-deployment-handoff.md` — local application contract and the still-open infrastructure proof that any deployed durability claim must consume. ## Visible product advance @@ -63,12 +64,11 @@ scenario declares reviewer authority + selected region + base revisions → reviewer enters the deployed Petrinaut assistant panel → host-supplied browser `ChatTransport` over `@flue/sdk` resumes the owning Flue conversation at the mounted route → foreground Brunch agent conducts 3–5 focused operational-language turns -→ Flue history retains the canonical conversation -→ harness-owned mechanical sweep durably captures the settled reviewer range +→ Flue history retains the canonical reviewer turns under the compaction posture Mission 7 established → one bounded foreground phase-boundary synthesis reads: - prior workpiece revision + current derivation/region + newly captured evidence + prior settled workpiece revision + current region lineage (basis, transition records, epochs) + the reviewer's message ids → synthesis classifies correction | qualification | coexistence | conflict | refusal -→ attributed next workpiece revision + semantic diff + impact declaration +→ `update_workpiece` settles the attributed next revision, citing reviewer message ids through the revision-time evidence relation, with semantic diff + impact declaration → authority, base-revision, evidence, and impact gates admit or refuse commit → SDCPN plugin applies the bounded patch through Petrinaut-owned canonical mutations → Petrinaut validates the current net and selected behavior @@ -82,11 +82,11 @@ The foreground phase-boundary synthesis is the default. It is one explicit seman One scenario-declared, consequential operational distinction must cross the real deployed path and produce: - 3–5 focused reviewer turns in operational vocabulary; -- mechanically retained, attributed reviewer evidence; +- reviewer evidence retained as canonical history and cited by message id in the next settled revision; - an inspectable prior/current workpiece pair and semantic diff; - the correct class disposition; -- a bounded patch or explicit refusal; -- updated element → derivation → workpiece revision → original and reviewer evidence provenance; and +- a bounded patch or explicit refusal, every mutation citing the new settled revision with declared basis; +- updated element → basis → settled revision → original and reviewer evidence, with the correction visible in change history and the original in origin; and - unchanged ids and behavior outside the declared impact, except where a visible, justified widening is accepted. The default tracer should be a correction because it proves canonical change. It must be selected so a mistaken overwrite, qualification, coexistence, and conflict treatment would be observably different. One successful correction is only throughline proof and the first internal milestone; it does not close the class stratum and it is not mission completion, which additionally requires the demo's visible refusal or qualification. @@ -97,10 +97,10 @@ The default tracer should be a correction because it proves canonical change. It This cluster may start only after the prior missions have supplied and accepted: -- Mission 7's honest prebuilt pair, durable exact-evidence provenance, broken-link behavior, and element/workpiece/evidence identity seam; -- Mission 9's meaningful automatically projected live region, derivation coverage, canonical provider-visible mutation path, repeated-projection identity behavior, and explicit partial/unsupported failure; -- the current workpiece revision and exact source Flue conversation selected at the prior handoff; -- a deployment boundary that actually persists every state this path consumes across the replacement behavior it claims. +- Mission 7's genuine conversation and constructed region with the settled-revision protocol, declared basis, independently verifiable transition records, identity epochs, passage identity policy, live-document reconciliation, recorded roles, compaction posture, fixture materialization route, and the safety and utility gates for why; +- Mission 9's repeat idempotence, changed-input identity, retirement, concurrent-change refusal, impact-boundary semantics, and explicit partial or unsupported failure; +- the current settled workpiece revision and the exact source Flue conversation selected at the prior handoff; +- a deployment posture named honestly: local unless a Mission 8 successor has landed, with every persisted state this path consumes surviving the replacement behaviour actually claimed. Draft links are not evidence. If Mission 7 or Mission 9 ships a different representation, Mission 10 must consume that actual contract or return here for re-cutting. @@ -134,19 +134,19 @@ Breadth beyond the named classes and accepted scenario portfolio remains unearne - **ORACLE GAP — successive semantic revision:** no current oracle compares prior workpiece + newly captured evidence against the next revision across all five classes. Before cut, freeze a reviewed fixture set and adjudication rubric that detects lost supported meaning, incorrect authority, unsupported strengthening, conflict collapse, and incorrect disposition. - **ORACLE GAP — patch locality and behavior:** no current oracle proves that a semantic revision changes the intended linked region while preserving unrelated ids and behavior. Before cut, define the selected region, explicit allowed impact set, before/after id inventory, semantic expectations, and—where discriminating—a Petrinaut simulation comparison. - **ORACLE GAP — outer path:** no current test or artifact witnesses the 3–5-turn scenario portfolio through a remotely deployed Petrinaut/Brunch path. Before claiming the visible advance, record a human witness against the accepted deployment, exact scenario/base revisions, transcript, workpiece diff, mutation trace, before/after net, and refusal output. -- **ORACLE GAP — durable capture join:** the deployment handoff explicitly leaves the JSON capture store inactive and non-durable. Before this path consumes capture remotely, Mission 7 or this cut must identify and test the durable implementation across the claimed task-replacement boundary. +- **ORACLE GAP — lineage retention across compaction and replacement:** reviewer evidence lives in canonical Flue history and is cited by message id. Before this path claims retained reviewer evidence, consume Mission 7's compaction-probe result (history read, disclosed uncompacted window, or hardened session-log archive lane) and test it across the replacement boundary actually claimed. ## Verification approach - **Inner mechanism:** deterministic tests for authority checks, base-revision refusal, exact evidence references, semantic-diff representation, class disposition, idempotent commit, impact calculation, and canonical mutation validation. Use the frozen class fixtures and revision oracle; parser success cannot substitute for semantic review. -- **Middle integration/contract:** drive the production `ChatAgent`/AI SDK path from the selected Mission 9 artifact, perform the mechanical settled-range capture and foreground synthesis, apply the patch through the actual browser client-tool callbacks, and compare persisted before/after workpiece, derivation, and net artifacts. Exercise a stale-base attempt and one explicit refusal. +- **Middle integration/contract:** drive the production `ChatAgent` through the Mission 5 browser transport on the accepted Mission 9 conversation, perform the foreground synthesis into a settled `update_workpiece` revision citing reviewer message ids, apply the patch through the actual browser client-tool callbacks with declared basis, and compare persisted before/after workpiece revisions, transition records, epochs, and net definitions. Exercise a stale-base attempt and one explicit refusal. - **Outer deployed/user-visible:** a named human witness performs each accepted peer class through the deployed panel, including the 3–5-turn correction tracer, and verifies visible attribution, semantic diff, changed region, stable unrelated ids/behavior, updated why answer, and comprehensible refusal/failure. The live mission owns this outer proof; it cannot be delegated to Mission 11. ## Inputs and joins -- Upstream source exit: the frozen workpiece, exact source Flue conversation, instrument manifest, and evaluation/adjudication explicitly selected by Mission 7 or a predecessor addendum; Mission 4 itself supplies no full-run candidate. -- Mission 7: prebuilt workpiece/net pair, current workpiece revision and references, capture evidence references, net-element ids, projection rationale, durability disposition, and the why interaction. -- Mission 9: selected meaningful region, canonical mutation surface, derivation records, repeat-projection identity evidence, and accepted unsupported/partial behavior. +- Upstream source exit: the genuine persona or human conversation, its settled workpiece revisions, and the adjudication accepted by Mission 7; Mission 4 itself supplies no full-run candidate and the Mission 6 prepared fixture is not promoted. +- Mission 7: the constructed region, settled revisions, declared basis, transition records, identity epochs, passage policy, reconciliation, recorded roles, and the why operation with its gates. +- Mission 9: the extended region, canonical mutation surface, repeat and changed-input identity evidence, retirement semantics, impact boundary, and accepted unsupported or partial behaviour. - Mission 8: consume the actual application contract—fail-closed Postgres Flue state, verified TLS, IAM/static-password paths, content-free OTel, restricted routes, liveness, singleton ownership policy—but do not imply it is deployed. The infrastructure handoff, real RDS/Anthropic/collector/replacement/rollback proof, and owner acceptance remain required before an outer deployed claim. - Mission 11: receives only an accepted final workpiece/net/evidence/derivation revision package and the six-beat real-path evidence; its consumer contract may not weaken Mission 10's revision-integrity closure. @@ -157,17 +157,17 @@ Breadth beyond the named classes and accepted scenario portfolio remains unearne - **ASSUMPTION:** Mission 9's stable ids and derivation neighborhood are sufficient to calculate a bounded impact. **Impact if false:** local revision can cause unrelated churn or require broader context. **Cheapest validation:** dry-run the selected semantic change against the frozen Mission 9 before/after artifact and enumerate the minimal connected impact. - **RISK:** semantic diff reports textual edits while hiding a changed operational claim. **Impact:** a reviewer cannot understand what changed. **Cheapest validation:** cold human comparison against the class fixture's expected preserved/changed meaning. - **RISK:** compaction removes the recoverable workpiece or evidence needed by synthesis. **Impact:** stale or transcript-dependent revision. **Cheapest validation:** if the real path crosses compaction, reconstruct the same current revision and evidence references after that boundary; otherwise label the limitation and keep it outside the shipped durability claim. -- **RISK:** the capture store remains task-local JSON while the service claims replacement durability. **Impact:** reviewer evidence may disappear after acceptance. **Cheapest validation:** inspect the consumed Mission 7/Mission 8 storage contract before cut and refuse remote revision until capture durability is observed. +- **RISK:** reviewer evidence in canonical history is folded by compaction or lost at replacement while the service claims retained evidence. **Impact:** reviewer evidence may disappear after acceptance. **Cheapest validation:** inspect Mission 7's compaction-probe outcome and the consumed storage contract before cut and refuse the retained-evidence claim until retention is observed at the boundary claimed. ## Accepted constraints and guarded invariants - **STOP-THE-LINE — bounded authority:** canonical state changes only under the scenario's declared reviewer authority. Guard: authority fixture plus allowed/refused outer witness. -- **STOP-THE-LINE — evidence retention:** original and reviewer evidence stay exact, attributed, immutable, and reachable; model prose is never presented as quotation. Guard: capture identity/excerpt assertions and provenance inspection. +- **STOP-THE-LINE — evidence retention:** original and reviewer evidence stay exact, attributed by recorded role, immutable, and reachable by message id; model prose is never presented as quotation. Guard: verbatim-quote verification against canonical history and provenance inspection through the reopened why operation. - **STOP-THE-LINE — no recency overwrite:** prior supported meaning survives unless explicitly corrected, qualified, context-split, or retired under authority. Guard: successive-revision oracle across every accepted class. - **STOP-THE-LINE — patch locality:** unrelated ids and behavior remain stable, and necessary expansion is declared before commit. Guard: before/after id inventory, accepted impact set, and semantic/simulation check where applicable. -- Flue history remains the canonical conversation log; the capture ledger is not a second transcript. -- Mechanical capture remains domain-opaque and harness-owned. The foreground Markdown workpiece owns semantic synthesis. -- The foreground model neither receives nor schedules a sweep tool. Ordinary turns do not block on extraction, fold, completion, or projection. +- Flue history remains the canonical conversation log; no second transcript, capture ledger, or derivation store is admitted. +- The foreground Markdown workpiece owns semantic synthesis; revisions settle only through `update_workpiece`. +- The foreground model receives no sweep or extraction tool. Ordinary turns do not block on fold, completion, or projection. - Petrinaut owns canonical SDCPN schemas and mutations. Brunch imports or mechanically consumes them and does not copy field shapes. - Brunch remains a second assistant; preserve stock-assistant operation and distinct histories. Keep the panel on AI SDK `useChat` / `onToolCall`. - No comprehensive ontology, closed claim kinds, typed completion algebra, generic assertion fold, generalized runtime, TUI, second agent, or second server is earned. @@ -196,7 +196,7 @@ libs/@hashintel/brunch-agent/ └── docs/evidence/evaluations/ + observed revision campaign/adjudication apps/brunch-agent/ ├── src/agents/chat-agent/ ~ compose only accepted capabilities -├── src/capture/ ~ settled-range durable join, not semantic fold +├── src/capture/ - retired unless the compaction probe hardened the session-log archive lane ├── src/conversation/ ? explicit phase-boundary operation if this is the earned home ├── src/http/ ? only if the existing real door needs generic transport support └── test/ ~ production-path revision, refusal, persistence, and locality coverage @@ -218,7 +218,7 @@ No path is permission to edit before the cluster is cut. Prefer existing generic - The smallest linked neighborhood sufficient for synthesis and impact analysis. - What counts as unchanged behavior outside the region and when simulation is a useful discriminator. - How legitimate impact widening is previewed, authorized, and either committed or refused. -- The exact durable storage/transaction boundary across captures, workpiece revision, derivation links, and net commit. +- The exact durable storage and reconciliation boundary across settled workpiece revisions, transition records, epochs, and net commit; Mission 7's operation protocol is the starting point, not a transaction. - Whether the short path crosses Flue compaction; if not, which limitation must remain visible in the handoff. - Whether the chat answer alone makes prior/current meaning and patch impact inspectable or a generic linked detail surface is required. - Exact latency and usage ceilings must come from the accepted scenario and deployment budget, not invention. @@ -242,7 +242,8 @@ No path is permission to edit before the cluster is cut. Prefer existing generic - **Observer/fold rejected by default:** no observer exists on the production path, and the current IR ruler has not tested successive observer revisions. The canonical promotion mechanics and extraction ladder live in [`MISSION.next.md`](../../MISSION.next.md#foreground-revision-and-observer-re-entry). Mission 10 is the decisive strain gate: re-entry is considered only after repeated consequential foreground blocking, loss of prior supported meaning, stale state, unrecoverability, or unavoidable unbounded-history dependence. An admitted observer still may not mutate the net, and its likely short-review barrier is a forced tail sweep/queue flush because the token threshold alone may never fire. - **Recency overwrite rejected:** newer testimony may correct, qualify, coexist with, or conflict with earlier testimony. Time order alone is not authority. - **Append-only journal rejected:** it preserves history but leaves excessive cold-reading and canonical-meaning burden; the observed workpiece intent is a maintained current account with retained revision history. -- **One artifact rejected:** immutable captures and editable semantic workpiece revisions have different lifecycles. +- **One artifact rejected:** immutable conversation evidence and editable semantic workpiece revisions have different lifecycles. +- **Capture envelopes and derivation fixtures rejected for provenance (2026-09-04):** reviewer evidence is canonical history cited by message id through the revision-time evidence relation; element provenance is constructor-declared basis plus recorded transitions. See the [decision log](../evidence/design/provenance-and-tooling-decision-log-2026-09-04.md) entries F5, G3, G7, and G20. - **Deterministic typed fold rejected:** Condition 5's typed mapping plus in-loop model judgment caused minute-scale ordinary turns. Re-entry requires evidence that foreground synthesis cannot reliably preserve or classify meaning and that the narrower mechanism fixes the observed failure. - **Full regeneration rejected as a visible patch claim:** an implementation may reconsider broader context internally only if the applied diff remains bounded and unrelated identities/behavior are proven stable; otherwise it must report widening or refuse. - Mission 3 evidence establishes an accepted, cold-usable workpiece leg and one observed correction, but its construction leg failed 0-for-9 on nested provider-visible shape and produced a vacuous empty net. Mission 9 must retire that risk before this cluster treats patching as available. diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/11-optimisation-handoff.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/11-optimisation-handoff.md index 4f163baa4ab..62e432f3c19 100644 --- a/libs/@hashintel/brunch-agent/docs/mission-drafts/11-optimisation-handoff.md +++ b/libs/@hashintel/brunch-agent/docs/mission-drafts/11-optimisation-handoff.md @@ -8,7 +8,8 @@ A fresh builder must read these durable sources before deepening this cluster: -- [`../../MISSION.md`](../../MISSION.md) — live Mission 5 Voice authority on this branch. Mission 4 is closed; later accepted mission archives and an owner-authorized Mission 11 cut become inherited authority before this draft can execute. +- [`../../MISSION.md`](../../MISSION.md) — the current branch's live authority. Mission 4 is closed; later accepted mission archives and an owner-authorized Mission 11 cut become inherited authority before this draft can execute. +- [`7-explainable-construction.md`](7-explainable-construction.md) and [`9-traceable-projection.md`](9-traceable-projection.md) — the 2026-09-04 recut predecessors. Mission 11 consumes their genuine conversation, settled revisions, declared basis, transition records, and the why operation; it does not inherit a capture store or derivation fixture, because neither exists. - [`../../MISSION.next.md`](../../MISSION.next.md) and [`README.md`](README.md) — shared frame, standing locks, draft authority, and lifecycle. - [`10-bounded-reviewer-revision.md`](10-bounded-reviewer-revision.md) and the eventual accepted Missions 7, 9, and 10 close evidence — inherited real-path artifacts and proof. Draft promises are not join evidence. - [`../mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) — accepted workpiece leg, falsified real-model construction, and the parser-valid-empty warning. @@ -83,7 +84,7 @@ One selected complete SDCPN and the known semantic artifact floor: - carry the accepted scenario and parameters with honest assumptions, omissions, losses, and limits; and - let them begin the one agreed optimisation experiment at the accepted boundary. -This proves one accepted handoff and is also the completion bar, since the consumer's acceptance is the readiness decision. It does not prove a generic export package, optimizer integration, result model, repeated-experiment protocol, public release, or broad scenario portfolio. +This proves one working handoff throughline. It is not the completion bar. Mission 11 has three distinct gates, corrected on 2026-09-04 after the [follow-up review](../evidence/design/provenance-by-lineage-follow-up-review-2026-09-04.md) item 23: (1) consumer contract acceptance of the six decisions and one fixture, which is the precondition for cutting; (2) the working handoff throughline above, which is the first internal milestone; and (3) post-throughline readiness closure sufficient for Chris and Yannis to begin the agreed experiment without reconstruction, which is completion. Artifact receipt or consumer enthusiasm is not an executable witnessed experiment start. The floor does not prove a generic export package, optimizer integration, result model, repeated-experiment protocol, public release, or broad scenario portfolio. ## Readiness ratchet @@ -91,8 +92,8 @@ This proves one accepted handoff and is also the completion bar, since the consu Mission 11 consumes rather than repairs: -- Mission 7's durable capture-backed provenance and visible why behavior; -- Mission 9's meaningful automatic projection, stable identities/derivations, and closed projection stratum for the selected region; +- Mission 7's genuine constructed region with settled revisions, declared basis, verifiable transition records, identity epochs, and the why operation past its safety and utility gates; +- Mission 9's repeat, changed-input, and retirement behaviour and closed breadth stratum for the extended region; - Mission 10's accepted reviewer-authority classes, retained evidence, semantic revision, scoped patch/refusal, and stable unrelated behavior; and - an actual deployment threshold sufficient for the consumers to use the path, with each claimed identity, durability, telemetry, access, and recovery property observed rather than inferred from the local image. @@ -100,9 +101,9 @@ If inherited closure is missing, return the defect to its owning mission. Missio ### Readiness gate after the new throughline -The lateral obligations are intentionally not enumerated beyond the six consumer decisions. Once the first accepted handoff works, enumerate only the package, transfer, execution, result, credibility, repeatability, access, or retention obligations that the actual boundary exposes. Close those required to trust and begin the selected experiment. Carry broader obligations only with a named successor, re-entry gate, and oracle. +The lateral obligations are intentionally not enumerated beyond the six consumer decisions. Once the handoff throughline works, enumerate the package, transfer, execution, result, credibility, repeatability, access, and retention obligations that the actual boundary exposes, and close those required for the consumers to begin the selected experiment without reconstruction. That closure is gate three and the completion bar; the throughline alone is not. Carry broader obligations only with a named successor, re-entry gate, and oracle. -Until consumer acceptance, any more detailed readiness list would plan past the fog-line. +Until consumer acceptance, any more detailed readiness list would plan past the fog-line. Lightweight, non-binding consumer discovery is nevertheless owed earlier, per the 2026-09-04 dispositions (decision log F15): before Mission 9 selects its extended region, record with Chris and Yannis one candidate optimisation question, the minimum scenario and parameter semantics it needs, the expected execution boundary, required outputs, and minimum credibility checks, so the proving cases exercise semantics the consumers will actually need and so file-level provenance can be judged load-bearing or not before Mission 11. Discovery informs selection; it does not authorize implementation here. ## Candidate evidence and oracles @@ -121,8 +122,9 @@ Until consumer acceptance, any more detailed readiness list would plan past the ## Inputs and joins -- Selected upstream source: frozen workpiece, exact source Flue conversation, instrument manifest, and adjudication chosen by Mission 7 or a predecessor addendum; Mission 4 itself closed without a full-run candidate. -- Missions 7, 9, and 10: accepted bounded workpiece/net/evidence/derivation chain, revision and patch-locality evidence, and the witnessed real path Mission 11 must broaden. +- Selected upstream source: the genuine conversation, settled workpiece revisions, and adjudication accepted by Mission 7; Mission 4 itself closed without a full-run candidate and the Mission 6 prepared fixture is not promoted. +- Missions 7, 9, and 10: accepted conversation, settled revisions, declared basis, transition records, identity epochs, repeat and change behaviour, revision and patch-locality evidence, and the witnessed real path Mission 11 must broaden. +- Early consumer discovery: the non-binding record of one candidate question, minimum semantics, execution boundary, outputs, and credibility checks gathered before Mission 9's region selection. - Mission 8 actual contract: locally verified application artifact plus still-open infrastructure handoff; no remote deployment is assumed. - Chris/Yannis: written acceptance of the six consumer decisions and one fixture. - Petrinaut: current serialization, scenario, optimization, and host capabilities are inspected as existing terrain and used only where the consumer contract accepts them. diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/7-capture-backed-review.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/7-capture-backed-review.md deleted file mode 100644 index 07ab3f6ca0c..00000000000 --- a/libs/@hashintel/brunch-agent/docs/mission-drafts/7-capture-backed-review.md +++ /dev/null @@ -1,294 +0,0 @@ -# Draft Mission 7 — Capture-backed review of an honest prebuilt pair - -> Draft cluster only. Not execution authority. Do not implement until this cluster is re-evaluated and cut into `MISSION.md`. - -## Cold-start reads - -- [FE-1573](https://linear.app/hash/issue/FE-1573/explain-one-prepared-petrinaut-net-from-exact-conversation-evidence) — tracker projection for this future branch mission; it advances stakeholder outcome [FE-1478](https://linear.app/hash/issue/FE-1478/provide-provenance-from-a-generated-net-back-to-the-requirements-graph) without rewriting that record. - -A fresh builder must resolve the current repository and the deployment handoff rather than treating this draft as a specification: - -- [`../../MISSION.md`](../../MISSION.md) — live Mission 6 viability authority on this branch, stacked on the live Mission 5 transport authority of [FE-1574](https://linear.app/hash/issue/FE-1574/let-voice-speak-through-canonical-brunch-conversations); neither supplies Mission 7 execution authority or a conversation/workpiece candidate, and Mission 4 produced no full-run candidate. -- [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) — live Mission 6 viability predecessor. If accepted, its deliberately prepared and honestly labelled fixture may become this mission's selected pair after a separate provenance-suitability decision; at cut time replace this live pointer with the accepted archive/evidence. A complete persona workpiece is not intrinsically required. -- [`../../MISSION.next.md`](../../MISSION.next.md) — compact future spine, FE-1476 product frame, shared proof obligations, standing locks, and any later evidence admitted after this draft was written. -- [`../mission-archive/2-mechanical-capture-sweep.md`](../mission-archive/2-mechanical-capture-sweep.md) — accepted mechanical capture throughline, exact close evidence, empty-payload boundary, conversation identity, and carried flags. -- [`../mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) and [`../evidence/implementations/fe-1525-headless-runbook-pn.md`](../evidence/implementations/fe-1525-headless-runbook-pn.md) — accepted runbook/workpiece leg, falsified real-model construction leg, and the distinction between a hermetic non-empty fixture and vacuous empty-net parser success. -- [`../evidence/evaluations/vestera-prospective-baseline-v1/campaign-adjudication.md`](../evidence/evaluations/vestera-prospective-baseline-v1/campaign-adjudication.md) — frozen Mission 3 control and cold-reader evidence; do not substitute current source for its instrument revision. -- [`apps/brunch-agent/test/petrinaut-chat.test.ts`](../../../../../apps/brunch-agent/test/petrinaut-chat.test.ts), [`apps/brunch-agent/test/petrinaut-chat.integration.ts`](../../../../../apps/brunch-agent/test/petrinaut-chat.integration.ts), and [`apps/brunch-agent/src/capture/apply-sweep.ts`](../../../../../apps/brunch-agent/src/capture/apply-sweep.ts) — current production chat door and explicit harness-owned sweep. -- [`../../packages/core/src/evidence/capture-store.ts`](../../packages/core/src/evidence/capture-store.ts), [`../../packages/core/test/capture-store.test.ts`](../../packages/core/test/capture-store.test.ts), [`../../packages/binding-flue/src/local-capture-store.ts`](../../packages/binding-flue/src/local-capture-store.ts), and [`../../packages/binding-flue/test/local-capture-store.test.ts`](../../packages/binding-flue/test/local-capture-store.test.ts) — capture envelope, archived evidence, ownership, atomicity, parse, and local durability contracts. Their richer historical types are not permission to expose a typed capture ontology in this mission. -- [`apps/brunch-agent/src/http/petrinaut-chat.ts`](../../../../../apps/brunch-agent/src/http/petrinaut-chat.ts), [`apps/brunch-agent/src/conversation/client-tools.ts`](../../../../../apps/brunch-agent/src/conversation/client-tools.ts), and [`../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx`](../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx) — AI SDK transport, Flue client-tool suspension/resume, and the existing `useChat` / `onToolCall` browser execution boundary. -- Commit `157730cc5a214dd9c543e8d95c7193a219c48aef` on deployment branch `ln/fe-1569-brunch-agent-deployment`, read with `git show`, especially `libs/@hashintel/brunch-agent/docs/evidence/implementations/mission-8-deployment-handoff.md`, plus its `MISSION.md`, `MISSION.next.md`, Mission 4 archive, and archive README. That commit proves a local application artifact and stops at the application-to-infrastructure handoff; it does not prove remote deployment. -- On that branch, inspect `apps/brunch-agent/src/db.ts`, `src/postgres.ts`, `src/database-config.ts`, `test/postgres.test.ts`, `test/database-config.test.ts`, and `test/container-smoke.integration.ts`. Mission 7 activates capture as product data and therefore must use a durable implementation at the claimed replacement boundary; task-local JSON is not an admissible deployed capture store. -- [`../../../petrinaut/docs/ai-assistant.md`](../../../petrinaut/docs/ai-assistant.md) and the other Petrinaut user-guide pages that mention the affected panel flow. Any user-visible change requires same-change documentation and a prompt to replace screenshots if they become stale. - -Mission 4 closed without admitting its full run and therefore retained no source conversation/workpiece handoff candidate. Mission 6 may establish an honestly prepared conversation/workpiece/document fixture without changing that fact. Mission 7 must select either that accepted prepared fixture, another explicitly eligible retained source, or a newly authorized run, then record why it is sufficient for the narrower capture-backed provenance claim. Selection is not retrospective persona acceptance or a general quality claim. - -## Visible product advance - -**Release note:** ask Brunch why any element in the demo net exists and get back what the expert actually said. - -**Demo script (no engineer present):** open the honestly prebuilt demo net in the Petrinaut Brunch panel, on the deployment posture named at cut time (a locally run panel is acceptable; remote durability stays in the readiness gate). Pick any consequential element and type its visible name or id. Read the current workpiece passage that supports it, the prebuilder's rationale including any assumption, default, omission, or loss, and the exact quoted excerpts from the source conversation. Pick the element the demo marks as unsupported and watch Brunch decline rather than improvise. - -**Previously impossible:** nothing connected a net element to the conversation evidence behind it; a reviewer had to trust the modeller. - -Each answer contains: - -1. the current selected Markdown workpiece passage that supports the modelled meaning; -2. the prebuilder's explicit projection rationale, including consequential assumption, uncertainty, omission, default, or representational loss; and -3. exact mechanically retained excerpts from the source Flue conversation. - -The response visibly identifies both the workpiece and SDCPN as prebuilt. It makes no claim that Brunch automatically projected the net, inferred a complete provenance graph, or observed and consolidated the conversation in the background. A deliberately broken provenance link returns a visible unsupported/unavailable result rather than a plausible reconstructed explanation. - -This is FE-1476 beats 1–3 over one honest pair. The six-beat story is the integrated floor, not the product or demo ceiling; the broader scenario portfolio remains unenumerated and must be named when this draft is cut. - -Typing a visible element name or id is the accepted first interaction. Click-to-chat and automatic canvas-selection context are deferred unless textual identification proves ambiguous or burdensome in observed review use. - -**Completion:** the mission is done when every consequential element in the demo net either resolves or visibly declines, at the readiness gate below. One resolving element is the throughline tracer inside the mission, not the mission. - -**Scope decision, 2026-09-03:** the earlier one-element cut was judged too small under the product-manager litmus. The owner expanded Mission 7 to the whole demo net rather than consolidating it. Folding it into Mission 6 was rejected because it would load the viability tracer with capture durability and delay it. Folding it into Mission 9 was rejected because it would tie explainability, a stakeholder outcome in its own right (FE-1478), to the unproved provider-schema projection route. Expansion is cheap: capture durability and the why route cost the same for one element or all of them, and the extra work is preparing provenance for the rest of the pair. Reverse toward consolidation with Mission 9 only if preparing whole-net provenance by hand proves to be the dominant cost with no mechanism strain, in which case the why route should ride on Mission 9's generated derivations instead. - -## Contract stratum - -Close the **capture-backed provenance stratum for the selected prebuilt workpiece/SDCPN pair**. - -The accepted objects and minimum seam are: - -- one current Markdown workpiece revision promoted from an explicitly named retained source only after eligibility inspection and owner selection; -- one exact source Flue conversation and explicit settled range; -- immutable mechanical capture envelopes containing exact evidence and source pointers; -- stable references from consequential workpiece passages to capture evidence; -- one honestly prebuilt non-empty SDCPN with stable element ids; -- a minimal derivation fixture from consequential net elements to current workpiece passages, projection rationale, and relevant uncertainty/assumption/loss; and -- one reviewer-facing resolution operation from a typed visible element name/id to that chain. - -This stratum is narrower than automatic projection and broader than one green lookup. Every consequential element in the selected pair must have either resolvable provenance or an explicit unsupported/unlinked disposition before the visible pair can be trusted as capture-backed. The contract also covers duplicate, ambiguous, and stale identity; missing evidence; replay/idempotency; capture durability; cross-owner refusal; visible failure; and recovery at the replacement boundary the deployed product claims. - -Capture remains domain-opaque evidence. The foreground Markdown workpiece owns semantic synthesis. The derivation fixture records what the human or explicitly identified prebuilder decided. No capture payload becomes the canonical workpiece, assertion card, SDCPN proposal, or semantic intermediate representation. - -## Boundary crossings and current throughline hypothesis - -```text -owner-selected eligible retained conversation/workpiece source - → harness explicitly names the settled source range - → Mission 2 mechanical sweep reads Flue history - → durable capture store archives exact user evidence and immutable envelopes - → prepared Markdown workpiece references the relevant capture ids/spans - → identified prebuilder creates a non-empty SDCPN and minimal derivation fixture - → durable product state preserves workpiece, derivation, captures, and owner binding - → deployed Petrinaut reviewer sees the selected prebuilt net - → reviewer types a visible element name or id in the existing AI panel - → AI SDK transport sends the turn to the Brunch Flue ChatAgent - → provenance capability resolves element → derivation → current workpiece → capture archive - → client/server response returns exact excerpts plus attributed rationale - → panel renders an evidence-grounded why answer or visible unsupported/unavailable refusal -``` - -Actor and authority crossings: - -- **Flue conversation → Brunch harness:** history is the canonical conversation log; an explicit harness fact, never the interviewer model, schedules the sweep. -- **Harness → capture store:** only mechanical capture projection and evidence archiving occur. The store validates ownership, source pointers, idempotency, atomicity, and durable format. -- **Capture store → workpiece preparation:** a person or explicit preparation step writes narrow references. There is no automatic capture-to-workpiece reducer. -- **Workpiece → prebuilder:** the prebuilder interprets the selected Markdown meaning and records its rationale. The net is not represented as model-generated. -- **Brunch server → Petrinaut browser:** the Flue agent emits a client-tool request or uses another application-level host extension; the existing `useChat` / `onToolCall` path executes it. Petrinaut library code must not gain Brunch-specific business logic. -- **Element id/name → evidence:** deterministic stored links select the derivation and evidence. The model may explain linked material but may not invent links or substitute a transcript reread. -- **Application → deployment substrate:** active Flue and capture/workpiece/derivation state cross the actual Mission 8 persistence boundary. The application artifact exists on the deployment branch; infrastructure deployment and replacement proof remain open. - -## Throughline proof floor - -At the real product boundary named at cut time: - -1. one consequential visible element in the honestly prebuilt SDCPN resolves from its stable id or unambiguous visible name to the current workpiece passage, prebuilder projection rationale, exact source excerpts, and at least one relevant uncertainty, assumption, omission, default, or loss; and -2. one deliberately broken or stale link visibly returns unsupported/unavailable without fabricated rationale or evidence. - -This floor is the first internal milestone: a real capture-backed why route for one element and its honest negative control. It is not mission completion, which is the readiness gate over every consequential element. It does not close the selected pair's whole provenance stratum, prove automatic projection, establish an observer, type capture semantics, or enumerate the broader scenario portfolio. - -## Readiness ratchet - -```text -Mission 2 mechanical-capture throughline -+ one retained source selected and promoted through an explicit eligibility and identity decision -+ Mission 8 landed application contract and still-open infrastructure handoff -→ inherited capture/workpiece/deployment closure required here -→ one deployed capture-backed why answer plus broken-link refusal -→ readiness gate -├─ close provenance breadth and durability for the selected prebuilt pair before Mission 7 ships -├─ admit the stable workpiece/derivation/element seam into Mission 9 automatic projection -└─ leave typed capture semantics, automatic observation, broad scenario coverage, and autonomous projection unearned -``` - -### Inherited stratum closure - -Mission 7 consumes, but must not overstate: - -- **Mission 2 throughline:** explicit settled Flue history ranges produce idempotent, source-linked envelopes with payload `{}` and no extraction model. Before use as product data, replay must preserve exact source evidence, owner refusal, format validity, and atomic all-or-nothing behavior. -- **Mission 3/4 evidence boundary:** Mission 4 accepted the core/plugin implementation on partial activation/restraint evidence but retained no full-run workpiece candidate. Before preparing the pair, this mission or its predecessor addendum must select a retained source, establish that its workpiece is cold-readable and sufficiently epistemically honest for the named review slice, freeze it with the exact source conversation and instrument, and record every accepted limitation. It may use only the topology-neutral rows made load-bearing by that slice and may not hide a known gap in the derivation. -- **Prebuilt-pair honesty:** all net content used by the visible path must have an identified preparation route, stable ids, and explicit projection rationale. Parser validity alone and the Mission 3 empty paid document are ineligible. -- **Deployment application contract:** the pinned Mission 8 handoff has locally verified fail-closed Postgres Flue storage, TLS, image, health, content-free telemetry, and container smoke, but no remote infrastructure proof. Because this mission activates capture, its durable storage and replacement behavior become application and infrastructure obligations. Its inactive local JSON capture store is not inherited closure. -- **Product door:** panel → AI SDK → Flue `ChatAgent` and client-tool resume already work. The panel remains the real entrypoint and the stock assistant remains independent. - -If any inherited item is unavailable at cut time, name it as open inherited closure with an owner and oracle; do not call the throughline a dependable base. - -### Readiness gate after the new throughline - -This gate is Mission 7's completion bar. Before Mission 7 can ship its selected-pair claim, assess every consequential element in the demo net and close: - -- resolvable current provenance or an explicit unsupported/unlinked disposition; -- duplicate ids/names, ambiguous name lookup, stale workpiece revision, stale derivation, deleted/renamed element, missing capture, and mismatched owner; -- exact-evidence replay, sweep idempotency, capture/workpiece/derivation durability, atomic update/refusal, format/version refusal, and replacement recovery; -- cross-owner read/write refusal and absence of evidence leakage in errors, telemetry, or rendered answers; -- visible negative states for unsupported, unavailable, ambiguous, stale, and temporarily failed resolution; -- deterministic context source: stored current workpiece and derivation, never transcript fallback disguised as provenance; -- stock-assistant coexistence and a Brunch selection/routing posture sufficient for the selected deployed path; -- representative latency, model/tool usage, timeout, and failure behavior without reintroducing minute-scale foreground extraction/fold work; and -- compaction/stale-state risk: either cross a real compaction boundary and preserve the resolution chain, or state and visibly guard the accepted non-compaction limit. - -Mission 9 may inherit the stable seam only after these leaves are enumerable and accepted: current workpiece revision identity, workpiece passage/reference identity, exact capture evidence references, stable net element ids, and projection rationale/derivation identity. **Owner:** Mission 9. **Re-entry gate:** its first automatic projection must write the same seam and Mission 7's why operation must resolve a generated element without fixture-only translation. **Oracle:** Mission 9's deployed generated-element why proof plus repeated/changed projection identity checks. - -Do not carry selected-pair provenance breadth, capture durability, owner refusal, or broken-link visibility into Mission 9: Mission 7's visible claim already depends on them. - -## Candidate evidence and oracles - -| Claim leaf | Existing evidence or candidate oracle | -| --- | --- | -| Explicit harness-owned sweep over real Flue history; no interviewer sweep tool; exact excerpt, `{}` payload, idempotent retry | Existing `apps/brunch-agent/test/petrinaut-chat.test.ts`, test `the committed /api/chat door streams a plain Flue agent through server and client tools`, driven by `apps/brunch-agent/test/petrinaut-chat.integration.ts`; recut Mission 5 re-expresses this scenario through the browser Flue transport against the mounted route while preserving its assertions, so cite the successor test it leaves behind. Run `yarn workspace @apps/brunch-agent test:unit`. | -| Capture command closure, source evidence, all-or-nothing refusal, supersession/conflict guards, persisted parse | Existing `libs/@hashintel/brunch-agent/packages/core/test/capture-store.test.ts`, suite `capture-store contract`. Run `yarn workspace @hashintel/brunch-agent test:unit`. These tests are evidence for internal historical mechanics, not permission to expose typed payload semantics. | -| Owner refusal, tmp-and-rename persistence, serialization, invalid-format failure | Existing `libs/@hashintel/brunch-agent/packages/binding-flue/test/local-capture-store.test.ts`, suite `local capture store`. Run `yarn workspace @hashintel/brunch-agent-binding-flue test:unit`. This is local-file evidence only. | -| Panel executes client tools and resumes one turn through AI SDK | Existing `apps/brunch-agent/test/petrinaut-chat.test.ts` plus `libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.test.tsx`, test `adds one dynamic output and sends one automatic follow-up`. Run `yarn workspace @apps/brunch-agent test:unit` and `yarn workspace @hashintel/petrinaut test:unit --run`. | -| Mission 3 workpiece is recoverable and cold-readable; empty paid net is semantically false | Existing `docs/evidence/implementations/fe-1525-headless-runbook-pn.md` and `docs/evidence/evaluations/vestera-prospective-baseline-v1/campaign-adjudication.md`; artifact inspection is the oracle. | -| Mission 8 application contract is locally verified but remote replacement remains open | `157730cc5a214dd9c543e8d95c7193a219c48aef:libs/@hashintel/brunch-agent/docs/evidence/implementations/mission-8-deployment-handoff.md`: exact recorded commands include `yarn workspace @apps/brunch-agent lint:tsc`, `lint:eslint`, `test:unit`, `build`, `build:docker`, and `turbo run test:unit --filter='@hashintel/brunch-agent...'`, plus native arm64, explicit `linux/amd64`, and Docker/Postgres/collector smoke. The handoff explicitly is not remote proof. | -| One retained source is exact, and one workpiece is explicitly promoted as eligible for the selected pair | **ORACLE GAP:** Mission 4 supplied no full-run candidate. Resolve before this draft is cut by naming an eligible retained source or addendum-owned run, selecting the smallest workpiece-eligibility checks required by the visible review slice, recording identity/remapping rules, freezing the promoted input, and obtaining owner selection. Do not imply full topology-neutral or comparative acceptance. | -| Every consequential element in the selected prebuilt pair has a derivation or explicit unsupported disposition | **ORACLE GAP:** no selected pair or inventory exists. Resolve with a frozen element inventory mechanically compared with the derivation fixture and human inspection of every unsupported disposition. | -| One typed name/id yields an evidence-grounded answer and broken link yields visible refusal in deployed panel | **ORACLE GAP:** no existing test or deployed witness exercises this operation. At cut time bind it to the exact production-path test and a human panel witness; do not count a server-only fixture. | -| Capture/workpiece/derivation survive the actual claimed replacement boundary | **ORACLE GAP:** deployment branch stopped before remote task replacement and left capture inactive. Resolve with one immutable image, selected durable store, process restart and cross-host replacement inspection against the same ids. | -| Cross-owner provenance refusal | Existing local capture-store owner refusal is inner evidence only. **ORACLE GAP:** bind an outer deployed second-principal probe to the selected identity/access boundary. | -| Stock assistant works with Brunch unavailable | **ORACLE GAP:** current standing lock is not an observed Mission 7 witness. Resolve with the exact host-mode test and browser witness selected at cut time. | -| Latency, usage, transcript fallback, and stale-state behavior are visible | **ORACLE GAP:** define thresholds only from a representative deployed run and owner acceptance; instrument the selected operation without content export. | - -## Verification approach - -- **Inner mechanism evidence:** run the existing core capture-store, binding local-store, and app sweep tests; add only tests required by the chosen narrow reference and durable-store representation. Mechanism checks must pin exact evidence, immutable captures, stable references, owner refusal, stale/ambiguous resolution, atomic failure, and format refusal. They do not establish the product claim. -- **Middle integration/contract evidence:** drive the production built Brunch application through AI SDK and Flue with the frozen pair, execute the actual provenance capability/client-tool boundary, and verify element → derivation → current workpiece → captures for positive and deliberately broken links. Exercise process restart and the selected durable implementation. Compare every consequential element to the frozen disposition inventory. -- **Outer deployed/user-visible evidence:** a human reviewer opens the selected prebuilt net through the deployed Petrinaut/Brunch boundary, types the visible element name/id, sees the attributed answer and prebuilt label, then exercises a broken link and a cross-owner attempt. Repeat after the claimed task replacement. Explicitly witness that stock mode still works. The mission owns this outer evidence; it may not defer it to Mission 9. -- **Semantic adjudication:** a cold reader checks that each answer distinguishes exact expert excerpts, current workpiece synthesis, and prebuilder rationale/assumption/loss. Plausible prose, source-path display, or link presence without semantic correspondence fails. - -## Inputs and joins - -- **Upstream source join:** Mission 4 supplies activation/restraint evidence and an explicit record that no full-run candidate exists. Mission 7 may consume Mission 6's honestly prepared fixture, name another retained source, or produce one under new authority, but must freeze the exact conversation/workpiece/document inputs and pass the minimum provenance-suitability and identity/remapping contract. The join fails if prepared material is presented as persona/model evidence, a branch-tip workpiece is treated as previously accepted, or a Flue identity is presented as Petrinaut net/user identity. -- **Mission 2 join:** explicit `applyCaptureSweep`-style harness operation, evidence archive, capture idempotency, owner key, and no interviewer scheduling. Reuse mechanics only after inspecting current contracts; do not revive generalized typed elicitation. -- **Prebuilt fixture join:** identified preparer, stable net element ids, current workpiece references, capture evidence references, projection rationale, and explicit unsupported dispositions. The pair must be non-empty and semantically inspectable. -- **Mission 8 join:** consume the landed application contract and the open infrastructure handoff accurately. Mission 7 must add durable capture/product-state scope before claiming replacement durability, then join to actual ECS/RDS/collector/ingress identity supplied by infrastructure. -- **Petrinaut host join:** use the existing generic panel tool-execution surface and canonical net identity. Any new UI or user behavior updates Petrinaut docs in the same change. -- **Mission 9 output join:** hand off the accepted seam and why operation so automatic projection can generate derivations that resolve without a fixture-specific adapter. - -## Risks and assumptions - -| Risk or assumption | Impact if false | Cheapest discriminating validation | -| --- | --- | --- | -| A workpiece promoted from the selected retained source can host stable passage/reference identity without becoming assertion cards | If false, links churn or a second semantic artifact is needed | Prepare references for the consequential prebuilt pair and revise a non-semantic line; observe whether meaning-bearing references remain unambiguous. Stop before choosing a new ontology. | -| Visible element name is unique enough for reviewer input, with id as escape hatch | If false, a name-only why request can resolve the wrong element | Inventory duplicate/renamed names and exercise an ambiguous query that must request/disclose the id rather than guess. | -| A minimal companion derivation fixture is sufficient for why review | If false, rationale or loss cannot be recovered without transcript reread | Cold-read one consequential and one unsupported element using only workpiece, derivation, and captures. | -| Exact excerpts plus workpiece context are enough for a useful why answer | If false, the UI may expose provenance yet fail the review task | Human reviewer judges whether the answer explains the modelling choice and its uncertainty, not merely lists ids or quotes. | -| The Mission 8 Postgres application boundary can durably host or coordinate activated capture/workpiece/derivation state | If false, task replacement breaks provenance or requires a different durable owner | Implement the least candidate behind existing storage boundaries and run process/cross-host replacement; do not infer from Flue-table durability. | -| The selected short path need not cross Flue compaction | If false, workpiece/evidence recovery may fail during the visible review | Measure the selected conversation against compaction behavior; if crossed, make compaction recovery part of this mission. If not, guard and disclose the limit. | -| A model can explain deterministic linked material without inventing provenance | If false, free-form generation can launder unsupported claims | Negative controls remove or stale one link and compare the answer; require structured unavailable state before explanatory prose. | -| One selected prebuilt pair makes the peer set enumerable | If false, stratum closure cannot be distinguished from one tracer | Freeze the pair and inventory all consequential elements before broadening. | - -## Accepted constraints and guarded invariants - -- **One authority:** this file remains non-executable until converted into `MISSION.md`. Guard: exact warning and absence of live mission headings. -- **Flue history is canonical conversation log; capture is not a second transcript.** Guard: sweep reads named Flue entries and stores exact spans/excerpts only. -- **Harness owns sweep scheduling.** The foreground model receives no sweep tool and no scheduling instruction. Guard: existing app throughline test's tool-name assertions plus production manifest inspection. -- **Capture envelopes are immutable, exact-evidence, and domain-opaque.** Guard: capture-store parse/idempotency tests and schema inspection; stop if SDCPN fields enter capture payload contracts. -- **Foreground Markdown workpiece owns semantic synthesis.** Guard: cold-reader inspection and absence of an automatic capture reducer. -- **Prebuilt means prebuilt.** Guard: visible product label and frozen preparation manifest. Stop the line if the pair is described as automatically projected. -- **No observer.** No token threshold, `useAgentFinish` scheduler, asynchronous model fold, assertion consolidation queue, or automatic background update enters this mission. Guard: dependency/tool/state inventory. -- **No typed capture ontology or assertion-card default.** No closed kinds, slots, subject/predicate/value, per-capture SDCPN hints, or typed completion algebra. Guard: public-schema review. -- **No automatic projection.** The net and derivation are fixtures/prepared artifacts; no workpiece-to-mutation engine is mounted. Guard: tool manifest and preparation record. -- **No transcript fallback.** A missing stored link returns unsupported/unavailable. Guard: broken-link negative control. -- **Durability matches the claim.** Task-local JSON cannot support replacement durability. Guard: restart and cross-host replacement with the same ids and owner binding; startup refuses incompatible/missing durable configuration. -- **Ownership fails closed.** Guard: existing local owner refusal plus deployed second-principal probe. -- **Petrinaut remains contract owner and stock assistant remains independent.** Guard: no Brunch-specific logic in the published Petrinaut core, host coexistence test, and stock-mode browser witness. -- **No content-bearing telemetry by default.** Guard: trace/log inspection for excerpts, prompts, tool payloads, credentials, and owner material. - -## Cross-cutting obligations - -- Workpiece sufficiency: a cold reader can reconstruct the relevant objective/process meaning and distinguish evidence, inference, assumption, unknown, conflict, omission, and construction-opened loss. -- Evidence provenance: exact conversation evidence remains attributable; normalized workpiece or model prose is never presented as quotation. -- Projection fidelity for this prebuilt pair: every consequential prebuilt region names the workpiece material and preparer's rationale; no automatic generation claim is made. -- Failure visibility: ambiguity, missing/stale links, owner mismatch, durable-store refusal, and unavailable Brunch visibly stop/degrade the operation without advancing or fabricating state. -- Interaction quality: the why operation remains in reviewer language and does not expose construction schemas or block on semantic extraction/fold work. -- Security/privacy: consume Mission 8's restricted-boundary posture, trusted identity decision, durable state, and content-free operational visibility as actually accepted at cut time. -- Host continuity: preserve `useChat` / `onToolCall`, separate histories, and stock-assistant availability. -- User docs: update affected Petrinaut docs with what the reviewer types, what appears, and failure behavior; prompt for screenshot replacement if the UI changes. -- Architecture docs: if a new Petrinaut/Brunch folder forms a real architectural unit, add the required local declaration and run the Petrinaut architecture-doc lint. - -## Expected touched paths - -Tentative only; re-evaluate after the real boundary survey. - -```text -libs/@hashintel/brunch-agent/ -├── MISSION.md ~ cut-time authority only -├── docs/evidence/ + selected-pair/provenance adjudication -├── packages/core/src/evidence/ ~ only if narrow reference/durable contracts belong in core -├── packages/core/test/ ~ corresponding contract guards -├── packages/binding-flue/src/ ~ durable capture adapter only if this remains the honest binding -└── packages/binding-flue/test/ ~ ownership/recovery/refusal guards - -apps/brunch-agent/ -├── src/capture/ ~ explicit harness sweep and durable store composition -├── src/conversation/ ~ narrow provenance capability/client-tool signal if earned -├── src/agents/chat-agent/ ~ mount only the why capability, never automatic projection -├── src/http/ ~ selected deployed route/identity composition if required -└── test/ ~ production throughline and replacement integration - -libs/@hashintel/petrinaut-core/ ? generic host contract only if an existing neutral extension is insufficient -libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel/ ~ generic visible why/failure presentation if required -libs/@hashintel/petrinaut/docs/ ~ affected user-facing guidance -deployment/infrastructure source outside this checkout ? actual durable restricted service resources and remote proof -``` - -Do not create a capture ontology package, observer package, projection engine, graph database, generalized provenance platform, second server, or TUI. - -## Fog-line - -- Which retained source or addendum-owned run is eligible for promotion, which limitations are accepted for the selected review slice, and whether stable references can be embedded in Markdown without changing its semantics. -- The exact source conversation/range and capture replay needed for the pair. -- The smallest honest derivation representation and whether it travels with the workpiece, net, or as a companion manifest. -- The consequential-element inventory and what counts as consequential for the selected pair. -- Whether visible names are unique, ids are discoverable, or the existing panel needs a generic element-reference affordance. -- The exact durable owner for capture, workpiece, and derivation data at the Mission 8 replacement boundary. Flue Postgres durability does not automatically include these objects. -- The deployed host selection and trusted identity/access boundary; deployment branch evidence stops before these exist. -- Whether the selected review crosses Flue compaction and, if so, how current workpiece and evidence references survive it. -- Representative latency/usage and the smallest non-content operational signals needed to diagnose why-resolution failure. -- The accepted broader scenario portfolio. Do not infer it from Vestera or from the one prebuilt pair. - -## Stop or reorient - -Stop and surface the smallest blocker if: - -- no exact retained source or addendum-owned run is selected, or no owner-approved eligibility and identity/remapping decision promotes it for the selected pair; -- a selected pair cannot be prepared without inventing unsupported operational meaning or hiding material workpiece gaps; -- product language or UI implies the prebuilt net was automatically projected; -- why resolution depends on rereading the transcript, model-generated plausible links, or source-path proximity rather than stored references; -- a missing/stale/broken link produces an answer instead of unsupported/unavailable; -- task-local JSON is retained while the product claims survival across task replacement; -- capture payloads acquire SDCPN types, assertion-card semantics, closed kinds/slots, mapping hints, or completion state; -- the foreground model gains a sweep tool, schedules capture, or ordinary turns wait for extraction/fold work; -- an observer, automatic projector, graph database, or one-artifact capture/workpiece merger appears to tidy the route; -- one green element is treated as closure without inventorying every consequential element in the selected pair; -- the published Petrinaut library gains Brunch-specific product logic or the stock assistant becomes dependent on Brunch; -- remote deployment, trusted identity, owner refusal, telemetry, or replacement recovery cannot be observed at the boundary being claimed; or -- the scenario portfolio must be invented rather than named honestly at cut time. - -## Carried evidence and rejected alternatives - -- Mission 2 established the least capture pipe: explicit harness range, one exact envelope per user utterance, payload `{}`, stable ids on replay, no model extraction, no sweep tool. It did not establish typed semantics, a workpiece join, or durable remote product data. -- Mission 3 accepted one Flue runbook/workpiece path and falsified real-model construction on the exercised provider-visible schema bridge. The hermetic non-empty callback fixture proves packaging and canonical validation; the paid empty net is not a candidate prebuilt pair. -- Mission 4 supplied no full-run conversation/workpiece candidate. Mission 7 may select an accepted Mission 6 prepared fixture for the named review slice, but must preserve its prepared status and may not silently invent candidate status, claim the full topology-neutral portfolio, or redesign accepted upstream semantics while adding references. -- The pinned Mission 8 handoff supplies a locally verified application contract and explicit handoff: fail-closed Postgres Flue state, IAM/static-password paths, TLS, image, health, content-free OTel, and container smoke landed; ECS/RDS/collector/ingress credentials, real IAM/provider turn, replacement recovery, rollback, and acceptance did not. Capture remained inactive and local JSON. That distinction is load-bearing. -- The full capture/workpiece A–D alternatives, shadow-join probe, measurements, and re-entry conditions live in [`MISSION.next.md`](../../MISSION.next.md#captureworkpiece-seam-history-and-rejected-mechanisms). **Mission 7 selects support links only for the prepared pair:** immutable evidence stays separate from editable Markdown synthesis and joins through stable references plus derivation. Complete independence loses only as a sufficient FE-1476 delivery posture; capture-fold and one-artifact shapes remain rejected here. -- Versioned assertion cards remain a possible future response only if the selected Markdown reference seam fails under observed revision strain. They are not the Mission 7 default. -- Typed capture payloads, per-capture loss categories, closed kind/slot catalogs, precision ladders, completion algebra, `firesWhen`, plugin/repertoire runtime, graph storage, and a target-document ontology remain rejected until a real consumer and failure require them. -- An asynchronous inferential observer remains absent. It may re-enter only under later foreground revision strain with its own evidence for ordering, failure, flush, prior-meaning preservation, and latency. -- Automatic projection belongs to Mission 9. Mission 7's prepared net and derivation make the provenance contract testable without pretending the provider-schema and repeated-projection risks are solved. diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/7-explainable-construction.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/7-explainable-construction.md new file mode 100644 index 00000000000..fda8898e0f2 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/mission-drafts/7-explainable-construction.md @@ -0,0 +1,362 @@ +# Draft Mission 7 — Construct and explain one real net region from a genuine conversation + +> Draft cluster only. Not execution authority. Do not implement until this cluster is re-evaluated and cut into `MISSION.md`. + +This draft is written at cut-level detail so that conversion into a live `MISSION.md` is a re-evaluation rather than a rewrite; the [cut conversion map](#cut-conversion-map) at the end names which section becomes which live address. It was recut on 2026-09-04 from the former "capture-backed review of an honest prebuilt pair" after two independent reviews of the provenance design; the reasoning is in the [decision log](../evidence/design/provenance-and-tooling-decision-log-2026-09-04.md) (sections C, F, G), the [mini spec](../evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md), the [independent review](../evidence/design/provenance-by-lineage-independent-review-2026-09-04.md), and the [follow-up review](../evidence/design/provenance-by-lineage-follow-up-review-2026-09-04.md). Where this draft cites an entry such as G7, that entry is the surviving rationale. + +## Cold-start reads + +Tracker: [FE-1573](https://linear.app/hash/issue/FE-1573/explain-one-prepared-petrinaut-net-from-exact-conversation-evidence) is the tracker projection for this future branch mission and advances the stakeholder outcome [FE-1478](https://linear.app/hash/issue/FE-1478/provide-provenance-from-a-generated-net-back-to-the-requirements-graph) without rewriting that record. Its current title and description describe the superseded prepared-pair cut and must be re-titled with owner approval before this draft is cut; FE-1478's "requirements graph" and "captured assertions" wording remains the stakeholder's, satisfied here by declared basis over settled workpiece revisions rather than by a graph. + +A fresh builder must resolve these authorities and this terrain before implementing anything: + +- [`../../MISSION.md`](../../MISSION.md) — the current branch's live authority (Mission 6 at the time of writing). Mission 7 stacks on Mission 6's accepted archive and on Mission 5's landed browser Flue transport. Mission 6's constraint that construction tools stay out of ordinary conversations is amended by this cut, not silently. +- [`../../MISSION.next.md`](../../MISSION.next.md) — compact spine, FE-1476 product frame, cross-mission obligations, standing locks, the 2026-09-04 planning migration matrix, and later evidence admitted after this draft. +- [`README.md`](README.md) — draft authority, lifecycle, and conversion rules. +- The four design-evidence documents named above. Design evidence, not authority; every settled item becomes authority only when written into the cut `MISSION.md`. +- [`../mission-archive/2-mechanical-capture-sweep.md`](../mission-archive/2-mechanical-capture-sweep.md) — the accepted mechanical capture throughline. Historical: capture envelopes and sweep semantics are rejected for this mission's provenance (G20); the session-log archive lane in `binding-flue` is a separate existing capability. +- [`../mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) and [`../evidence/implementations/fe-1525-headless-runbook-pn.md`](../evidence/implementations/fe-1525-headless-runbook-pn.md) — accepted workpiece leg, falsified provider-visible nested-schema construction (0 for 9 on `addType.elements`), and the vacuous empty-net warning. This mission retires that blocker. +- [`../mission-archive/4-core-plugin-elicitation-proof-of-life.md`](../mission-archive/4-core-plugin-elicitation-proof-of-life.md) — the accepted core/plugin/app split and interaction decisions this mission composes within. +- [`../evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md`](../evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md) and the r2 outer witness beside it — Mission 6's viability proof of transport, least mutation, settled manifest, and two-tab resume, and its honest admissions: the prepared fixture's "Current Petrinaut correspondence" section was fixture-authored (A3), and the fenced-block workpiece source is a Mission 6 contract this mission replaces (A4). The Mission 6 fixture is not promoted into this mission's pair. +- [`../evidence/implementations/mission-5-direct-voice-flue/README.md`](../evidence/implementations/mission-5-direct-voice-flue/README.md) — the browser Flue `ChatTransport` at `/agents/chat/:instanceId`, client-tool-result correlation, and admission timing this mission consumes. +- [`../../packages/core/src/workpiece.ts`](../../packages/core/src/workpiece.ts) — the current resolver: tagged prepared signal or latest fenced `runbook-ir` block, identified by message id plus SHA-256. Replaced for model-produced revisions by `update_workpiece`; retained for the tagged prepared route. +- [`../../packages/core/src/flue.ts`](../../packages/core/src/flue.ts) and [`../../packages/core/src/client-tools.ts`](../../packages/core/src/client-tools.ts) — core owns no model-facing tool today and states the rule for adding one; the `ask` and `sweep` names here are orphans this mission retires. +- [`../../packages/plugin-sdcpn/src/flue.ts`](../../packages/plugin-sdcpn/src/flue.ts), [`../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts`](../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts), and [`../../packages/plugin-sdcpn/test/construction-tools.test.ts`](../../packages/plugin-sdcpn/test/construction-tools.test.ts) — the tool factory with the falsified carrier (`v.looseObject({})` plus `rawTransform` and the JSON Schema pasted into the description), the headless-only and fixture-only mounting modes, and the six-tool and two-tool subsets this mission retires as product surfaces. +- [`../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/SKILL.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/SKILL.md), [`templates/workpiece.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/templates/workpiece.md), [`references/pn-construction.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/references/pn-construction.md), and [`references/checks.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/references/checks.md) — current teaching: concepts, the fenced-block emission rule, and Construction notes. This mission adds construction posture and the settled-revision and basis discipline. +- [`../../packages/binding-flue/src/history-reader.ts`](../../packages/binding-flue/src/history-reader.ts) and [`../../packages/transport-aisdk/src/client-tool-history.ts`](../../packages/transport-aisdk/src/client-tool-history.ts) — how history is acquired in-process with host-owned URL and transport, and how client-tool results are projected today (opaque correlated outputs, no effect semantics). +- [`apps/brunch-agent/src/agents/chat-agent/agent.ts`](../../../../../apps/brunch-agent/src/agents/chat-agent/agent.ts), [`src/conversation/identity.ts`](../../../../../apps/brunch-agent/src/conversation/identity.ts), [`src/http/ownership.ts`](../../../../../apps/brunch-agent/src/http/ownership.ts), and [`src/capture/apply-sweep.ts`](../../../../../apps/brunch-agent/src/capture/apply-sweep.ts) — composition, the principal key and conversation id that are the only identity the system carries, and the in-process fetch pattern the why lookups reuse. +- [`apps/brunch-agent/.pi/extensions/brunch-persona-testing/README.md`](../../../../../apps/brunch-agent/.pi/extensions/brunch-persona-testing/README.md) and [`src/evaluations/persona/brunch-turn.ts`](../../../../../apps/brunch-agent/src/evaluations/persona/brunch-turn.ts) — the persona harness: `--brunch-tool-host` (`none`, `mock`, `real-headless`), `--brunch-tool-mocks`, `--brunch-evidence-dir` retaining `snapshot.json` and projections per settled read, turn budget in the launch prompt only. +- [`../../evaluations/README.md`](../../evaluations/README.md), [`../../evaluations/cases/`](../../evaluations/cases/), and [`../../evaluations/oracles/`](../../evaluations/oracles/) — six persona cases with hidden truth ledgers, and the frozen protocols not to rerun. +- [`../../../petrinaut-core/src/ai.ts`](../../../petrinaut-core/src/ai.ts), [`action-schemas.ts`](../../../petrinaut-core/src/action-schemas.ts), [`command-schemas.ts`](../../../petrinaut-core/src/command-schemas.ts), [`schemas/entity-schemas.ts`](../../../petrinaut-core/src/schemas/entity-schemas.ts), [`schemas/metric-schema.ts`](../../../petrinaut-core/src/schemas/metric-schema.ts), and [`file-format/types.ts`](../../../petrinaut-core/src/file-format/types.ts) — canonical AI tool bundle, mutation and command schemas, strict entity objects with no metadata slot, and the file wrapper (`version`, document arrays, `title`, optional generator `meta`) with no provenance field. Authority; never copied. +- [`../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx`](../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx) and [`../../../petrinaut/docs/ai-assistant.md`](../../../petrinaut/docs/ai-assistant.md) — the host execution boundary and the user guide that must change with any user-visible behaviour. +- [`../specs/petrinaut-batched-construction-tools.md`](../specs/petrinaut-batched-construction-tools.md) — candidate `pn_read`/`pn_edit` input; observation O2 (the Mission 3 failure is a carrier failure, not a granularity failure) is load-bearing here; batching itself is Mission 9's decision unless this mission's scenario forces it. +- [`../reference/architecture/flue-routing.md`](../reference/architecture/flue-routing.md) — per-conversation versus cross-conversation state, `usePersistentState`, signals, and the upgrade pins. +- Installed Flue 2.0.3 reference under `node_modules/@flue/runtime/docs/reference/`: `agent-api.md` (tool `run` contract: a multi-tool batch ends the turn only when every result terminates; `ToolContext.toolCallId`), `agent-hooks-api.md` ("Rendering and the rules of hooks": hooks only at render, setters only in callbacks), and `guide/models.md` (compaction folds older history into a summary, default 8000 recent tokens verbatim). These settle G1, G2, and F2 and motivate the compaction probe. +- Commit `157730cc5a214dd9c543e8d95c7193a219c48aef` on `ln/fe-1569-brunch-agent-deployment`, especially `docs/evidence/implementations/mission-8-deployment-handoff.md` — locally verified application contract; no remote deployment. This mission names local posture. + +## Visible product advance + +**Release note:** talk to Brunch about a process and watch it build that part of the net; then ask why any element exists and see the workpiece passage the constructor declared as its basis, the conversation behind it, and which recorded step did what, or an explicit refusal. + +**Demo script (no engineer present):** with the local Brunch and Petrinaut stack running, open the demo conversation and its net in the Petrinaut Brunch panel. The workpiece pane shows the current revision, the revision list, and a diff between any two. Scroll the conversation: a real interview, labelled with its source (synthetic persona, internal human, or customer-derived), in which Brunch elicited the process, revised the workpiece as it went, and then built the region you see. Pick any element in the net and type its name or id. Read the passage Brunch declared as that element's basis, the revision it came from, the conversation lines or turns behind that passage, and the recorded steps: which assistant tool call requested it, which browser step applied it. Pick the element the demo marks as changed by hand and watch Brunch say it cannot attribute the current state. Pick the element marked as built without a declared basis and watch Brunch say so rather than improvise. + +**Previously impossible:** Brunch had never built a net region inside a real conversation, only from a prepared fixture or a headless harness, and nothing connected any element to what was said. + +**Completion:** the mission is done when a product manager can run that script for the proving scenario and every readiness-gate obligation below is closed, including the safety and utility gates for the why operation. The first green pass through the adversarial tracer and the first real constructed region are internal milestones. + +**Scope history.** On 2026-09-03 the one-element explainability cut was judged too small under the product-manager litmus and expanded to a whole prepared net. On 2026-09-04 the prepared pair and its hand-authored derivation fixture were rejected as fixture-rigging and useless respectively (A3, B4), and the owner consolidated construction and explanation into this mission rather than splitting a thin visible-workpiece mission first, to resist the regression to thin tracers and to build fully connected parts with real test beds (F12). The follow-up review then established that this mission must close the readiness of its own claim and may move only breadth to Mission 9 (G16). Reversal condition: if the adversarial tracer shows the model cannot construct with a usable declared basis under any revised interaction, the explainability release is withheld and construction stands on its own gates (decision table below). + +## Contract stratum + +Close the **construction-and-explanation stratum for one genuine conversation, one proving scenario, and one document incarnation**. Its objects and minimum seams: + +- **Settled workpiece revisions**: `update_workpiece` tool calls with revision id, SHA-256, and Markdown persisted in per-conversation state; the fenced-block route retired for model-produced revisions; the tagged prepared signal retained only for test-authored material. +- **Declared basis** on every mutation request: `declared { revisionId, sha256, locators, rationale, scope }` or `absent { reason }`, operation-level unless an intended-effect mapping names elements (G7). +- **Optional revision-time evidence relation** on `update_workpiece`: `evidence: [{ locator, messageIds, kind }]`, kind in elicited, inference, default, formalism-constraint, external, correction; carried forward unchanged passages inherit their relation (G3). +- **Mutation transition records**: requested base hash, observed pre-apply hash, post hash, outcome, disjoint derived effects, diff accounting, one authoritative result per call, conflicting duplicates to unknown (G9). +- **Identity epochs**: ids never reused; delete and recreate opens a new epoch; origin, current state, change history, attempt history are distinct query semantics (G8). +- **Passage identity policy** and its probe (G11). +- **Document reconciliation**: one conversation bound to one document incarnation; every why answer reconciles against the live hash or labels its staleness; external import records without laundering (G4, G5, G10). +- **Recorded roles**: assistant tool call, local browser executor, user under principal key, test-authored fixture author; human identity unknown; time is stream order (G6). +- **Scenario-selected tool admission with canonically derived schemas** over a repaired carrier (G15). +- **Consequential inventory** with one disposition per item and published numerator, denominator, and exclusions (G13). +- **Safety and utility gates** for the why operation (G14). +- **Runtime migration matrix** with a removal gate for any dual-read bridge (F15). + +Outside this stratum and owned by Mission 9 with re-entry gates: unchanged repeat, changed input, deletion and retirement beyond the single negative case exercised here, concurrent user change beyond the single hand edit, cross-conversation document access and a document-scoped lineage owner, schema classes beyond the proving scenario, and the per-action versus batch decision. + +## Boundary crossings and current throughline hypothesis + +```text +persona or human conversation in the Petrinaut Brunch panel (or the persona harness against the production agent) + → Mission 5 browser Flue ChatTransport → /agents/chat/:instanceId → ChatAgent + → agent revises the workpiece: update_workpiece { markdown, evidence? } settles; state holds { revisionId, sha256, revision, markdown } + → workpiece pane shows the revision; chat shows a one-line marker + → next render exposes the settled revision; agent reads the live definition via getLatestNetDefinition + → agent requests one mutation at a time citing { revisionId, sha256 } with declared basis; the turn terminates on the browser tool + → Petrinaut panel: observes pre-apply hash, validates canonical input, applies, derives effects, returns one transition record + → client-tool-result signal resumes the conversation; the agent reconciles effects against intent; unanticipated effects are basis-absent + → agent calls getNetCompilationErrors, repairs within budget, and records decisions in Construction notes and a closing update_workpiece + → reviewer types an element name or id; the why operation: locate element → epochs and transition records → basis → span in the cited revision → evidence relation or temporal context → recorded roles → live hash reconciliation + → panel renders the answer in the workpiece pane, or a structured refusal: unsupported, not attributable, external, stale, ambiguous +``` + +Actor and authority crossings: + +- **Flue log as substrate.** Revisions and mutations are tool-call records; correlation is by call id and submission order, never a shared turn id (F1). `update_workpiece` is never batched with a terminating construction tool (G1). +- **Agent to state.** `usePersistentState` at render, setter in the tool closure, called from `run` (F2). State holds the Markdown so the current revision survives compaction of the model's context (F10). +- **Agent to Petrinaut.** The plugin strips `basis` before forwarding canonical input; Petrinaut's contract is unchanged; schemas are derived mechanically (3.6 in the spec). Petrinaut library code gains no Brunch logic. +- **Browser to record.** The transition record is the only admissible statement of effect; a plan or self-report that fails diff accounting advances nothing (G9). +- **Core, plugin, binding, app.** Core owns revision and query semantics and `update_workpiece`; plugin owns mutation names, inputs, effects, template conformance, and the element locator; binding and app own authorized history acquisition and compose the why operation (F9). +- **Authorization.** Single principal, local, one conversation per document incarnation; retrieved history is untrusted evidence returned in the smallest range (F11, G5). + +## Throughline proof floor + +The floor has two steps, each under this mission's authority, separated by an owner gate (G18). + +### Step A — adversarial tracer and probes under the initial narrow authority + +One genuine conversation on the proving scenario, run through the production agent with the persona harness in `real-headless` mode or the panel, containing at least: two distinguishable workpiece passages, two mutations with declared basis, one no-op or failed mutation, one correction that changes a passage and its element, one hand edit made outside the conversation, one carried-forward passage, one passage with non-adjacent evidence, and one multi-source synthesis. The why operation must return deterministic answers or explicit refusals for every element, with no false attribution. + +The four probes run alongside, each with its decision table: + +| Probe | Pass | Partial | Fail | Re-entry | +| --- | --- | --- | --- | --- | +| **Compaction.** Set `keepRecentTokens` low, run past threshold, read `history()`. Do folded `update_workpiece` inputs, mutation parts, and user lines survive? | Lineage reads from `history()` | Current revision from state; history claims limited to the uncompacted window and disclosed in every answer | Harden the existing session-log archive lane into an immutable lineage projection before any exact-line claim; no new log, no capture envelopes (G20) | Flue exposes a supported pre-compaction read | +| **Fixture materialization.** Export or retain, relocate, reopen, authorize, and query the tracer conversation | Retained live store or supported relocation is the demo fixture route | Relocation works but identities must be re-bound; record the binding rule | Prepared-projection route only, honestly labelled; the why claim narrows to that projection | Flue adds a supported export or import surface | +| **Passage identity** under the G11 policy, on the tracer workpiece, across rename, move, paraphrase, split, merge, deletion, reintroduction, duplicate headings | Locator scheme selected | Some edit classes refuse continuity; the refusals become part of the claim | Revision-local text only; no cross-revision "introduced by" | A cheaper anchor lifecycle appears in the template | +| **Carrier repair** for one real nested mutation from the proving scenario's classes | Admit the scenario's classes | Flat classes only; nested classes refused with a named blocker | Crisp upstream Flue requirement (Standard Schema or supplied JSON Schema); no local schema copy | Flue accepts Standard Schema | + +Two further measurements are taken in the tracer and gate the release, not the cut: + +| Measurement | Pass | Partial | Fail | +| --- | --- | --- | --- | +| **Revision cadence and basis quality.** How often `update_workpiece` is called unprompted; how often basis is declared, relevant, and non-contradictory | Blame and basis have grain | Coarser ranges disclosed; skill wording and pane interaction adjusted before breadth | Explainability release withheld; construction stands on its own gates | +| **Reviewer utility** under the blinded rubric | Utility gate passes | Coverage below threshold on named classes; claim scoped to passing classes | Explainability release withheld | + +Step A passes when every probe has a recorded outcome and the tracer produces no false attribution. The owner then decides whether to amend the authority into Step B, narrow it, or stop. + +### Step B — the visible advance on the proving scenario + +One or more genuine persona conversations on the proving scenario, run to construction with the tool set the carrier probe admitted, each retained through the harness's evidence directory and reopened through the fixture route the probe selected. The demo script runs on one of them. Every consequential element in its net resolves or refuses through the reopened authorized why operation, the safety gate passes, and the utility gate passes at the predeclared coverage. + +## Readiness ratchet + +```text +Mission 5 browser Flue transport + Mission 6 viability (transport, least mutation, settled manifest, resume) +→ inherited: core/plugin/app split; canonical Petrinaut contracts; persona harness; Flue 2.0.3 contracts as pinned +→ Step A: adversarial tracer + four probes with decision tables → owner gate +→ Step B: real conversations to construction; why over them +→ readiness gate: close identity, failure, durability, basis quality, current state, oracle obligations for this claim +├─ hand Mission 9 the seam: settled revisions, basis, transition records, epochs, passage policy, reconciliation, tool set, compaction posture, fixture route, gates +├─ hand Mission 10 basis, transition records, epochs, evidence relation for reviewer citation +└─ leave repeat, changed input, retirement breadth, concurrent change, cross-conversation access, schema breadth, batching, observer, remote durability unearned +``` + +### Inherited stratum closure + +Mission 7 consumes, and must not overstate: + +- **Mission 5.** The browser `ChatTransport`, the mounted route, client-tool-result correlation, and admission timing are landed and tested; the human Voice witness is Mission 5's own gate and not consumed here. +- **Mission 6.** Transport-carried least mutation, runtime settled manifest, and two-tab resume are viability facts. The prepared fixture's correspondence section was fixture-authored and the fixture is not promoted. The fenced-block resolver is a Mission 6 contract replaced here; Mission 6's close report names the carried change (A3, A4). +- **Mission 3 and 4.** Accepted workpiece leg and core/plugin architecture; falsified nested carrier; no full-run candidate. The tracer conversation is the first genuine full run and is labelled synthetic-persona if produced by the harness. +- **Mission 2.** Capture envelopes and sweep semantics are not consumed. The session-log archive lane exists and may be hardened only under the compaction probe's fail branch. +- **Mission 8.** Local application contract only. This mission names local posture; remote durability stays with a scheduled Mission 8 successor or a pre-handoff release gate. +- **Flue 2.0.3.** The tool `run` termination contract, the rules of hooks, `ToolContext.toolCallId`, `usePersistentState` semantics, and compaction defaults are documented and pinned; the upgrade row in the routing guidance applies. + +### Readiness gate after the new throughline + +This gate is the completion bar. For the proving scenario's net, close: + +- **Inventory.** Consequential rule frozen before the run; inventory generated mechanically from the final canonical document; every identity-bearing or behaviour-affecting entity or field included; exactly one disposition per item (supported, partially supported, basis-absent, external, retired, refused); numerator, denominator, and exclusions published (G13). +- **Safety.** No false attribution; every required refusal correct: unsupported, not attributable, external, stale, ambiguous name, unknown outcome. +- **Utility.** Predeclared nonzero coverage of consequential elements with usable current-state answers, minimum coverage per admitted entity class, blinded reviewer task with the fixed rubric: identify the governing passage, distinguish elicited evidence from constructor inference, understand the current definition and latest correction, decide whether the answer changes the review judgement (G14). +- **Revision protocol.** No mixed batch; every mutation cites a settled revision; citation of an unknown or superseded revision refuses unless supersession is marked intended (G1, G2). +- **Basis quality.** Declared or absent-with-reason on every request; graded for relevance, contradiction, granularity, omitted dependencies; Construction notes never substitute (G7). +- **Transition records.** Independently verifiable on every call; duplicate delivery does not apply twice; conflicting duplicates resolve to unknown; failed, no-op, stale, unknown contribute only attempt history (G9). +- **Identity epochs.** One delete-and-recreate exercised; id not reused; origin and change history queryable (G8). +- **Reconciliation.** One hand edit exercised; the why answer refuses attribution for the affected state or discloses staleness; one external import exercised with dispositions retained (G4, G10). +- **Binding.** One-conversation-one-incarnation recorded and enforced; a second conversation targeting the document refuses (G5). +- **Roles and time.** Answers name recorded roles and stream order only (G6). +- **Passage policy.** Selected locator scheme or the revision-local fallback, with refusals as part of the claim (G11). +- **Compaction posture and fixture route.** Whichever branch the probes selected, disclosed in the product and the close report. +- **Carrier and tools.** Scenario-selected classes admitted over the repaired carrier; each class cites the case requirement it discharges; provider-schema rejection distinct from canonical rejection; repair budget enforced and visibly exhausted (G15). +- **Teaching.** Skill construction posture in place; measured cadence and basis quality recorded. +- **Visible workpiece.** Pane with current revision, list, diff; chat marker; projection in app or transport, not the Petrinaut library. +- **Subtraction.** `ask` and `sweep` client handling removed; six-tool and two-tool subsets retired as product surfaces once Mission 6 archives. +- **Runtime migration matrix.** Old history with new code; new history with rolled-back code; conversations mixing fenced and tool revisions; mixed browser and server versions; Mission 6 fixture mode; retained evidence restoration; tool-manifest rollback; any dual-read bridge with an explicit removal gate (F15). +- **Behavioural discriminator.** One executable check derived from the workpiece (resource reservation and release, reachability, token conservation, or one scenario outcome) passes on the constructed region and is carried unchanged to Missions 9 and 10 (F15). +- **Stock coexistence, docs, telemetry.** Stock assistant unchanged when Brunch is absent or unselected; Petrinaut user guide updated for the pane and the why interaction with a screenshot prompt; no content-bearing telemetry. + +Mission 9 inherits the seam listed in the ratchet. **Owner:** Mission 9. **Re-entry gate:** an unchanged repeat request on the accepted conversation produces attempt history only, and one changed input produces a frozen expected impact set. **Oracle:** Mission 9's repeat, change, retirement, and current-state why witnesses. Mission 10 inherits basis, transition records, epochs, and the evidence relation for reviewer citation. **Re-entry gate:** an authorized reviewer's 3–5 turns produce a settled revision citing reviewer message ids and a bounded patch. Do not carry into Mission 9 anything this mission's visible claim already depends on. + +## Candidate evidence and oracles + +| Claim leaf | Existing evidence or candidate oracle | +| --- | --- | +| Browser Flue transport carries typed turns, history hydration, and correlated client-tool results | Existing Mission 5 evidence README and its 36-task Turbo run; Mission 6 focused tests for read, mutation, original call-id result, and continuation. Run `yarn exec turbo run test:unit --filter @apps/brunch-agent --filter @apps/petrinaut-website`. | +| Prepared signal retry and append-only selection; fixture-only advertisement; mismatch refusal; manifest retention | Existing Mission 6 tests named in `fe-1575-resumable-workpiece-petrinaut.md`. These remain guards for the prepared route only. | +| Construction tools currently expose the six-tool subset over the falsified carrier | Existing `plugin-sdcpn/test/construction-tools.test.ts`; `headless-petrinaut-client.test.ts`. Baseline to change, not success. | +| Multi-tool batch termination and hook rules | Installed Flue 2.0.3 reference; pin with a focused test that `update_workpiece` is non-terminating and never co-batched, and that the setter is captured at render. **ORACLE GAP** until that test exists. | +| `update_workpiece` settles, hashes, persists state, refuses empty or oversize input | **ORACLE GAP:** new core unit tests plus one production-agent integration through the Mission 5 transport. | +| Mutation cites a settled revision; unknown or superseded citation refuses | **ORACLE GAP:** plugin unit tests plus the tracer. | +| Transition record is independently verifiable; duplicates resolve to unknown | **ORACLE GAP:** website unit tests for pre-hash observation, effect derivation, diff accounting, duplicate handling; production-path integration. | +| Identity epochs; no id reuse | **ORACLE GAP:** epoch ledger unit test plus the tracer's delete-and-recreate. | +| Hand edit and external import are detected and disposed honestly | **ORACLE GAP:** the tracer's hand edit; reconciliation unit tests. | +| Passage policy holds under semantic edits | **ORACLE GAP:** the passage probe's recorded outcomes on the tracer workpiece. | +| Compaction posture | **ORACLE GAP:** the compaction probe's recorded outcome and its selected branch. | +| Fixture route | **ORACLE GAP:** the materialization probe's recorded outcome; acceptance assertions run through the reopened why operation. | +| Carrier carries one real nested mutation | **ORACLE GAP:** one budgeted paid call on the proving scenario's nested class with the exact schema artifact and raw arguments retained. | +| Why answers are safe and useful | **ORACLE GAP:** safety assertions over the frozen inventory through the reopened why operation; blinded reviewer task with the fixed rubric. | +| Constructed region is meaningful | **ORACLE GAP:** human semantic adjudication against the workpiece plus the behavioural discriminator. | +| Stock assistant unchanged | Existing host-mode test and browser witness pattern from Mission 6; rerun at close. | +| Product | A product manager runs the demo script on the proving scenario without an engineer. | + +## Verification approach + +- **Inner.** Core: `update_workpiece` validation, hashing, state write, revision numbering; query semantics for origin, current state, change history, attempt history. Plugin: basis parsing and refusal, locator resolution, effect interpretation, template conformance, class admission by scenario rule with schemas structurally compared to canonical Zod. Website: pre-hash observation, effect derivation, diff accounting, duplicate resolution, external import. Binding and app: history acquisition, authorization, why composition. Passage policy invariants as unit tests. +- **Middle.** The built production `ChatAgent` over the Mission 5 transport at `/agents/chat/:instanceId`: revise, cite, mutate, receive a transition record, resume, reconcile, and answer why, with duplicate delivery, stale base, unknown outcome, and hand edit injected. Run through root Turbo: `test:unit`, `lint:tsc`, `lint:eslint`, and `build` for `@apps/brunch-agent`, `@apps/petrinaut-website`, `@hashintel/petrinaut`, `@hashintel/brunch-agent`, `@hashintel/brunch-agent-plugin-sdcpn`, and `@hashintel/brunch-agent-transport-aisdk`. +- **Outer.** The adversarial tracer and the Step B conversations retained through `--brunch-evidence-dir`, reopened through the selected fixture route, and queried through the product why operation in the panel with `yarn dev:brunch` running and a real provider credential. Snapshots and projections are diagnostics only (G12). +- **Semantic and behavioural.** Human adjudication of the constructed region against the workpiece; the behavioural discriminator; the blinded utility rubric. +- **Product.** The demo script, last, after the readiness gate. + +Paid provider evidence requires cut-time authorization with model, maximum calls, and spend ceiling recorded before execution. + +## Inputs and joins + +- **Mission 5 join.** The browser transport and correlation contract as landed; no second route. +- **Mission 6 join.** Viability facts and the two admissions; the prepared-signal route retained for test-authored material only; the fixture not promoted; Mission 6's construction-tool constraint amended here. +- **Persona harness join.** `real-headless` host for construction calls; evidence directory retention; turn budget in the launch prompt; a completion signal from Brunch's delivery status; ledger coverage as post-hoc grade (D4). Workpiece recovery in the harness must read `update_workpiece` tool parts. +- **Petrinaut canonical-contract join.** `petrinautAiTools`, `mutationActionInputSchemas`, `aiCommandActionInputSchemas`, entity schemas, writable callbacks, by import or mechanical derivation; mismatches route upstream; no schema change for provenance. +- **Flue join.** Documented tool, hook, state, signal, and history contracts; upstream requirement if the carrier cannot be repaired locally. +- **Scenario join.** The owner selects the proving scenario from the six cases, its admitted classes with cited requirements, its consequential rule, its behavioural discriminator, and the utility coverage threshold before the run. +- **Consumer discovery join.** Lightweight, non-binding discovery with Chris and Yannis before the proving scenario is fixed, so the region exercises semantics they will need (F15; Mission 11 draft). +- **Mission 9 and 10 output joins.** As listed in the ratchet. + +## Risks and assumptions + +| Risk or assumption | Impact if false | Cheapest discriminating validation | +| --- | --- | --- | +| The model calls `update_workpiece` often enough for revisions to have grain | Blame collapses to "the workpiece came from the conversation"; explainability release withheld | Count calls per turn in the tracer before Step B; adjust skill wording and pane interaction once | +| The model declares a usable basis unprompted | Basis is absent or circular; answers degrade to temporal context | Grade basis in the tracer for relevance, contradiction, granularity, omitted dependencies | +| `history()` keeps folded records | Exact lines and revision history vanish past 8000 tokens | Compaction probe | +| A genuine conversation can be relocated and reopened with identities intact | Persona runs cannot power the demo | Materialization probe on the tracer before any paid breadth | +| A locator scheme survives semantic edits under the policy | No cross-revision claim | Passage probe | +| The JSON Schema to Valibot interpreter preserves the scenario's nested classes | Nested classes blocked upstream | One real nested call | +| Effects can be derived mechanically from pre and post definitions and account for the diff | Self-report is unverifiable | Website unit tests with injected extra effects and hand edits | +| One-conversation-one-incarnation is enough for the proving scenario | A second conversation or principal needs the document | Decide at cut time; refuse otherwise | +| Visible names are unique enough for reviewer input, with id as escape hatch | A name-only query resolves the wrong element | Inventory duplicates; an ambiguous query must ask for the id | +| Exact lines plus declared basis are enough for a useful answer | Provenance exposed but review not helped | Blinded rubric | +| A synthetic persona yields a representative conversation | Provenance trivial on unique wording; fails on human messiness | Label sources; include the adversarial fixture with duplicate wording and rejected quotations (G12) | +| The proving scenario's consequential rule can be frozen before the run | Inventory gamed after generation | Freeze the rule and generate the inventory mechanically (G13) | +| Full-document emission per revision is affordable on the proving scenario's length | Cost forces coarser cadence | Measure tokens per revision in the tracer; structured patch is the later absorber | +| The interpreter, pane, tools, and probes fit one mission without unrelated fronts invalidating each other | Large implementation lands before a probe fails it | Step A gate before Step B (G18) | + +## Accepted constraints and guarded invariants + +- **STOP-THE-LINE — no false attribution.** A why answer never presents temporal context as evidence, a plan as effect, or absence as basis. Guard: safety assertions over the frozen inventory; negative controls. +- **STOP-THE-LINE — settled revision before mutation.** No mixed batch; explicit citation. Guard: co-batch and citation tests; tracer. +- **STOP-THE-LINE — transition record is the only statement of effect.** Guard: diff accounting and duplicate resolution tests. +- **STOP-THE-LINE — ids are never reused across epochs.** Guard: epoch ledger. +- **STOP-THE-LINE — external state is never laundered.** Guard: import dispositions retained until replaced. +- Flue history remains the canonical conversation log; no second log, capture ledger, or derivation store. Guard: dependency and state inventory. +- Markdown remains the semantic workpiece; revisions settle only through `update_workpiece`; the prepared signal remains tagged test-authored. Guard: resolver tests and public-schema inspection. +- Petrinaut owns canonical schemas, validation, mutations, document state; Brunch derives, never copies. Guard: structural alignment tests; stop on hand-copied fields. +- Core owns revision and query semantics; plugin owns operation semantics and locators; binding and app own acquisition and composition; the Petrinaut library gains no Brunch logic. Guard: topology tests. +- Stock assistant unchanged when Brunch is absent or unselected. Guard: host-mode test and witness. +- Single-principal local authorization named as a limit; retrieved history is untrusted evidence in the smallest range. Guard: ownership tests; answer inspection. +- No observer, automatic evidence fold, closed ontology, typed completion, assertion-card default, graph database, second agent or server, workflow engine, or general projection engine. Guard: dependency, tool, and state inventory. +- No content-bearing telemetry by default. Guard: trace inspection. +- Local posture only; "locally run," "locally verified image," and "remote replacement-safe" stay distinct claims. +- Paid provider evidence only under recorded budget. + +## Cross-cutting obligations + +- Workpiece sufficiency, projection fidelity, evidence provenance, revision integrity, Petrinaut semantic acceptance, deployed interaction quality, and visible failure, as stated in the spine's cross-mission obligations, hold over the constructed region and its why answers. +- Runtime migration matrix with removal gate (F15). +- Petrinaut user guide updated for the workpiece pane and why interaction; screenshot replacement prompted. +- Architecture docs: if a new folder forms a real architectural unit, add the local declaration and run the Petrinaut architecture-doc lint. +- Close report: each proof leaf's outcome, each probe's branch, the measured cadence and basis quality, the inventory numbers, the gates, and the flags carried to Missions 9 and 10. + +## Expected touched paths + +Tentative; Step A may shrink or redirect this manifest. + +```text +libs/@hashintel/brunch-agent/ +├── MISSION.md ~ cut-time authority; amended after the Step A gate +├── MISSION.next.md ~ carried flags only +├── docs/evidence/ + probe outcomes, tracer, Step B witnesses, adjudications, gates +├── packages/core/src/ + update_workpiece; revision and query semantics; passage policy +├── packages/core/src/client-tools.ts, _suspended/ - ask and sweep names and contract +├── packages/plugin-sdcpn/src/tools/ ~ carrier interpreter; scenario-selected admission; basis handling; locators +├── packages/plugin-sdcpn/src/flue.ts ~ mount by scenario; retire subsets after Mission 6 archives +├── packages/plugin-sdcpn/src/skills/sdcpn-modelling/ ~ construction posture; settled-revision and basis discipline +├── packages/binding-flue/src/ ~ history acquisition for why; archive lane only under the compaction fail branch +├── packages/transport-aisdk/src/ ~ transition-record projection; deduplication by call id; pane projection +└── evaluations/ + proving-scenario consequential rule, discriminator, rubric + +apps/brunch-agent/ +├── src/agents/chat-agent/ ~ compose update_workpiece and the why operation +├── src/capture/apply-sweep.ts - retired unless the compaction fail branch keeps the archive lane +├── src/evaluations/persona/ ~ workpiece recovery from tool parts; cadence and basis measurement +└── test/ + protocol, record, epoch, reconciliation, why integration + +apps/petrinaut-website/src/main/app/ +├── local-storage-demo/ ~ transition records; binding; pane; why rendering; remove ask/sweep handling +└── voice-interview/ - ask and sweep references + +libs/@hashintel/petrinaut/ +├── src/ui/views/Editor/panels/ai-assistant-panel* ? generic host surface only if the app cannot host the pane +└── docs/ ~ pane and why guidance + +libs/@hashintel/petrinaut-core/ ? only for an observed canonical contract defect; no provenance slot +``` + +## Fog-line + +- Compaction survival of `history()` records; the probe decides the branch. +- Fixture materialization route; the probe decides. +- Locator scheme under the passage policy; the probe decides. +- Carrier repair route: local interpreter or upstream Flue; the probe decides. +- Revision cadence and basis quality in a real conversation; measured in the tracer. +- Whether the optional evidence relation on `update_workpiece` is used by the model unprompted, and whether it drifts toward assertion cards under use. +- Whether one or two model-facing why tools serve the reviewer better. +- Token cost of full-document emission on the proving scenario, and when a structured patch earns its place. +- Which admitted classes misbehave at the provider boundary once the carrier carries fields. +- Whether the proving scenario needs cross-conversation document access. +- The proving scenario itself, its consequential rule, discriminator, and utility threshold: owner decisions at cut time, informed by consumer discovery. + +Resolve these at the real boundaries. If a choice changes accepted interaction policy, architectural ownership, or the claim, return it to the owner and amend the authority before continuing. + +## Stop or reorient + +Stop and surface evidence if: + +- the tracer cannot produce deterministic answers or explicit refusals without guessing, after one round of interaction adjustment; +- `update_workpiece` and a construction tool must share a batch to make the interaction work; +- a mutation cannot cite a settled revision because the model cannot reliably use the returned ids; +- the compaction probe fails and the only remedy is a new log rather than hardening the existing archive lane; +- the materialization probe fails and the prepared-projection route would make the why claim fixture-only; +- the carrier cannot be repaired locally without copying Petrinaut fields; record the upstream blocker; +- effects cannot be derived mechanically and the browser must self-report; +- a hand edit or external state is presented as attributed provenance; +- an id is reused across epochs; +- the constructor's basis is systematically circular or absent and no interaction change helps; withhold the explainability release; +- the utility gate cannot be met on any admitted class; withhold the explainability release; +- the pane or why operation requires Brunch logic in the Petrinaut library; +- a second conversation or principal must reach the document; that is Mission 9's owner and gate; +- the mission widens into repeat, changed input, retirement breadth, observer, remote durability, or reviewer authority; or +- the inventory rule is defined after the artifact is inspected. + +## Carried evidence and rejected alternatives + +- Mission 2 established the least capture pipe: explicit harness range, one exact envelope per user utterance, payload `{}`, stable ids on replay, no model extraction, no sweep tool. It did not establish typed semantics, a workpiece join, or durable product data. **Rejected for this mission's provenance (C8, G20):** Flue history already carries message ids and exact text; the store duplicated it under a second identity scheme. Its session-log archive lane survives as a separate capability with one named re-entry. +- Mission 3 accepted one Flue workpiece path and falsified real-model construction on the provider-visible carrier; the hermetic fixture proved packaging and canonical validation; the paid empty net is not a pair. **Consumed:** this mission repairs the carrier (B9, C11). +- Mission 4 supplied no full-run candidate. **Consumed:** the tracer is the first genuine full run, labelled by source. +- Mission 6 proved transport, least mutation, settled manifest, and resume. **Two admissions carried:** fixture-rigging (A3) and the fenced-block-to-tool change (A4). +- **Rejected: the honest prebuilt pair with a hand-authored derivation fixture** (B4, C1). Provenance now comes from constructor-declared basis and recorded transitions on a genuine conversation. +- **Rejected: temporal adjacency as causation** (F5, G3). "Latest revision before the mutation" is context, not basis; passage-to-turn ranges are context, not evidence, unless a revision-time relation is declared. +- **Rejected: a hash-only join between net and workpiece revisions** (F7, G9). Replaced by the transition record. +- **Rejected: storing provenance pointers in the Petrinaut document** (C6, B7). No slot exists; a file-level pointer waits for a Mission 11 consumer. +- **Rejected: the six-tool subset as a product surface** (C10) and **full-bundle admission by default** (F13, G15). Replaced by scenario-selected operations with canonically derived schemas. +- **Rejected: capture-fold, one-artifact merger, versioned assertion cards as default, closed kinds and slots, typed completion, per-capture losses, observer, graph database, general projection engine.** Their re-entry conditions live in the spine's backlog and standing locks. +- **Rejected: a side quest under Mission 6 or a separate probe mission for the probes** (G18). The two-step authority within this mission was chosen. +- Versioned assertion cards remain a possible future response only if the optional evidence relation on `update_workpiece` proves insufficient under observed revision strain; they are not the default. +- Typing a visible element name or id remains the accepted first interaction; click-to-chat and canvas-selection context are deferred unless textual identification proves ambiguous or burdensome (carried from the 2026-09-03 draft). +- The FE-1476 six-beat story remains the integrated floor, not the ceiling; the broader scenario portfolio remains unenumerated and must be named at cut time. + +## Cut conversion map + +| Live `MISSION.md` address | Source in this draft | +| --- | --- | +| Status | New at cut: branch, issue re-title, two-step authority note, Mission 6 constraint amendment | +| Imperative | Visible product advance, with the release note, demo script, previously impossible, deployment posture (local), and completion | +| Throughline | Boundary crossings and current throughline hypothesis, plus Expected touched paths | +| Proof | Throughline proof floor (Step A with decision tables, Step B), Readiness gate after the new throughline, Candidate evidence and oracles, Verification approach | +| Constraints | Accepted constraints and guarded invariants, Cross-cutting obligations, Inputs and joins | +| Fog-line | Fog-line, plus the open rows of the decision tables | +| Stop or reorient | Stop or reorient | +| Deferred | The Mission 9 and 10 handoffs in the Readiness ratchet, and the rejected alternatives with their re-entry conditions | + +Before cutting, re-read the four design-evidence documents and the two reviews' evidence lists, inspect the real boundary for each cold-start read, confirm the proving scenario with consumer discovery, obtain the FE-1573 re-title, and record the paid-evidence budget. diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/9-traceable-projection.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/9-traceable-projection.md index 8412c4b41dd..90a2ef9e7f2 100644 --- a/libs/@hashintel/brunch-agent/docs/mission-drafts/9-traceable-projection.md +++ b/libs/@hashintel/brunch-agent/docs/mission-drafts/9-traceable-projection.md @@ -1,341 +1,283 @@ -# Draft Mission 9 — Automatic traceable projection of one meaningful region +# Draft Mission 9 — Repeatable projection breadth over the accepted lineage seam > Draft cluster only. Not execution authority. Do not implement until this cluster is re-evaluated and cut into `MISSION.md`. +Recut on 2026-09-04. The construction half of the former Mission 9 (schema-carrier repair, the first real nested mutation, one meaningful region built by the model, stable ids, and the positive why over a generated element) moved into the consolidated [Mission 7](7-explainable-construction.md), because the owner chose fully connected parts over thin tracers and because the provenance design showed that lineage only exists when the model actually constructs. This draft keeps what "repeatable" first makes load-bearing: unchanged repeat, changed input, deletion and retirement, concurrent user change, cross-conversation document access, broader schema classes, and the per-action versus batch decision if Mission 7 has not settled it. The reasoning is recorded in the [decision log](../evidence/design/provenance-and-tooling-decision-log-2026-09-04.md) entries F12 and G16 and the [follow-up review](../evidence/design/provenance-by-lineage-follow-up-review-2026-09-04.md) items 16 and 18. + ## Cold-start reads -- [FE-1438](https://linear.app/hash/issue/FE-1438/project-an-evidence-backed-workpiece-into-a-traceable-live-sdcpn) — tracker projection for this future branch mission; the eventual branch `MISSION.md` remains execution authority. +- [FE-1438](https://linear.app/hash/issue/FE-1438/project-an-evidence-backed-workpiece-into-a-traceable-live-sdcpn) — tracker projection for this future branch mission; the eventual branch `MISSION.md` remains execution authority. Its description predates the 2026-09-04 recut and must be re-titled to breadth and repeat behaviour with owner approval before the cut. A fresh builder must resolve these authorities and evidence before choosing a mechanism: -- [`../../MISSION.md`](../../MISSION.md) — live Mission 5 Voice authority on this branch. Mission 9 may be cut only after Mission 7 validly closes its accepted join and a new owner-authorized mission replaces the then-current branch authority. -- [`../../MISSION.next.md`](../../MISSION.next.md) — compact future spine, FE-1476 floor, cross-mission obligations, standing locks, and current Mission 10 handoff. -- [`../../MISSION.md`](../../MISSION.md), [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs), and [`7-capture-backed-review.md`](7-capture-backed-review.md) — live Mission 6 viability authority plus the provisional provenance predecessor. At cut time replace the live pointer and assumptions with accepted evidence, the exact current workpiece/derivation seam, and observed browser mutation behavior. -- [`../mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) and [`../evidence/implementations/fe-1525-headless-runbook-pn.md`](../evidence/implementations/fe-1525-headless-runbook-pn.md) — accepted workpiece leg, canonical callback fixture, provider-visible nested-schema failure, vacuous empty-net result, and explicit next-boundary decision. -- [`../specs/petrinaut-batched-construction-tools.md`](../specs/petrinaut-batched-construction-tools.md) — candidate `pn_read`/`pn_edit` design input and its corrected transaction, outcome, identity, carrier, and ownership constraints. It does not select batching; this mission repairs the known single-action carrier first and admits a batch only if subsequent probes establish it as the least sufficient mechanism. -- [`apps/brunch-agent/src/evaluations/runbook/headless-petrinaut-client.ts`](../../../../../apps/brunch-agent/src/evaluations/runbook/headless-petrinaut-client.ts), [`apps/brunch-agent/test/headless-petrinaut-client.test.ts`](../../../../../apps/brunch-agent/test/headless-petrinaut-client.test.ts), and [`../../packages/plugin-sdcpn/test/construction-tools.test.ts`](../../packages/plugin-sdcpn/test/construction-tools.test.ts) — current bounded six-tool callback route and its limits. -- [`../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts`](../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts) and [`../../packages/plugin-sdcpn/src/flue.ts`](../../packages/plugin-sdcpn/src/flue.ts) — the failed Valibot `looseObject({})` + `rawTransform` provider bridge, canonical runtime delegation, conditional construct-only mounting, and exact current tool subset. +- [`../../MISSION.md`](../../MISSION.md) — the current branch's live authority. Mission 9 may be cut only after Mission 7 validly closes its construction-and-explanation stratum and a new owner-authorized mission replaces the then-current branch authority. +- [`../../MISSION.next.md`](../../MISSION.next.md) — compact future spine, FE-1476 floor, cross-mission obligations, standing locks, the 2026-09-04 planning migration matrix, and the current Mission 10 handoff. +- [`7-explainable-construction.md`](7-explainable-construction.md) — the consolidated predecessor at cut-level detail: settled-revision protocol, declared basis, transition record, identity epochs, passage policy, document reconciliation, recorded roles, scenario-selected tool admission, and its readiness gate. At cut time replace this draft pointer with Mission 7's accepted archive and close evidence, and consume the actual seam it shipped. +- [`../evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md`](../evidence/design/provenance-by-lineage-mini-spec-2026-09-04.md) and the two reviews beside it — the design rationale, the four contracts, the probe decision tables, and the rejected alternatives. Design evidence, not authority. +- [`../mission-archive/3-structurally-typed-runbook-to-headless-pn.md`](../mission-archive/3-structurally-typed-runbook-to-headless-pn.md) and [`../evidence/implementations/fe-1525-headless-runbook-pn.md`](../evidence/implementations/fe-1525-headless-runbook-pn.md) — accepted workpiece leg, canonical callback fixture, the provider-visible nested-schema failure that Mission 7 now retires, and the vacuous empty-net warning. +- [`../specs/petrinaut-batched-construction-tools.md`](../specs/petrinaut-batched-construction-tools.md) — candidate `pn_read`/`pn_edit` design input and its corrected transaction, outcome, identity, carrier, and ownership constraints. It does not select batching. Mission 7 repairs the single-action carrier; this mission admits a batch only if the probes below establish it as the least sufficient mechanism for repeat and changed-input projection. +- [`../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts`](../../packages/plugin-sdcpn/src/tools/petrinaut-construction.ts), [`../../packages/plugin-sdcpn/src/flue.ts`](../../packages/plugin-sdcpn/src/flue.ts), and [`../../packages/plugin-sdcpn/test/construction-tools.test.ts`](../../packages/plugin-sdcpn/test/construction-tools.test.ts) — the tool factory, mounting seams, and alignment guards as Mission 7 leaves them. - [`../../../petrinaut-core/src/ai.ts`](../../../petrinaut-core/src/ai.ts), [`../../../petrinaut-core/src/action-schemas.ts`](../../../petrinaut-core/src/action-schemas.ts), [`../../../petrinaut-core/src/schemas/entity-schemas.ts`](../../../petrinaut-core/src/schemas/entity-schemas.ts), and [`../../../petrinaut-core/src/ai.test.ts`](../../../petrinaut-core/src/ai.test.ts) — canonical Petrinaut AI schemas, mutation callbacks, ids, nested types, and JSON Schema evidence. These are the authority; Brunch prose or copied field catalogs are not. -- [`../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx`](../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx) and [`../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.test.tsx`](../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.test.tsx) — current `useChat` / `onToolCall`, canonical input parsing, mutation execution, diagnostics sequencing, dynamic interactive tools, and visible failure surface. -- [`apps/brunch-agent/src/http/petrinaut-chat.ts`](../../../../../apps/brunch-agent/src/http/petrinaut-chat.ts), [`apps/brunch-agent/src/conversation/client-tools.ts`](../../../../../apps/brunch-agent/src/conversation/client-tools.ts), and [`apps/brunch-agent/test/petrinaut-chat.test.ts`](../../../../../apps/brunch-agent/test/petrinaut-chat.test.ts) — real panel-to-Flue transport and browser callback resume. -- [`../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/SKILL.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/SKILL.md), [`../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/templates/workpiece.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/templates/workpiece.md), the skill's construction/check references, and the exact source/workpiece versions eventually selected by Mission 7 or a predecessor addendum — target-formalism guidance and current workpiece contract. Mission 4 produced no full-run candidate; do not treat branch-tip resources or probe evidence as one. -- Commit `157730cc5a214dd9c543e8d95c7193a219c48aef` on deployment branch `ln/fe-1569-brunch-agent-deployment`, read with `git show`, especially `libs/@hashintel/brunch-agent/docs/evidence/implementations/mission-8-deployment-handoff.md`, plus its `MISSION.md`, application persistence/telemetry files, and open infrastructure gates. Mission 9 consumes the actual deployed contract inherited through Mission 7; it must not imply the branch achieved remote deployment. -- [`../../../petrinaut/docs/ai-assistant.md`](../../../petrinaut/docs/ai-assistant.md), [`../../../petrinaut/docs/drawing-a-net.md`](../../../petrinaut/docs/drawing-a-net.md), and affected simulation/formalism guidance. User-visible projection behavior must update the user guide and prompt screenshot replacement where applicable. +- [`../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx`](../../../petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx) and its test — current `useChat` / `onToolCall`, canonical input parsing, mutation execution, and visible failure surface. +- [`../../packages/transport-aisdk/src/client-tool-history.ts`](../../packages/transport-aisdk/src/client-tool-history.ts) and the Mission 7 transition-record contract — how browser results are correlated and deduplicated by call id. +- [`../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/SKILL.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/SKILL.md), [`templates/workpiece.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/templates/workpiece.md), and [`references/pn-construction.md`](../../packages/plugin-sdcpn/src/skills/sdcpn-modelling/references/pn-construction.md) — construction posture as Mission 7 leaves it. +- [`../reference/architecture/flue-routing.md`](../reference/architecture/flue-routing.md) — the per-conversation versus cross-conversation state distinction that governs the document-scoped owner this mission may need. +- Commit `157730cc5a214dd9c543e8d95c7193a219c48aef` on `ln/fe-1569-brunch-agent-deployment`, especially `libs/@hashintel/brunch-agent/docs/evidence/implementations/mission-8-deployment-handoff.md` — the locally verified application contract and the still-open infrastructure handoff. Mission 9 names local posture unless a Mission 8 successor has landed. +- [`../../../petrinaut/docs/ai-assistant.md`](../../../petrinaut/docs/ai-assistant.md) and [`drawing-a-net.md`](../../../petrinaut/docs/drawing-a-net.md) — user-visible projection behaviour must update the user guide and prompt screenshot replacement. -The accepted bounded workpiece region, Mission 7 pair, derivation representation, generated-region semantics, and Mission 10 correction are not yet canonical paths. They must be named from accepted predecessor evidence when this draft is cut. +The accepted Mission 7 region, proving scenario, transition-record shape, and passage policy are not yet canonical paths. Name them from accepted predecessor evidence when this draft is cut. ## Visible product advance -**Release note:** Brunch builds a recognisable part of the net itself from the conversation, and can still explain every piece it built. - -**Demo script (no engineer present):** open the demo workpiece in the Petrinaut Brunch panel, on the deployment posture named at cut time. Ask Brunch to model the named region. Watch a non-empty region appear in the live net that a person who knows the process recognises as the thing that was discussed. Ask why about one of the generated elements and get the workpiece meaning and quoted conversation evidence back, exactly as for the prebuilt net in Mission 7. - -**Previously impossible:** every net in the demo was prebuilt by a person; Brunch's only real-model construction attempt produced a parser-valid but empty net. +**Release note:** ask Brunch to model the next part of the process and the net grows without disturbing what was already built; ask again and nothing duplicates. -Consequential generated elements carry stable caller-supplied ids and derivations that make Mission 7's why operation resolve back to the current workpiece and its exact retained evidence. +**Demo script (no engineer present):** open the Mission 7 demo conversation and its net in the Petrinaut Brunch panel, on the deployment posture named at cut time. Ask Brunch to model the part of the process the workpiece already describes but the net does not yet contain. Watch a non-empty region appear that a person who knows the process recognises. Ask the same thing again and confirm nothing duplicated or moved. Change one fact in the workpiece through the conversation, ask Brunch to bring the net up to date, and confirm only the affected elements changed while every other id and shape stayed put. Ask why about one generated element after the change and get the current-state answer, not the original one. -The region must be visually inspectable and operationally meaningful: it must exercise the canonical coloured type, parameter, place, transition, and arc contracts required by the selected process meaning. A toy place/transition pair, empty net, parser-only artifact, headless-only result, or one successful nested tool call is not the visible advance. Repeat, changed-input, and failure-class obligations harden this line at the readiness gate; they do not define whether the first line exists. +**Previously impossible:** Mission 7 proves Brunch can build and explain one region once. Nothing yet shows that doing it again is safe, that a changed workpiece yields a bounded change, or that removed meaning retires elements honestly. -Provider-schema repair, the transaction probe, and the per-action versus batch decision are internal sequencing for this mission and are recorded under the throughline hypothesis below. They are not the advance and must not be presented as progress to a product manager. +Repeat, changed-input, and retirement behaviour are the visible advance. Provider-schema classes beyond Mission 7's proving scenario, the per-action versus batch decision, and the document-scoped lineage owner are internal sequencing recorded under the throughline hypothesis; they are not the advance. -**Completion:** the mission is done when a product manager can run the demo script at the readiness gate below, not when the first nested tool call succeeds. +**Completion:** the mission is done when a product manager can run the demo script at the readiness gate below, not when the first unchanged repeat is idempotent. ## Contract stratum -Close the **automatic projection stratum for one named meaningful workpiece region and the canonical Petrinaut mutation classes it uses**. +Close the **repeatable projection stratum over the accepted Mission 7 lineage seam for the same document incarnation**: unchanged repeat, changed input, deletion and retirement, concurrent user change, and the schema classes the extended region requires. The bounded stratum includes: -- current workpiece-region identity and revision; -- canonical Petrinaut coloured types and nested elements used by the region; -- canonical net-level parameters used by the region; -- places, transitions, input/output arcs, and any executable fields required by the selected semantics; -- stable caller-supplied ids and explicit treatment of additions, changes, unchanged elements, and removals if the selected changed-input case requires them; -- derivations from every consequential generated element to current workpiece material, evidence references, projection rationale, assumptions/defaults/omissions/losses, and projector identity/version; -- rejection, bounded repair, unsupported/default behavior, and visible partial failure; -- repeated projection and changed-input projection against current net state; -- semantic correspondence and visual inspectability in the real panel; and -- the exact predecessor provenance operation and durable state boundary. +- unchanged repeat against current net state: no duplicate elements, no id churn, no unrelated mutation, attempt history only; +- changed input: identity-preserving change for touched elements, stable ids and definitions for untouched ones, an explicit impact boundary, and a visible reason where widening is legitimate; +- deletion and retirement: identity epochs closed rather than ids reused; retired elements keep origin and change history and answer why with a retired disposition; +- concurrent or hand change during projection: stale-base refusal per the Mission 7 transition record, external-import semantics, and never a silent overwrite; +- cross-conversation document access, if the proving scenario needs it: a document-scoped durable owner for shared current-workpiece and lineage indexes, replacing Mission 7's one-conversation-one-incarnation binding with its own identity and authorization rule; +- every canonical schema and mutation class the extended region uses, admitted per the scenario-selected rule with canonically derived schemas; +- the per-action versus bounded-batch decision, only if Mission 7 left it open and repeat or changed-input projection exposes a measurable need; +- basis and transition records for every generated, changed, and retired element, and the current-state why answer over them. -Stratum closure is over the named region, accepted scenario/peer set, and mutation classes actually used—not all Petrinaut tools, all SDCPN semantics, or the full optimisation handoff. Mission 11 owns broadening to its accepted full handoff scenario after Mission 10 proves bounded reviewer revision. - -Petrinaut owns canonical schemas and mutations. The projector may select and sequence them, but no Brunch schema copy becomes a parallel authority. The current Markdown workpiece is the semantic input. Captures remain evidence referenced by the workpiece; neither captures nor the full transcript are semantic projection IR. +Stratum closure is over the named extended region, accepted peer set, and mutation classes actually used, not all Petrinaut tools or the full optimisation handoff. Mission 10 owns reviewer authority; Mission 11 owns broadening to its accepted handoff scenario. ## Boundary crossings and current throughline hypothesis ```text -accepted Mission 7 workpiece/prebuilt pair/provenance seam - → select one bounded current workpiece region and its expected operational meaning - → person requests projection in the deployed Petrinaut Brunch panel - → AI SDK transport dispatches to the Flue ChatAgent - → projector reads the current workpiece region, current net, and accepted derivation state - → Brunch/Flue exposes mechanically preserved provider-visible schemas from canonical Petrinaut Zod contracts - → real model emits canonical caller-supplied ids and nested mutation inputs through the selected per-action or bounded-batch surface - → Flue suspends on client tools - → Petrinaut panel parses inputs with canonical schemas and executes canonical mutations through the selected, proved transaction boundary - → client-tool results resume the same Flue turn - → panel visibly shows the meaningful generated region - → Mission 7 why operation resolves generated element → derivation → workpiece → captures +accepted Mission 7 conversation, settled workpiece revisions, transition records, identity epochs + → person asks, in the Petrinaut Brunch panel, to model the next region or bring the net up to date + → Mission 5 browser Flue transport dispatches to the ChatAgent + → agent reads the current workpiece revision from state, the live document through getLatestNetDefinition, and its own lineage through the why lookups + → agent emits a projection plan: intended effects per element with basis locators, stable caller-supplied ids, and expected base hash + → each mutation request cites the settled revision and carries declared basis; the turn terminates on browser tools + → Petrinaut panel validates against the observed pre-apply hash, executes canonical mutations, returns transition records + → agent reconciles effects against the plan; unanticipated effects become basis-absent; stale outcomes refuse + → repeat: the plan finds every intended effect already present and records attempt history only + → changed input: the plan names touched elements, untouched elements, retirements, and any widening, and applies only that + → why over a generated, changed, or retired element resolves through current-state semantics ``` -Authority and actor crossings: +Actor and authority crossings: -- **Workpiece → projector:** semantic interpretation occurs here and is recorded as rationale. The transcript is not primary input and captures are not folded into a semantic model. -- **Petrinaut Zod → provider schema:** schema exposure must preserve arrays, nested objects, refinements that can be represented, descriptions, and required/optional structure mechanically. Provider limitations and any lossy conversion are explicit. -- **Provider → Flue runtime:** provider arguments cross Flue's supported tool-schema interface. Runtime canonical validation remains decisive even when provider schema accepts an approximation. -- **Flue server → Petrinaut browser:** client-tool suspension/resume carries mutation requests/results through the existing AI SDK panel contract. -- **Petrinaut schema → mutation operation → live document:** canonical input parsing precedes canonical mutation. Provider-envelope rejection and canonical per-step rejection are distinct. A non-throwing action may still be a no-op, so operation success requires an explicit outcome or verified postcondition; callback success is not semantic success. -- **Generated element → Mission 7 provenance:** the predecessor why operation consumes the same stable seam. A fixture-specific translation fails the join. -- **Application → deployed substrate:** workpiece, derivation, Flue conversation, and current net identity must survive the accepted Mission 7/Mission 8 replacement boundary. +- **Workpiece to projector:** semantic interpretation occurs here and is recorded as declared basis; the transcript is not primary input. +- **Projector to identity:** stable caller-supplied ids and identity epochs are load-bearing; a retired id is never reused. +- **Petrinaut Zod to provider schema:** Mission 7's repaired carrier; this mission adds classes, never a copy. +- **Browser to record:** the transition record is the only admissible statement of what happened; the plan is not. +- **Conversation to document:** if a second conversation or principal reaches the same document, the document-scoped owner arbitrates; otherwise Mission 7's binding stands and cross-conversation access refuses. -Internal sequencing hypothesis: the first in-mission tracer is narrower than the visible advance. Repair the provider-visible nested schema path enough for one real model call to emit and apply a single canonical nested input such as `addType.elements`. That tracer retires the Mission 3 blocker; it does not complete Mission 9 or select batching. Next, a bounded core transaction probe must establish rollback, readonly/extensions parity, indexed failure, and honest no-op outcomes before a five-action batch is tried through Flue and the production client path. Mission 9 selects the batch only if that comparison shows a material advantage over per-action tools without weakening feedback, identity, or failure visibility. +Internal sequencing hypothesis: first the unchanged repeat against the Mission 7 net, because it is the cheapest discriminator of duplicate and churn behaviour; then one changed input with an expected impact set frozen in advance; then one retirement; then, only if the extended region needs it, additional schema classes and the batch comparison from the batched-tools spec (bounded core transaction probe, then five-action production-path comparison against per-action tools). ## Throughline proof floor -The smallest deployed end-to-end proof must observe all of the following: +The smallest deployed end-to-end proof must observe all of the following on the accepted Mission 7 conversation and document: -1. A person requests projection of one named bounded workpiece region through the real Petrinaut Brunch panel. -2. The resulting automatically projected live region is non-empty, visually inspectable, and semantically corresponds to the selected operational meaning through the required type, parameter, places, transitions, and arcs. -3. Every consequential generated element has a stable caller-supplied id and derivation to the current workpiece, evidence references, and projection rationale, including any assumption or loss. -4. Mission 7's why operation resolves at least one generated element through that derivation. +1. An unchanged repeat request produces no canonical change, no duplicate element, no id churn, and one attempt-history record per intended effect. +2. One changed input produces a bounded canonical change whose applied effects equal the frozen expected impact set, with every untouched id and definition unchanged. +3. One retirement closes an identity epoch, leaves origin and change history queryable, and returns a retired disposition on why. +4. Why over one generated, one changed, and one retired element resolves through current-state semantics without fixture translation. -This floor is the first internal milestone, not mission completion: one automatic traceable meaningful region and the positive generated-element provenance link. It does not close repeat/change behavior, schema-class breadth, stale or partial states, repair exhaustion, derivation atomicity, visible failure, full-net generation, arbitrary revision, Mission 10 reviewer authority, an observer, simulation fidelity, or the Mission 11 optimisation package. Those first seven obligations belong to this mission's readiness gate and stratum closure, not to acknowledgment that the working line exists. +This floor is the first internal milestone, not completion. It does not close concurrent change, cross-conversation access, broader schema classes, the batch decision, or the accepted peer set. ## Readiness ratchet ```text -Mission 7 deployed capture-backed why over a closed prebuilt-pair provenance stratum -→ inherited provenance/durability closure required by automatic generation -→ single-action provider-visible nested-schema risk tracer -→ bounded transaction/outcome probe → per-action versus batch mechanism decision -→ meaningful live bounded region with stable ids, derivations, and positive why +Mission 7 construction-and-explanation stratum closed on one conversation and document +→ inherited: settled-revision protocol, declared basis, transition record, identity epochs, passage policy, reconciliation, recorded roles +→ unchanged repeat → changed input → retirement → current-state why → readiness gate -├─ close repeat/change, schema/mutation breadth, stale/partial state, repair, derivation, and failure obligations -├─ admit a stable current-region projection seam and selected correction into Mission 10 -└─ leave full handoff breadth, broad regeneration, observer consolidation, and optimisation unearned +├─ close concurrent change, cross-conversation access, schema-class breadth, batch decision, peer set +├─ admit a stable region identity, impact-boundary semantics, and one selected correction into Mission 10 +└─ leave reviewer authority, observer consolidation, full handoff breadth, and optimisation unearned ``` ### Inherited stratum closure -Mission 9 requires accepted evidence, not draft promises, for: - -- one current Mission 7 workpiece revision and stable region/passage references; -- exact evidence references and a durable, owner-bound capture/workpiece/derivation boundary; -- a why operation that resolves prebuilt element → derivation → workpiece → captures and visibly refuses stale/broken/cross-owner paths; -- a selected non-empty prebuilt pair whose consequential elements have closed provenance dispositions; -- the real deployed panel/AI SDK/Flue/client-tool path and stock-assistant coexistence; -- the actual Mission 8/Mission 7 persistence, identity, telemetry, and replacement contract. - -If the predecessor seam cannot accept a generated derivation without fixture translation, or Mission 7 did not close durability and negative provenance behavior, Mission 9 must stop at inherited closure. Automatic projection cannot turn a provisional provenance route into a dependable base by using it. +Mission 9 requires accepted evidence, not draft promises, for everything Mission 7 closed: the settled-revision protocol; declared operation-level basis with intended-effect mapping; the independently verifiable transition record; identity epochs; passage identity policy; live-document reconciliation; recorded roles; the one-conversation-one-incarnation binding; the scenario-selected tool set with a repaired carrier; the compaction posture and fixture materialization route; the safety and utility gates. If Mission 7 shipped a different representation, consume that actual contract or return here for re-cutting. Automatic repetition cannot turn a provisional line into a dependable base by using it. ### Readiness gate after the new throughline -For the named region, enumerate and close: +For the extended region, enumerate and close: -- every canonical schema and mutation class used, including nested arrays/objects, optional/null fields, ids, descriptions, runtime-only refinements, error messages, and actions that can no-op without throwing; -- provider-schema rejection versus canonical per-step rejection, repair budget, duplicate tool delivery, client-tool resume, timeout, abort, and partial sequence failure; -- if batching is selected, its supported handle scope, rollback contract, effective readonly and disabled-extension parity, per-step applied/no-op/failure outcomes, and state postconditions; +- unchanged repeat under duplicate delivery, retry, and reload; +- changed input for each accepted change class: added meaning, changed meaning, removed meaning, and legitimate widening; +- retirement semantics, including elements referenced by executable code, scenarios, or metrics; +- concurrent user mutation and hand edit during projection: stale-base refusal, external import, and no silent overwrite; +- cross-conversation and second-principal access to the same document, or an explicit refusal and its owner; +- every canonical schema and mutation class used by the extended region, including nested arrays and objects, optional and null fields, runtime-only refinements, and actions that can no-op without throwing; +- provider-schema rejection versus canonical per-step rejection, repair budget, timeout, abort, and partial sequence failure; +- if batching is selected: supported handle scope, rollback contract, readonly and disabled-extension parity, per-step outcomes, and state postconditions; - unsupported consequential defaults and every assumption, inference, omission, or construction-opened loss; -- semantic correspondence of type elements, parameters, places, transitions, arc direction/type/weight, executable code where used, and canvas-visible structure; -- unchanged repeat, changed input, stale workpiece revision, stale current net, partial prior projection, and concurrent/user change behavior; -- stable ids for unchanged elements, deliberate ids for new elements, deletion/retirement behavior where exercised, and absence of unrelated churn; -- derivation completeness, atomicity relative to applied state, lineage/change account, stale-link refusal, and no successful derivation for rejected mutation; -- visible partial failure and recovery/retry without duplicate state; -- path isolation from the stock assistant and from unrelated net regions; -- latency, usage, transcript fallback, compaction/recovery, and deployed replacement behavior where the real path crosses them. - -Mission 10 may inherit: +- semantic correspondence of the extended region, with the behavioural discriminator carried from Mission 7 rerun after each change; +- visible partial failure and recovery without duplicate state; +- path isolation from the stock assistant and unrelated regions; +- latency, usage, compaction, and replacement behaviour where the real path crosses them. -- one accepted bounded workpiece-region identity and current revision; -- one generated live net neighborhood with stable unrelated ids; -- one traceable projection operation and explicit impact boundary; -- one selected operational distinction whose correction has observable but bounded consequences; -- derivation lineage/change-account semantics that can represent retained, changed, added, retired, unsupported, and widened-impact dispositions. +Mission 10 may inherit: one accepted region identity and current revision; one generated neighbourhood with stable unrelated ids; the impact-boundary semantics; one selected operational distinction whose correction has observable but bounded consequences; and change-account semantics able to represent retained, changed, added, retired, unsupported, external, and widened dispositions. **Owner:** Mission 10. **Re-entry gate:** an explicitly authorized reviewer supplies new evidence in 3–5 focused turns, a foreground phase-boundary synthesis creates an inspectable revision citing reviewer message ids, and the same projector applies a scoped patch or explicit refusal without unrelated churn. **Oracle:** Mission 10's deployed correction, qualification, coexistence, conflict matrix and stable-unrelated-id check. -**Owner:** Mission 10. **Re-entry gate:** an explicitly authorized reviewer supplies new evidence in 3–5 focused turns, a foreground phase-boundary synthesis creates an inspectable revision, and the same projector applies a scoped patch or explicit refusal without unrelated churn. **Oracle:** Mission 10's deployed correction/qualification/contextual-coexistence/conflict matrix and stable-unrelated-id check. - -Do not defer provider-schema fidelity, repeated projection, changed-input identity, derivation atomicity, semantic correspondence, or visible partial failure to Mission 10: Mission 9's automatic projection claim already depends on them. +Do not defer repeat idempotence, changed-input identity, retirement, or concurrent-change refusal to Mission 10: Mission 9's repeatable claim already depends on them. ## Candidate evidence and oracles | Claim leaf | Existing evidence or candidate oracle | | --- | --- | -| Canonical callback path can build a non-empty parser-accepted type/parameter/place/transition/arc fixture | Existing `apps/brunch-agent/test/headless-petrinaut-client.test.ts`, test `constructs a parser-accepted document through the bounded callbacks`. Run `yarn workspace @apps/brunch-agent test:unit`. This is inner headless evidence only. | -| Current plugin exposes exactly the bounded six-tool subset and delegates runtime acceptance/rejection to canonical Zod | Existing `libs/@hashintel/brunch-agent/packages/plugin-sdcpn/test/construction-tools.test.ts`, tests `exposes exactly the bounded canonical subset`, `mechanically carries the canonical input contract`, and `delegates accepted and rejected inputs to Petrinaut's Zod schemas`. Run `yarn workspace @hashintel/brunch-agent-plugin-sdcpn test:unit`. | -| Petrinaut tool metadata aligns with canonical schemas; JSON Schema for representative tools is AI-friendly; callbacks validate before applying | Existing `libs/@hashintel/petrinaut-core/src/ai.test.ts`, suite `Petrinaut AI core exports`, including `tool metadata stays aligned with input schemas and has no execute`, `addArc exposes an AI-friendly object input schema`, and callback tests. Run `yarn workspace @hashintel/petrinaut-core test:unit --run`. | -| Real panel parses canonical mutation input and executes callbacks through `onToolCall` | Existing source in `libs/@hashintel/petrinaut/src/ui/views/Editor/panels/ai-assistant-panel.tsx`; current test covers dynamic follow-up, not automatic construction. **ORACLE GAP:** bind a panel integration test to the actual selected mutation sequence. | -| Real server/client suspension and resume work | Existing `apps/brunch-agent/test/petrinaut-chat.test.ts`, production-door test driven by `petrinaut-chat.integration.ts`. It currently mounts no construction tools on ordinary panel conversations; that negative assertion is a guard, not Mission 9 success. | -| Mission 3 provider-visible bridge failed specifically on nested `addType.elements`, 0-for-9, and empty parser success was vacuous | Existing `docs/evidence/implementations/fe-1525-headless-runbook-pn.md`; inspect the paid-run artifact named there. | -| Live provider accepts the mechanically preserved nested canonical schema | **ORACLE GAP:** no existing real-model call proves this. Resolve first with one budgeted single-action `addType.elements` tracer using the exact provider/model/schema artifact and retain raw tool call/rejection evidence. A successful call does not select batching or complete the mission. | -| A bounded batch can preserve canonical semantics and improve the selected path | **ORACLE GAP:** follow the three probes in `docs/specs/petrinaut-batched-construction-tools.md`: single-action carrier; first-class core transaction/outcome contract; then five-action production-path comparison against per-action tools. Batch selection requires rollback, readonly/extensions parity, indexed failure, no-op honesty, supported-handle scope, production client routing, and material measured benefit. | -| Selected meaningful region exercises required type/parameter/place/transition/arc semantics | **ORACLE GAP:** region and scenario portfolio are not selected. Resolve with a frozen workpiece-region fixture, expected semantic account, canonical resulting definition, and human visual inspection. | -| Mission 7 why resolves generated elements through the same derivation seam | **ORACLE GAP:** Mission 7 is provisional and no generated derivation exists. Resolve through the real deployed why operation without fixture-specific conversion. | -| Unchanged repeat is idempotent and changed input yields bounded identity-preserving change | **ORACLE GAP:** no projection operation exists. Bind to exact current-net before/after definitions, mutation log, derivation diff, and stable-id assertions when implemented. | -| Rejection/repair and partial failure do not advance canonical or derivation state incorrectly | Canonical mutation rejection is locally evidenced by `headless-petrinaut-client.test.ts` and plugin schema tests. **ORACLE GAP:** sequence-level atomicity/partial-state policy and visible deployed recovery are unresolved. | -| Semantic correspondence exceeds parser acceptance | **ORACLE GAP:** establish a workpiece-specific human adjudication; optionally admit a simulation-backed check only if it discriminates the selected meaning cheaply. Parser `ok: true` is explicitly insufficient. | -| Mission 10-ready selected correction has bounded observable consequences | **ORACLE GAP:** choose the correction with the owner only after the generated region exists; record expected retained/changed ids and behavior before Mission 10 is cut. | -| Deployment durability/identity/telemetry survive projection | **ORACLE GAP:** consume Mission 7 accepted remote evidence. The Mission 8 branch handoff alone stopped before infrastructure/replacement proof. | +| Canonical callbacks build a non-empty parser-accepted fixture | Existing `apps/brunch-agent/test/headless-petrinaut-client.test.ts`, test `constructs a parser-accepted document through the bounded callbacks`. Inner headless evidence only. | +| Petrinaut tool metadata aligns with canonical schemas; callbacks validate before applying | Existing `libs/@hashintel/petrinaut-core/src/ai.test.ts`, suite `Petrinaut AI core exports`. | +| Repaired carrier admits nested inputs; scenario-selected classes are mounted | Mission 7 close evidence; cite its exact tests at cut time. | +| Transition records are independently verifiable; duplicates resolve to unknown | Mission 7 close evidence; cite at cut time. | +| Unchanged repeat is idempotent | **ORACLE GAP:** bind to exact before/after canonical definitions, the transition-record log showing attempt history only, and a stable-id assertion when implemented. | +| Changed input yields bounded identity-preserving change | **ORACLE GAP:** freeze the expected impact set before the run; compare applied effects, untouched ids, and definitions. | +| Retirement closes an epoch and answers why | **ORACLE GAP:** bind to an epoch ledger assertion and a why answer with retired disposition. | +| Concurrent or hand change refuses rather than overwrites | **ORACLE GAP:** inject a hand edit between plan and apply and assert stale refusal plus external-import disposition. | +| Cross-conversation access is arbitrated or refused | **ORACLE GAP:** decide at cut time whether the proving scenario needs it; if so, bind a second-conversation probe to the document-scoped owner. | +| A bounded batch improves repeat or changed-input projection | **ORACLE GAP:** follow the three probes in `docs/specs/petrinaut-batched-construction-tools.md`; batch selection requires rollback, readonly and extension parity, indexed failure, no-op honesty, supported-handle scope, production client routing, and material measured benefit. | +| Semantic correspondence of the extended region | **ORACLE GAP:** workpiece-specific human adjudication plus the Mission 7 behavioural discriminator rerun after each change. | +| Mission 10-ready correction | **ORACLE GAP:** choose with the owner after the extended region exists; record expected retained and changed ids and behaviour before Mission 10 is cut. | ## Verification approach -- **Inner mechanism evidence:** verify mechanical schema derivation from canonical Petrinaut sources, provider-visible nested shape, canonical runtime rejection, stable id planning, deterministic derivation construction, and no derivation commit for rejected or no-op calls. Keep conversion tests structural and compare against canonical source schemas; do not bless copied snapshots as a second authority. If batching is selected, prove its transaction semantics through a first-class core operation rather than direct handle access. -- **First tracer:** make one real provider call against the single canonical nested schema that failed in Mission 3. Record provider/model, generated schema, raw arguments, runtime result, repair count, latency, and cost. Stop on a crisp upstream blocker. Passing retires only the provider-schema risk. -- **Mechanism decision:** after the carrier tracer, run the core transaction probe and then compare the bounded batch with the repaired per-action surface through the production client path. Record schema size, calls, latency, correction behavior, state outcome, and failure visibility. Keep per-action tools if batching does not earn its added core and host contracts. -- **Middle integration/contract evidence:** drive the built Brunch application through Flue client-tool suspension/resume into a real Petrinaut instance. Apply the complete meaningful region, inspect canonical state and derivations, run unchanged repeat, then changed-input projection and an invalid/unsupported case. Include stale revision/current-net and duplicate-delivery probes where the selected protocol permits them. -- **Outer deployed/user-visible evidence:** a human requests the bounded projection in the deployed panel, watches the meaningful region appear, inspects the region, asks why a generated element, repeats unchanged projection, changes the selected workpiece input, and observes bounded visible change or explicit refusal. Witness stock mode remains independent. Mission 9 owns this evidence. -- **Semantic adjudication:** compare current workpiece meaning and explicit expected consequences against the resulting SDCPN, not merely tool logs. Record assumptions/defaults/losses and any mismatch. A simulation-backed check may supplement but not replace this adjudication unless its discriminating contract is accepted. -- **Failure verification:** provider-schema error, canonical rejection, client callback failure, stale state, repair exhaustion, and partial sequence failure must be visible and must not produce false successful derivations. +- **Inner mechanism:** projection-plan construction from workpiece revision and live definition; intended-effect to basis mapping; stable id planning; epoch ledger; reconciliation of transition records against the plan; no basis for unanticipated effects; no state advance on rejected or no-op calls. +- **Middle integration:** drive the built Brunch application through the Mission 5 transport into a real Petrinaut instance on the Mission 7 conversation. Run unchanged repeat, one changed input, one retirement, a duplicate delivery, a stale-base attempt, and a hand edit between plan and apply. Inspect canonical state, transition records, epochs, and why answers. +- **Outer deployed and user-visible:** a human runs the demo script in the panel and witnesses no duplication, a bounded change, an honest retirement, and a current-state why. Stock mode remains independent. Mission 9 owns this evidence. +- **Semantic and behavioural:** compare the extended region with the workpiece meaning, and rerun the Mission 7 behavioural discriminator after each change. +- **Failure:** provider-schema error, canonical rejection, client callback failure, stale state, repair exhaustion, and partial sequence failure remain visible and never produce false success. +- **Mechanism decision:** only after repeat and changed input work per action, compare the bounded batch through the production client path and keep per-action tools unless the batch earns its core and host contracts. ## Inputs and joins -- **Mission 7 join:** accepted current workpiece, durable exact evidence references, stable workpiece/derivation/element seam, deployed why operation, selected prebuilt pair, negative provenance behavior, and owner/replacement guarantees. -- **Mission 3 failure join:** exact paid-run evidence for the failed Valibot open-object bridge and the canonical six-tool hermetic fixture. Repair only the provider-visible loss first; do not reinterpret empty parser success as partial semantic success. -- **Petrinaut canonical-contract join:** consume `petrinautAiTools`, `mutationActionInputSchemas`, entity schemas, and writable callbacks by import or mechanical generation. Mismatches between file-format and action schemas route upstream to Petrinaut. The batched-tools design is candidate input: Petrinaut core may own a generic subset-derived schema and first-class transaction/outcome operation, while Brunch retains subset selection, Flue carriage, client routing, and projection identity. -- **Flue join:** use a documented supported schema/tool path. If Flue cannot preserve the canonical nested schema, produce a crisp upstream requirement instead of deepening an opaque carrier. -- **Host join:** preserve AI SDK `useChat` / `onToolCall` and client-tool result resumption. Mutation execution remains browser/Petrinaut-owned. -- **Scenario join:** owner selects one meaningful workpiece region, operational expected account, accepted peer cases, and one Mission 10 correction. A toy fixture cannot supply this join. -- **Mission 10 output join:** stable region identity/current revision, impact boundary, repeat/change semantics, derivation lineage, and selected correction with expected consequences. -- **Mission 11 horizon:** record omissions needed to broaden from this region to the later accepted optimisation handoff; do not implement that breadth here. +- **Mission 7 join:** the accepted conversation, settled revisions, transition records, epochs, passage policy, tool set, compaction posture, fixture route, and gates. Draft promises are not join evidence. +- **Petrinaut canonical-contract join:** consume `petrinautAiTools`, `mutationActionInputSchemas`, entity schemas, and writable callbacks by import or mechanical generation. Mismatches route upstream. The batched-tools design is candidate input: Petrinaut core may own a generic subset-derived schema and first-class transaction operation; Brunch retains selection, Flue carriage, client routing, and identity. +- **Flue join:** the repaired carrier from Mission 7; a new upstream requirement if a class cannot be carried. +- **Host join:** preserve `useChat` / `onToolCall` and client-tool result resumption; mutation execution remains browser and Petrinaut owned. +- **Scenario join:** the owner selects the extended region, expected impact sets, accepted change classes, and one Mission 10 correction. +- **Mission 10 output join:** region identity, impact boundary, change-account semantics, and the selected correction with expected consequences. +- **Mission 11 horizon:** record the omissions needed to broaden from this region to the accepted handoff; do not implement that breadth here. ## Risks and assumptions | Risk or assumption | Impact if false | Cheapest discriminating validation | | --- | --- | --- | -| Flue can expose a mechanically preserved Petrinaut nested schema to the provider | If false, automatic projection is blocked upstream or requires a different supported schema bridge | First real `addType.elements` tracer using Standard Schema/supplied JSON Schema or the least mechanical shape-preserving path. | -| A Zod-to-provider conversion can preserve the load-bearing contract without copying fields | If false, provider acceptance and runtime semantics diverge | Compare generated nested JSON Schema and positive/negative samples directly against canonical Zod for every used tool class. | -| One bounded region can be both meaningful and small enough to close | If false, the mission either proves a toy or expands toward a full net | Select the region and expected operational account before implementation; reject candidates lacking type, parameter, flow, and an observable change. | -| Stable caller-supplied ids plus projection-level operation/base identity are enough for repeat/change locality | If false, generated ids churn, duplicate delivery mutates twice, or stale edits land | Run unchanged repeat, duplicate delivery, stale-base submission, and one changed input against a frozen current net; inspect all ids and unrelated definitions. | -| A first-class bounded batch can improve construction without weakening canonical mutation behavior | If false, atomicity is handle-specific, no-ops appear successful, or coarse feedback increases retries | Compare equivalent sequential and batch results under readonly and disabled extensions, inject duplicate/missing IDs and an invalid late step, then run the selected case through the production client path. | -| The projector can consume bounded context rather than the full workpiece/transcript | If false, locality and later revision become unreliable | Project from the selected region plus explicitly named dependencies; withhold unrelated transcript and observe whether the result remains sufficient. | -| A desired-region recomputation followed by bounded mutations satisfies locality | If false, internal global reasoning may cause hidden dependence/churn | Compare accessed inputs, proposed diff, and applied mutations; owner decides whether applied locality is sufficient for the delivery contract. | -| Mission 7's derivation representation can describe generated and changed elements | If false, automatic generation needs a seam revision before implementation continues | Emit one add, retain, change, and unsupported disposition on paper/fixture and run Mission 7 why resolution. | -| Bounded repair can recover provider mistakes without loops or silent defaulting | If false, projection latency/failure becomes unsafe | Inject one recoverable and one unrecoverable canonical rejection; enforce and visibly exhaust the accepted budget. | -| The selected changed-input case prepares Mission 10 without pre-solving reviewer authority | If false, Mission 10 inherits an irrelevant region or this mission expands into revision | Choose only expected operational consequence here; leave who may revise and how foreground synthesis authorizes it to Mission 10. | -| Parser plus visual inspection is enough for this region | If false, semantically wrong dynamics may look plausible | Try the cheapest workpiece-specific simulation expectation; promote only if it catches a plausible wrong projection. | +| A projection plan can find already-present intended effects without re-mutating | Repeat duplicates or churns | Run unchanged repeat against the Mission 7 net and inspect the transition log for attempt history only. | +| Stable caller-supplied ids plus epochs are enough for changed-input locality | Ids churn, stale edits land, or retired ids are reused | Frozen expected impact set; before/after id inventory; retire one element and attempt to reuse its id. | +| Mission 7's one-conversation-one-incarnation binding is sufficient for the proving scenario | A second conversation or principal reaches the document with no arbiter | Decide at cut time; if needed, place a document-scoped owner behind the existing storage boundary and probe two conversations. | +| A first-class bounded batch improves repeat or change without weakening canonical behaviour | Atomicity is handle-specific, no-ops look successful, coarse feedback increases retries | Compare sequential and batch results under readonly and disabled extensions with injected duplicate, missing, and invalid late steps, then the production client path. | +| The projector can consume the region plus named dependencies rather than the full workpiece | Locality and later revision become unreliable | Withhold unrelated workpiece sections and observe whether the plan remains sufficient. | +| Desired-region recomputation with bounded applied diff satisfies locality | Hidden global dependence causes churn | Compare accessed inputs, proposed diff, and applied mutations; the owner decides whether applied locality suffices. | +| Retirement can be represented without breaking executable references | Removing meaning breaks scenarios, metrics, or code | Retire an element referenced by a scenario and observe the canonical outcome and why answer. | +| Parser plus visual inspection plus the discriminator are enough for the extended region | Semantically wrong dynamics look plausible | Rerun the Mission 7 discriminator after each change; promote a second discriminator only if it catches a plausible wrong projection. | ## Accepted constraints and guarded invariants -- **Petrinaut owns canonical schemas and mutations.** Guard: imports/mechanical generation and structural alignment tests. A generic batch, if earned, is a first-class Petrinaut operation with explicit supported-handle, readonly, extension, rollback, and outcome semantics; Brunch does not reach through an instance to `handle.change`. Stop if field shapes are hand-copied into Brunch prose, Valibot, fixtures presented as authority, or a parallel schema package. -- **Provider repair is only the first risk tracer.** Guard: acknowledge the working line only after the meaningful-region and positive-why floor; mission acceptance then requires readiness closure for repeat, change, and failure classes. -- **Workpiece is semantic input.** Guard: projector input manifest names current workpiece revision/region; transcript and captures are excluded as primary semantic input. -- **Captures remain evidence, not projection IR.** Guard: derivations reference evidence through the workpiece; projector has no capture-to-model reducer. -- **Stable caller-supplied ids are load-bearing.** Guard: unchanged-repeat and changed-input before/after assertions. -- **Applied state and derivation agree.** Guard: derivations commit only after canonical mutation result/current-state confirmation; rejected calls cannot appear successful. -- **No unsupported consequential defaults.** Guard: expected semantic account and assumption/default/loss inspection; unsupported cases visibly stop or remain explicit. -- **Non-empty and semantically meaningful.** Guard: required canonical type/parameter/place/transition/arc inventory, panel witness, and workpiece-specific adjudication. Parser acceptance alone fails. -- **Bounded repair and bounded region.** Guard: named repair budget, selected region/dependencies, mutation/impact log, and stop on widening beyond the accepted boundary. -- **No unrelated churn.** Guard: stable unrelated-id and definition comparison for repeat/change. -- **No observer or automatic workpiece revision.** Mission 9 projects the current accepted workpiece; it does not consolidate conversation evidence or decide reviewer authority. Guard: no scheduler/fold queue and no canonical workpiece writes. -- **One agent, one mounted job skill, existing panel door.** Guard: composition/dependency inventory; no second server, TUI, workflow engine, or subagent topology. +- **Petrinaut owns canonical schemas and mutations.** Guard: imports or mechanical generation and structural alignment tests. A generic batch, if earned, is a first-class Petrinaut operation with explicit supported-handle, readonly, extension, rollback, and outcome semantics; Brunch does not reach through an instance to `handle.change`. +- **The transition record is the only statement of effect.** Guard: no basis, epoch, or why state advances from a plan or a self-reported effect set that fails diff accounting. +- **Identity epochs are never reused.** Guard: epoch ledger assertion on retire and recreate. +- **Repeat is idempotent; change is bounded; widening is declared.** Guard: attempt-history-only repeat log; frozen impact set; visible widening reason. +- **Workpiece is semantic input; captures and transcript are not.** Guard: projector input manifest names the settled revision; declared basis on every request. +- **No unsupported consequential defaults.** Guard: expected semantic account and assumption, default, loss inspection. +- **No observer or automatic workpiece revision.** Mission 9 projects the current accepted revision; it does not consolidate evidence or decide reviewer authority. Guard: no scheduler, fold queue, or canonical workpiece writes outside `update_workpiece` called by the foreground agent. +- **One agent, one mounted job skill, existing panel door.** Guard: composition and dependency inventory. - **Stock assistant remains independent.** Guard: path isolation and host witness. -- **Deployment claims match observed evidence.** Guard: consume accepted Mission 7 replacement proof; do not cite Mission 8's local image as remote deployment. -- **Visible failures do not advance canonical state silently.** Guard: injected rejection, stale state, partial sequence, and timeout/abort tests. -- **Paid provider evidence requires cut-time authorization and a stated budget.** Guard: no real-provider tracer runs from this draft; the eventual live mission records model, maximum calls, and spend ceiling before execution. +- **Deployment claims match observed evidence.** Guard: name local posture unless a Mission 8 successor has landed. +- **Paid provider evidence requires cut-time authorization and a stated budget.** Guard: the live mission records model, maximum calls, and spend ceiling before execution. ## Cross-cutting obligations -- Projection fidelity: the generated region comes from the current workpiece and every consequential decision has an attributable rationale. -- Evidence provenance: Mission 7 why reaches exact evidence without laundering model prose into quotation. -- Workpiece sufficiency: construction names a smallest gap instead of silently filling missing objective/process meaning. -- Petrinaut acceptance: canonical schema/mutation validity, non-empty state, diagnostics where executable code is used, visual inspection, and semantic correspondence are distinct leaves. -- Identity and derivation integrity: repeat/change preserve unrelated identities and explain all necessary impact widening. -- Failure visibility: provider schema, canonical rejection, unsupported meaning, stale state, client callback, and partial failure visibly stop/degrade. -- Interaction quality: projection and why occur through the real panel in operational language; construction schema vocabulary does not take over reviewer interaction. -- Deployment/privacy: stable owner-bound product state and content-free observability survive the accepted replacement boundary. -- User docs: document request, visible generated result, why flow, repeat/change behavior, and failure states; prompt replacement of stale screenshots. -- Mission 10 readiness: leave one meaningful selected correction and a trustworthy bounded projection seam, not a generic revision platform. -- Mission 11 horizon: retain omissions and breadth gaps needed for the eventual optimisation handoff. +- Projection fidelity, evidence provenance, and workpiece sufficiency as stated in the spine's cross-mission obligations, over generated, changed, and retired elements. +- Identity and change-account integrity: repeat and change preserve unrelated identities and explain all necessary widening. +- Failure visibility across provider schema, canonical rejection, unsupported meaning, stale state, hand edit, client callback, and partial failure. +- Interaction quality: projection and why in operational language; construction vocabulary does not take over reviewer interaction. +- Runtime migration matrix continued from Mission 7 for any representation this mission changes, with a removal gate. +- User docs: request, visible generated result, repeat and change behaviour, retirement, failure states; prompt replacement of stale screenshots. +- Mission 10 readiness: one selected correction and trustworthy impact-boundary semantics, not a generic revision platform. +- Mission 11 horizon: retained omissions and breadth gaps. ## Expected touched paths -Tentative only; the first real schema tracer may expose an upstream boundary and shrink or redirect this manifest. +Tentative only; Mission 7's accepted seam may shrink or redirect this manifest. ```text libs/@hashintel/brunch-agent/ ├── MISSION.md ~ cut-time authority only -├── docs/evidence/ + provider tracer, semantic adjudication, deployed projection -├── packages/plugin-sdcpn/src/tools/petrinaut-construction.ts ~ provider-visible canonical schema path and bounded tools -├── packages/plugin-sdcpn/src/flue.ts ~ mount projection capability only on the accepted product route -├── packages/plugin-sdcpn/src/skills/sdcpn-modelling/ ~ construction/projection guidance only where observed strain requires -├── packages/plugin-sdcpn/test/construction-tools.test.ts ~ canonical alignment/provider shape guards -├── packages/core/ ? minimal derivation mechanics only if Mission 7 places them here -└── packages/binding-flue/ ? no change unless supported Flue schema translation belongs at this boundary +├── docs/evidence/ + repeat/change/retirement witnesses and adjudication +├── packages/plugin-sdcpn/src/tools/ ~ additional scenario-selected classes; projection plan if plugin-owned +├── packages/plugin-sdcpn/src/skills/sdcpn-modelling/ ~ repeat/change/retirement posture +├── packages/plugin-sdcpn/test/ ~ alignment and plan guards +├── packages/core/ ~ epoch and change-account semantics if core-owned +└── packages/binding-flue/ ? document-scoped owner only if cross-conversation access is admitted apps/brunch-agent/ -├── src/agents/chat-agent/ ~ compose bounded projection capability -├── src/conversation/client-tools.ts ~ client-tool names/results as required -├── src/http/petrinaut-chat.ts ~ preserve production dispatch/resume -├── src/evaluations/runbook/headless-petrinaut-client.ts ~ evidence harness only, not product substitute -└── test/ ~ real provider tracer and production throughline +├── src/agents/chat-agent/ ~ compose the projection capability +└── test/ ~ repeat, change, retirement, stale, hand-edit integration libs/@hashintel/petrinaut-core/ -├── src/ai.ts ~ canonical schema export/generation; subset batch schema only if selected -├── src/instance.ts ~ first-class transaction/outcome operation only if the batch probe earns it -├── src/handle/ ? explicit transaction capability only if existing contracts cannot support the claim -├── src/action-schemas.ts ~ only canonical contract correction discovered at source -└── src/*.test.ts ~ canonical, transaction, readonly/extensions, no-op, and mutation guards +├── src/ai.ts, src/instance.ts, src/handle/ ? subset batch schema and first-class transaction only if the batch probe earns it +└── src/*.test.ts ~ canonical, transaction, readonly/extensions, no-op guards libs/@hashintel/petrinaut/ -├── src/ui/views/Editor/panels/ai-assistant-panel.tsx ~ generic host execution/visible failure only if needed -├── src/ui/views/Editor/panels/ai-assistant-panel.test.tsx ~ real host integration +├── src/ui/views/Editor/panels/ai-assistant-panel* ~ generic host execution and visible failure only if needed └── docs/ ~ affected user-facing guidance - -deployment/infrastructure source outside this checkout ? only if accepted product route exposes a missing deployed contract ``` -Do not add a hand-copied Brunch schema catalog, graph database, generalized projection framework, automatic observer, capture fold, workflow engine, second agent/server, or full 46-tool stock-modeller surface. +Do not add a hand-copied Brunch schema catalog, graph database, generalized projection framework, automatic observer, capture fold, workflow engine, second agent or server, or full stock-modeller parity. ## Fog-line -- Which Flue-supported schema interface can preserve canonical Zod nested shape: Standard Schema, supplied JSON Schema, a mechanical shape-preserving conversion, or an upstream Flue change. -- Which canonical refinements are provider-expressible and how runtime-only constraints are described without pretending the provider enforces them. -- The smallest operationally meaningful region and accepted peer cases; the broader demo portfolio remains unenumerated. -- Exact type elements, parameter, places, transitions, arcs, executable code, and extension requirements for that region. -- Whether the current Mission 7 Markdown reference seam supplies stable bounded region identity or needs the least additional revision marker. -- The smallest projector implementation and where its projection plan/derivation state belongs. -- Whether recomputing a desired bounded region internally while applying a local diff satisfies the owner, or genuinely local computation is required. -- How deletions/retirements are represented if the selected changed-input case removes meaning. -- Whether repaired per-action tools or a bounded batch are the least sufficient surface after measured schema cost, calls, latency, correction behavior, and failure visibility. -- If batching is selected, which handles explicitly support rollback, how silent canonical no-ops are reported, and whether one history checkpoint is acceptable in the stock editor. -- Repair budget, provider-envelope versus canonical per-step feedback, timeout, and partial-sequence policy. -- Concurrent user mutation, duplicate delivery, operation identity, base revision, and stale-current-net behavior during projection. -- The exact semantic oracle beyond workpiece-specific human adjudication; simulation remains optional until discriminating. +- The extended region, its accepted change classes, and the peer set; the broader demo portfolio remains unenumerated. +- Whether the proving scenario needs cross-conversation document access and therefore a document-scoped owner. +- How retirement interacts with executable references in scenarios, metrics, and code. +- Whether repaired per-action tools or a bounded batch are the least sufficient surface after measured schema cost, calls, latency, correction behaviour, and failure visibility. +- If batching is selected, which handles support rollback, how silent canonical no-ops are reported, and whether one history checkpoint is acceptable in the stock editor. +- Repair budget, provider-envelope versus canonical per-step feedback, timeout, and partial-sequence policy for multi-element plans. +- Whether desired-region recomputation with a bounded applied diff satisfies the owner or genuinely local computation is required. - The selected Mission 10 correction and what counts as a sufficiently local patch when connected semantics legitimately widen impact. -- Representative deployed latency/usage, compaction/recovery behavior, and any host selection needed for this path. +- Representative deployed latency, usage, and compaction behaviour for longer conversations. ## Stop or reorient Stop and surface evidence if: -- Mission 7's accepted workpiece/provenance/durability seam is unavailable or generated derivations require a fixture-specific translation; +- Mission 7's accepted seam is unavailable or repeat and change require a fixture-specific translation; - canonical Petrinaut field shapes are manually copied into Brunch; -- Flue/provider cannot receive the required nested shape through a supported mechanical path; record the crisp upstream blocker rather than extending the opaque open-object carrier; -- batching is implemented before the single-action carrier is proved, or selected without explicit transaction scope, readonly/extensions parity, honest no-op outcomes, production client routing, and measured advantage over per-action tools; -- one successful `addType.elements` call, empty net, toy pair, parser result, or hermetic fixture is presented as mission completion; -- the projector reads the full transcript as primary model or treats captures as semantic IR; -- construction silently invents an objective, process spine, resource fate, contention rule, timing/tail behavior, or consequential default absent from the workpiece; +- a class cannot be carried through the repaired carrier; record the upstream blocker rather than extending an opaque carrier; +- batching is implemented before per-action repeat and change are proved, or selected without transaction scope, parity, honest no-ops, production routing, and measured advantage; - repeated unchanged projection duplicates elements, churns ids, or mutates unrelated state; -- changed input triggers unrelated regeneration without a visible impact boundary and explanation; -- rejected/failed tool calls acquire successful derivations or partial state is represented as complete; +- changed input triggers unrelated regeneration without a visible impact boundary and reason; +- a retired id is reused or a retired element loses its history; +- a hand edit or concurrent change is overwritten rather than refused and imported; +- rejected or failed calls acquire basis or advance epochs, or partial state is represented as complete; - semantic correspondence cannot be distinguished from attractive canvas output; -- the bounded region expands toward a complete net or all Petrinaut tools without an accepted consumer; +- the region expands toward a complete net or all Petrinaut tools without an accepted consumer; - an observer, automatic evidence fold, reviewer-authority mechanism, or generic revision platform enters to prepare Mission 10; -- Brunch-specific logic enters Petrinaut's published library instead of a generic host/canonical contract; -- stock assistant behavior or separate history becomes dependent on Brunch; or -- deployment, owner binding, visible failure, or replacement durability is claimed without real-boundary evidence. +- Brunch-specific logic enters Petrinaut's published library; +- stock assistant behaviour or separate history becomes dependent on Brunch; or +- deployment, owner binding, or replacement durability is claimed without real-boundary evidence. ## Carried evidence and rejected alternatives -- Mission 3 proved canonical Petrinaut callbacks can construct a non-empty fixture through `getLatestNetDefinition`, `addType`, `addParameter`, `addPlace`, `addTransition`, and `addArc`. It also proved runtime rejection of a zero-weight arc and correction in the faux path. -- The paid Mission 3 model run falsified the provider-visible Valibot `looseObject({})` + `rawTransform` carrier: nine `addType.elements` arrays arrived as strings, all were correctly rejected, and the parser accepted only an empty legacy document. Preserve the 0-for-9 result; do not describe it as partial construction success. -- The next accepted move from that evidence was Flue support for Standard Schema/supplied JSON Schema or a mechanical shape-preserving conversion. Extending the open-object carrier or copying Petrinaut fields into Valibot remains rejected. -- Petrinaut's canonical Zod schemas, action schemas, AI tool bundle, and mutation callbacks are current authority. The file-format and action-schema families are aligned by source code and tests, not guaranteed by Brunch; discovered mismatch routes upstream. -- Mission 7 deliberately proves why over an honest prebuilt pair first. Mission 9 must replace the prebuilt projection step with bounded automatic generation while preserving the same provenance contract. -- A comprehensive requirements graph, process-domain ontology, universal subject/predicate/value model, closed kinds/slots, typed completion algebra, deterministic capture-to-model fold, and full regeneration engine remain rejected. They re-enter only under repeated observed inability of workpiece prose plus explicit derivations to support projection or readiness. -- Optional SDCPN mapping hints remain advisory and absent by default. They may re-enter only if projection repeatedly misses consequential structures and a hint demonstrably helps without biasing workpiece meaning; they never copy Petrinaut payload fields. -- Stable caller-supplied ids remain the current least identity hypothesis. A stronger identity ledger re-enters only if repeat/change projection demonstrates unavoidable churn or ambiguity. -- Full desired-net recomputation with bounded applied diff remains fog, not accepted architecture. Unrelated churn or hidden global dependence rejects it. -- Broad 46-tool parity with the stock modeller is rejected; close only the canonical mutation classes the meaningful region actually uses. -- `pn_read`/`pn_edit` are candidate model-facing names, not accepted architecture. Reuse `getLatestNetDefinition` unless an alias earns its production routing cost; retain repaired per-action tools if a bounded batch does not earn its transaction and host surface. -- An inferential observer remains absent. Mission 10's default revision mechanism is foreground phase-boundary synthesis; observer promotion requires separate evidence for ordering, flush, failure, prior-meaning preservation, and foreground latency. -- Mission 11 owns broadening to the accepted full optimisation handoff scenario. Mission 9 must not stop automatically after one tracer, but neither may it expand without the named region, peer set, and oracle. +- Mission 3 proved canonical Petrinaut callbacks can construct a non-empty fixture through `getLatestNetDefinition`, `addType`, `addParameter`, `addPlace`, `addTransition`, and `addArc`, and proved runtime rejection of a zero-weight arc with correction in the faux path. +- The paid Mission 3 model run falsified the provider-visible Valibot `looseObject({})` + `rawTransform` carrier: nine `addType.elements` arrays arrived as strings, all correctly rejected, and the parser accepted only an empty legacy document. Preserve the 0-for-9 result. Mission 7 now owns the repair; this mission consumes it. +- The next accepted move from that evidence was Flue support for Standard Schema or supplied JSON Schema, or a mechanical shape-preserving conversion. Extending the open-object carrier or copying Petrinaut fields into Valibot remains rejected. +- Petrinaut's canonical Zod schemas, action schemas, AI tool bundle, and mutation callbacks are current authority; file-format and action-schema families are aligned by source and tests, not guaranteed by Brunch. +- The former Mission 7 "honest prebuilt pair" with a hand-authored derivation fixture was rejected on 2026-09-04 as useless; provenance now comes from constructor-declared basis and recorded transitions on a genuine conversation, so this mission's why join is to Mission 7's real seam, not to a prepared translation. +- A comprehensive requirements graph, process-domain ontology, universal subject/predicate/value model, closed kinds and slots, typed completion algebra, deterministic capture-to-model fold, and full regeneration engine remain rejected; they re-enter only under repeated observed inability of workpiece prose plus declared basis to support projection or readiness. +- Optional SDCPN mapping hints remain advisory and absent by default; they may re-enter only if projection repeatedly misses consequential structures and a hint demonstrably helps without biasing meaning, and they never copy Petrinaut payload fields. +- Stable caller-supplied ids plus identity epochs remain the least identity hypothesis; a stronger identity ledger re-enters only if repeat or change demonstrates unavoidable churn or ambiguity. +- Full desired-net recomputation with bounded applied diff remains fog, not accepted architecture; unrelated churn or hidden global dependence rejects it. +- Broad stock-modeller tool parity is rejected; admission is scenario-selected with canonically derived schemas and expands on observed need. +- `pn_read` / `pn_edit` are candidate model-facing names, not accepted architecture; reuse `getLatestNetDefinition` unless an alias earns its routing cost; retain per-action tools unless a bounded batch earns its transaction and host surface. +- An inferential observer remains absent; Mission 10's default revision mechanism is foreground phase-boundary synthesis. +- Mission 11 owns broadening to the accepted full optimisation handoff scenario; Mission 9 must not stop automatically after one repeat, but neither may it expand without the named region, peer set, and oracle. diff --git a/libs/@hashintel/brunch-agent/docs/mission-drafts/README.md b/libs/@hashintel/brunch-agent/docs/mission-drafts/README.md index 4d1d119658c..3b31268ca18 100644 --- a/libs/@hashintel/brunch-agent/docs/mission-drafts/README.md +++ b/libs/@hashintel/brunch-agent/docs/mission-drafts/README.md @@ -1,6 +1,6 @@ # Provisional mission drafts -Files in this directory are detailed context repositories for possible future missions. They are not execution authority, do not create live missions, and must not be implemented. [`MISSION.md`](../../MISSION.md) is the current branch's sole live Mission 5 authority and [`MISSION.next.md`](../../MISSION.next.md) is the compact future spine. A draft must be re-evaluated and converted into a new root `MISSION.md` as the sole execution authority on its own issue, branch, and PR before implementation. +Files in this directory are detailed context repositories for possible future missions. They are not execution authority, do not create live missions, and must not be implemented. [`MISSION.md`](../../MISSION.md) is the current branch's sole live mission authority and [`MISSION.next.md`](../../MISSION.next.md) is the compact future spine. A draft must be re-evaluated and converted into a new root `MISSION.md` as the sole execution authority on its own issue, branch, and PR before implementation. Each planning item has one authoritative planning home across `MISSION.next.md` and these linked drafts. A spine summary is only a pointer. Keep accepted decisions, rejected alternatives and reasons, re-entry conditions, scenario classes, evidence, constraints, fog, stop conditions, risks, assumptions, and named mechanisms in one discoverable home at the precision needed by a cold-start builder. From ebb84c8d5f25a1f9f07d2479c293f9da18a7bc05 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 12:49:08 +0200 Subject: [PATCH 17/31] Amend Mission 6 deferred items for the recut planning record Point the Deferred section at the 2026-09-04 provenance replanning, carry the fixture-authorship and fenced-block admissions into the close record, and note in Status that no other section of the live authority changed. Co-Authored-By: Claude Fable 5.1 --- libs/@hashintel/brunch-agent/MISSION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/@hashintel/brunch-agent/MISSION.md b/libs/@hashintel/brunch-agent/MISSION.md index 843d4d55ed4..23e48f73672 100644 --- a/libs/@hashintel/brunch-agent/MISSION.md +++ b/libs/@hashintel/brunch-agent/MISSION.md @@ -2,7 +2,7 @@ ## Status -**Live on `ln/fe-1575-resumable-workpiece-petrinaut`.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) remains in progress. The implementation and outer mechanical witness are complete; cold-reader semantic adjudication and the product-manager demo remain the final acceptance gates. See the [retained implementation and witness evidence](docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md). +**Live on `ln/fe-1575-resumable-workpiece-petrinaut`.** [FE-1575](https://linear.app/hash/issue/FE-1575/resume-one-brunch-workpiece-and-petrinaut-document-across-tabs) remains in progress. The implementation and outer mechanical witness are complete; cold-reader semantic adjudication and the product-manager demo remain the final acceptance gates. See the [retained implementation and witness evidence](docs/evidence/implementations/fe-1575-resumable-workpiece-petrinaut.md). On 2026-09-04 the owner amended only the Deferred section, to point at the recut future planning record and carry two admissions from this mission's evidence; the imperative, throughline, proof, constraints, fog-line, and stop conditions are unchanged. ## Imperative @@ -159,4 +159,4 @@ Stop and surface evidence if: ## Deferred -Mission 7 still owns capture-backed visible why/provenance and broken-link refusal after this fixture is viable. Mission 9 still owns repeatable automatic projection, broader nested provider-schema classes, stable generated-element derivations, repeated/changed-input behavior, and the breadth of semantic correspondence. Remote replacement durability and release infrastructure remain in the historical Mission 8 handoff. Multi-tab concurrent editing, a durable cross-store commit protocol, explicit localStorage failure injection and refusal of a concurrent write from a tab holding an older revision (distinct from the readiness-gate refusal to reopen onto stale or mismatched artifacts), and promotion of this prepared fixture into a reusable product seed re-enter only if the automatic mirror loses or overwrites state, a later consumer requires atomic bundle identity, or this mission otherwise exposes concrete strain; their current planning home and re-entry conditions remain in [`MISSION.next.md`](MISSION.next.md) and the linked Mission 7/9 drafts. +On 2026-09-04 the future planning record was recut around provenance by lineage with declared basis; see the [2026-09-04 migration disposition](MISSION.next.md#2026-09-04-provenance-replanning-migration-disposition). Mission 7 now owns construction and explanation of one real net region from a genuine conversation: settled workpiece revisions as `update_workpiece` tool calls, constructor-declared basis on each mutation, verifiable transition records, the why operation with its safety and utility gates, schema-carrier repair, scenario-selected tool admission, and retirement of the orphaned `ask` and `sweep` client handling. Mission 9 owns repeatable projection breadth: unchanged repeat, changed input, retirement, concurrent change, cross-conversation document access, and the schema classes an extended region adds. Two facts from this mission carry into that record and its close report: the prepared fixture's "Current Petrinaut correspondence" section was fixture-authored rather than produced by any skill directive, so this fixture is a viability proof and is not promoted into the provenance pair; and the fenced `runbook-ir` block plus message-id-and-hash selection is a Mission 6 contract that Mission 7 replaces for model-produced revisions, keeping the tagged prepared signal for test-authored material only. This mission's constraint that construction tools stay out of ordinary conversations is amended by the Mission 7 cut, not here. Remote replacement durability and release infrastructure remain in the historical Mission 8 handoff, and a Mission 8 successor must be scheduled before any remote claim. Multi-tab concurrent editing, a durable cross-store commit protocol, explicit localStorage failure injection and refusal of a concurrent write from a tab holding an older revision (distinct from the readiness-gate refusal to reopen onto stale or mismatched artifacts), and promotion of this prepared fixture into a reusable product seed re-enter only if the automatic mirror loses or overwrites state, a later consumer requires atomic bundle identity, or this mission otherwise exposes concrete strain; their current planning home and re-entry conditions remain in [`MISSION.next.md`](MISSION.next.md) and the linked Mission 7/9 drafts. From 2122621410328977296fb8075b41b442dbec79d8 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 13:03:39 +0200 Subject: [PATCH 18/31] Record Mission 6 cold-reader acceptance Co-authored-by: Cursor --- .../cold-reader-gate.md | 79 ++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-gate.md b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-gate.md index eb90497ed0e..0beb540a721 100644 --- a/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-gate.md +++ b/libs/@hashintel/brunch-agent/docs/evidence/implementations/fe-1575-outer-browser-witness-2026-09-04-r2/cold-reader-gate.md @@ -28,4 +28,81 @@ Record the reviewer's identity, date, verbatim response, and explicit accept/rej ## Human verdict -Pending. +- Reviewer identity: friend +- Review date: 2026-09-04 +- Explicit decision: **ACCEPT** + +### Verbatim response + +```text +1. Authorship of each revision + + prepared-workpiece.md — test/harness-authored, not model-produced. + Discriminators in cold-reader-records.json → preparedRecord: + - role: "system", purpose: "dispatch", display: "diagnostic" — a system-injected diagnostic entry, not an assistant turn. No turnId. + - signal.tagName: "prepared-fixture" with attributes.authorship: "test-authored" and claimBoundary: "prepared-not-model-produced". + - The text part opens "Fixture authorship: test-authored preparation for Mission 6" and its runbook-ir block is content-identical to prepared-workpiece.md. + - The entry id entry_direct_c3ViX2lr… is entry_direct_ + base64 of its own submissionId (sub_ik_f24939…), consistent with a directly-inserted record rather + than a generated turn. + + latest-workpiece.md — assistant (model) authored. + Discriminators in revisedRecord: + - role: "assistant", purpose: "assistant", display: "visible", and a turnId (turn_01M1NQGQ…) — a model turn under a distinct submission (sub_ik_6dbc18…). + - The runbook-ir block inside that record is content-identical to latest-workpiece.md. + - No signal block / authorship attribute exists on this record; attribution rests on role alone. + + Two caveats a reader should hold: + - The assistant-authored revision's own Claim boundary still says "This is test-authored diagnostic material." That sentence is inherited prose and is wrong + for this revision per the record's role. The record, not the in-text sentence, is the discriminator. + - Neither record carries a timestamp, model identifier, or provider. The prepared→revised ordering is inferred from content ("Revised", "has been added") + and from the differing submission ids, not from metadata. Nothing in these records links the two submissions causally. + + 2. Recorded quantity / resource policy + + Both revisions: exactly one dispatch crew. "Starting final inspection consumes that one available crew; sign-off returns it." + + Differences between revisions: + - Prepared qualifies it "in this fixture"; revised drops the qualifier. + - Revised adds the general firing rule "No transition fires without sufficient tokens in all input places" and describes dispatch-crew-available as "(1 + token when free)". + + Note: the "exactly one" is stated as policy in prose. No initial marking appears in any of the three files (the assistant's JSON excerpt shows inputArcs + only), so the quantity is asserted, not shown. + + 3. Reserve / return operations + + - Reserves: Start final inspection / start-final-inspection, via a weight-1 standard input arc from dispatch-crew-available. + - Returns: Sign-off / sign-off, via an output arc to dispatch-crew-available. + + Evidence status within the packet: the prepared workpiece says the reserving arc is deliberately absent; the revised says it "has been added and verified." + The only support in these files is the assistant's self-quoted inputArcs snippet inside its own text — no tool result, snapshot, or hash. The sign-off→crew + return arc is asserted in prose in both revisions and never shown as data in any of the three files. + + 4. Unresolved timing, failure, and recovery points + + From the prepared revision (one sentence): inspection and sign-off timing, failure modes, recovery behavior. + + From the revised revision (enumerated): + 1. Inspection timing — duration, stochasticity, determinism. + 2. Sign-off timing — duration, stochasticity, determinism. + 3. Failure modes — whether inspection can fail, halt, or reject a batch. + 4. Recovery behavior — how failures/rejections affect batch state or crew availability. + + Also excluded by the revised Claim boundary (unresolved by omission): failure handling, full process projection, integration with upstream/downstream + operations. + + Reviewer observation (inference from the described net, not a stated unknown): as specified, the crew token is consumed by start-final-inspection and + returned only by sign-off. Any failure/reject path that does not pass through sign-off would leave the single crew permanently unavailable — i.e., items 3 + and 4 above are not independent; unresolved failure modes imply a potential deadlock in the sole-crew resource. Neither revision names this. + + 5. Behavioral-execution or operational-provenance claims supportable from these materials alone + + None. + - Both workpieces explicitly disclaim capture provenance and behavioral execution. + - No firing sequence, marking trace, simulation output, or tool-call result appears in any of the three files. + - The revised record's "Verification successful" / "verified in the live Petrinaut definition" is an assistant assertion supported only by the assistant's + own quoted JSON. From these files you can say the model claimed verification; you cannot say verification occurred, nor that the live definition contains + the arc. + - Operational provenance of the prepared fixture is established only to the extent "a system-role record with a test-authored signal exists" — not who/what + produced it, or when. +``` From 969ea0cb5741ae82efe7ef0219e63b06d374b9b2 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 4 Sep 2026 14:10:12 +0200 Subject: [PATCH 19/31] Reposition the prepared fixture status banner Co-authored-by: Cursor --- .../local-storage-demo-app.tsx | 17 ++++++++++------- .../prepared-fixture-banner.tsx | 11 ++++++++++- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx b/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx index 1bf304f08f6..f6d6425c073 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx @@ -6,6 +6,7 @@ import { createFlueClient, type FlueConversationSettlement } from "@flue/sdk"; import { castDraft, produce } from "immer"; import { useCallback, useEffect, useMemo, useState } from "react"; +import { createPortal } from "react-dom"; import { agentOwnershipHeaders, @@ -735,13 +736,15 @@ export const LocalStorageDemoApp = ({ width: "100vw", }} > - {preparedFixtureIsCurrent && ( - - )} + {preparedFixtureIsCurrent && + createPortal( + , + document.body, + )} {!preparedFixtureIsCurrent && } diff --git a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.tsx b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.tsx index 77e60581d2d..6dc06884761 100644 --- a/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.tsx +++ b/apps/petrinaut-website/src/main/app/local-storage-demo/prepared-fixture-banner.tsx @@ -22,6 +22,15 @@ const fixturePanelStyle = { zIndex: 20, } as const; +const fixtureBannerStyle = { + ...fixturePanelStyle, + left: "50%", + position: "fixed", + top: 80, + transform: "translateX(-50%)", + width: "calc(100vw - 32px)", +} as const; + export const PreparedFixtureSelector = () => (