From d0f7a7ba8754acfa96155028210f2a69bd7fada5 Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 28 Aug 2026 11:10:50 +0200 Subject: [PATCH 01/22] Keep upcoming-mission drafts at conversational fidelity. Co-authored-by: Cursor --- libs/@hashintel/brunch-agent/AGENTS.md | 29 +- libs/@hashintel/brunch-agent/MISSION.md | 9 +- libs/@hashintel/brunch-agent/MISSION.next.md | 312 ++++++-- libs/@hashintel/brunch-agent/README.md | 5 +- .../brunch-agent/docs/agents/git-workflow.md | 8 +- .../2026-08-27-mission-close-and-next.md | 668 ++++++++++++++++++ .../docs/mission-archive/README.md | 3 +- 7 files changed, 962 insertions(+), 72 deletions(-) create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md diff --git a/libs/@hashintel/brunch-agent/AGENTS.md b/libs/@hashintel/brunch-agent/AGENTS.md index 4b77a051ae2..3572274f6cf 100644 --- a/libs/@hashintel/brunch-agent/AGENTS.md +++ b/libs/@hashintel/brunch-agent/AGENTS.md @@ -26,7 +26,7 @@ from this file. When work starts on a branch, state these six things in [`MISSION.md`](MISSION.md) and copy them into the branch/PR description. Do not create additional planning or control documents, except the -next-concerns scratchpad below. +next-concerns draft below. - **Imperative** — what must become true, and why now. - **Throughline** — the real entrypoint or boundary being changed. @@ -39,22 +39,35 @@ next-concerns scratchpad below. Running the path may lengthen this list; that is calibration, not regression. - **Stop or reorient** — evidence that invalidates or changes the route. -### One live mission, next-concerns scratchpad +### One live mission, next-concerns draft [`MISSION.md`](MISSION.md) is the only execution authority. Agents and humans implement against it. -[`MISSION.next.md`](MISSION.next.md) is the scratchpad for discussing all next concerns. It may -hold a longer horizon than a single mission. It is not a mission: do not implement it, do not -treat it as a second concurrent mission, and do not declare its focus until planning is resolved. +[`MISSION.next.md`](MISSION.next.md) is the draft of upcoming work and the comprehensive record of +ideas, observations, questions, and named mechanisms already raised. It may hold a longer horizon +than a single mission. It is not a mission: do not implement it, do not treat it as a second +concurrent mission, and do not declare its focus until a cluster is cut. -A current mission's **Deferred** items belong in that scratchpad as well. Do not silently drop or +Keep every hypothesis, observation, question, and named mechanism at conversational fidelity. A +heading plus a one-line label is not a record of a design. Rejected alternatives and the reason +they lost belong next to the locked choice. Ungrilled fog stays marked unasked. + +Group likely future missions as multiple `#` headings (one cluster per heading). Spikes that are +not missions, and standing lock / out-of-scope decisions, get their own headings — they are not +fake missions. Do not pre-fill Imperative, Throughline, Proof, or Status on a cluster; those +sections are the cut into `MISSION.md`. Record Constraints, Fog-line, and Stop or reorient on a +cluster only when the conversation already earned them. + +A current mission's **Deferred** items belong in that draft as well. Do not silently drop or supersede them when adding other concerns. When the current mission is accepted and the next focus is resolved: 1. Move `MISSION.md` to `docs/mission-archive/{n}-{slug}.md`. -2. Cut a single focused `MISSION.md` from the scratchpad (the six-section contract above). -3. Leave everything that did not make the cut in `MISSION.next.md`. +2. Cut a single focused `MISSION.md` from one cluster (the six-section contract above). +3. Leave everything that did not make the cut in `MISSION.next.md` at the same fidelity — still + hypotheses, still rejected alternatives, still named mechanisms. A cut is a copy of one cluster + into authority, not a summary of the remainder. Do not promote `MISSION.next.md` wholesale. Do not keep two live missions. Do not delete a closed mission; the archive is evidence of what was proven, not marching orders. Re-earn before building diff --git a/libs/@hashintel/brunch-agent/MISSION.md b/libs/@hashintel/brunch-agent/MISSION.md index 1bd9fb64ba8..848ce036df5 100644 --- a/libs/@hashintel/brunch-agent/MISSION.md +++ b/libs/@hashintel/brunch-agent/MISSION.md @@ -4,9 +4,10 @@ Live. This file is execution authority. -Later concerns are clustered in [`MISSION.next.md`](MISSION.next.md). That file is a scratchpad, -not a mission; do not implement it. Host-trunk work, Petrinaut read/write tools, typed IR maps, -observer-triggered sweeps, and any join to Mission 2's capture store are not this mission. +Later concerns are clustered in [`MISSION.next.md`](MISSION.next.md). That file is a draft of +upcoming work, not a mission; do not implement it. Host-trunk work, Petrinaut read/write tools, +typed IR maps, observer-triggered sweeps, and any join to Mission 2's capture store are not this +mission. ## Imperative @@ -107,5 +108,5 @@ Stop and surface the evidence before continuing if: Host trunk, typed map and Petrinaut read/write via existing `onToolCall`, capture improvement (token-threshold observer, typed payloads), and whether capture and runbooks converge, are -clustered in [`MISSION.next.md`](MISSION.next.md). That scratchpad does not supersede this +clustered in [`MISSION.next.md`](MISSION.next.md). That draft does not supersede this section. diff --git a/libs/@hashintel/brunch-agent/MISSION.next.md b/libs/@hashintel/brunch-agent/MISSION.next.md index cba4464c5b4..a4cbd16f6ef 100644 --- a/libs/@hashintel/brunch-agent/MISSION.next.md +++ b/libs/@hashintel/brunch-agent/MISSION.next.md @@ -1,71 +1,274 @@ -# Next concerns +Draft of upcoming missions, and the record of what we currently think we know about what to +do next — ideas, observations, questions, and named mechanisms already raised. Not execution +authority. Implement against [`MISSION.md`](MISSION.md). Do not promote this file wholesale. +Do not keep two live missions. -Scratchpad, not a mission. [`MISSION.md`](MISSION.md) remains execution authority. Do not -implement from this file. Clusters are ordered; they are not a second concurrent mission. -When a focus is cut into a new `MISSION.md`, leave everything that did not make the cut here. +Likely future missions are the `#` headings that name a cut. Imperative, Throughline, Proof, +and Status wait until a cluster is cut into `MISSION.md`. Constraints, fog, and stop lines +appear where the 2026-08-27 grill (Q1–Q17) already earned them. Spikes that are not missions, +and standing lock / out-of-scope decisions, are not fake missions. -Capture (archived Mission 2) and the live runbook/IR path (Mission 3) are **independent**. -Whether they converge, and if so where, when, and in what form, is an open later question. Do -not wire them in order to tidy the list. +Provenance for the grill: [`docs/inbox/2026-08-27-mission-close-and-next.md`](docs/inbox/2026-08-27-mission-close-and-next.md). +Live Mission 3 is the runbook / template / headless / off-canvas-PN experiment. Archived +Mission 2 is the mechanical capture pipe. Neither is restated here as a mission. -## Host trunk +```text +M1 chat (done) M2 pipe (archived) M3 runbook (live) +├─ Host (uncut) +│ ├─ two brains, same panel +│ ├─ net create/save/load = session discriminator +│ └─ compaction reconstructs panel + transcript +└─ Brunch elicitation + ├─ M4 typed map + Petrinaut R/W + └─ M5 capture improvement (observer, maybe types, maybe subagents) +LATER / parallel — OTel/eval, watch-sims, HarnessAgent +``` -Later cut. Does not need the capture pipe. Does not need a runbook. +Two trunks, one live `MISSION.md`. Parallel means stacked branches or worktrees, not two +authority files. Q1-C (two live missions at once) was rejected. -- **Two brains, same panel.** Stock modeller and Brunch selectable without relaunching. Today - the switch is `yarn dev` vs `yarn dev:brunch`. Locked: Brunch is not the new Petrinaut - assistant; panel stays `useChat` / `onToolCall`; do not splice conversations; stock must work - with brunch-agent down; HASH embed stays stock unless opted in. Open: origin sharing, picker - location, mid-net vs start-only switch. -- **Net create/save/load is the session lifecycle.** Working assumption: Petrinaut net id - discriminates one Flue conversation per principal. Prove save/load keeps the same conversation; - a new net id mints a new one. If net ids are unstable, drop the assumption and rekey (Mission 2 - stores by Flue conversation identity until then). -- **Compaction.** Prove panel and transcript reconstruct across a real Flue compaction boundary - (`compaction-vs-durable-history` / FE-1386). Product control to compact or to show a summarized - range only after that pin. +# Capture and runbook stay independent -Voice is a git parent on `kostandin/h-6763-openai-canonical-speech`, not a cluster here. Same -`POST /api/chat` dock Mission 1 named. Resolve UUID-per-net vs `petrinaut-preview:${netId}` and -stolen vs configured `/api/chat` on that stack. Brunch owns no provider audio. +Not a mission. A standing constraint on every elicitation cut. -## Elicitation ladder +Capture (archived Mission 2) and the runbook / IR path (live Mission 3) were brought in +together so strain is visible. There is **no designed join**. Whether they converge, and if +so where, when, and in what form, is an open later question. Do not wire them in order to +tidy the list. -Mission 3 holds the prompting experiment (runbook, template, headless drive, off-canvas PN). -Remaining order after that: typed map plus canvas I/O, then capture improvement. Watch for the -strain threshold (condition 5: typed mapping, in-loop LLM judgment, ~2 min question turns). +Q12 A/B/C were all refused: -### Typed map and Petrinaut read/write +- **A (refused).** Two artifacts with a designed join: capture store as provenance ledger, + template as workpiece, M5 when ledger entries grow types that match M4's map. +- **B (refused).** One artifact: sweep's opaque payload *is* the template update. +- **C (refused).** M3 ignores the capture store; M2's store sits idle until something typed + exists. -FE: minimal typing — what maps to what — so generation can reject a vague shape. Brunch agent -read/write of the live net via existing panel `onToolCall`, not by absorbing the stock modeller -or its 46-tool set. Agent generates a PN on the canvas from an IR. Which tools, when: not -decided. +**Why the typed-capture kernel failed (observation, not a plan).** The sweep mechanism with +typed captures became too complex and demanded too much LLM judgment to use it and to map +each part. The most recent real test was incredibly slow; the headline catastrophic outcome +was ordinary question turns taking upwards of two minutes. Progressive reintegration is how +the threshold becomes visible: re-admit pieces of that design until the mechanism is +untenable again, and notice where. -### Capture improvement +Runbooks and templates are **not yet connected** to the capture sweep. They are a prompting +experiment: how far a comprehensive runbook goes **without typed claims at capture**, pulling +in the research and design modeling already on disk. Template fill is not a sweep. Sweep +means capture-store apply. -Token-threshold observer: arm after N tokens (no model call), fire on next turn settle. Maybe -typed payloads that match the FE map; maybe not, if the runbook path is winning. Subagents / -micro-cognitive tasks: undecided. This is where latency and judgment re-enter on purpose, so -the threshold is visible. +**Strain threshold to watch** (condition 5): typed mapping, in-loop LLM judgment, question +turns on the order of minutes. Stop lines that carry forward from M2: producing captures +requires a model call; a sweep tool appears on the interviewer; kinds / slots / fold / +plugins / repertoire re-enter as the teaching vehicle; the runbook or IR template is wired +to the store; ordinary turns return to condition-5 latency. -## Later / parallel +# Host trunk + +Later cut. Does not need the capture pipe. Does not need a runbook. Compaction sits here +because it is the same reconstruction family as save/load, not because it is prompting. + +OTel may ride this trunk if it is in flight; it must not sequence the elicitation ladder +(Q4-B). Voice is a git parent, not a cluster here. + +## Two brains, same panel + +A person using the Petrinaut demo should be able to choose the stock modeller or the Brunch +Flue agent without relaunching. Today the switch is `yarn dev` vs `yarn dev:brunch`. + +**Locked.** Brunch is a second assistant, not the new Petrinaut modeller. Panel stays +`useChat` / `onToolCall`. Do not splice conversations. Stock must work with brunch-agent +down. HASH embed stays stock unless opted in. Do not rewrite the panel onto `@flue/react`. + +**Fog, unasked.** How both backends share an origin; where the picker lives; whether you can +switch mid-net or only at start. These were never grilled. They are unanswered questions, +not a thin cut. + +## Net create/save/load is the session lifecycle + +**Working assumption.** Petrinaut net id discriminates one Flue conversation per principal. +Prove create / save / load is also the session lifecycle: save/load keeps the same +conversation; a new net id mints a new one. If net ids regenerate or collide, drop the +assumption and rekey. + +**Facts.** Conversation ids today are a localStorage map keyed by `netId`. New session = +mint another conversation id; resume = reload the same net. Archived Mission 2 already keys +the capture store by Flue conversation identity (principal + conversation id) until this +proof lands. + +**Locked (Q3-A).** Net id is only the conversation discriminator. A distinct Brunch +target-document stays later. Do not collapse "one net *is* the target-document" — that is an +unearned product ontology and would leak into HASH entity vs demo localStorage. Q3-B +(collapse) and Q3-C (sweep in a throwaway store, splice later) were rejected. + +## Compaction + +Prove the panel and transcript still reconstruct across a real Flue compaction boundary +(`compaction-vs-durable-history` / FE-1386). Compaction is Flue-default and unpinned. +Product control to compact, or to show a summarized range, only after that pin. + +Moved here from the original M3 batching: it is history reconstruction, not a prompting +concern. + +## Voice (git parent, not this cut) + +Stack on `kostandin/h-6763-openai-canonical-speech` when that branch is the parent. Same +`POST /api/chat` dock Mission 1 named. Resolve UUID-per-net vs `petrinaut-preview:${netId}`, +stolen vs configured `/api/chat`, and `submitText` with no `brunch_ask`. Brunch owns no +provider audio. Not a mission. + +# Typed map and Petrinaut read/write + +After live Mission 3. FE Petri-net generation from some kind of IR, at the minimal typing +sophistication necessary: what maps to what. The flue agent must be able to generate a PN +using tools, given an IR. + +**Why this cluster exists.** FE generation is the consumer that can reject a vague shape, +and it is how you learn the target BE capture has to converge on. It is also a chance to +iterate on the PN tools and see whether many changes can land at once. + +**Locked.** Brunch agent read/write of the live net via existing panel `onToolCall`, not by +absorbing the stock modeller or its 46-tool set. Second assistant, not a replacement +modeller. No canvas mutation tools before this cut — they waited here so Mission 3 could +not draw nets from vibes. Which tools, when: not decided. + +**IR at this cut.** Mission 3's IR is a markdown template (skill supporting file), +structured but not strictly typed; generation uses inference. This cut introduces the typed +map (which fields become places / transitions / arcs). Q8-B (M3 already uses core kind/slot +tables; the template is only a projection of the fold) and Q8-C (skip the document +template; typed IR starts in M3) were rejected. B would put the full plugin IR back on the +door too early. + +**Teaching vehicle.** Q2-A: one real Flue skill is the cheap proof that the teaching +*mechanism* works (Mission 2 landed `defineSkill` / `useSkill` / `activate_skill`). Do not +grow a skill catalog. Iterate the runbook body (which may live inside that one skill, or as +instruction text). Flue `useSkill` (progressive-disclosure `SKILL.md` catalogs, +`activate_skill`) is not always-on `useInstruction` / the agent's return string, and is not +Brunch repertoire (core YAML, off this path). Q2-C (re-admit repertoire/plugin keys onto +this door) was rejected. + +**Headless vs canvas.** Headless JS-API drive (`createFlueClient` → `send` → `wait` → +`history()`) is how you iterate a runbook; it belongs with Mission 3, not as a sibling of +R/W. Q7-A (keep R/W in M3) and Q7-C (runbook is just ongoing edits, not a mission) were +rejected. + +# Capture improvement + +After the typed map, or after the runbook path has shown what it can do without types. +This is where latency and judgment re-enter **on purpose**, so the untenable threshold is +visible. Maybe typed payloads that match the FE map; maybe not, if the runbook path is +winning. + +## Observer agent as the sweep mechanism + +Not a harness counter parked as a label. The observer **is** the sweep mechanism. + +**When (from the Pi extension, and Q11).** Count tokens — no model call to decide *whether* +to sweep. Arm after N tokens (Pi precedent: on the order of 10,000). Fire on the next +settled turn. Anything that does not require an LLM call to decide when to trigger is a +latency saving. The trigger is not the interviewer calling a tool. + +Q11-A locked this observer out of Mission 2: a token counter is a scheduler, and putting it +in the pipe proof would make "did we pick the right N?" look like a sweep failure. Q11-B +(M2 includes the observer; lower N so a short chat crosses it) and Q11-C (bonus hook on the +same `apply-sweep` in M2) were rejected. + +**Calls.** Fire-and-forget, **queued**, **retried on failure**. + +**Fold gate.** Cannot fold unless the queue is valid. + +**Ordinary turns.** The elicitor mostly follows tip / heuristic / situation / example +guidance and **does not consult the fold**. A periodic **re-group every XX tokens** lets +the queue settle, fold, and see what is still needed. + +**Fold semantics** as generic as we can possibly get away with. + +**Scheduler vs model.** Binding can still *run* apply-sweep; the model is not the +scheduler. A sweep tool on the interviewer is an LLM decision about *when*, which is the +latency mechanism to keep off the path until this cut admits judgment on purpose (Q15-A, +carried forward from M2). + +## Extraction thickness (reintegration ladder) + +Mission 2 proved the pipe with no extraction model: one envelope per user utterance, quote += that text, payload `{}`. That stays the floor. + +Progressive re-entry after the pipe is green, when you are trying to notice the threshold: + +1. Stub envelopes (done). +2. A **separate** cheap extraction call (not the interviewer) that emits quotes / opaque + blobs only — no slot types, no mapping to kinds (Q14-B, not yet admitted). +3. Typed claims / plugin proposal catalog (`statement-noted`, SDCPN slots, …) — the + condition-5 failure mode (Q14-C). Re-enter only to see the threshold, not as the + teaching vehicle. + +Q14-A was M2's cut (no extraction model). B and C belong on this path, not earlier. + +## Subagents + +Undecided as a go-ahead. The idea is specific: subagents for **micro-cognitive tasks** that +help **decisioning and decomposition**. Not a floating maybe, and not the M2 teaching stub. + +# Later / parallel Not sequenced on the elicitation ladder. May ride along a live mission if the throughline -already has the hook. - -- **Observability / eval / tracing.** Node OTel SDK → HASH collector/Tempo; Flue - `instrument(...)` already in `app.ts` but nothing exports. `dispatch()` does not propagate - `traceparent`. Content capture off until a privacy policy. FE-1505 / FE-1423 stay production - gates. -- **Watch simulated conversations.** Driver: `@flue/sdk` JSON (`send` / `wait` / `history`), - not PTY poll. Human observer: same conversation URL on `:4321` (render `dynamic-tool` / - `data-*` / skill activation). Herdr panes are terminals; at most open that URL or tail the - transcript CLI. `HarnessAgent` is not this surface. -- **AI SDK 7 `HarnessAgent`.** Converse of the current door (resume a harness session by chat - id). Flue already owns that session; `transport-aisdk` is the UI adapter. A Pi/Claude Code - harness would be another substrate — what `binding-flue` isolates — or a Flue replacement. - Undecided. +already has the hook. Not a numbered mission. + +## Observability / eval / tracing + +Node OTel SDK → HASH collector / Tempo. Flue `instrument(...)` already in `app.ts` but +nothing exports. Prove `gen_ai.conversation.id` = Flue instance id. `dispatch()` (the +`/api/chat` path) does not propagate `traceparent`. Content capture stays off until a +privacy policy. FE-1505 / FE-1423 stay production gates. + +Q4-B: do this on Host if that trunk is in flight; do not let it sequence the ladder. Not +C (OTel as a proof bullet of the first Brunch or Host mission). The original "prove this +too, in mission 2" was retracted. + +## Watch simulated conversations + +Parallel spike, not a mission. The product itch: there is not yet a way to visually observe +simulated conversations. That dissatisfaction is the reason this spike exists; it is not +on the critical path. + +**Locked (Q9-A).** Driver: `@flue/sdk` JSON (`createFlueClient` → `send` → `wait` → +`history()`), not PTY poll. Human observer: the same conversation URL. `:4321` already +follows a conversation (`useFlueAgent`) but only paints text — render `dynamic-tool` / +`data-*` / skill activation. The missing piece is a **second observer on the same +conversation URL**, not a new protocol. Herdr panes are PTYs, not browsers; herdr cannot +embed that page. A pane can at most open the URL or tail the transcript CLI. + +**Rejected.** Q9-B: wait for a herdr webview / JSON pane as the real product (blocks on +herdr). Q9-C: watch sims in the Petrinaut panel, including a client-tool stand-in (couples +every sim to panel client tools you do not need for elicitation rehearsal). +`HarnessAgent` is not this surface. + +## AI SDK 7 `HarnessAgent` + +Undecided. Converse of the current door (resume a harness session by chat id). Flue already +owns that session; `transport-aisdk` is the UI adapter. A Pi / Claude Code harness would be +another substrate — what `binding-flue` isolates — or a Flue replacement. Left as LATER, +not as the watch-sims surface. + +# Mission 3 leftovers + +Live Mission 3 locked a one-shot desk net (PN JSON, petrinaut validate, manual load OK) and +no canvas tools. These did not make that cut: + +- Original M3 also allowed **periodic** PN generation from a filling template ("one-shot at + end, or periodic"). Q13-B locked one-shot for Mission 3 so the runbook experiment has a + score. Periodic generation remains a later idea. +- "Maybe wire PN JSON into the app programmatically" — manual load is enough to score + whether the template contained enough. Programmatic load is leftover, not a Mission 3 + proof item. + +Teaching ingredients (placement still fog on the live mission; recorded so a later cut does +not re-invent the bundle): some system prompting, some skill prompting, instructions on how +to interpret the runbook (system or skill), and a template resource that is the IR. +Bundling them in the skill is allowed. Growing a catalog is not. + +# Standing decisions + +Not missions. ## Locked, not a mission @@ -74,6 +277,9 @@ already has the hook. - `binding-flue` stays a package even if it is the only binding. - Exploded-view net prototypes belong on petrinaut-website host routes, not on `:4321`. - When `ChatAgent` leaves the app: `packages//` in libs; app remains the shell. +- Conditions 1 / 2 / 4 / 5 exist as batch jobs; condition 5's runner is broken on this app + (deleted elicitor imports). The useful drive loop is `createFlueClient` → `send` → `wait` + → `history()`. No TUI. Mission 3 restores that drive pattern, not the old SDCPN elicitor. ## Out of scope diff --git a/libs/@hashintel/brunch-agent/README.md b/libs/@hashintel/brunch-agent/README.md index 36d5366912e..f1c7d920c26 100644 --- a/libs/@hashintel/brunch-agent/README.md +++ b/libs/@hashintel/brunch-agent/README.md @@ -4,8 +4,9 @@ Brunch is the stateful elicitation harness and package family at `libs/@hashinte - [`AGENTS.md`](./AGENTS.md) is the agent charter. - [`MISSION.md`](./MISSION.md) is the current objective and stop conditions. - [`MISSION.next.md`](./MISSION.next.md) is the scratchpad for later concerns (longer horizon than - one mission; not execution authority). Closed missions live under + [`MISSION.next.md`](./MISSION.next.md) is the draft of upcoming missions and the record of + successor concerns (longer horizon than one mission; not execution authority). Closed missions + live under [`docs/mission-archive/`](./docs/mission-archive/). - [`CONTEXT.md`](./CONTEXT.md) defines the domain language. - [`docs/specs/`](./docs/specs/) and [`docs/adr/`](./docs/adr/) record the harness contract and diff --git a/libs/@hashintel/brunch-agent/docs/agents/git-workflow.md b/libs/@hashintel/brunch-agent/docs/agents/git-workflow.md index 8526898d18e..341af35d866 100644 --- a/libs/@hashintel/brunch-agent/docs/agents/git-workflow.md +++ b/libs/@hashintel/brunch-agent/docs/agents/git-workflow.md @@ -36,10 +36,10 @@ changes to make a stack operation proceed. ## Lifecycle -1. State the mission in `MISSION.md`. Collect successor concerns in `MISSION.next.md` without - declaring the next mission's focus or changing execution authority. On acceptance, archive the - closed mission under `docs/mission-archive/` and cut a focused `MISSION.md` from the scratchpad, - per `AGENTS.md`. +1. State the mission in `MISSION.md`. Record successor concerns in `MISSION.next.md` at + conversational fidelity, without declaring the next mission's focus or changing execution + authority. On acceptance, archive the closed mission under `docs/mission-archive/` and cut a + focused `MISSION.md` from one cluster, per `AGENTS.md`. 2. After explicit approval, create its Linear issue in the `brunch-agent` project and assign the accountable human. 3. Create the Graphite branch from the intended parent, or explicitly link a pre-existing branch. diff --git a/libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md b/libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md new file mode 100644 index 00000000000..9bd67f84843 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md @@ -0,0 +1,668 @@ +# Kickoff (new session) + +Copy everything in this section into a new thread. Context in the originating session was high; do not continue that thread. + +## Task + +Re-analyze the transcript below, restore what `MISSION.next.md` dropped, and thicken the protocol for how that file is maintained. + +Work in `libs/@hashintel/brunch-agent/`. HASH root guidance still wins. Live execution authority remains [`MISSION.md`](../../MISSION.md). Do not implement a successor mission from the scratchpad. + +### 1. Restore `MISSION.next.md` + +Read this whole transcript (not only the headings). Compare it to the current [`MISSION.next.md`](../../MISSION.next.md). Put back ideas, observations, questions, and design hypotheses that were compressed or dropped. + +A known example of loss (not the only one — hunt): the **observer agent as sweep mechanism**. The live file flattened this to “token-threshold observer: arm after N tokens, fire on next turn settle.” The discussion also included: the observer *is* the sweep mechanism; calls are fire-and-forget, queued, retried on failure; cannot fold unless the queue is valid; the elicitor mostly follows tip/heuristic/situation/example guidance and does not consult the fold on ordinary turns; a periodic re-group every XX tokens lets the queue settle, fold, and see what is still needed; fold semantics as generic as possible; subagents for micro-cognitive tasks (decisioning and decomposition). Restore that class of detail everywhere it is missing, not only this example. + +Driver guidance for the file’s *job* (2026-08-28): + +- Treat `MISSION.next.md` as a **draft of upcoming missions**, not a bullet list of leftover topics. +- Tentative groupings may use multiple `#` headings (one cluster / likely future mission per heading). +- Whether every live-mission section (Imperative, Throughline, Proof, Constraints, Fog-line, Stop or reorient, plus Status/Deferred) belongs on every cluster is open: it may be too far; some sections may wait until a cluster is about to be cut. Decide that in protocol, then apply it consistently. +- Essential bar: the file is a representation of **everything we currently think we know** about what we can and should do next, **and** a comprehensive record of the ideas, observations, and questions already raised. Summarizing so that a hypothesis becomes a label is a defect. + +Do not promote the scratchpad wholesale. Do not keep two live missions. Do not delete archived missions. + +### 2. Update the maintenance protocol + +The current rule in [`AGENTS.md`](../../AGENTS.md) / [`CLAUDE.md`](../../CLAUDE.md) only says the scratchpad collects successor concerns and leftover items after a cut. That licensed a summary and lost design content. + +Write the new rule into those files (keep them in sync). Also touch [`docs/agents/git-workflow.md`](../agents/git-workflow.md) and the context-root [`README.md`](../../README.md) if they describe the scratchpad. The rule must tell agents: + +- what the file is for (draft of upcoming work + comprehensive record); +- how to group (multiple h1s vs lighter clustering — pick one after judging the driver’s “maybe too far”); +- which mission-template sections are required vs deferred until cut; +- that compression that drops a hypothesis, an observation, a question, or a named mechanism is not allowed; +- that a cut into `MISSION.md` still leaves everything that did not make the cut in `MISSION.next.md` at the same fidelity. + +Suggest the same guideline for `.cursor/rules` only if a brunch-agent-specific rule file is the right home; prefer the existing `AGENTS.md` contract. + +### 3. Stop + +Do not start implementing Mission 3 or Host-trunk work. Do not mint Linear issues or branches unless the driver asks. Commit only if asked. + +## Pointers + +- This transcript: `libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md` +- Live mission: `MISSION.md` +- Scratchpad: `MISSION.next.md` +- Closed Mission 1: `docs/mission-archive/1-bare-petrinaut-flue-chat.md` +- Charter: `AGENTS.md` (mirrored `CLAUDE.md`) + +--- + +# Session transcript + +Brunch-agent mission close and next-mission cut. Cursor session `56b0adcc-bd0e-4ceb-a645-b36f549ed543`, 2026-08-27–28. User/assistant prose only; tool calls omitted. The last user turn is included even if it landed after the JSONL snapshot. + + +## User — Thursday, Aug 27, 2026, 5:16 PM (UTC+2) + +run `cd libs/@hashintel/brunch-agent/` and get oriented there, then we'll working on closing out the currrent mission and preparing the next one + +## Assistant + +I'll start by exploring `libs/@hashintel/brunch-agent/` and the current mission context so we're ready to close this one and plan the next. + +## Assistant + +Key mission files are on disk. I'll read those plus the package orientation docs so we have a shared picture of this mission and the next. + +## Assistant + +Mission 1 is marked nominally complete. Next I’ll read the proof, archive, git/PR state, and workflow docs so we know what’s left to close. + +## Assistant + +Oriented. `libs/@hashintel/brunch-agent` is the Brunch context root — charter, mission, and evidence live here; HASH root still owns Yarn/Turbo. The live app is `apps/brunch-agent`. + +**Mission 1** (`ln/fe-1522-mission-1`, Linear [FE-1522](https://linear.app/hash/issue/FE-1522)) is the live authority: prove the real Petrinaut demo can hold a durable, observable conversation with a plain Flue agent before any capture or elicitation. Status: **nominally complete, still under verification.** + +The throughline is in place: + +`Petrinaut panel → POST /api/chat → transport-aisdk → ChatAgent (ping + readPetrinautDoc) → Flue history` + +Working tree is clean. Five commits sit on `ln/fe-1521-machete-protocol`. No upstream, no GitHub PR. Linear is In Progress; the issue body still names the old branch `ln/mission-1`. + +**Still open for close** + +The proof file (`docs/evidence/proofs/implementations/fe-1522-petrinaut-flue-chat.md`) says the integration test covers the path, including ownership on `/agents/chat/:id`. What was **not** watched in-browser: panel `readPetrinautDoc`, pending vs completion, reload hydration, and the `transcript` CLI against a real conversation. Until that human run is recorded, `MISSION.md` stays in verification. + +**Close procedure** (from this context’s `AGENTS.md`) + +1. Accept Mission 1. +2. Archive `MISSION.md` → `docs/mission-archive/{n}-{slug}.md`. +3. Cut one focused next `MISSION.md` from the scratchpad. +4. Leave everything else in `MISSION.next.md`. +5. Update the PR (none exists yet) with proof results, fog-line answers, and carried flags. + +Do not promote the scratchpad wholesale. Linear writes need explicit approval. + +**Scratchpad clusters** (collected, not ranked; “mission 2” is a cluster name, not a cut): + +- First Brunch-owned sweep/capture (the Mission 1 deferral) +- Session identity / Petrinaut net lifecycle +- OTel on the brunch-agent process +- Voice stacked on KA’s composer `submitText` +- Keep the AI SDK adapter (do not rewrite the panel onto `@flue/react`) +- Two brains, same panel (stock modeller vs Brunch) +- Later Petrinaut read/write tools +- Restore the headless JS-API interview loop +- Move the chat agent into `libs` when it leaves the app + +Ready to close and cut the next mission whenever you are. Natural first moves: record the remaining human run, then decide the next focus before archiving. + +## User — Thursday, Aug 27, 2026, 5:18 PM (UTC+2) + +OK tell me more about the open items, I thought we covered tehm + +## Assistant + +I'll check the proof items against tests, evidence, and prior session notes — the remaining gaps may already be covered. + +## Assistant + +There's an earlier session that walked the proof items. I'll check what was actually witnessed versus what's still marked open. + +## Assistant + +You did cover them. I was reading a later review note that never saw that session. Mission 1’s eight proof items were witnessed this afternoon. What is still “open” is successor work on the scratchpad, plus some disk that never caught up. + +**Mission 1 proofs — done** + +| # | Claim | How it was witnessed | +|---|---|---| +| 1–4 | Message, pending vs done, `ping`, `readPetrinautDoc` | You, in the Petrinaut panel | +| 5 | Reload from Flue history | You confirmed; GET `/api/chat?id=` replaces the UI cache | +| 6 | Survive brunch restart | Process bounce; same SQLite snapshot; you confirmed the panel still had the chat | +| 7 | Transcript from Flue `history()` | Live pull of your conversation (`ping` + `readPetrinautDoc`); projector, not a second log | +| 8 | Voice dock named | Same `POST /api/chat` contract; checked against KA’s `submitText` path | + +Bonus `@flue/sdk` against the public conversation URL was also done. + +What did **not** get updated: `MISSION.md` still says “under verification,” and the later review file claims the human run is missing. That is bookkeeping, not unfinished proof. + +--- + +**Scratchpad — collected, not ranked** + +These are not leftover Mission 1 work. Several were spoken of as “mission 2”; that names a cluster, not a cut. + +**Capture / sweep (the original Mission 1 deferral).** First Brunch-owned behavior: sweep one settled transcript range into durable, source-linked capture, prove idempotent reapplication. Extraction quality, plugins, IR, completion, review/revise stay out until separately earned. Target-document association (elicitation case vs Petrinaut canvas net) sits here too. + +**Session identity / net lifecycle.** Working assumption: Petrinaut **net id** is the discriminator (one Flue conversation per net per principal). You flagged that net ids may not be stable. A later mission has to prove create / save / load is also the session lifecycle; if net ids regenerate or collide, drop the assumption. Compaction is Flue-default and unpinned (`compaction-vs-durable-history` / FE-1386). New session = mint another conversation id; resume = reload the same net. + +**OTel.** The Flue `instrument(...)` hook is already in `app.ts` but nothing exports. Prove Node SDK → HASH collector/Tempo, `gen_ai.conversation.id` = Flue instance id. `dispatch()` (the `/api/chat` path) does not propagate `traceparent`. Content capture stays off. You said “let’s prove this too, in mission 2.” + +**Voice, stacked on KA.** Mission 1 named the dock; joining it means stacking on `kostandin/h-6763-openai-canonical-speech` and resolving UUID-per-net vs `petrinaut-preview:${netId}`, stolen `/api/chat` vs configured, and `submitText` with no `brunch_ask`. Brunch still owns no audio. + +**Keep the adapter (locked).** Panel stays `useChat` / `onToolCall`. Do not rewrite onto `@flue/react`. `HarnessAgent` would be another substrate or a Flue replacement — left undecided. + +**Two brains, same panel (locked product rule, half-built).** Stock modeller and Brunch selectable without relaunch. Today the switch is `yarn dev` vs `yarn dev:brunch`. Open: how both backends share an origin, where the picker lives, whether you can switch mid-net. + +**Brunch Petrinaut read/write (locked direction, not scoped).** Second assistant, not a replacement modeller. Shared panel `onToolCall`, not absorbing the 46-tool set. Which tools, when: not decided. + +**Headless interview drive.** Conditions 1/2/4/5 exist as batch jobs; condition 5 is broken on this app (imports deleted elicitor). Useful drive loop is `createFlueClient` → `send` → `wait` → `history()`, restore when elicitation returns. No TUI. + +**Package layout.** Move `ChatAgent` into libs when it leaves the app; `binding-flue` stays a package. Exploded-net demos belong on petrinaut-website, not `:4321`. + +**Out of scope:** HASH embed talking to Brunch. + +--- + +Close work is: accept Mission 1 on disk, then cut one next `MISSION.md` from that pad. Nothing on the pad is already a mission. The natural tension is capture/sweep vs two-brains vs OTel vs net-lifecycle — you named more than one of those “mission 2.” + +## User — Thursday, Aug 27, 2026, 5:22 PM (UTC+2) + +/ds-grilling I copied some phrases from there as shorthand identifiers, and combined them with my own notes, and re-ordered them. This is the rough batching I see; if different groupings would afford faster progress (related concerns together) or parallel progress (independent/orthogonal) propose them; otherwise interview me to clarify/expand any parts that are unknown or cryptic: MISSION 2 + +- mechanically sweep one explicit settled transcript range into durable, source-linked capture and prove idempotent reapplication +- (system) prompt and skills (at least one test) in place +- prove that Petrinaut create / save / load of a net is also the session lifecycle +- A person using the Petrinaut demo should be able to choose the stock modeller or the Brunch Flue +agent without relaunching + +MISSION 3 + +- runbook style guidance for the agent, as the main iteration surface for prompting; no skills, IR document is basically a template to be filled out. one-shot at end, or periodic sweeps; LLM call to generate PN from it +- Petrinaut read/write tools +- prove the panel and transcript still reconstruct across a real compaction boundary +- Headless interview surfaces (agent-drive) + +MISSION 4 + +- petri net generation in FE, from __some kind of IR__. should be the minimal typing sophistication necessary: what maps to what. will help to figure out the target that the BE capture has to converge on. can also iterate on the PN tools and see if we can make many changes at once. the flue agent must be able to generate a PN using tools, given an IR + +MISSION 5 + +- flue agent capture improvement, converging on the typed IR that PN generation wants + - idea: observer-based sweeping. every X tokens is trigger; sweep on next turn settle. observer calls are FaF but in a queue, and must be retried if one fails. Can't fold unless queue is valid. elicitor follows tip/heuristic/situation/example based guidance, rather than consulting the fold, during most turns; but does a periodic "re-group" every XX tokens to let the sweep log queue settle and fold, and figure out what it still needs. semantics of the fold are as generic as we can possibly get away with + - idea: subagents, with micro-cognitive tasks to to help decisioning and decomposition. + +## Assistant + +I'll treat this as a design tree: first pull the facts behind the cryptic terms, then ask only the questions that are unblocked. + +## Assistant + +Explore agents aren't available here, so I'll pull the Flue/skills and sweep facts directly, then open the first grill round. + +## Assistant + +Your batching is a **serial elicitation ladder** (sweep → teaching → generate PN → improve capture). That ladder is real. What it hides is that two of the M2 bullets, and one of the M3 bullets, are a **host/identity track** that does not need capture at all. + +```text +Mission 1 chat (done) +├─ Host / identity +│ ├─ two brains, same panel +│ ├─ net create/save/load = session +│ └─ compaction reconstructs panel + transcript ← you put this in M3 +└─ Brunch elicitation + ├─ mechanical sweep + teaching stub ← your M2 + ├─ runbook iteration + R/W tools + headless ← your M3 + ├─ FE PN from IR ← M4 + └─ capture converges on that IR ← M5 +``` + +Those two trunks can proceed in parallel. Compaction is the same reconstruction family as session lifecycle, not a prompting concern. Headless drive is an eval door for the elicitation trunk, not a sibling of Petrinaut R/W. + +Facts already in hand (not questions): ChatAgent has no `useSkill`. Flue skills are progressive-disclosure `SKILL.md` catalogs (`activate_skill`). Brunch’s repertoire is a different, always-on teaching store in core, off this path. Sweep/capture types still exist in core and are unwired. Conversation ids are a localStorage map keyed by `netId`. OTel and voice are not in this list. + +--- + +❓ **Q1** - **Cut two parallel trunks, or keep your four-bullet M2?** + +Your M2 mixes a host product control (stock vs Brunch, no relaunch) and a session-identity proof (Petrinaut create/save/load) with the first Brunch-owned capture and a teaching stub. None of the first pair needs a sweep; the sweep does not need a picker. + +Options: + +- **A.** Keep your M2 as one mission: one human-visible “Brunch demo” slice. +- **B.** Split into two missions that may stack or run in parallel: + - **Host:** two brains + net lifecycle = session. Move **compaction** here from your M3 (same history reconstruction). + - **Brunch:** mechanical sweep + system prompt + at least one skill + a test. +- **C.** Serial but thinner: Host first (so the demo is choosable and nets are sessions), then Brunch sweep. Compaction still with Host. + +➡️ **B.** Fastest progress: Host can land without touching core sweep; Brunch can land without solving origin-sharing for two backends. Compaction in Host, not next to runbooks. + +--- + +❓ **Q2** - **What is “skills” in M2, given M3 says “no skills”?** + +Flue `useSkill` is progressive disclosure: catalog line always in the prompt, body loaded on `activate_skill`. Always-on text is `useInstruction` / the agent’s return string. Brunch **repertoire** is a third thing (core YAML, not on ChatAgent). + +M2 “prompt and skills (at least one test)” vs M3 “runbook-style guidance as the main iteration surface; **no skills**; IR is a template” only coheres if M2 mounts **one** Flue skill as a stub, and M3 means: do not grow a skill *catalog*; iterate the **runbook body** (which may live inside that one skill, or as instruction text). + +Options: + +- **A.** Flue `useSkill`: M2 proves mount + activate + a test; M3 iterates the runbook inside that skill (or replaces it) and does not add more skills. +- **B.** Always-on instruction only (`useInstruction` / agent return). “Skills” was shorthand for teaching. M3 runbook is that same file. No `useSkill` until much later (your M5 subagents). +- **C.** Re-admit Brunch repertoire/plugin keys onto this path in M2. + +➡️ **A.** One real Flue skill is the cheap proof that the teaching *mechanism* works; M3 then treats that file (runbook + IR template as supporting file) as the iteration surface. C reopens Mission 1’s “no plugins on this door” without a new strain. + +--- + +❓ **Q3** - **Is the Petrinaut net the elicitation target-document, or only the session key?** + +Earlier: target-document (capture store + session logs) ≠ Petrinaut canvas net. Your M2 “create/save/load of a net is also the session lifecycle” can be read as collapsing them. + +Options: + +- **A.** Net id is only the **conversation discriminator**. Capture in M2 hangs off the Flue conversation (or a store keyed by principal+net). A distinct Brunch target-document stays later. +- **B.** Collapse: one net **is** the target-document. Sweep writes into something owned by that net. No second document identity. +- **C.** Defer the join: M2 session proof is “same net ⇒ same Flue conversation after save/load”; sweep in M2 uses a throwaway store and does not bind to the net yet. + +➡️ **A.** Prove the working assumption without inventing a document model. B is a product ontology decision you have not earned; it would leak into HASH entity vs demo localStorage. C leaves sweep floating and you will splice later. + +--- + +❓ **Q4** - **Where did OTel and voice go?** + +You previously put OTel in “mission 2” and said you may stack on KA’s voice branch. This batching omits both. + +Options: + +- **A.** Parked past M5. Elicitation ladder is the numbered missions. Voice joins when KA’s branch is the parent; OTel is opportunistic, not a mission. +- **B.** OTel is a thin parallel on the Host trunk (process already has `instrument(...)`, nothing exports). Voice is not a mission; stacking is a git parent choice. +- **C.** Put OTel back in the first Brunch or Host mission as a proof bullet. + +➡️ **B.** Voice is a parent-branch decision, not a mission. OTel is small and independent; do it on Host if that trunk is in flight, do not let it sequence the ladder. Not C: it is not what M2 is for. + +--- + +Answer Q1–Q4. Next round: M3 IR-as-template vs core IR, what the M2 test actually asserts, and whether Petrinaut R/W belongs with runbooks or with M4. + +## User — Thursday, Aug 27, 2026, 5:28 PM (UTC+2) + +Your recommended answers make sense. I accept all of those. Regarding the last one yes there was a final piece, which was sort of a bucket I stuck at the end of my list : + +LATER + +- observability, evaluation, tracing, etc. etc. +- viewable demos in herdr panes, just using the json streaming from flue server? how does an LLM drive, in this case? it is getting the JSON response, or does it have to poll and read from PTY? +- AI SDK 7 `HarnessAgent` question + +I will perhaps try to solve it as a parallel concern, maybe running alongside one of the others since it's pretty independent of everything else on this list. I am still trying to think of what might be effective there. I'm honestly a little dissatisfied that we don't yet have a solution for a way for me to visually observe simulated conversations. I wish we could figure that one out but it's not completely on the critical path + +## Assistant + +Those four are locked. I'll pull how Flue streams and how herdr panes can show a conversation, then ask only the questions that that unblocks. + +## Assistant + +Locked: two parallel trunks (Host / Brunch); one Flue skill as the teaching stub; net id is session key, not target-document; OTel/voice/eval sit in LATER or ride along. + +Your LATER bucket is the right home for observability, `HarnessAgent`, and “I want to watch sims.” Herdr panes are PTYs, not browsers. The drive path is already JSON (`createFlueClient` → `send` → `wait` → `history()`). PTY polling is the thing not to do. The missing piece is a **second observer** on the same conversation URL, not a new protocol. + +--- + +❓ **Q5** - **What does the Brunch-trunk sweep write, if there is no target-document yet?** + +Core already has envelope + `apply-sweep` + idempotency tests, unwired from ChatAgent. M2 still has to persist *something* source-linked. + +- **A.** Re-enter the capture store, keyed by principal+net (or Flue conversation id). Envelope + evidence spans; payload opaque. Prove apply twice → same identities. No plugin schema, no fold quality. +- **B.** Don’t touch core. Dump sweep JSON beside the conversation (file, or Flue `data-*`). Envelope later. +- **C.** Fill a markdown IR template in M2 (jump to your old M3 document-IR). + +➡️ **A.** That *is* the Mission 1 deferral. B is a second store you’ll delete. C mixes teaching IR with capture before the mechanism exists. + +--- + +❓ **Q6** - **What is the Brunch-trunk proof test?** + +M2 needs “prompt + skills (at least one test)” and idempotent sweep. + +- **A.** Two tests: skill activation appears in Flue history; sweep-twice identity. +- **B.** One production-path test: a short settled range, `activate_skill` happened, sweep applied twice to the same captures. Extraction quality not asserted. +- **C.** Sweep only. Mounting the skill is enough; no activation proof. + +➡️ **B.** Same style as Mission 1: one real throughline. Activation without a sweep, or a sweep the model never used the skill for, would leave the teaching stub unproven. + +--- + +❓ **Q7** - **After compaction moved to Host, is the rest of your M3 still one mission?** + +Left: runbook as iteration surface; Petrinaut read/write tools; headless interview drive. + +- **A.** Keep them as one M3. +- **B.** M3 = runbook + restore the JS-API drive loop (iterate teaching without the GUI). Move Petrinaut R/W to M4 (that’s when the agent must write a net). +- **C.** M3 = R/W + headless. Runbook is just ongoing edits to the skill file, not a mission. + +➡️ **B.** Headless drive is how you iterate a runbook. Canvas mutation before an IR→PN map invites the agent to draw nets from vibes. R/W earns its keep in M4. + +--- + +❓ **Q8** - **What is “the IR” at M3 vs M4?** + +Your M3: template to fill, then an LLM call to make a PN. Your M4: minimal typing, what maps to what, FE generation, agent tools given an IR. + +- **A.** M3 IR is a markdown template (skill supporting file). M4 introduces the typed map (which fields become places/transitions/arcs). M5 is when sweep *emits* that type. +- **B.** M2/M3 already use core kind/slot tables; the template is only a projection of the fold. +- **C.** Skip the document template; typed IR starts in M3. + +➡️ **A.** Matches “runbook is the iteration surface; IR is a template.” M4 is where typing is earned, because FE generation is the consumer that can reject a vague shape. B puts the full plugin IR back on the door too early. + +--- + +❓ **Q9** - **Visual observation of simulated conversations (parallel, not numbered)** + +Driver: SDK JSON, not PTY. Human watch: same Flue conversation URL. `:4321` already follows a conversation (`useFlueAgent`) but only paints text. Herdr cannot embed that page; a pane can only open a URL or tail the transcript CLI. + +- **A.** Parallel spike, not a mission: one conversation id; script/agent drives via SDK; you watch `:4321` (render `dynamic-tool` / `data-*` / skill activation). Herdr at most opens that URL. `HarnessAgent` stays LATER and is not this surface. +- **B.** Wait for a herdr webview/JSON pane as the real product. +- **C.** Watch sims in the Petrinaut panel (AI SDK door), including a client-tool stand-in. + +➡️ **A.** That discharges “I want to see it” without sequencing the ladder. B blocks on herdr. C couples every sim to panel client tools you don’t need for elicitation rehearsal. + +--- + +Answer Q5–Q9. After that the remaining frontier is Host-trunk fog (picker, origin, mid-net switch) and M5’s observer-sweep / subagents — only if you want those pinned before cutting `MISSION.md`. + +## User — Thursday, Aug 27, 2026, 5:35 PM (UTC+2) + +Q5: A +Q6: yes, B - Although I will mention that I recently came across a Pi extension that was doing an interesting thing with a kind of running memory solution. In that case the trigger was not the agent calling a tool but something which was triggered by a certain number of tokens. Every time 10,000 tokens went by, the sweep would be activated and then triggered the next time a turn settled. It seemed like a good idea because anything that doesn't require an LLM call to decide when to trigger it is a latency saving +Q7: B. yes the PN tools can move to M4 +Q8: Correct. That's where I'm going with the runbook idea. I think the runbook and template solution is probably some system prompting, some skill prompting, and the actual runbook instructions (that is, the instructions on how to interpret the runbook) might be in the system prompt or they might be in the skill prompt. There is a template resource inside the skill prompt which actually provides the IR that is meant to be used. + +Maybe that's it. Maybe everything is bundled in the skill. It doesn't really matter that much. The point is basically those are the ingredients. I want to see how far I can get with an approach that's based on this and that pulls together everything we know from our research and other design modeling into the runbook to try to make that runbook as comprehensive as possible. Ultimately it's a system that doesn't rely on the extraction of typed claims at the capture stage +Q9: Yep that sounds good + +## Assistant + +Locked: capture store re-entered with opaque payloads; one throughline test (skill used, sweep twice); M3 is runbook + headless drive; R/W and canvas tools wait for M4; M3 IR is a template in the skill; types are earned by FE generation; watch sims by sharing a conversation URL. + +Also locked as M3 fog-line, not a design task now: system prompt vs skill body vs supporting file. The ingredients are those four; bundling them in the skill is allowed. The experiment is how far a comprehensive runbook goes **without typed claims at capture**. + +That last point plus the token-threshold trigger are the new strain. They collide with “M2 is a mechanical capture sweep” unless we say what each sweep is for. + +--- + +❓ **Q10** - **Which trunk is the next live `MISSION.md`?** + +The charter is one live mission. “Parallel trunks” means two stacked branches or two worktrees, not two files. + +- **A.** Host first: two brains, net = session, compaction. Sweep waits. Today `yarn dev:brunch` already works; this makes the demo choosable and the discriminator proven. +- **B.** Brunch sweep first: envelope + opaque payload, one skill, idempotent apply. Host stays on the scratchpad until cut. Store keys on the Flue conversation identity already in play; if net-lifecycle later fails, rekey. +- **C.** Explicit exception: two worktrees, two live missions, Host and Brunch at once. + +➡️ **B.** Your attention is the runbook experiment. Host is real but not what you need in order to sweep a range. Conversation identity already exists; net-lifecycle is a later proof of the same key, not a blocker. + +--- + +❓ **Q11** - **When does a sweep fire in the Brunch trunk?** + +The Pi extension’s trick: count tokens (no model call), arm, run on the next settled turn. That is *when*, not *what*. M2’s written proof is still “one explicit settled range.” Your old M5 was the observer loop. + +- **A.** M2: the test (or a harness fact) names the range. Token-threshold observer waits for the capture-improvement mission. +- **B.** M2 includes the observer (arm every N tokens, fire on settle). The test lowers N so a short chat crosses it. +- **C.** M2 is explicit-range; if the observer is a small hook on the same `apply-sweep`, it may land in the same mission as a bonus, not as completion. + +➡️ **A.** Idempotent reapplication is the strain. A token counter is a scheduler; putting it in M2 makes “did we pick the right N?” look like a proof failure. Keep the trigger for the mission that cares about latency and “don’t ask the model whether to sweep.” + +--- + +❓ **Q12** - **Is M2’s capture the IR template, or a separate ledger?** + +You want to go far without typed claims. M2 still re-enters the capture store. M3 still fills a markdown template and (eventually) makes a PN from it. + +- **A.** Two artifacts. Capture store = provenance ledger (envelopes, quotes, spans, opaque payload). Template = workpiece the runbook fills (skill resource / conversation document). M5 is when ledger entries grow types that match M4’s map. +- **B.** One artifact. Sweep’s opaque payload *is* the template update. Idempotency = applying twice doesn’t duplicate sections. No slot types. M4 types a map over that document; M5 may still not extract claims if the runbook path is winning. +- **C.** M3 ignores the capture store. Template lives only in the skill/conversation. M2’s store is a mechanism proof that sits idle until something typed exists. + +➡️ **A.** You accepted a real capture store in M2; C wastes it. B collapses workpiece into the ledger and makes “opaque payload” mean “the whole IR doc,” which is harder to cite and to re-apply. Ledger cites; template is what the runbook is for. + +--- + +❓ **Q13** - **Does M3 still generate a Petri net, with no canvas tools?** + +R/W moved to M4. Your M3 still said “one-shot at end, or periodic; LLM call to generate PN from the filled template.” + +- **A.** M3 stops at a filled template plus headless transcript. No net. +- **B.** M3 may one-shot a **desk** net (markdown/JSON file, not the canvas) so you can see whether the template contained enough. No Petrinaut tools. +- **C.** Wait: no PN until M4’s typed map and tools. + +➡️ **B.** That is the runbook experiment’s score: can a comprehensive template plus one generation call produce a recognizable net. If it can’t, you learn that before building FE typing. If it can, M4 has a target. Not on the canvas, so it doesn’t sneak R/W back in. + +--- + +Answer Q10–Q13. After that I can ask Host fog (picker / origin / mid-net) only if you want that trunk pinned before it is cut; otherwise the tree for the Brunch-first cut is almost empty. + +## User — Thursday, Aug 27, 2026, 5:44 PM (UTC+2) + +Q10 and Q11: yes to your recommendation +Q12: I'll explain this by saying that the sweep mechanism with the typed captures became too complex and required too much LLM judgment in order to use it and in order to correctly map each part of it. Those are my guesses. + +The bottom line is that the most recent test that we ran with this mechanism was incredibly slow. The headline catastrophic outcome was that question turns would take upwards of two minutes. The reintroduction of capture sweeping and, in parallel, the convergence on some type of IR design and prompting-based approach are actually two independent but converging paths aimed at progressively reintroducing aspects of the thinking and the design that led to the kind of overcomplicated state that we have now. + +I want to do those progressive reintegrations to see where the strains show up and see if we can clearly notice the threshold where the mechanism becomes untenable. Runbooks and templates are not yet actually connecting to the capture sweep mechanism. I'm just bringing them both in at the same time and considering whether they need to converge. If so, where and when should they converge and in what form? +Q13: That's a good question. Even if we don't give the agent any canvas tools, it could generate a Petri-Nut structure and even validate it using functions exported from Petri-Nut because there are functions for validating the structure. The idea of generating the PN from the filled template, I think we do need to do this actually because we do need to do it even in M3. We're also trying to evaluate how good the IR design is and get a Petri-Nut. Even if we get one as JSON and then I have to load it manually, like a manual load JSON into the Petri-Nut app in order to see it, that's still fine to do this manually. Maybe we can find a way to wire it through programmatically. + +The point is we don't need front-end Petri-Nut mutation tools, canvas mutation tools, in order to be able to do the step of trying to figure out whether the IR that we are creating through our run book and template-based approach is actually then going to be something that can translate in any reasonable way to a Petri-Nut. Obviously in that version, which is not lying on strictly typed captures, the IR is also not going to be super strictly typed. It can be well structured but not strictly typed and therefore it will require inference to generate the Petri-Nut + +## Assistant + +Q10/Q11 locked. Q12 is not A/B/C: two **independent** paths brought in together so you can watch for strain, with **no join designed**. Q13 locked as M3: structured-not-typed template → PN JSON (petrinaut validate, manual load OK); no canvas tools. + +That changes the Brunch trunk. M2’s sweep is a mechanism re-entry, not the IR’s source. M3’s runbook is a prompting experiment, not a consumer of captures. Convergence is a later question, not a hidden architecture. + +To cut the next `MISSION.md` (sweep first) these are still open: + +--- + +❓ **Q14** - **How thin is M2 extraction?** + +Condition 5’s failure mode was LLM judgment in the loop (mapping, typed claims, ~2 min question turns). “Mechanically sweep” can still smuggle that back if producing a proposal is a model call. + +- **A.** No extraction model. Stub: e.g. one envelope per user utterance, quote = that text, payload `{}`. Prove store, spans, idempotent re-apply. The interviewer does not decide to sweep; a test/harness names the range (Q11). +- **B.** A **separate** cheap extraction call (not the interviewer) that emits quotes/opaque blobs only — no slot types, no mapping to kinds. +- **C.** Re-enter the old plugin proposal catalog (`statement-noted`, SDCPN slots, …). + +➡️ **A.** M2 is “does the pipe still work.” A second LLM is the first strain you already observed; putting it in the proof makes latency look like a product regression. B/C belong on the reintegration path *after* the pipe is green, when you are trying to notice the untenable threshold. + +--- + +❓ **Q15** - **Does the interviewer call a sweep tool?** + +- **A.** No. Sweep is harness-side on an explicit settled range. No `sweep` tool, no model choice of when/what. +- **B.** A tool exists but the M2 proof never requires the model to call it (test invokes apply directly). +- **C.** The skill teaches the model to call sweep. That’s part of the throughline. + +➡️ **A.** A tool is an LLM decision about *when*. That contradicts Q11 and reintroduces the latency you are trying to keep off this path. Binding can still *run* apply-sweep; the model is not the scheduler. + +--- + +❓ **Q16** - **How much teaching is in M2’s one skill?** + +M2 still includes prompt + one Flue skill + a test. M3 is the comprehensive runbook/template experiment. + +- **A.** Stub skill: short “use when…” + enough body that `activate_skill` shows in history. Full research dump waits for M3. +- **B.** M2 already ships the first real runbook/template (M3 then only iterates it). +- **C.** M2 skill is empty catalog; teaching is `useInstruction` only. Skill activation is not in the proof. + +➡️ **A.** Two experiments, two missions. A comprehensive runbook in M2 makes a failed elicitation look like a failed sweep. C drops the skill-mechanism proof you wanted. + +--- + +❓ **Q17** - **When does M2 stop and reorient?** + +The point of progressive reintegration is to *see* the threshold. M2 needs a stop line so “a bit of judgment leaked in” doesn’t become the old kernel. + +- **A.** Stop if producing captures requires a model call, if a sweep tool appears on the interviewer, if plugins/kinds/slots/fold re-enter, if the runbook/template is wired to the store, or if a turn on this path is in condition-5 territory (order-of-minutes for an ordinary question). Opaque envelope + harness apply only. +- **B.** Softer: allow a hidden extraction call if it stays under some latency budget. +- **C.** No latency stop; only architectural stop (no types, no join with the template). + +➡️ **A.** You already have the catastrophic baseline. M2’s job is a pipe that cannot recreate it. Latency budget (B) invites bargaining. The join with runbooks is M3+ and explicit. + +--- + +Answer Q14–Q17. If those land, the Brunch-first mission contract is specified enough to read back as a tree and ask whether we have a shared understanding — still no `MISSION.md` until you say so. Host picker/origin stays unasked until that trunk is cut. M3 PN-from-template details go on the scratchpad, not this mission. + +## User — Thursday, Aug 27, 2026, 5:46 PM (UTC+2) + +Your recommended answers are all correct for these ones + +## Assistant + +All of Q14–Q17 are locked. For cutting the next mission, the frontier is empty. Remaining Host details (picker, origin, mid-net switch) stay fog for that trunk, not this one. + +**Do not treat this as a go-ahead to write `MISSION.md`.** Say if this matches what you meant. + +--- + +### Settled tree + +**Mission 1** — done (proof witnessed; disk still says “under verification”). + +**Two trunks, one live mission.** Next `MISSION.md` is the **Brunch sweep** trunk. Host stays on the scratchpad until cut. No second live mission file. + +```text +M1 chat (done) +├─ Host (later cut) +│ ├─ two brains, same panel +│ ├─ net create/save/load = session discriminator +│ └─ compaction reconstructs panel + transcript +└─ Brunch elicitation (next live mission = this sweep) + ├─ M2 pipe: harness sweep, stub skill, no join to IR + ├─ M3 runbook + template + headless drive + off-canvas PN + ├─ M4 typed map + Petrinaut R/W tools + └─ M5 capture improvement (observer trigger, maybe types) +LATER / parallel + ├─ OTel, eval, tracing + ├─ watch sims: SDK drive + :4321 observer (same conversation URL) + └─ HarnessAgent (undecided) +``` + +**M2 — first Brunch-owned behavior (next cut)** +Re-enter the capture store, keyed by existing Flue conversation identity. Envelope + evidence spans; payload `{}`. One envelope per user utterance is enough. Harness names an explicit settled range and `apply-sweep`; the model does not call a sweep tool and does not decide when. No extraction LLM. One Flue skill: stub, only to prove `activate_skill`. One production-path test: skill used, sweep twice, same identities. +**Stop** if a model call is required to produce captures, a sweep tool appears on the interviewer, kinds/slots/fold/plugins re-enter, the runbook/template is wired to the store, or ordinary turns return to condition-5 latency (minutes). + +**M3** — independent prompting path, **not** a consumer of M2 captures. Comprehensive runbook + IR template (skill/supporting file/system prompt — placement is fog). Headless JS-API drive. Generate a Petri net from the filled template (JSON, petrinaut validate, manual load OK). Structured, not strictly typed; generation uses inference. No canvas mutation tools. +**Sweep** means capture-store apply. Template fill is not a sweep. + +**Convergence** of capture and runbook/IR is an open later question: whether, where, when, in what form. Progressive reintegration is how you find the untenable threshold. Do not design the join now. + +**M4** — FE: minimal typing (what maps to what); agent read/write tools; generate on canvas from an IR. +**M5** — observer (token threshold → next settle), capture quality, maybe types; subagents still undecided. +**Host** — two brains, net = session, compaction. Voice = git parent on KA, not a mission. + +--- + +If this is the shared understanding, next is close-out on disk: archive Mission 1, cut this M2 into `MISSION.md`, leave Host/M3+ in `MISSION.next.md`. That is a separate go. + +## User — Thursday, Aug 27, 2026, 5:49 PM (UTC+2) + +All that stuff is a go. The format for the mission file is already there in the current one of course (Is it documented anywhere or was it invented out of thin air? Is it just meant to be its own documentation? ); anyway I felt it was fairly successful on this mission run, so we should use it again. I would also suggest that the mission.next file adopt the clustering and ordering that we've identified, even if not the fully worked out verbose detail of the full mission file. + +## Assistant + +The six-section contract lives in this context’s `AGENTS.md` — we’ll keep that shape. Next I’ll archive Mission 1, cut Mission 2, and regroup `MISSION.next.md` to match the tree we locked. + +## Assistant + +The six-section contract is specified in `AGENTS.md` (and mirrored in `CLAUDE.md`); the live `MISSION.md` is the instance. I’ll archive Mission 1 with a close report, cut Mission 2 in that same shape, and regroup the scratchpad. + +## Assistant + +The format is specified, not improvised. `AGENTS.md` (mirrored in `CLAUDE.md`) requires those six sections in `MISSION.md` and in the branch/PR description: Imperative, Throughline, Proof, Constraints, Fog-line, Stop or reorient. The live file is the instance of that contract. Mission 1 also used **Status** and **Deferred**; those are not in the six, but they worked, so Mission 2 keeps them. Close reports belong on the PR; there is no PR yet, so the archive file carries that report. + +**On disk** + +- Mission 1 archived: `docs/mission-archive/1-bare-petrinaut-flue-chat.md` (charter + proof results, fog-line answers, carried flags). +- Live `MISSION.md` is **Mission 2 — mechanical capture sweep**. +- `MISSION.next.md` is clustered in the order we locked: Host trunk → elicitation ladder (runbook/PN, then typed map + R/W, then capture improvement) → later/parallel. Capture and runbook stay independent. +- The FE-1522 proof note now records the human run and points at the archive. + +Nothing committed. No Linear write. Mission 2 on this branch is a charter change on FE-1522’s worktree; a new issue/branch for the sweep is a separate, approval-gated step. + +## User — Thursday, Aug 27, 2026, 5:52 PM (UTC+2) + +Please commit all the open changes and now let's mint a linear issue to represent mission two + +## Assistant + +I'll commit the open files, then create the Mission 2 Linear issue using the brunch tracker rules. + +## Assistant + +Commit landed. Nearby capture issues are Done or the old harness plan — I’ll mint a new issue related to FE-1522, not reuse those. + +## Assistant + +Commit is on `ln/fe-1522-mission-1`: + +`4e4f19288d` — Archive Mission 1 and cut the mechanical capture-sweep mission. + +**Linear:** [FE-1524](https://linear.app/hash/issue/FE-1524/prove-idempotent-capture-sweep-on-the-live-flue-chat-path) — *Prove idempotent capture sweep on the live Flue chat path* + +- Team `FE`, project `brunch-agent`, assignee ln, state Triage +- Related to FE-1522 (and Linear also linked FE-1392, FE-1419, FE-1503 from the body URLs) +- Did not reuse those Done/plan issues; they stay history + +FE-1522 is still In Progress. I did not close it or create a Graphite branch for FE-1524. Next, if you want the one-issue-one-branch rule: `gt create ln/fe-1524-…` from this parent (or after FE-1522 lands). + +## User — Friday, Aug 28, 2026, 10:39 AM (UTC+2) + +I think the guidance protocol for how to maintain the mission.next document is too thin and undisciplined. I'm disappointed to see that, despite the level of detail in which we talked about things in this discussion, the mission.next document does not capture, for example, the idea about an observer agent acting as the sweep mechanism. Many other details have been lost I think + +You have a function for exporting a markdown transcript of this entire session ? + +## Assistant + +You're right that `MISSION.next.md` was compressed past usefulness. I'll check whether this session can be exported as markdown, then we can put the lost detail back. + +## Assistant + +No first-class export. Cursor keeps this chat as JSONL (`agent-transcripts/56b0adcc-…jsonl`). I can turn the user/assistant text into markdown; there is no session-export tool, and tool-call noise would be stripped unless you want it. + +You are right about `MISSION.next.md`. The charter only says “collect successor concerns” and “leave what did not make the cut.” That licenses a summary. It does not say preserve hypotheses at conversational fidelity, which is how the observer design got flattened. + +What is on disk now is one compressed bullet: + +> Token-threshold observer: arm after N tokens, fire on next turn settle. + +What you actually said, and what is not there: + +- An **observer agent** is the sweep mechanism, not a harness counter with a later maybe. +- Calls are fire-and-forget, **queued**, **retried on failure**. +- **Cannot fold unless the queue is valid.** +- The elicitor mostly follows tip/heuristic/situation/example guidance and **does not consult the fold** on ordinary turns. +- A periodic **re-group** every XX tokens lets the queue settle, fold, and see what is still needed. +- Fold semantics as generic as you can get away with. +- Subagents for micro-cognitive tasks (decisioning and decomposition). + +That is a design hypothesis, not a cluster label. Same failure mode as `dev-handoff` warns about: summarizing instead of keeping the structure. + +I can write a readable markdown of this session (this thread from yesterday’s orientation through FE-1524), then restore those hypotheses into `MISSION.next.md` and tighten the scratchpad rule in `AGENTS.md` so later cuts cannot drop them. Say where you want the transcript (repo path vs `/tmp`) and I will do that. + +## User — Friday, Aug 28, 2026, 10:44 AM (UTC+2) + +Put the transcript in to `docs/inbox/` for now, And I think because this session already has quite a high context level, it would be good to include a kickoff prompt in that transcript precisely to do what we're talking about doing right now, which is to re-analyze the transcript for the missed details and then to update the protocols around the maintenance of the Mission.next file + +FTR: + +My suggestion for how to maintain the mission.next file is to essentially treat it as a draft for upcoming missions, up to and including maybe all of the sections and structures that we apply to the main mission file. That is I would simply use multiple h1 headings within the mission.next file in order to essentially maintain tentative groupings and sectionings of material. Maybe that is extending a bit too far. Maybe some of the sections we apply to the full mission file template don't really need to be applied until we are about to cut the mission. In any case my essential guidance would be to maintain the file as a representation of everything that we currently think we know about what we can and should do next, as well as a comprehensive record of all the ideas, observations, and questions that we have brought up + +## Assistant + +I'll convert this session to markdown in `docs/inbox/`, with a kickoff prompt at the top for a fresh thread to restore missed detail and tighten the `MISSION.next.md` protocol. diff --git a/libs/@hashintel/brunch-agent/docs/mission-archive/README.md b/libs/@hashintel/brunch-agent/docs/mission-archive/README.md index 58830f56096..abdf8c67d2f 100644 --- a/libs/@hashintel/brunch-agent/docs/mission-archive/README.md +++ b/libs/@hashintel/brunch-agent/docs/mission-archive/README.md @@ -1,7 +1,8 @@ # Closed missions Accepted `MISSION.md` files, moved here on close. Evidence of what was proven, not execution -authority. The scratchpad and cut rule live in the context-root [`AGENTS.md`](../../AGENTS.md). +authority. The next-concerns draft and cut rule live in the context-root +[`AGENTS.md`](../../AGENTS.md). - [`1-bare-petrinaut-flue-chat.md`](1-bare-petrinaut-flue-chat.md) — Mission 1, accepted 2026-08-27. From fcb46f46f33047a8dd396638f989b066e0f1ab0a Mon Sep 17 00:00:00 2001 From: Lu Nelson Date: Fri, 28 Aug 2026 12:36:11 +0200 Subject: [PATCH 02/22] housekeeping and new inbox sources Signed-off-by: Lu Nelson --- libs/@hashintel/brunch-agent/AGENTS.md | 41 +- .../brunch-agent/docs/agents/git-workflow.md | 10 +- .../2026-08-27-mission-close-and-next.md | 668 -- ...ed AI \342\200\223 Final Exam (Sketch).md" | 378 + .../amp-session-reviewing-architecture.md | 6996 +++++++++++++++++ .../docs/inbox/claude-dafny-lean.md | 757 ++ ...iting-and-constructing-processes-to-PNs.md | 118 + .../brunch-agent/docs/inbox/jetty-runbooks.md | 73 + .../docs/inbox/jetty-writing-runbooks.md | 73 + ...g-design-rationale-2026-04-18T12-57-01Z.md | 331 + .../inbox/pplx-agent-skill-rule-loading.md | 173 + .../inbox/pplx-single-global-agents-file.md | 80 + ...gases-1-pn-consumption-trigger-layout.json | 0 .../gases-1-pn-layout.json | 0 .../gases-2-spn-layout.json | 0 .../gases-3-cpn-layout.json | 0 .../gases-4-dcpn-layout.json | 0 .../semiconductor-fab-drift-layout.json | 0 ...k-fleet-predictive-maintenance-layout.json | 0 .../reference/architecture/flue-routing.md | 40 +- 20 files changed, 9032 insertions(+), 706 deletions(-) delete mode 100644 libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md create mode 100644 "libs/@hashintel/brunch-agent/docs/inbox/[shared] Safeguarded AI \342\200\223 Final Exam (Sketch).md" create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/amp-session-reviewing-architecture.md create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/claude-dafny-lean.md create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/eliciting-and-constructing-processes-to-PNs.md create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/jetty-runbooks.md create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/jetty-writing-runbooks.md create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/kleppmanns-geolog-design-rationale-2026-04-18T12-57-01Z.md create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/pplx-agent-skill-rule-loading.md create mode 100644 libs/@hashintel/brunch-agent/docs/inbox/pplx-single-global-agents-file.md rename libs/@hashintel/brunch-agent/docs/inbox/{SDCPNs => sdcpn-examples-to-validate}/gases-1-pn-consumption-trigger-layout.json (100%) rename libs/@hashintel/brunch-agent/docs/inbox/{SDCPNs => sdcpn-examples-to-validate}/gases-1-pn-layout.json (100%) rename libs/@hashintel/brunch-agent/docs/inbox/{SDCPNs => sdcpn-examples-to-validate}/gases-2-spn-layout.json (100%) rename libs/@hashintel/brunch-agent/docs/inbox/{SDCPNs => sdcpn-examples-to-validate}/gases-3-cpn-layout.json (100%) rename libs/@hashintel/brunch-agent/docs/inbox/{SDCPNs => sdcpn-examples-to-validate}/gases-4-dcpn-layout.json (100%) rename libs/@hashintel/brunch-agent/docs/inbox/{SDCPNs => sdcpn-examples-to-validate}/semiconductor-fab-drift-layout.json (100%) rename libs/@hashintel/brunch-agent/docs/inbox/{SDCPNs => sdcpn-examples-to-validate}/truck-fleet-predictive-maintenance-layout.json (100%) diff --git a/libs/@hashintel/brunch-agent/AGENTS.md b/libs/@hashintel/brunch-agent/AGENTS.md index 3572274f6cf..6331891ed94 100644 --- a/libs/@hashintel/brunch-agent/AGENTS.md +++ b/libs/@hashintel/brunch-agent/AGENTS.md @@ -39,24 +39,37 @@ next-concerns draft below. Running the path may lengthen this list; that is calibration, not regression. - **Stop or reorient** — evidence that invalidates or changes the route. +The six sections are the contract. Missions have also carried two additions that earned their +keep: a short **Status** header (live / accepted) above the contract, and a closing **Deferred** +section pointing at the draft. Keep both on future missions. + ### One live mission, next-concerns draft [`MISSION.md`](MISSION.md) is the only execution authority. Agents and humans implement against it. -[`MISSION.next.md`](MISSION.next.md) is the draft of upcoming work and the comprehensive record of -ideas, observations, questions, and named mechanisms already raised. It may hold a longer horizon -than a single mission. It is not a mission: do not implement it, do not treat it as a second -concurrent mission, and do not declare its focus until a cluster is cut. - -Keep every hypothesis, observation, question, and named mechanism at conversational fidelity. A -heading plus a one-line label is not a record of a design. Rejected alternatives and the reason -they lost belong next to the locked choice. Ungrilled fog stays marked unasked. - -Group likely future missions as multiple `#` headings (one cluster per heading). Spikes that are -not missions, and standing lock / out-of-scope decisions, get their own headings — they are not -fake missions. Do not pre-fill Imperative, Throughline, Proof, or Status on a cluster; those -sections are the cut into `MISSION.md`. Record Constraints, Fog-line, and Stop or reorient on a -cluster only when the conversation already earned them. +[`MISSION.next.md`](MISSION.next.md) is the self-contained canonical capture repository for +upcoming work: the draft missions and the comprehensive record of ideas, observations, questions, +and named mechanisms already raised. It may hold a longer horizon than a single mission. It is not +a mission: do not implement it, do not treat it as a second concurrent mission, and do not declare +its focus until a cluster is cut. + +Update the draft during planning, design, grilling, or other mission elicitation while the context +is active. Keep every hypothesis, observation, question, and named mechanism at conversational +fidelity. A heading plus a one-line label is not a record of a design. Rejected alternatives and +the reason they lost belong next to the locked choice. Ungrilled fog stays marked unasked. The +draft must stand on its own; do not rely on or link to a transcript as a substitute for capturing +that content here. + +When regrouping or cutting, compare the draft before and after. Every item must either move into +the live mission or remain in the draft at the same fidelity. Once an elicitation session is over, +the draft — not an external transcript — is the source for future cuts. + +Group plausible future missions as ordered, numbered `# Mission N — …` headings. Spikes that are +not missions, standing lock / out-of-scope decisions, and a live mission's leftover / Deferred +items get their own unnumbered headings — they are not fake missions. Do not pre-fill Imperative, +Throughline, Proof, or Status on a cluster; those sections are the cut into `MISSION.md`. Record +Constraints, Fog-line, and Stop or reorient on a cluster only when the conversation already earned +them. A current mission's **Deferred** items belong in that draft as well. Do not silently drop or supersede them when adding other concerns. diff --git a/libs/@hashintel/brunch-agent/docs/agents/git-workflow.md b/libs/@hashintel/brunch-agent/docs/agents/git-workflow.md index 341af35d866..ff4d9c5c742 100644 --- a/libs/@hashintel/brunch-agent/docs/agents/git-workflow.md +++ b/libs/@hashintel/brunch-agent/docs/agents/git-workflow.md @@ -36,10 +36,12 @@ changes to make a stack operation proceed. ## Lifecycle -1. State the mission in `MISSION.md`. Record successor concerns in `MISSION.next.md` at - conversational fidelity, without declaring the next mission's focus or changing execution - authority. On acceptance, archive the closed mission under `docs/mission-archive/` and cut a - focused `MISSION.md` from one cluster, per `AGENTS.md`. +1. State the mission in `MISSION.md`. While planning context is active, capture successor concerns + in `MISSION.next.md` at conversational fidelity without changing execution authority. That draft + is the self-contained canonical source for future cuts; do not substitute an external transcript. + On acceptance, archive the closed mission, cut a focused `MISSION.md` from the next numbered + cluster, and compare the draft before and after so uncopied material stays at the same fidelity, + per `AGENTS.md`. 2. After explicit approval, create its Linear issue in the `brunch-agent` project and assign the accountable human. 3. Create the Graphite branch from the intended parent, or explicitly link a pre-existing branch. diff --git a/libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md b/libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md deleted file mode 100644 index 9bd67f84843..00000000000 --- a/libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md +++ /dev/null @@ -1,668 +0,0 @@ -# Kickoff (new session) - -Copy everything in this section into a new thread. Context in the originating session was high; do not continue that thread. - -## Task - -Re-analyze the transcript below, restore what `MISSION.next.md` dropped, and thicken the protocol for how that file is maintained. - -Work in `libs/@hashintel/brunch-agent/`. HASH root guidance still wins. Live execution authority remains [`MISSION.md`](../../MISSION.md). Do not implement a successor mission from the scratchpad. - -### 1. Restore `MISSION.next.md` - -Read this whole transcript (not only the headings). Compare it to the current [`MISSION.next.md`](../../MISSION.next.md). Put back ideas, observations, questions, and design hypotheses that were compressed or dropped. - -A known example of loss (not the only one — hunt): the **observer agent as sweep mechanism**. The live file flattened this to “token-threshold observer: arm after N tokens, fire on next turn settle.” The discussion also included: the observer *is* the sweep mechanism; calls are fire-and-forget, queued, retried on failure; cannot fold unless the queue is valid; the elicitor mostly follows tip/heuristic/situation/example guidance and does not consult the fold on ordinary turns; a periodic re-group every XX tokens lets the queue settle, fold, and see what is still needed; fold semantics as generic as possible; subagents for micro-cognitive tasks (decisioning and decomposition). Restore that class of detail everywhere it is missing, not only this example. - -Driver guidance for the file’s *job* (2026-08-28): - -- Treat `MISSION.next.md` as a **draft of upcoming missions**, not a bullet list of leftover topics. -- Tentative groupings may use multiple `#` headings (one cluster / likely future mission per heading). -- Whether every live-mission section (Imperative, Throughline, Proof, Constraints, Fog-line, Stop or reorient, plus Status/Deferred) belongs on every cluster is open: it may be too far; some sections may wait until a cluster is about to be cut. Decide that in protocol, then apply it consistently. -- Essential bar: the file is a representation of **everything we currently think we know** about what we can and should do next, **and** a comprehensive record of the ideas, observations, and questions already raised. Summarizing so that a hypothesis becomes a label is a defect. - -Do not promote the scratchpad wholesale. Do not keep two live missions. Do not delete archived missions. - -### 2. Update the maintenance protocol - -The current rule in [`AGENTS.md`](../../AGENTS.md) / [`CLAUDE.md`](../../CLAUDE.md) only says the scratchpad collects successor concerns and leftover items after a cut. That licensed a summary and lost design content. - -Write the new rule into those files (keep them in sync). Also touch [`docs/agents/git-workflow.md`](../agents/git-workflow.md) and the context-root [`README.md`](../../README.md) if they describe the scratchpad. The rule must tell agents: - -- what the file is for (draft of upcoming work + comprehensive record); -- how to group (multiple h1s vs lighter clustering — pick one after judging the driver’s “maybe too far”); -- which mission-template sections are required vs deferred until cut; -- that compression that drops a hypothesis, an observation, a question, or a named mechanism is not allowed; -- that a cut into `MISSION.md` still leaves everything that did not make the cut in `MISSION.next.md` at the same fidelity. - -Suggest the same guideline for `.cursor/rules` only if a brunch-agent-specific rule file is the right home; prefer the existing `AGENTS.md` contract. - -### 3. Stop - -Do not start implementing Mission 3 or Host-trunk work. Do not mint Linear issues or branches unless the driver asks. Commit only if asked. - -## Pointers - -- This transcript: `libs/@hashintel/brunch-agent/docs/inbox/2026-08-27-mission-close-and-next.md` -- Live mission: `MISSION.md` -- Scratchpad: `MISSION.next.md` -- Closed Mission 1: `docs/mission-archive/1-bare-petrinaut-flue-chat.md` -- Charter: `AGENTS.md` (mirrored `CLAUDE.md`) - ---- - -# Session transcript - -Brunch-agent mission close and next-mission cut. Cursor session `56b0adcc-bd0e-4ceb-a645-b36f549ed543`, 2026-08-27–28. User/assistant prose only; tool calls omitted. The last user turn is included even if it landed after the JSONL snapshot. - - -## User — Thursday, Aug 27, 2026, 5:16 PM (UTC+2) - -run `cd libs/@hashintel/brunch-agent/` and get oriented there, then we'll working on closing out the currrent mission and preparing the next one - -## Assistant - -I'll start by exploring `libs/@hashintel/brunch-agent/` and the current mission context so we're ready to close this one and plan the next. - -## Assistant - -Key mission files are on disk. I'll read those plus the package orientation docs so we have a shared picture of this mission and the next. - -## Assistant - -Mission 1 is marked nominally complete. Next I’ll read the proof, archive, git/PR state, and workflow docs so we know what’s left to close. - -## Assistant - -Oriented. `libs/@hashintel/brunch-agent` is the Brunch context root — charter, mission, and evidence live here; HASH root still owns Yarn/Turbo. The live app is `apps/brunch-agent`. - -**Mission 1** (`ln/fe-1522-mission-1`, Linear [FE-1522](https://linear.app/hash/issue/FE-1522)) is the live authority: prove the real Petrinaut demo can hold a durable, observable conversation with a plain Flue agent before any capture or elicitation. Status: **nominally complete, still under verification.** - -The throughline is in place: - -`Petrinaut panel → POST /api/chat → transport-aisdk → ChatAgent (ping + readPetrinautDoc) → Flue history` - -Working tree is clean. Five commits sit on `ln/fe-1521-machete-protocol`. No upstream, no GitHub PR. Linear is In Progress; the issue body still names the old branch `ln/mission-1`. - -**Still open for close** - -The proof file (`docs/evidence/proofs/implementations/fe-1522-petrinaut-flue-chat.md`) says the integration test covers the path, including ownership on `/agents/chat/:id`. What was **not** watched in-browser: panel `readPetrinautDoc`, pending vs completion, reload hydration, and the `transcript` CLI against a real conversation. Until that human run is recorded, `MISSION.md` stays in verification. - -**Close procedure** (from this context’s `AGENTS.md`) - -1. Accept Mission 1. -2. Archive `MISSION.md` → `docs/mission-archive/{n}-{slug}.md`. -3. Cut one focused next `MISSION.md` from the scratchpad. -4. Leave everything else in `MISSION.next.md`. -5. Update the PR (none exists yet) with proof results, fog-line answers, and carried flags. - -Do not promote the scratchpad wholesale. Linear writes need explicit approval. - -**Scratchpad clusters** (collected, not ranked; “mission 2” is a cluster name, not a cut): - -- First Brunch-owned sweep/capture (the Mission 1 deferral) -- Session identity / Petrinaut net lifecycle -- OTel on the brunch-agent process -- Voice stacked on KA’s composer `submitText` -- Keep the AI SDK adapter (do not rewrite the panel onto `@flue/react`) -- Two brains, same panel (stock modeller vs Brunch) -- Later Petrinaut read/write tools -- Restore the headless JS-API interview loop -- Move the chat agent into `libs` when it leaves the app - -Ready to close and cut the next mission whenever you are. Natural first moves: record the remaining human run, then decide the next focus before archiving. - -## User — Thursday, Aug 27, 2026, 5:18 PM (UTC+2) - -OK tell me more about the open items, I thought we covered tehm - -## Assistant - -I'll check the proof items against tests, evidence, and prior session notes — the remaining gaps may already be covered. - -## Assistant - -There's an earlier session that walked the proof items. I'll check what was actually witnessed versus what's still marked open. - -## Assistant - -You did cover them. I was reading a later review note that never saw that session. Mission 1’s eight proof items were witnessed this afternoon. What is still “open” is successor work on the scratchpad, plus some disk that never caught up. - -**Mission 1 proofs — done** - -| # | Claim | How it was witnessed | -|---|---|---| -| 1–4 | Message, pending vs done, `ping`, `readPetrinautDoc` | You, in the Petrinaut panel | -| 5 | Reload from Flue history | You confirmed; GET `/api/chat?id=` replaces the UI cache | -| 6 | Survive brunch restart | Process bounce; same SQLite snapshot; you confirmed the panel still had the chat | -| 7 | Transcript from Flue `history()` | Live pull of your conversation (`ping` + `readPetrinautDoc`); projector, not a second log | -| 8 | Voice dock named | Same `POST /api/chat` contract; checked against KA’s `submitText` path | - -Bonus `@flue/sdk` against the public conversation URL was also done. - -What did **not** get updated: `MISSION.md` still says “under verification,” and the later review file claims the human run is missing. That is bookkeeping, not unfinished proof. - ---- - -**Scratchpad — collected, not ranked** - -These are not leftover Mission 1 work. Several were spoken of as “mission 2”; that names a cluster, not a cut. - -**Capture / sweep (the original Mission 1 deferral).** First Brunch-owned behavior: sweep one settled transcript range into durable, source-linked capture, prove idempotent reapplication. Extraction quality, plugins, IR, completion, review/revise stay out until separately earned. Target-document association (elicitation case vs Petrinaut canvas net) sits here too. - -**Session identity / net lifecycle.** Working assumption: Petrinaut **net id** is the discriminator (one Flue conversation per net per principal). You flagged that net ids may not be stable. A later mission has to prove create / save / load is also the session lifecycle; if net ids regenerate or collide, drop the assumption. Compaction is Flue-default and unpinned (`compaction-vs-durable-history` / FE-1386). New session = mint another conversation id; resume = reload the same net. - -**OTel.** The Flue `instrument(...)` hook is already in `app.ts` but nothing exports. Prove Node SDK → HASH collector/Tempo, `gen_ai.conversation.id` = Flue instance id. `dispatch()` (the `/api/chat` path) does not propagate `traceparent`. Content capture stays off. You said “let’s prove this too, in mission 2.” - -**Voice, stacked on KA.** Mission 1 named the dock; joining it means stacking on `kostandin/h-6763-openai-canonical-speech` and resolving UUID-per-net vs `petrinaut-preview:${netId}`, stolen `/api/chat` vs configured, and `submitText` with no `brunch_ask`. Brunch still owns no audio. - -**Keep the adapter (locked).** Panel stays `useChat` / `onToolCall`. Do not rewrite onto `@flue/react`. `HarnessAgent` would be another substrate or a Flue replacement — left undecided. - -**Two brains, same panel (locked product rule, half-built).** Stock modeller and Brunch selectable without relaunch. Today the switch is `yarn dev` vs `yarn dev:brunch`. Open: how both backends share an origin, where the picker lives, whether you can switch mid-net. - -**Brunch Petrinaut read/write (locked direction, not scoped).** Second assistant, not a replacement modeller. Shared panel `onToolCall`, not absorbing the 46-tool set. Which tools, when: not decided. - -**Headless interview drive.** Conditions 1/2/4/5 exist as batch jobs; condition 5 is broken on this app (imports deleted elicitor). Useful drive loop is `createFlueClient` → `send` → `wait` → `history()`, restore when elicitation returns. No TUI. - -**Package layout.** Move `ChatAgent` into libs when it leaves the app; `binding-flue` stays a package. Exploded-net demos belong on petrinaut-website, not `:4321`. - -**Out of scope:** HASH embed talking to Brunch. - ---- - -Close work is: accept Mission 1 on disk, then cut one next `MISSION.md` from that pad. Nothing on the pad is already a mission. The natural tension is capture/sweep vs two-brains vs OTel vs net-lifecycle — you named more than one of those “mission 2.” - -## User — Thursday, Aug 27, 2026, 5:22 PM (UTC+2) - -/ds-grilling I copied some phrases from there as shorthand identifiers, and combined them with my own notes, and re-ordered them. This is the rough batching I see; if different groupings would afford faster progress (related concerns together) or parallel progress (independent/orthogonal) propose them; otherwise interview me to clarify/expand any parts that are unknown or cryptic: MISSION 2 - -- mechanically sweep one explicit settled transcript range into durable, source-linked capture and prove idempotent reapplication -- (system) prompt and skills (at least one test) in place -- prove that Petrinaut create / save / load of a net is also the session lifecycle -- A person using the Petrinaut demo should be able to choose the stock modeller or the Brunch Flue -agent without relaunching - -MISSION 3 - -- runbook style guidance for the agent, as the main iteration surface for prompting; no skills, IR document is basically a template to be filled out. one-shot at end, or periodic sweeps; LLM call to generate PN from it -- Petrinaut read/write tools -- prove the panel and transcript still reconstruct across a real compaction boundary -- Headless interview surfaces (agent-drive) - -MISSION 4 - -- petri net generation in FE, from __some kind of IR__. should be the minimal typing sophistication necessary: what maps to what. will help to figure out the target that the BE capture has to converge on. can also iterate on the PN tools and see if we can make many changes at once. the flue agent must be able to generate a PN using tools, given an IR - -MISSION 5 - -- flue agent capture improvement, converging on the typed IR that PN generation wants - - idea: observer-based sweeping. every X tokens is trigger; sweep on next turn settle. observer calls are FaF but in a queue, and must be retried if one fails. Can't fold unless queue is valid. elicitor follows tip/heuristic/situation/example based guidance, rather than consulting the fold, during most turns; but does a periodic "re-group" every XX tokens to let the sweep log queue settle and fold, and figure out what it still needs. semantics of the fold are as generic as we can possibly get away with - - idea: subagents, with micro-cognitive tasks to to help decisioning and decomposition. - -## Assistant - -I'll treat this as a design tree: first pull the facts behind the cryptic terms, then ask only the questions that are unblocked. - -## Assistant - -Explore agents aren't available here, so I'll pull the Flue/skills and sweep facts directly, then open the first grill round. - -## Assistant - -Your batching is a **serial elicitation ladder** (sweep → teaching → generate PN → improve capture). That ladder is real. What it hides is that two of the M2 bullets, and one of the M3 bullets, are a **host/identity track** that does not need capture at all. - -```text -Mission 1 chat (done) -├─ Host / identity -│ ├─ two brains, same panel -│ ├─ net create/save/load = session -│ └─ compaction reconstructs panel + transcript ← you put this in M3 -└─ Brunch elicitation - ├─ mechanical sweep + teaching stub ← your M2 - ├─ runbook iteration + R/W tools + headless ← your M3 - ├─ FE PN from IR ← M4 - └─ capture converges on that IR ← M5 -``` - -Those two trunks can proceed in parallel. Compaction is the same reconstruction family as session lifecycle, not a prompting concern. Headless drive is an eval door for the elicitation trunk, not a sibling of Petrinaut R/W. - -Facts already in hand (not questions): ChatAgent has no `useSkill`. Flue skills are progressive-disclosure `SKILL.md` catalogs (`activate_skill`). Brunch’s repertoire is a different, always-on teaching store in core, off this path. Sweep/capture types still exist in core and are unwired. Conversation ids are a localStorage map keyed by `netId`. OTel and voice are not in this list. - ---- - -❓ **Q1** - **Cut two parallel trunks, or keep your four-bullet M2?** - -Your M2 mixes a host product control (stock vs Brunch, no relaunch) and a session-identity proof (Petrinaut create/save/load) with the first Brunch-owned capture and a teaching stub. None of the first pair needs a sweep; the sweep does not need a picker. - -Options: - -- **A.** Keep your M2 as one mission: one human-visible “Brunch demo” slice. -- **B.** Split into two missions that may stack or run in parallel: - - **Host:** two brains + net lifecycle = session. Move **compaction** here from your M3 (same history reconstruction). - - **Brunch:** mechanical sweep + system prompt + at least one skill + a test. -- **C.** Serial but thinner: Host first (so the demo is choosable and nets are sessions), then Brunch sweep. Compaction still with Host. - -➡️ **B.** Fastest progress: Host can land without touching core sweep; Brunch can land without solving origin-sharing for two backends. Compaction in Host, not next to runbooks. - ---- - -❓ **Q2** - **What is “skills” in M2, given M3 says “no skills”?** - -Flue `useSkill` is progressive disclosure: catalog line always in the prompt, body loaded on `activate_skill`. Always-on text is `useInstruction` / the agent’s return string. Brunch **repertoire** is a third thing (core YAML, not on ChatAgent). - -M2 “prompt and skills (at least one test)” vs M3 “runbook-style guidance as the main iteration surface; **no skills**; IR is a template” only coheres if M2 mounts **one** Flue skill as a stub, and M3 means: do not grow a skill *catalog*; iterate the **runbook body** (which may live inside that one skill, or as instruction text). - -Options: - -- **A.** Flue `useSkill`: M2 proves mount + activate + a test; M3 iterates the runbook inside that skill (or replaces it) and does not add more skills. -- **B.** Always-on instruction only (`useInstruction` / agent return). “Skills” was shorthand for teaching. M3 runbook is that same file. No `useSkill` until much later (your M5 subagents). -- **C.** Re-admit Brunch repertoire/plugin keys onto this path in M2. - -➡️ **A.** One real Flue skill is the cheap proof that the teaching *mechanism* works; M3 then treats that file (runbook + IR template as supporting file) as the iteration surface. C reopens Mission 1’s “no plugins on this door” without a new strain. - ---- - -❓ **Q3** - **Is the Petrinaut net the elicitation target-document, or only the session key?** - -Earlier: target-document (capture store + session logs) ≠ Petrinaut canvas net. Your M2 “create/save/load of a net is also the session lifecycle” can be read as collapsing them. - -Options: - -- **A.** Net id is only the **conversation discriminator**. Capture in M2 hangs off the Flue conversation (or a store keyed by principal+net). A distinct Brunch target-document stays later. -- **B.** Collapse: one net **is** the target-document. Sweep writes into something owned by that net. No second document identity. -- **C.** Defer the join: M2 session proof is “same net ⇒ same Flue conversation after save/load”; sweep in M2 uses a throwaway store and does not bind to the net yet. - -➡️ **A.** Prove the working assumption without inventing a document model. B is a product ontology decision you have not earned; it would leak into HASH entity vs demo localStorage. C leaves sweep floating and you will splice later. - ---- - -❓ **Q4** - **Where did OTel and voice go?** - -You previously put OTel in “mission 2” and said you may stack on KA’s voice branch. This batching omits both. - -Options: - -- **A.** Parked past M5. Elicitation ladder is the numbered missions. Voice joins when KA’s branch is the parent; OTel is opportunistic, not a mission. -- **B.** OTel is a thin parallel on the Host trunk (process already has `instrument(...)`, nothing exports). Voice is not a mission; stacking is a git parent choice. -- **C.** Put OTel back in the first Brunch or Host mission as a proof bullet. - -➡️ **B.** Voice is a parent-branch decision, not a mission. OTel is small and independent; do it on Host if that trunk is in flight, do not let it sequence the ladder. Not C: it is not what M2 is for. - ---- - -Answer Q1–Q4. Next round: M3 IR-as-template vs core IR, what the M2 test actually asserts, and whether Petrinaut R/W belongs with runbooks or with M4. - -## User — Thursday, Aug 27, 2026, 5:28 PM (UTC+2) - -Your recommended answers make sense. I accept all of those. Regarding the last one yes there was a final piece, which was sort of a bucket I stuck at the end of my list : - -LATER - -- observability, evaluation, tracing, etc. etc. -- viewable demos in herdr panes, just using the json streaming from flue server? how does an LLM drive, in this case? it is getting the JSON response, or does it have to poll and read from PTY? -- AI SDK 7 `HarnessAgent` question - -I will perhaps try to solve it as a parallel concern, maybe running alongside one of the others since it's pretty independent of everything else on this list. I am still trying to think of what might be effective there. I'm honestly a little dissatisfied that we don't yet have a solution for a way for me to visually observe simulated conversations. I wish we could figure that one out but it's not completely on the critical path - -## Assistant - -Those four are locked. I'll pull how Flue streams and how herdr panes can show a conversation, then ask only the questions that that unblocks. - -## Assistant - -Locked: two parallel trunks (Host / Brunch); one Flue skill as the teaching stub; net id is session key, not target-document; OTel/voice/eval sit in LATER or ride along. - -Your LATER bucket is the right home for observability, `HarnessAgent`, and “I want to watch sims.” Herdr panes are PTYs, not browsers. The drive path is already JSON (`createFlueClient` → `send` → `wait` → `history()`). PTY polling is the thing not to do. The missing piece is a **second observer** on the same conversation URL, not a new protocol. - ---- - -❓ **Q5** - **What does the Brunch-trunk sweep write, if there is no target-document yet?** - -Core already has envelope + `apply-sweep` + idempotency tests, unwired from ChatAgent. M2 still has to persist *something* source-linked. - -- **A.** Re-enter the capture store, keyed by principal+net (or Flue conversation id). Envelope + evidence spans; payload opaque. Prove apply twice → same identities. No plugin schema, no fold quality. -- **B.** Don’t touch core. Dump sweep JSON beside the conversation (file, or Flue `data-*`). Envelope later. -- **C.** Fill a markdown IR template in M2 (jump to your old M3 document-IR). - -➡️ **A.** That *is* the Mission 1 deferral. B is a second store you’ll delete. C mixes teaching IR with capture before the mechanism exists. - ---- - -❓ **Q6** - **What is the Brunch-trunk proof test?** - -M2 needs “prompt + skills (at least one test)” and idempotent sweep. - -- **A.** Two tests: skill activation appears in Flue history; sweep-twice identity. -- **B.** One production-path test: a short settled range, `activate_skill` happened, sweep applied twice to the same captures. Extraction quality not asserted. -- **C.** Sweep only. Mounting the skill is enough; no activation proof. - -➡️ **B.** Same style as Mission 1: one real throughline. Activation without a sweep, or a sweep the model never used the skill for, would leave the teaching stub unproven. - ---- - -❓ **Q7** - **After compaction moved to Host, is the rest of your M3 still one mission?** - -Left: runbook as iteration surface; Petrinaut read/write tools; headless interview drive. - -- **A.** Keep them as one M3. -- **B.** M3 = runbook + restore the JS-API drive loop (iterate teaching without the GUI). Move Petrinaut R/W to M4 (that’s when the agent must write a net). -- **C.** M3 = R/W + headless. Runbook is just ongoing edits to the skill file, not a mission. - -➡️ **B.** Headless drive is how you iterate a runbook. Canvas mutation before an IR→PN map invites the agent to draw nets from vibes. R/W earns its keep in M4. - ---- - -❓ **Q8** - **What is “the IR” at M3 vs M4?** - -Your M3: template to fill, then an LLM call to make a PN. Your M4: minimal typing, what maps to what, FE generation, agent tools given an IR. - -- **A.** M3 IR is a markdown template (skill supporting file). M4 introduces the typed map (which fields become places/transitions/arcs). M5 is when sweep *emits* that type. -- **B.** M2/M3 already use core kind/slot tables; the template is only a projection of the fold. -- **C.** Skip the document template; typed IR starts in M3. - -➡️ **A.** Matches “runbook is the iteration surface; IR is a template.” M4 is where typing is earned, because FE generation is the consumer that can reject a vague shape. B puts the full plugin IR back on the door too early. - ---- - -❓ **Q9** - **Visual observation of simulated conversations (parallel, not numbered)** - -Driver: SDK JSON, not PTY. Human watch: same Flue conversation URL. `:4321` already follows a conversation (`useFlueAgent`) but only paints text. Herdr cannot embed that page; a pane can only open a URL or tail the transcript CLI. - -- **A.** Parallel spike, not a mission: one conversation id; script/agent drives via SDK; you watch `:4321` (render `dynamic-tool` / `data-*` / skill activation). Herdr at most opens that URL. `HarnessAgent` stays LATER and is not this surface. -- **B.** Wait for a herdr webview/JSON pane as the real product. -- **C.** Watch sims in the Petrinaut panel (AI SDK door), including a client-tool stand-in. - -➡️ **A.** That discharges “I want to see it” without sequencing the ladder. B blocks on herdr. C couples every sim to panel client tools you don’t need for elicitation rehearsal. - ---- - -Answer Q5–Q9. After that the remaining frontier is Host-trunk fog (picker, origin, mid-net switch) and M5’s observer-sweep / subagents — only if you want those pinned before cutting `MISSION.md`. - -## User — Thursday, Aug 27, 2026, 5:35 PM (UTC+2) - -Q5: A -Q6: yes, B - Although I will mention that I recently came across a Pi extension that was doing an interesting thing with a kind of running memory solution. In that case the trigger was not the agent calling a tool but something which was triggered by a certain number of tokens. Every time 10,000 tokens went by, the sweep would be activated and then triggered the next time a turn settled. It seemed like a good idea because anything that doesn't require an LLM call to decide when to trigger it is a latency saving -Q7: B. yes the PN tools can move to M4 -Q8: Correct. That's where I'm going with the runbook idea. I think the runbook and template solution is probably some system prompting, some skill prompting, and the actual runbook instructions (that is, the instructions on how to interpret the runbook) might be in the system prompt or they might be in the skill prompt. There is a template resource inside the skill prompt which actually provides the IR that is meant to be used. - -Maybe that's it. Maybe everything is bundled in the skill. It doesn't really matter that much. The point is basically those are the ingredients. I want to see how far I can get with an approach that's based on this and that pulls together everything we know from our research and other design modeling into the runbook to try to make that runbook as comprehensive as possible. Ultimately it's a system that doesn't rely on the extraction of typed claims at the capture stage -Q9: Yep that sounds good - -## Assistant - -Locked: capture store re-entered with opaque payloads; one throughline test (skill used, sweep twice); M3 is runbook + headless drive; R/W and canvas tools wait for M4; M3 IR is a template in the skill; types are earned by FE generation; watch sims by sharing a conversation URL. - -Also locked as M3 fog-line, not a design task now: system prompt vs skill body vs supporting file. The ingredients are those four; bundling them in the skill is allowed. The experiment is how far a comprehensive runbook goes **without typed claims at capture**. - -That last point plus the token-threshold trigger are the new strain. They collide with “M2 is a mechanical capture sweep” unless we say what each sweep is for. - ---- - -❓ **Q10** - **Which trunk is the next live `MISSION.md`?** - -The charter is one live mission. “Parallel trunks” means two stacked branches or two worktrees, not two files. - -- **A.** Host first: two brains, net = session, compaction. Sweep waits. Today `yarn dev:brunch` already works; this makes the demo choosable and the discriminator proven. -- **B.** Brunch sweep first: envelope + opaque payload, one skill, idempotent apply. Host stays on the scratchpad until cut. Store keys on the Flue conversation identity already in play; if net-lifecycle later fails, rekey. -- **C.** Explicit exception: two worktrees, two live missions, Host and Brunch at once. - -➡️ **B.** Your attention is the runbook experiment. Host is real but not what you need in order to sweep a range. Conversation identity already exists; net-lifecycle is a later proof of the same key, not a blocker. - ---- - -❓ **Q11** - **When does a sweep fire in the Brunch trunk?** - -The Pi extension’s trick: count tokens (no model call), arm, run on the next settled turn. That is *when*, not *what*. M2’s written proof is still “one explicit settled range.” Your old M5 was the observer loop. - -- **A.** M2: the test (or a harness fact) names the range. Token-threshold observer waits for the capture-improvement mission. -- **B.** M2 includes the observer (arm every N tokens, fire on settle). The test lowers N so a short chat crosses it. -- **C.** M2 is explicit-range; if the observer is a small hook on the same `apply-sweep`, it may land in the same mission as a bonus, not as completion. - -➡️ **A.** Idempotent reapplication is the strain. A token counter is a scheduler; putting it in M2 makes “did we pick the right N?” look like a proof failure. Keep the trigger for the mission that cares about latency and “don’t ask the model whether to sweep.” - ---- - -❓ **Q12** - **Is M2’s capture the IR template, or a separate ledger?** - -You want to go far without typed claims. M2 still re-enters the capture store. M3 still fills a markdown template and (eventually) makes a PN from it. - -- **A.** Two artifacts. Capture store = provenance ledger (envelopes, quotes, spans, opaque payload). Template = workpiece the runbook fills (skill resource / conversation document). M5 is when ledger entries grow types that match M4’s map. -- **B.** One artifact. Sweep’s opaque payload *is* the template update. Idempotency = applying twice doesn’t duplicate sections. No slot types. M4 types a map over that document; M5 may still not extract claims if the runbook path is winning. -- **C.** M3 ignores the capture store. Template lives only in the skill/conversation. M2’s store is a mechanism proof that sits idle until something typed exists. - -➡️ **A.** You accepted a real capture store in M2; C wastes it. B collapses workpiece into the ledger and makes “opaque payload” mean “the whole IR doc,” which is harder to cite and to re-apply. Ledger cites; template is what the runbook is for. - ---- - -❓ **Q13** - **Does M3 still generate a Petri net, with no canvas tools?** - -R/W moved to M4. Your M3 still said “one-shot at end, or periodic; LLM call to generate PN from the filled template.” - -- **A.** M3 stops at a filled template plus headless transcript. No net. -- **B.** M3 may one-shot a **desk** net (markdown/JSON file, not the canvas) so you can see whether the template contained enough. No Petrinaut tools. -- **C.** Wait: no PN until M4’s typed map and tools. - -➡️ **B.** That is the runbook experiment’s score: can a comprehensive template plus one generation call produce a recognizable net. If it can’t, you learn that before building FE typing. If it can, M4 has a target. Not on the canvas, so it doesn’t sneak R/W back in. - ---- - -Answer Q10–Q13. After that I can ask Host fog (picker / origin / mid-net) only if you want that trunk pinned before it is cut; otherwise the tree for the Brunch-first cut is almost empty. - -## User — Thursday, Aug 27, 2026, 5:44 PM (UTC+2) - -Q10 and Q11: yes to your recommendation -Q12: I'll explain this by saying that the sweep mechanism with the typed captures became too complex and required too much LLM judgment in order to use it and in order to correctly map each part of it. Those are my guesses. - -The bottom line is that the most recent test that we ran with this mechanism was incredibly slow. The headline catastrophic outcome was that question turns would take upwards of two minutes. The reintroduction of capture sweeping and, in parallel, the convergence on some type of IR design and prompting-based approach are actually two independent but converging paths aimed at progressively reintroducing aspects of the thinking and the design that led to the kind of overcomplicated state that we have now. - -I want to do those progressive reintegrations to see where the strains show up and see if we can clearly notice the threshold where the mechanism becomes untenable. Runbooks and templates are not yet actually connecting to the capture sweep mechanism. I'm just bringing them both in at the same time and considering whether they need to converge. If so, where and when should they converge and in what form? -Q13: That's a good question. Even if we don't give the agent any canvas tools, it could generate a Petri-Nut structure and even validate it using functions exported from Petri-Nut because there are functions for validating the structure. The idea of generating the PN from the filled template, I think we do need to do this actually because we do need to do it even in M3. We're also trying to evaluate how good the IR design is and get a Petri-Nut. Even if we get one as JSON and then I have to load it manually, like a manual load JSON into the Petri-Nut app in order to see it, that's still fine to do this manually. Maybe we can find a way to wire it through programmatically. - -The point is we don't need front-end Petri-Nut mutation tools, canvas mutation tools, in order to be able to do the step of trying to figure out whether the IR that we are creating through our run book and template-based approach is actually then going to be something that can translate in any reasonable way to a Petri-Nut. Obviously in that version, which is not lying on strictly typed captures, the IR is also not going to be super strictly typed. It can be well structured but not strictly typed and therefore it will require inference to generate the Petri-Nut - -## Assistant - -Q10/Q11 locked. Q12 is not A/B/C: two **independent** paths brought in together so you can watch for strain, with **no join designed**. Q13 locked as M3: structured-not-typed template → PN JSON (petrinaut validate, manual load OK); no canvas tools. - -That changes the Brunch trunk. M2’s sweep is a mechanism re-entry, not the IR’s source. M3’s runbook is a prompting experiment, not a consumer of captures. Convergence is a later question, not a hidden architecture. - -To cut the next `MISSION.md` (sweep first) these are still open: - ---- - -❓ **Q14** - **How thin is M2 extraction?** - -Condition 5’s failure mode was LLM judgment in the loop (mapping, typed claims, ~2 min question turns). “Mechanically sweep” can still smuggle that back if producing a proposal is a model call. - -- **A.** No extraction model. Stub: e.g. one envelope per user utterance, quote = that text, payload `{}`. Prove store, spans, idempotent re-apply. The interviewer does not decide to sweep; a test/harness names the range (Q11). -- **B.** A **separate** cheap extraction call (not the interviewer) that emits quotes/opaque blobs only — no slot types, no mapping to kinds. -- **C.** Re-enter the old plugin proposal catalog (`statement-noted`, SDCPN slots, …). - -➡️ **A.** M2 is “does the pipe still work.” A second LLM is the first strain you already observed; putting it in the proof makes latency look like a product regression. B/C belong on the reintegration path *after* the pipe is green, when you are trying to notice the untenable threshold. - ---- - -❓ **Q15** - **Does the interviewer call a sweep tool?** - -- **A.** No. Sweep is harness-side on an explicit settled range. No `sweep` tool, no model choice of when/what. -- **B.** A tool exists but the M2 proof never requires the model to call it (test invokes apply directly). -- **C.** The skill teaches the model to call sweep. That’s part of the throughline. - -➡️ **A.** A tool is an LLM decision about *when*. That contradicts Q11 and reintroduces the latency you are trying to keep off this path. Binding can still *run* apply-sweep; the model is not the scheduler. - ---- - -❓ **Q16** - **How much teaching is in M2’s one skill?** - -M2 still includes prompt + one Flue skill + a test. M3 is the comprehensive runbook/template experiment. - -- **A.** Stub skill: short “use when…” + enough body that `activate_skill` shows in history. Full research dump waits for M3. -- **B.** M2 already ships the first real runbook/template (M3 then only iterates it). -- **C.** M2 skill is empty catalog; teaching is `useInstruction` only. Skill activation is not in the proof. - -➡️ **A.** Two experiments, two missions. A comprehensive runbook in M2 makes a failed elicitation look like a failed sweep. C drops the skill-mechanism proof you wanted. - ---- - -❓ **Q17** - **When does M2 stop and reorient?** - -The point of progressive reintegration is to *see* the threshold. M2 needs a stop line so “a bit of judgment leaked in” doesn’t become the old kernel. - -- **A.** Stop if producing captures requires a model call, if a sweep tool appears on the interviewer, if plugins/kinds/slots/fold re-enter, if the runbook/template is wired to the store, or if a turn on this path is in condition-5 territory (order-of-minutes for an ordinary question). Opaque envelope + harness apply only. -- **B.** Softer: allow a hidden extraction call if it stays under some latency budget. -- **C.** No latency stop; only architectural stop (no types, no join with the template). - -➡️ **A.** You already have the catastrophic baseline. M2’s job is a pipe that cannot recreate it. Latency budget (B) invites bargaining. The join with runbooks is M3+ and explicit. - ---- - -Answer Q14–Q17. If those land, the Brunch-first mission contract is specified enough to read back as a tree and ask whether we have a shared understanding — still no `MISSION.md` until you say so. Host picker/origin stays unasked until that trunk is cut. M3 PN-from-template details go on the scratchpad, not this mission. - -## User — Thursday, Aug 27, 2026, 5:46 PM (UTC+2) - -Your recommended answers are all correct for these ones - -## Assistant - -All of Q14–Q17 are locked. For cutting the next mission, the frontier is empty. Remaining Host details (picker, origin, mid-net switch) stay fog for that trunk, not this one. - -**Do not treat this as a go-ahead to write `MISSION.md`.** Say if this matches what you meant. - ---- - -### Settled tree - -**Mission 1** — done (proof witnessed; disk still says “under verification”). - -**Two trunks, one live mission.** Next `MISSION.md` is the **Brunch sweep** trunk. Host stays on the scratchpad until cut. No second live mission file. - -```text -M1 chat (done) -├─ Host (later cut) -│ ├─ two brains, same panel -│ ├─ net create/save/load = session discriminator -│ └─ compaction reconstructs panel + transcript -└─ Brunch elicitation (next live mission = this sweep) - ├─ M2 pipe: harness sweep, stub skill, no join to IR - ├─ M3 runbook + template + headless drive + off-canvas PN - ├─ M4 typed map + Petrinaut R/W tools - └─ M5 capture improvement (observer trigger, maybe types) -LATER / parallel - ├─ OTel, eval, tracing - ├─ watch sims: SDK drive + :4321 observer (same conversation URL) - └─ HarnessAgent (undecided) -``` - -**M2 — first Brunch-owned behavior (next cut)** -Re-enter the capture store, keyed by existing Flue conversation identity. Envelope + evidence spans; payload `{}`. One envelope per user utterance is enough. Harness names an explicit settled range and `apply-sweep`; the model does not call a sweep tool and does not decide when. No extraction LLM. One Flue skill: stub, only to prove `activate_skill`. One production-path test: skill used, sweep twice, same identities. -**Stop** if a model call is required to produce captures, a sweep tool appears on the interviewer, kinds/slots/fold/plugins re-enter, the runbook/template is wired to the store, or ordinary turns return to condition-5 latency (minutes). - -**M3** — independent prompting path, **not** a consumer of M2 captures. Comprehensive runbook + IR template (skill/supporting file/system prompt — placement is fog). Headless JS-API drive. Generate a Petri net from the filled template (JSON, petrinaut validate, manual load OK). Structured, not strictly typed; generation uses inference. No canvas mutation tools. -**Sweep** means capture-store apply. Template fill is not a sweep. - -**Convergence** of capture and runbook/IR is an open later question: whether, where, when, in what form. Progressive reintegration is how you find the untenable threshold. Do not design the join now. - -**M4** — FE: minimal typing (what maps to what); agent read/write tools; generate on canvas from an IR. -**M5** — observer (token threshold → next settle), capture quality, maybe types; subagents still undecided. -**Host** — two brains, net = session, compaction. Voice = git parent on KA, not a mission. - ---- - -If this is the shared understanding, next is close-out on disk: archive Mission 1, cut this M2 into `MISSION.md`, leave Host/M3+ in `MISSION.next.md`. That is a separate go. - -## User — Thursday, Aug 27, 2026, 5:49 PM (UTC+2) - -All that stuff is a go. The format for the mission file is already there in the current one of course (Is it documented anywhere or was it invented out of thin air? Is it just meant to be its own documentation? ); anyway I felt it was fairly successful on this mission run, so we should use it again. I would also suggest that the mission.next file adopt the clustering and ordering that we've identified, even if not the fully worked out verbose detail of the full mission file. - -## Assistant - -The six-section contract lives in this context’s `AGENTS.md` — we’ll keep that shape. Next I’ll archive Mission 1, cut Mission 2, and regroup `MISSION.next.md` to match the tree we locked. - -## Assistant - -The six-section contract is specified in `AGENTS.md` (and mirrored in `CLAUDE.md`); the live `MISSION.md` is the instance. I’ll archive Mission 1 with a close report, cut Mission 2 in that same shape, and regroup the scratchpad. - -## Assistant - -The format is specified, not improvised. `AGENTS.md` (mirrored in `CLAUDE.md`) requires those six sections in `MISSION.md` and in the branch/PR description: Imperative, Throughline, Proof, Constraints, Fog-line, Stop or reorient. The live file is the instance of that contract. Mission 1 also used **Status** and **Deferred**; those are not in the six, but they worked, so Mission 2 keeps them. Close reports belong on the PR; there is no PR yet, so the archive file carries that report. - -**On disk** - -- Mission 1 archived: `docs/mission-archive/1-bare-petrinaut-flue-chat.md` (charter + proof results, fog-line answers, carried flags). -- Live `MISSION.md` is **Mission 2 — mechanical capture sweep**. -- `MISSION.next.md` is clustered in the order we locked: Host trunk → elicitation ladder (runbook/PN, then typed map + R/W, then capture improvement) → later/parallel. Capture and runbook stay independent. -- The FE-1522 proof note now records the human run and points at the archive. - -Nothing committed. No Linear write. Mission 2 on this branch is a charter change on FE-1522’s worktree; a new issue/branch for the sweep is a separate, approval-gated step. - -## User — Thursday, Aug 27, 2026, 5:52 PM (UTC+2) - -Please commit all the open changes and now let's mint a linear issue to represent mission two - -## Assistant - -I'll commit the open files, then create the Mission 2 Linear issue using the brunch tracker rules. - -## Assistant - -Commit landed. Nearby capture issues are Done or the old harness plan — I’ll mint a new issue related to FE-1522, not reuse those. - -## Assistant - -Commit is on `ln/fe-1522-mission-1`: - -`4e4f19288d` — Archive Mission 1 and cut the mechanical capture-sweep mission. - -**Linear:** [FE-1524](https://linear.app/hash/issue/FE-1524/prove-idempotent-capture-sweep-on-the-live-flue-chat-path) — *Prove idempotent capture sweep on the live Flue chat path* - -- Team `FE`, project `brunch-agent`, assignee ln, state Triage -- Related to FE-1522 (and Linear also linked FE-1392, FE-1419, FE-1503 from the body URLs) -- Did not reuse those Done/plan issues; they stay history - -FE-1522 is still In Progress. I did not close it or create a Graphite branch for FE-1524. Next, if you want the one-issue-one-branch rule: `gt create ln/fe-1524-…` from this parent (or after FE-1522 lands). - -## User — Friday, Aug 28, 2026, 10:39 AM (UTC+2) - -I think the guidance protocol for how to maintain the mission.next document is too thin and undisciplined. I'm disappointed to see that, despite the level of detail in which we talked about things in this discussion, the mission.next document does not capture, for example, the idea about an observer agent acting as the sweep mechanism. Many other details have been lost I think - -You have a function for exporting a markdown transcript of this entire session ? - -## Assistant - -You're right that `MISSION.next.md` was compressed past usefulness. I'll check whether this session can be exported as markdown, then we can put the lost detail back. - -## Assistant - -No first-class export. Cursor keeps this chat as JSONL (`agent-transcripts/56b0adcc-…jsonl`). I can turn the user/assistant text into markdown; there is no session-export tool, and tool-call noise would be stripped unless you want it. - -You are right about `MISSION.next.md`. The charter only says “collect successor concerns” and “leave what did not make the cut.” That licenses a summary. It does not say preserve hypotheses at conversational fidelity, which is how the observer design got flattened. - -What is on disk now is one compressed bullet: - -> Token-threshold observer: arm after N tokens, fire on next turn settle. - -What you actually said, and what is not there: - -- An **observer agent** is the sweep mechanism, not a harness counter with a later maybe. -- Calls are fire-and-forget, **queued**, **retried on failure**. -- **Cannot fold unless the queue is valid.** -- The elicitor mostly follows tip/heuristic/situation/example guidance and **does not consult the fold** on ordinary turns. -- A periodic **re-group** every XX tokens lets the queue settle, fold, and see what is still needed. -- Fold semantics as generic as you can get away with. -- Subagents for micro-cognitive tasks (decisioning and decomposition). - -That is a design hypothesis, not a cluster label. Same failure mode as `dev-handoff` warns about: summarizing instead of keeping the structure. - -I can write a readable markdown of this session (this thread from yesterday’s orientation through FE-1524), then restore those hypotheses into `MISSION.next.md` and tighten the scratchpad rule in `AGENTS.md` so later cuts cannot drop them. Say where you want the transcript (repo path vs `/tmp`) and I will do that. - -## User — Friday, Aug 28, 2026, 10:44 AM (UTC+2) - -Put the transcript in to `docs/inbox/` for now, And I think because this session already has quite a high context level, it would be good to include a kickoff prompt in that transcript precisely to do what we're talking about doing right now, which is to re-analyze the transcript for the missed details and then to update the protocols around the maintenance of the Mission.next file - -FTR: - -My suggestion for how to maintain the mission.next file is to essentially treat it as a draft for upcoming missions, up to and including maybe all of the sections and structures that we apply to the main mission file. That is I would simply use multiple h1 headings within the mission.next file in order to essentially maintain tentative groupings and sectionings of material. Maybe that is extending a bit too far. Maybe some of the sections we apply to the full mission file template don't really need to be applied until we are about to cut the mission. In any case my essential guidance would be to maintain the file as a representation of everything that we currently think we know about what we can and should do next, as well as a comprehensive record of all the ideas, observations, and questions that we have brought up - -## Assistant - -I'll convert this session to markdown in `docs/inbox/`, with a kickoff prompt at the top for a fresh thread to restore missed detail and tighten the `MISSION.next.md` protocol. diff --git "a/libs/@hashintel/brunch-agent/docs/inbox/[shared] Safeguarded AI \342\200\223 Final Exam (Sketch).md" "b/libs/@hashintel/brunch-agent/docs/inbox/[shared] Safeguarded AI \342\200\223 Final Exam (Sketch).md" new file mode 100644 index 00000000000..daff47d57a5 --- /dev/null +++ "b/libs/@hashintel/brunch-agent/docs/inbox/[shared] Safeguarded AI \342\200\223 Final Exam (Sketch).md" @@ -0,0 +1,378 @@ +# Safeguarded AI – ‘Final Exam’ + +**End-of-programme demonstration for Safeguarded AI: Cyberphysical – Draft Notes** + +*\~Nora* + +# Why a final exam + +As we enter the last phase of the programme, I want to decide on a small set of demonstrations (‘exams’) against which the capabilities will be tested by programme end. What motivates this: + +1. **A Schelling point.** One concrete target focuses attention across teams, and helps answer design questions and make informed trade-offs. +2. **Capabilities we can't demonstrate are not enough.** If we build genuine breakthrough capabilities, but we don’t demonstrate it, we haven’t succeeded: the tools won't get used, they won't shift the discourse on what's possible, and we fail to position Creator teams for follow up funding or commercial engagements to carry the work forward. As we push into the unexplored frontier, there are no existing benchmarks we can test our tools against; we have to create them ourselves. + +In true ARIA manner, our final exam should be more ambitious than what we're confident we can achieve, while being structured in such a way that capabilities are demonstrated in degrees, not as a pass/fail. + +*We are separately aiming for demonstrations in cyber/secure code, but here we focus exclusively on TA2b – Cyberphysical.* + +# What are we evaluating / demonstrating + +**The Safeguarded AI pipeline:** + +| domain context (docs, data, logs, experts) *(natural language)* | → | model ℳ \+ spec φ | | → | policy π , certificate C | +| :---: | :---: | :---: | :---: | :---: | :---: | +| *Phase A* | | | *Phase B* | | | + +* **Phase A — modelling.** Have a problem brief and raw artifacts (process docs, event logs, synthetic ERP data); produce a formal model (SDCPN) and specifications. + * *Squarely the concern of TA1.3 and TA1.1, with some overlap with efforts in TA1.0.* +* **Phase B — certification.** Have a formal model and spec; produce a policy and a machine-checkable certificate. + * *Squarely the concern of TA1.2 and TA1.1, with some overlap with efforts in TA1.0.* + + +Our modelling formalism of choice for cyberphysical is **SDCPNs**, due to them being equivalent in expressivity to General Stochastic Hybrid Systems (GSHS). + +# Supply Chain Problem Curriculum Design + +Our domain of choice for the final exam is Supply Chains. + +*(This will be the central, but not necessarily only demonstration domain for SgAI Cyberphysical; for now I’m looking to focus the discussion on this.)* + +**Why Supply Chains?** + +* They allow us to demonstrate (and vary gradually) the full range of semantic expressivity (up to fully fledged SDCPNs) and size which we’d like to claim. +* They are economically and societally important. +* We have established access to domain experts/end users through HASH. + +**Why a Problem Curriculum?** + +* Instances in the problem curriculum span from simple to complex across complexity dimensions (see Section 2.). They thus let us evaluate the *degree* to which we have been able to push the reach of our toolsuite, rather than providing only a binary assessment. +* The semifab testbeds serve as loose inspiration for the curriculum design (MiniFab → MIMAC → SMT2020/SMAT2022). + * Though note that semifab testbeds are simulators plus KPI definitions; a declarative model must be lifted out of the code. Coverage wise, the semifab testbeds are only discrete-event models, but pushed to very large size. + +What does the problem curriculum/exam look like, schematically? The curriculum consists of instances representing end-to-end runs of the Safeguarded AI pipeline. Each instance is generated according to the schema described in the following Section. + +1. ## Curriculum instance (dataset) schema + +The curriculum specifies the different types of data associated with each instance and phase. The blueprint defining the structure of each instance is the **instance schema**, which is split into two parts: one for Phase A outputs and one for Phase B outputs. + +### Phase A inputs + +| Component | What it is | What it's for | Current form | +| :---- | :---- | :---- | :---- | +| Domain Context | Natural language and data artifacts about the problem domain (docs, event logs, synthetic ERP data, expert input). | Basis on which formal model and specs are elicited and synthesised | | + +### Phase A outputs + +| Component | What it is | What it's for | Current form | +| :---- | :---- | :---- | :---- | +| Domain Context | Natural language and data artifacts about the problem domain (docs, event logs, synthetic ERP data, expert input). | Basis on which formal model and specs are elicited and synthesised | | +| Model ℳ | A formal/declarative Petri net model of the domain (e.g. SDCPNs) consisting of its structure (places, transitions, and the arcs between them) and its features (e.g. stochasticity, colouredness etc.). | Defines the domain / problem for which a policy is found and certified | | +| KPIs 𝒦 | Performance metrics, e.g P(stockout ≤ T), waste/expiry rate, holding+backlog cost, cold-chain excursion probability, recovery time after disruption. | Metrics against which the policy is evaluated | | +| Specification **φ** (decision problem, constraint) | Close-ended (YES-or-NO) question over KPIs. This is a decision problem and can be interpreted as a constraint. A constraint is satisfied if a decision problem admits a YES answer and is violated otherwise. Format: {KPI, relational operator, threshold, time frame}, Examples: P(stockout ≤ T) ≤ δ in 99% of simulation time, same for service level, quality-on-delivery etc. | Defines the safety specifications against which the policy is certified | | +| Baseline policies **π₀** (Ground truth) | Standard, specified policies from practice (where available). | Benchmarking other policies in Phase B | | + +### Phase B inputs + +Every output of Phase A is also input in Phase B. Additionally: + +| Component | What it is | What it's for | Current form | +| :---- | :---- | :---- | :---- | +| Model verification tool **𝒯** – specifically a model checker | Exact model checking (small); pre-registered statistical estimates (large) (where available) | Checks whether a certificate is valid for a specification or not conditioned on a policy – equivalent to whether a specification is certified or not. | | + +### Phase B outputs + +| Component | What it is | What it's for | Current form | +| :---- | :---- | :---- | :---- | +| Policy **π** | A set of rules governing which Petri Net transitions are permitted at any time. This is an umbrella term for artifacts resolving non-determinism. | Resolves Petri Net execution (runs) | | +| Certificate **C** | Verifiable evidence that a given specification is *universally* satisfied (for all PN runs) conditioned on a choice of policy **π**. | Guarantees a specification \-conditioned on a policy- is satisfied | | +| False certificate **C̄** (Mutant) | A corrupted (false) certificate is a purported certificate that claims a specification is satisfied when, in fact, it is not. Corrupted certificates that the model verification tools must refuse. | Ensures the model verification tools reject it as a certificate | | + +Each instance varies by complexity dimension (see Section 2.), so grading reports complexity scaling curves rather than single points. + +**Simulations** may appear as secondary artifact, with four potential purposes: generating the raw artifacts in context briefs; as source material from which declarative reference models are built; as pre-registered ground-truth estimator on instances too large for exact checking; and as the uncertified baseline that certified results are measured against. + +2. ## Curriculum complexity dimensions + +Our curriculum, going from ‘simple’ to ‘complex’, has several dimensions each associated with an instance schema component: + +| Instance component | Complexity dimension | Ladder steps *(arrows indicate direction of increasing difficulty)* | Semantic expressivity dependence | +| :---- | :---- | :---- | :---- | +| Model ℳ | **Semantic expressivity** | **L0** (PN) → **L4** (SDC-PN) | *N/A* | +| | **Node size** (transition \+ place count) x **Time horizon** | **Small**: 1–3 products, 2–3 echelons, one node per echelon, time horizon of weeks. *(MiniFab-scale.)* → **Medium**: \~10–50 SKUs, 3–5 echelons with parallel nodes, shared resources and batching, time horizon of months. *(MIMAC-scale.)* → **Large**: Hundreds of SKUs, multi-region networks of tens of nodes, dynamic order/shipment fleets, time horizon of quarters. *(SMT2020-scale.)* | | +| | **Marking graph size** (token count) x **State space size** (size of space of token values/colouring) | **Finite** (finite token count, uncoloured tokens ) → **Countably infinite** (arbitrary token count, finitely coloured tokens) → **Continuous** (finite token count, dynamically coloured tokens) → **Variadic** (arbitrary token count, dynamically coloured tokens) (parameterised model checking) | *Finite:* L0 \- L1c *Countably infinite:* L2a \- L2b *Continuous:* L3-L4 *Variadic:* L3-L4 | +| | **Modularity / hierarchy** | **Monolithic** → **Compositional** (finite number of models joined together) → **Parameterised** (unbounded number of models) | | +| | **Determinism** | **Determinism** → **Non-determinism** | | +| | **Composition width** (models are joined along a fixed boundary of size k) | **k Small** → **k Large** | *Deterministic PNs (L0):* this boundary will be a spatial glueing, *Stochastic PNs (L1-L4):* we will need assume-guarantee contracts whose size also depends on composition width | +| | **Stochastic process** | **Ito process** (drift diffusion) → **Feller process** → **Continuous Markov Process** → **Continuous Stochastic Process** | L4: By default we assume the SDE is a continuous Markov process | +| Specification **φ** | **Verification objective** | **Safety** → **Termination** → **Stability** → **Quantitative Reach-Avoid Reactivity** (good infinitely often) | | + +In the Sections that follow, we elaborate on the ladder levels (steps) of semantic expressivity and hierarchy / modularity. + +1. ### Semantic expressivity levels + +Semantic expressivity characterises the type of Petri net model ℳ, as determined by its treatment of: + +1. *Time* *(global clock):* discrete or continuous. +2. *Arc type:* normal, read and inhibitor arcs. +3. *Token colouredness*: uncoloured, statically coloured or dynamically coloured. +4. *Transition delay distribution*: transition delay are samples from the Dirac distribution (deterministic delays), the exponential distribution or more general distributions (e.g. lognormal). +5. *Transition kernel stochasticity*: transition-produced token counts and their colouring are either deterministically generated or randomly sampled. +6. *Place dynamics:* no dynamics, ODE-governed or SDE-governed dynamics. + +Full SDCPNs represent the North Star. For the ladder to degrade well, ideally: + +1. **Each step is a conservative extension of the former step.** Every level-k model is also a level-(k+1) model, so the levels strictly nest and capability is monotone up the ladder. +2. **Each step crosses exactly one verification-technology boundary.** The feature added at each level is chosen because it breaks the certification methods that suffice at the level below. + +*A preliminary sketch:* + +| Level | Acronym | Formalism | Feature added | Supply-chain phenomenon (guesses) | Supply-chain specification (guesses) | Verification technology exercised | +| :---- | :---- | :---- | :---- | :---- | :---- | :---- | +| *L0* | PN | *Monolithic, Uncoloured, deterministic, untimed **PN** with only normal arcs* | *N/A* | *flow topology, routing, resource contention* | | *structural analysis; coverability; sound reachability* | +| L1a | ST-PN | Uncoloured, **S**tochastic-**T**ransition, discrete-time **PN** with exponential delays (generates a DTMC) | Stochastic transition firings (randomly sampled transition delays), discrete global clock (time) | Environment. | | *Compositional / Modular probabilistic model checking (Prism/storm encodings). Composition of Supermartingale certificates for LTL.* | +| L1b | ST-PN | Uncoloured, **S**tochastic-**T**ransition, continuous-time **PN** with exponential delays (generates a CTMC) | Continuous global clock (time) | Poisson order arrivals, machine & transport failures | | exact/numerical probabilistic model checking; transient & steady-state analysis | +| L1c | ST-PN | Uncoloured, **S**tochastic-**T**ransition, continuous-time **PN** with general delay distributions (generates a GSMP, fixed dimension) | Transition delay distributions are arbitrary. | realistic (lognormal, Dirac) lead times, periodic review cycles, shelf-life clocks | | Neural supermartingales | +| L2a | SC-PN | **S**tatically **C**oloured, **S**tochastic-**T**ransition, continuous-time **PN** (generates a GSMP over structured state) | Token colouring, transition guards & rates operate on discretely-coloured tokens (semantically enabled transitions), transition kernels probabilistically produce coloured tokens (both their colouring and count) | SKUs / product types, batching, age-class perishability, customer classes | | neural supermartingales with plate notation (symmetry- and colour-exploiting model checking); statistical model checking | +| L2b | SC-PN | **S**tatically **C**oloured, **S**tochastic-**T**ransition, continuous-time **PN** with any arc type (generates a GSMP over structured state) | Inhibitor, read arcs | | | | +| L3 | DC-PN | ODE-evolving **C**olour **D**ynamics, **S**tochastic-**T**ransition, continuous-time **PN** (generates a PDMP with infinitely many discrete modes) | Continuous colouring, transition guards, rates & kernels behave as in L2 but on continuously-coloured tokens, deterministic place dynamics ( continuous ODE flows), boundary-hit (forced) jumps | cold-chain temperature, continuous degradation, tank & production levels | | certificates over ℝⁿ — barrier / Lyapunov-style, certified abstractions; certified Morse graph | +| L4 | SDC-PN | **S**DE-evolving **C**olour **D**ynamics, **S**tochastic-**T**ransition, continuous-time **PN** (generates a GSHS, variable dimension) | SDE is a Markov Process, Stochastic place dynamics (continuous SDE flows using Brownian motion and a colour-dependent diffusion coefficient) | dynamic fleets of orders/shipments, SKU churn, network reconfiguration, disruption cascades | | neural supermartingales with or without plate notation (need to be once continuously differentiable and their additional certification conditions) | + +### B. Modularity / hierarchy levels + +Modularly structured PNs are Petri net models **ℳ** that are either: + +* ***Monolithic***: PNs that cannot be non-decomposed further – these represent the lowest level of the hierarchy –, +* ***Compositional***: PNs that can be decomposed into finitely many connected modules (either monolithic PNs or other compositional PNs), thereby introducing multiple but finitely many levels of abstraction, and +* ***Parameterised***: compositional PNs that allow for an infinite number of nested PNs. + +This modular structure allows a complex PN to be represented in terms of simpler, interconnected components, with compositionality providing the mechanism through which these components are combined to form the overall PN. Although managing this modular structure requires additional theoretical developments, the hierarchy should ultimately enable more efficient model checking, rather than introduce additional computational burden. + +1. ## Curriculum real-world validation + +We want to be confident that the curriculum captures real-world problems of great socio-economic import. The curriculum is therefore validated through external domain experts/end users for real-world relevance, in a structured, legible and citable form. + +2. ## Curriculum grading (evaluating) dimensions + +Overall, in evaluating programme capabilities, we ask, for each level of the curriculum attempted (expressivity level × size), what is the strongest assurance class achieved, and at what costs. + +| Grading/Evaluation Dimension | What is it | +| :---- | :---- | +| Curriculum Coverage | Which levels of curriculum complexity was reached | +| Assurance strength | Uncertified estimate → anytime-valid statistical bound → certified abstraction → exact result | +| Cost | Formal model synthesis from domain context computation time (Phase A), human model review time, user experience scores (Phase A), model verification tool computation time (Phase B). | + +**Phase A** capabilities seek to produce formal models ℳ, KPIs 𝒦 and their associated specifications **φ**. They are graded against: + +- a withheld reference model (where available), and/or +- an expert review judging the quality of the elicited model and specifications, and/or +- human review time spent and user experience (compared to incumbent tooling). +- cost (formal model synthesis computation time) + +**Phase B** capabilities seek to produce policy **π** \+certificate **C** pairs as well as model verification tools 𝒯 and their artefacts, which can be machine-graded for: + +- certificate validity (including refusing every false certificate)), +- verification tool’s bound tightness (vs. baseline policies, incumbent or empirical estimates), +- policy performance (measured in KPIs and compared against baseline policies derived from domain context), and +- cost (verification tool computation time, human review time). + +Notably, all capabilities (and the grading) need to be **reproducible** by an external examiner without trusting the solvers. + +# Building the curriculum + +## Who + +I’m imagining **HASH** to lead on curriculum development. Building the curriculum is a meaningful (if time bound) piece of work and will come at the expense of other scope. + +HASH can draw on support, such as from **Coherence**, especially on mathematics and synthesis capabilities needed for the construction of the curriculum; as well as **other TA Creators**, as useful. + +We should explore whether, in collaboration with the **Birmingham/AstraZeneca** team, we can create certain problems that involve biopharmaceutical manufacturing or degradation processes. + +I also encourage engagement with **Zeroth** on Phase B-facing design choices; and **Topos** and **Ink & Switch** on Phase A. + +## Synthesis of Models M + +At some point, formal models become larger and more complex than can be meaningfully authored by hand. From there, the TA1.3 **agentic elicitation tooling** is needed to generate the curriculum problems themselves: agents propose a modular, declarative model from the domain context (domain experts, data, logs, reference materials); humans review and validate. The curriculum development thus becomes the testing ground for the TA1.3 tooling needed in Phase A. + +In the longer term (likely beyond the horizon of curriculum development), further mechanisms become relevant: + +1. **A validated (imprecise) model/hypothesis comparison procedure, where agents compete to best explain the data.** The trust anchor moves from the generation process into the selection processes: competing agents propose candidate models, a pre-validated procedure grades how well each explains the data (across imprecise and nondeterministic hypotheses), and adversarial review agents grade proposals against multi-objective rubrics and human validation. +2. **Trust-webs of reusable signed component models (‘ModelLib’).** Model authoring becomes compositional across organisations: a principal imports component models from libraries signed by principals they trust, so large models are assembled from independently validated, reusable parts rather than built from scratch. + +## Timeline + +Fixing the final exam as soon as possible is useful because it helps create clarity and shared north star across programme efforts. However, building the curriculum is a substantial effort. + +I currently envision something like the following timeline: + +1. **\~Sep 15: Fix the framework/schema.** + 1. Define the instance schema, the grading dimensions, and provide a few worked examples. The goal is that every team knows the exam's type signature. +2. **\~Oct 15: Finish building V1.** + 1. Have small size problems across the full semantic range, and medium size problems across the lower half of the semantic range. (indicative) +3. **\~Feb 15: Finish building V2.** + 1. Full matrix populated; domain-expert validation complete. + +Freezing the schema by September already buys a lot in terms of clarity and focus across the Creator cohort. Creating especially large instances of models may require the development of more synthesis capabilities first, and is thus deferred to several months later. + +# Assorted comments + +* **Independence.** We are building the exam, as well as the capabilities the exam seeks to grade. Mitigation: the curriculum and the baseline (incumbent tooling and performance) are validated by external domain experts, in a legible and citable form, and logged before the (final) solving attempts begin. Several aspects of the evaluation design and execution need further refinement, and will involve external expert review/validation. +* \<...\> + +# (Touching on briefly) Building the capabilities the curriculum tests + +Once the high-level design scheme for the exam is clarified, it may be worth reconsidering what team / coordination structures are most conducive to success. A few quick, preliminary thoughts: + +1. **Phase A taskforce** — brief and data to formal model and spec, plus the human ability to validate both. + 1. Mainly TA1.3 teams, led by HASH; Topos and Ink & Switch core, and others TA1.0 teams as relevant (Cyrus/Andrew, etc.) (?) +2. **Phase B taskforce** — model and spec to policy and certificate. + 1. Zeroth, DJM+team and Coherence on theory, Zeroth on synthesis infrastructure. + 1. Who (if anyone) to lead? Who to cover policy-training / ML capacity? +3. **“Phase C” – SgAI Stack Integration.** Coln ↔ GAOIS ↔ {Tooling}, and Coln ↔ Zeroth Infra/Lean. + 1. Coln \+ Ink\&Switch responsible for Coln:GAOIS integration (e.g. Coln to replace Automerge). + 2. Ink\&Switch responsible for GAOIS maturity/stability, and for meeting all demands from ‘Tooling’ (HASH, Topos) + 3. Coln \+ Zeroth responsible for Coln:Zeroth integration. + +I encourage something like an ‘open-problems’ list via which **other TA1 Creators** can be ‘recruited’ to the task. + +# Appendix + +# Nomenclature + +**Nets (syntax):** + +* **PN** — ‘Vanilla’ Petri net. Places, transitions, tokens; transitions fire by consuming/producing tokens. Transition kernels handle token production. This is the base model on top of which every other Petri net is built. +* **SPN** — Stochastic Petri net. PN with random firing delays. +* **CPN** — Coloured Petri net. Tokens carry discrete data ("colours"); guards and routing can read it. *(In the table: "coloured, timed stochastic PN".)* +* **DCPN** — Dynamically Coloured Petri net. Colours are continuous and evolve by ODEs between firings; guards, rates and jumps can depend on them. +* **SDCPN** — Stochastically and Dynamically Coloured Petri net. As DCPN, but colours evolve by SDEs (adds diffusion). + +**Processes (semantics):** + +* **CTMC** — Continuous-Time Markov Chain. Memoryless jump process; exponential holding times. +* **GSMP** — Generalised Semi-Markov Process. Multiple concurrent clocks with general distributions; the future depends on clock ages, not just the discrete state. +* **PDMP** — Piecewise-Deterministic (Markov) Process. Deterministic ODE flow punctuated by random and boundary-forced jumps; no diffusion. +* **GSHS** — General Stochastic Hybrid System. Hybrid discrete \+ continuous state, SDE flows, random and forced jumps; the maximal class, and SDCPN's equivalent. + +**Dynamics:** + +* **ODE** — Ordinary Differential Equation. Deterministic continuous dynamics (drift only). +* **SDE** — Stochastic Differential Equation. Drift plus Brownian diffusion. + +**Transitions:** + +- **Enablement time** – time it takes for a disabled transition to become enabled. +- **Delay** – time it takes for a transition to fire from the moment it becomes enabled: a sample from the transition firing measure. +- **Firing rate** – parameter associated with transition firing measure. +- **Firing time** – time it takes for transition to become enabled and fire: equal to delay \+ enablement time. + +**Colouring and token types:** + +* **Token type** – a unique collection of token attributes (fields, properties) in coloured PNs. +* **Colouring space** – space where all the token tuples (token attributes) of a given type lie. +* **Discrete colouring** – Colouring space is a subset of the finite-dimensional integer lattice. Categorical token attributes are encoded (one-hot, ordinal etc.) to lie in this colouring space. +* **Continuous colouring** – Colouring space is a subset of the n-dimensional real space (n is arbitrary). + +**Model verification:** + +- **Model checker \[1\] –** given a formal specification φ of “correctness” (desired behaviour) a model checker answers the question of whether the PN model ℳ satisfies the specification with mathematical certainty, for every possible run of the PN model. It is one model verification method. If specifications are constraints, then a model checker checks whether these constraints are always satisfied or not for every PN run**.** +- **Witness w –** *One* example of a Petri Net run that provides verifiable evidence that a given specification is satisfied for a given choice of policy. It is a weaker form of certificate because it is *existential* and not *universal*. + +## SemiFab Testbed + +| Name | Machines | Products | Steps | Features | +| :---- | :---- | :---- | :---- | :---- | +| [MiniFab](https://aar.faculty.asu.edu/research/intel/papers/fabspec.html) (Kempf/Intel, 1994\) | 5 | 3 | 6 | With re-entrant flow, batching, setups | +| Harris fab (Kayton et al., 1997\) | 12 | 3 | 22 | | +| MIMAC (SEMATECH, 1995; 6 datasets) | ≤260 | ≤21 | ≤280 | | +| SEMATECH 300mm (Kiba et al., 2009\) | 275 | 1 | 364 | Adds automated material handling | +| [SMT2020](https://ieeexplore.ieee.org/document/9115710/) (Kopp et al., 2020\) | ≤1314 | 10 | ≤632 | Adds high/low volume/mix conditions | +| [SMAT2022](https://github.com/kwoo-lee/SMAT2022) (Lee et al., 2022\) | ≤1314 | 10 | ≤632 | Adds Automated Material Handling System (AMHS) | + +## Speculative: The Field Exam + +As a second potential ‘exam’ – designed less to test the frontiers of SgAI capabilities, but to compellingly demonstrate real-world applicability – we could explore something along the lines of the following scheme: + +In \~Summer 2027, send a small ‘forward-deployed’ Safeguarded AI contingent to a real semiconductor fab (or similar production line) for a 2-3 week sprint where, together with 1-2 fab-side engineers, the team runs the SgAI pipeline end-to-end on the fab's actual problem: from raw artifacts (process docs, MES/event logs, expert interviews) to formal model and specs (Phase A), to a certified dispatch/planning policy (Phase B). The exit artifact is a policy with a machine-checkable certificate against pre-registered specs, produced on-site, on real data, in bounded wall-clock time, and tested in the real fab. + + +- Minimum: replay on withheld historical logs against the incumbent dispatcher's actual decisions. +- Better: live shadow mode during the sprint's final days, with recommendations logged alongside incumbent decisions. +- Stretch: a limited advisory or live window on a low-risk toolgroup, subject to fab sign-off. + +This demonstration would not test semantic expressivity, but the tooling’s ability to handle incomplete and messy data, tacit knowledge held by people rather than documents, and operations under time pressure with real end users. + +It also has a certain ‘retweetable’, demonstrative force that the benchmark cannot match. + +## Site Candidates + +*Early search results:* + +| Site | What is it | Fit | +| :---- | :---- | :---- | +| [Pragmatic Semiconductor](http://pragmaticsemi.com) (Durham) | 300mm fab, flexible ICs; each line a fully automated 600 m² "fab-in-a-box", billions of chips/yr; up to nine lines. \~350 staff, PhD-heavy. Opened 2024\. | **Scale:** Harris-band; short flow, \<48h cycles (vs 600+ steps/months at leading edge), shallow re-entrancy. Short cycles; complete lot journeys observable within the sprint. **Access:** Good. Research-native culture, no foreign-corporate approval chain. | +| [Vishay Newport](http://vishay.com/en/company/newport) (South Wales) | UK's largest fab: automotive-certified 200mm, 30k+ wafers/month; £250m SiC ramp underway | **Scale**: MIMAC/SMT band; the only UK site with industrial-scale re-entrant flow. **Access**: hardest; US parent \+ standing national-security conditions; slow data negotiation. | +| [Diodes OFAB](http://diodes.com) (Oldham) | 150mm fab, multiple process families (discrete \+ analog IC), 200+ manufacturing staff, on-site process development team. Repeat NMI ‘Site of the Year’, recognising “outstanding operational efficiencies, technical success, new process development, and strategic market growth.” Wafer fabs in Oldham, England and Greenock, Scotland. | **Scale**: MIMAC band; real multi-process toolgroup contention. **Access**: medium; US parent, but strong site identity. | +| [Clas-SiC](http://clas-sic.com) (Lochgelly) / [Semefab](http://semefab.co.uk) (Glenrothes) | Small independent Scottish open foundries: SiC power (Clas-SiC); MEMS/CMOS/discretes, 500M+ die/yr (Semefab). | **Scale**: MiniFab/Harris, but densest mix per machine; many customer processes on shared tools. **Access**: easiest; small, independent, R\&D-native. | +| [CPI Medicines Manufacturing Innovation Centre](http://uk-cpi.com/work-with-us/medicines-manufacturing-innovation-centre) (Glasgow) | £88m pharma manufacturing testbed; digitally-twinned continuous direct compression line with AZ, GSK, Pfizer, Siemens | **Scale**: MiniFab-size, but exercises rungs a fab doesn't (shelf-life clocks, cold chain, degradation; L1b–L3a). Demonstrator, not a live commercial line. **Access**: good; built for trials; adjacent to AZ satellite. | +| Commercial biopharma sites (AZ Macclesfield, GSK Barnard Castle, Fujifilm Diosynth Billingham) | Live fill-finish/secondary pharma manufacturing: multi-product campaigns, cold chain, expiry-dated inventory. | **Scale**: MIMAC-comparable campaign complexity \+ same L1b–L3a bonus, on a real line. **Access**: medium; GMP data governance heavy; AZ is a warm door. | +| Catapult pilot lines ([AMRC](http://amrc.co.uk), [MTC](http://the-mtc.org)) | Research factories for aerospace/machining job-shop trials. | **Scale:** MiniFab job shops. **Access:** easy but pure demonstrator; weakest exit artifact. | +| [IHP](http://ihp-open-pdk-docs.readthedocs.io) (Frankfurt/Oder, DE) | Leibniz research institute running a 130nm SiGe BiCMOS pilot line with MPW shuttle runs; the world's first open-source PDK — process specs, control parameters, reject criteria all public. | **Scale:** MiniFab/Harris band; pilot line, not volume fab; shuttle scheduling (batching designs onto shared runs) is its distinctive flavour. **Access:** unique; openness by institutional mission dissolves the NDA problem that constrains every commercial site. Not UK. | + +Other domains: + +* Container ports + +# The ladder from the point of view of a Petri net + +~~Three~~ Two things you can globally count over a Petri net: ~~\#places,~~ \#transitions, \#tokens. Let’s consider tokens as first class citizens: + +## Tokens + +### State + +* One colour +* Finitely many colours +* Countably many colours +* Uncountably many colours + +### Jump behaviour + +* Reset to constant colour +* Reset to deterministic expression (includes “no change”) +* Reset to nondeterministic expression +* Reset to probabilistic expression + +(there is also the question of whether the expressions are linear or nonlinear) + +### Delay behaviour + +* Stay constant +* Evolve deterministically (ODE) +* Evolve nondeterministically (differential inclusion) +* Evolve stochastically (SDE) + +(there is also the question of whether the evolution is linear in time, or not) + +## Transitions + +State + +* (are transitions memoryless?) + +Delay behaviour + +* Deterministic (includes timed and synchronous) +* Nondeterministic (includes asynchronous) +* Stochastic (includes Poisson) + +Jump behaviour + +* how many places/tokens does a transition interact with? Composition width\! + +## Places + +Aren’t places just a special case of colours? (sorry, I hope this does not take us down a rabbit hole. But it makes things simple. All we need to take care of are tokens and transitions). What I mean is: let color just be of type Place x TheActualColour and voila\! + +## References + +\[1\]: \ No newline at end of file diff --git a/libs/@hashintel/brunch-agent/docs/inbox/amp-session-reviewing-architecture.md b/libs/@hashintel/brunch-agent/docs/inbox/amp-session-reviewing-architecture.md new file mode 100644 index 00000000000..0de291bc352 --- /dev/null +++ b/libs/@hashintel/brunch-agent/docs/inbox/amp-session-reviewing-architecture.md @@ -0,0 +1,6996 @@ +--- +title: Package architecture review +author: Lu Nelson +threadId: T-01a032f5-37ff-7328-a0d5-f8ee48678dd2 +created: 2026-08-24T08:48:46.591Z +agentMode: high +--- + +# Package architecture review + +## User + +please get oriented in this package, and then I'd like to conduct a high-level design- and planning-review session + +## Assistant + +I’ll first map the package’s declared architecture, posture, active planning artifacts, and recent work. Then I’ll frame the review around the decisions that are actually open rather than giving a generic codebase tour. + +## User + +it's actually multiple packages; I should have referred to it as a "context root" + +## Assistant + +Right — I’ll treat `libs/@hashintel/brunch-agent` as the **Brunch context root**: one authority surface for the glossary, ADRs, protocols, and planning records; four child package workspaces; plus the separately located `apps/brunch-agent` application. That distinction is architecturally important here. + +The initial read suggests the package boundaries are comparatively settled; the more consequential review target is likely the transition from the completed import/integration spine to the still-provisional elicitation semantics and milestone plan. I’m narrowing that now against the coordination ledger and current Linear state. + +## Assistant + +The coordination document’s literal `yarn turbo …` form is stale for this Yarn setup; it fails before invoking Turbo. I’ll use the repository’s installed Turbo binary directly, preserving the same read-only graph task. + +## Assistant + +The live DAG materially diverges from the 21 August coordination snapshot: seven new root-level issues, FE-1476–FE-1482, now describe the September/demo, routing, provenance, re-elicitation, requirements-graph projection, and CPS-plugin direction. Before proposing a review frame, I’m reading those issue contracts and the three established root maps to determine whether this is intentional reframing or planning drift. + +## Assistant + +I’m oriented to the **Brunch context root**: + +```diagram +┌──────────────────────────────────────────────┐ +│ Brunch context root │ +│ glossary · ADRs · protocols · planning │ +└───────────────┬──────────────────────────────┘ + │ + ┌────────────┼─────────────┬──────────────┐ + ▼ ▼ ▼ ▼ + core binding-flue transport-aisdk plugin-gherkin + harness substrate UI wire target policy + └────────────┴─────────────┴──────────────┘ + │ + ▼ + apps/brunch-agent + remote server + │ + ▼ + apps/petrinaut-website + user-facing composition +``` + +### Assessment + +- Package boundaries are coherent and mechanically guarded by the [ratified topology](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/topology.md#L10-L75). +- The durable mechanics exist: ask/reply, settlement and sweep, provenance anchoring, capture storage, Flue binding, and AI SDK transport. +- The product-defining path remains mostly design: the plugin API is intentionally skeletal, and Gherkin is only a one-proposal tracer ([plugin API](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/packages/core/src/plugin.ts#L5-L14), [Gherkin tracer](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/packages/plugin-gherkin/src/index.ts#L43-L54)). +- The live Linear plan has drifted beyond [COORDINATION.md](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md#L14-L65): FE-1476–FE-1482 are unregistered roots, FE-1477 substantially duplicates FE-1440, and several new tickets overlap earlier plugin/demo work. +- Most importantly, FE-1480 assumes an inferential requirements-graph → SDCPN projection. That conflicts with ADR-0003’s rule that projections are deterministic over register 2 and semantic inference occurs only through contestable captures ([decision](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/adr/0003-three-register-ir.md#L24-L49)). + +### Recommendation + +Next: an `arc-map` review of the September milestone—but first settle that projection boundary. Afterwards we can reconcile the demo story, dependencies, and duplicate tickets. + +Opening question: + +**Where should the non-deterministic requirements → SDCPN judgment live?** + +1. **Preserve ADR-0003:** the LLM emits explicit, provenance-bearing formalization captures; folding and SDCPN projection remain pure. +2. **Amend ADR-0003:** projection itself may infer, requiring an auditable and reproducible projection-run model. + +My initial recommendation is **1**. Is that still your intended architecture? + +## User + +To your points: + +- yes, there are new tickets, drafted by my PM Dora, which we must adopt and fold-in to our graph +- package boundaries are in place yes; but implementation boundaries and paths are only traced so far, and this needs serious attention +- and yes FE-1480 will require discussion (as will other issues) + +Before we address those things, let me give you the high-level concerns that are on my mind, as other entrypoints: + +- the integration with the petrinaut demo website is only the thinnest of tracer bullets so far; completing the full contract layers here will bloom in to much larger scopes +- we haven't even begun `plugin-cps`, which is the actual thing we need to build a critical demo around, very soon (2 weeks in human time) +- the current design for the elicitor architecture seems sound; but its rigor may be at cross-purposes with establishing an e2e working model as fast as we can +- IMO the current issue topology/graph likely does not inherently express the goals we need to be driving at + +## Assistant + +Those concerns point to one underlying problem: the current plan is organized around **contract completion**, while the urgent objective is a **demo-capable vertical system**. That makes locally sensible work compete with global time-to-proof. + +I think the review should separate what must stay rigorous from what may remain deliberately narrow for two weeks, then rebuild the dependency graph around the demonstrated outcome. + +## Assistant + +Your diagnosis matches mine. The tension is less **rigor versus speed** than **generality versus speed**. + +We should retain rigor at irreversible boundaries—provenance, capture correction, real application wiring, valid SDCPN output—and defer broad genericity: complete plugin SDK, full CPS ontology, every affordance, multi-target validation, and contract freeze. + +I’d reshape the plan around vertical proofs: + +```diagram +Fixture captures ─▶ CPS model ─▶ valid SDCPN + │ +Live correction ─▶ supersession ─▶ changed SDCPN + │ +Net element ─▶ model slot ─▶ capture ─▶ user evidence + │ + real Petrinaut demo website +``` + +Existing capability tickets become constraints and inputs, not the primary execution sequence. FE-1476 should likely own the demo outcome, with FE-1477–FE-1482 folded beneath it and reconciled against FE-1393/1402/1403/1438/1440/1442. + +The first decisive question: + +**Is FE-1476 now the authoritative demo contract, replacing cold-start comprehensive elicitation with the prebuilt-model → provenance → targeted revision story?** + +My recommendation: **yes**. Otherwise we are planning two demos in two weeks. This would remove full cold-start elicitation and comprehensive completion accounting from the critical path unless they are still explicitly required. + +## User + +This essential line of reasoning is correct; but may still be working on too-thin signals. The core concern that exhibits the tension between the priorities of correct/complete vs "works effective e2e" is the actual elicitor architecture, and I think we should work through a fuller evaluation of this, to understand what's really on the critical path and what's not + +## Assistant + +Agreed. We should not infer the critical path from ticket titles or the demo script yet. We need to evaluate the elicitor as a system: trace each runtime responsibility from user turn to durable assertion, model, projection, and UI effect; then distinguish **missing load-bearing behavior** from merely incomplete contract breadth. + +I’ll assess the traced layers for role completeness, contract coverage, and fidelity to the proposed architecture before we resume prioritization. + +## Assistant + +One concrete issue is already emerging: the implemented loop can interview and append provenance-safe captures, but it cannot yet *reason over the target-document it has built*. The binding gives the model generic ask/sweep instructions; the private sweep sees conversation text and a proposal schema, but there is no register-2 model, demand state, projection, or plugin guidance feeding the next turn. + +I’m checking the correction and projection seams now, because the new demo requires the loop to revise existing knowledge—not merely capture new statements. + +### Readiness Map: Elicitor architecture + +**Verdict:** the substrate and capture foundation is strong, but the system is only tracer-complete. The implemented path currently terminates at captures: + +```diagram +Implemented +─────────── +User ─▶ agent ─▶ ask/reply ─▶ settlement ─▶ sweep ─▶ durable captures + │ + └── dead end + +Designed but absent +─────────────────── +captures ─▶ fold ─▶ elicited model ─┬─▶ completion/gaps ─▶ next-question policy + ├─▶ SDCPN projection ─▶ Petrinaut + └─▶ provenance map ─▶ targeted revision +``` + +| Layer | Readiness | Critical-path judgment | +|---|---|---| +| Ask/suspend/transport | Mechanically substantial | Foundation ready; broader affordances are deferrable | +| Sweep/capture/provenance | Mechanically substantial | Foundation ready, but not yet usable for revision | +| Model-aware elicitation loop | Absent | **Critical** | +| Register-2 fold/model | Design only | **Critical**, in a deliberately narrow CPS form | +| CPS plugin | Absent | **Critical** | +| SDCPN projection | Design only and contested | **Critical design decision** | +| Petrinaut document application | Ask-only local tracer | **Critical**, but its correct mechanism is unresolved | +| Existing-document/reviewer session | Domain primitives exist; host collapses document to conversation | **Critical** for FE-1476 | +| Artifact provenance and scoped re-elicitation | Store primitives only | **Critical** for FE-1478/1479 | +| Generic plugin authoring, completion, loss reporting, full catalog | Design only | Mostly deferrable unless selected by the demo story | +| Public durability/security/deployment | Partial | Critical only after the functional loop exists | + +#### Important architectural findings + +1. **The elicitor does not yet consult what it has elicited.** + Sweep extraction receives conversation text and proposal names, not active captures, issues, or a derived model ([binding](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/packages/binding-flue/src/index.ts#L138-L227)). Consequently, no model state can steer the next question. + +2. **Targeted correction is not reachable.** + The store rigorously supports `supersedes`, but extraction cannot see the active capture IDs it must reference. The current Gherkin schema cannot emit `supersedes` either. + +3. **The planned projection and client-tool paths potentially duplicate semantic authority.** + The plugin design says register 2 projects to a canonical SDCPN. FE-1438 instead has the agent manipulate Petrinaut through browser tools. If both perform modelling judgments, provenance and reproducibility break. We must separate: + - semantic projection: model → SDCPN; + - application: SDCPN/diff → live document; + - optional repair: diagnostics → revised projection. + +4. **The reviewer workflow needs a real target-document boundary.** + The domain model supports multiple sessions against one document, but the current host maps `targetDocumentId` directly from `conversationId` ([current mapping](file:///Users/lunelson/Code/hashintel/hash/apps/brunch-agent/src/petrinaut-chat.ts#L31-L45)). FE-1476 requires a reviewer session reopening an existing elicitation. + +5. **The generic plugin architecture may be premature, but its fundamental registers are not.** + We probably need captures → model → projection for provenance and revision. We probably do **not** need the complete declarative meta-schema, generic fold algebra, Gherkin-first SDK, all CPS proposal kinds, and contract freeze before proving one CPS path. + +My resulting hypothesis is: + +> Preserve the three-register architecture, but let the first CPS implementation discover the executable plugin boundary instead of completing the generic plugin framework first. + +The next unresolved design area is therefore the **semantic materialization boundary**: concrete CPS fold, projection ownership, provenance mapping, and how the resulting artifact enters Petrinaut. + +**Routing**: where should we go next? + +1. **Explore module shape (Recommended)** — design two competing executable shapes for that semantic boundary. +2. **Design verification** — first define the minimum end-to-end proof and its oracles. +3. **Back to triage** — continue auditing other architectural layers before choosing a boundary. + +Reply **1–3**, or redirect the review. + +## User + +Those routing options are good; but let's keep discussing for now. + +FWIW, your observations match my intuition and my suspicions. + +I must say, that tracer discpline has been a real double-edged sword: it's been a very common for the agent to take the tracer as the "definition of done" and for the actual implementation to be essentially left not only incomplete but barely started. + +I think your essential prioritization and plan-shape is correct; but we're going to need a new protocol for representing and driving that kind of plan or it's going to evaporate after this session: the `COORDINATION.md` doc is nice, but right now only tracks the issue-graph topology with a bias toward _what is mechanically next_ i.e. unblocked, while not having any way to track an actual strategic execution plan, which should rather be objective-driven, epistemically-tracked and with the issue-graph as a sequencing and trade-off surface + +I want to offer the mental model I have of the elicitor architecture so far, which I had skethed out before starting this thread, and which you can also therefore analyze as both a proposal and and an inventory, and help me determine where I have gaps or weak layers. So far, I think of it in roughly four parts, which belong to two essential layers (there are more layers than these two but these are the two with real architectural design pressure and which are currently hollow) + +1. __harness layer: elicitation agentics__. the prompting and skilling parts, general to all elicitations: + - orientations, motivations, licenses + - interviewing/question-formulation guidance +2. __harness layer: capture mechanics and agentics__. the capture mechanics so far; but lacking further build-out, as you've observed + - evidence sweeping and logging mechanism; with annotations re: supersession, conflicts etc. + - next-question ledger and loop? + - mapping plugin-defined types from utterances: entities (nodes), relations (edges), quantities, conditionalities +3. __plugin layer: typologies, critical points and motifs, ...?__. the things for the capture parts to be aware of + - what entities are we after + - what shapes and relations do they have +4. __plugin: runbook (objectives, trajectories, boundaries)__. this is the least sketched part so far IMO, and so "runbook" is a proposal at this point, about how the rest of the plugin manifest could actually be shaped + - the job + - what 'done' looks like + - how to check + - ... (what else?) + +## Assistant + +Your model is sound. I would make two refinements: + +1. Separate the **elicitation controller** from capture mechanics. +2. Separate the plugin’s static **runbook** from the dynamic **engagement brief** it produces for one target-document. + +```diagram + HARNESS +┌─────────────────────────────────────────────┐ +│ Strategy repertoire │ +│ orientations · techniques · licenses │ +└───────────────────┬─────────────────────────┘ + ▼ +┌─────────────────────────────────────────────┐ +│ Elicitation controller │ +│ assess situation · choose move · stop/replan│ +└───────▲───────────────────────────┬─────────┘ + │ ▼ +┌───────┴───────────────┐ ask · propose · validate +│ Evidence engine │ +│ sweep · capture · │ +│ supersede · resolve │ +└──────────┬────────────┘ + │ assertions + ▼ + PLUGIN +┌─────────────────────────────────────────────┐ +│ Domain contract │ +│ proposals · model · fold · diagnostics · │ +│ projection · provenance │ +└──────────▲──────────────────────────────────┘ + │ model state and gaps +┌──────────┴──────────────────────────────────┐ +│ Job runbook │ +│ objectives · trajectory · checks · stopping │ +└─────────────────────────────────────────────┘ +``` + +### 1. Harness: strategy repertoire + +Your contents fit, with one qualification: + +- **Orientations**: generic role and epistemic posture. +- **Licenses**: re-ask, challenge, propose for correction, expose assumptions. +- **Techniques**: contrastive questions, incident reconstruction, quantile elicitation. +- **Question formulation guidance**: generic forms only. + +The harness should define these capabilities, but not decide when domain-specific questions matter. Prompting and Flue skills are their delivery mechanism—not the architectural concepts themselves. + +**Current weakness:** the generic quiver is named but not designed. More importantly, there is no module composing its strategies into a coherent engagement. + +### 2. Harness: evidence engine + +This should own: + +- conversation archive and evidence classification; +- settlement and sweep execution; +- capture envelope and provenance; +- atomic application; +- issues, conflicts, supersession and retraction; +- invocation of plugin-defined proposal extraction. + +But two items in your list sit elsewhere: + +- **“Next-question ledger and loop” belongs to the controller.** +- **Entities, relations and conditionalities belong to plugin vocabulary.** The harness executes schema-constrained extraction; the plugin defines what can be extracted. Quantities may come from a shared stated-form library, but should not become universal harness ontology. + +A useful decomposition is: + +```diagram +Model demand ─▶ knowledge gap ─▶ candidate move ─▶ chosen move ─▶ concrete ask + derived derived derived session state transcript +``` + +The “ledger” should mostly be derived, not persisted. Persist the selected trajectory or active commitment only when continuity requires it; otherwise stale agendas will compete with the current model. + +**Current weakness:** the evidence engine writes captures but provides no read path back into an elicitation controller. It is an append-capable substrate, not yet a closed loop. + +### 3. Plugin: domain contract + +This is broader than “what entities are we after.” It owns: + +- model node kinds, slots and relations; +- utterance-shaped proposal catalog; +- fold and identity semantics; +- grade and conflict semantics; +- domain validators and diagnostics; +- projection into artifacts; +- artifact-element → model-slot → capture provenance mapping. + +I would place your concepts as follows: + +- **Typologies** → model/proposal schemas. +- **Critical points** → derived diagnostics and question triggers. +- **Motifs** → runbook hypotheses or questioning scaffolds, not model facts unless the user confirms them. + +The existing “two schemas, two tables” design covers much of this, but is probably overcommitted to a generic authoring representation before one real CPS model works. + +### 4. Plugin: runbook + +“Runbook” is a good provisional name because it adds time, direction and judgment to the current `ElicitationPack`, which is otherwise mostly a bag of cards and checks ([current contract](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/spec.md#L531-L550)). + +A runbook likely needs: + +- **Supported job**: build, review, explain, or revise. +- **Kickoff contract**: objective, intended use, scope, audience, available effort. +- **Trajectory**: orient → skeleton → deepen → cross-examine → validate → hand off. +- **Priority policy**: objective relevance, information gain, dependency, user effort and risk. +- **Demand/completion rules**: what knowledge is required and to what grade. +- **Challenge checks**: contradictions, ungrounded assumptions, missing boundaries, invalid projections. +- **Stopping outcomes**: sufficient, useful-partial, stalled, budget-exhausted, user-stopped. +- **Default/inference policy**: what may be proposed, defaulted, inferred or must be asked. +- **Revision policy**: how to scope targeted re-elicitation and determine affected projections. +- **Output/handoff contract**: artifacts, provenance, visible gaps and validation results. +- **Recovery policy**: re-entry after another session or changed target-document. + +However, “the job” is not wholly static plugin content. The plugin offers a runbook template; kickoff creates an **engagement brief** containing the actual objective, boundaries, appetite and selected trajectory. + +### The largest missing architectural role + +The current design contains pieces of the controller—`demandRunner`, `affordanceCuer`, `firesWhen`, completion—but no interface unifying them. The controller must read: + +```text +engagement brief ++ current model and open issues ++ runbook ++ available generic strategies ++ recent conversation state +``` + +and produce a bounded next move: + +```text +ask | propose | contrast | validate | project | explain | stop +``` + +That is the hollow center between “we captured facts” and “we conducted an effective elicitation.” + +There is a parallel planning insight here: **the issue graph is analogous to the capture store**—durable inventory and dependencies, but not an execution strategy. `COORDINATION.md` is a projection over that inventory. A separate strategic plan must act like the controller/runbook: objective, current model of reality, confidence, current bet, proof spine, issue mapping and replanning triggers. + +The next architectural question I would examine is: + +> Does a plugin have one runbook, or a family of job-specific runbooks sharing one domain contract? + +My recommendation is the latter. For CPS, at least **cold-start construction** and **review-and-revise** have different kickoff, trajectory and stopping conditions. The September demo can then implement one honest `review-and-revise` runbook without pretending the complete CPS elicitor already exists. + +## User + +I agree a plugin could define multiple runbooks, that makes sense. And yes the planning insight echoes the gaps we're seeing in teh implementation. The planning itself needs a kind of "runbook" as well, in effect. The routines we've instituted so far here around the COORDINATION.md doc are just one part of that surface, and that surface should be the central sense-making tool for running the project + +## Assistant + +Exactly. **Unblocked is a property of the work graph, not a reason to perform work.** The missing surface must decide what matters next from objectives, evidence, risk and time. + +```diagram +Code/tests/docs/Linear + │ evidence + ▼ +┌──────────────────────────┐ +│ Strategic execution model│ +│ objective · current truth│ +│ bets · proof spine · risk│ +└────────────┬─────────────┘ + │ selects and scopes + ▼ + Issue graph / work + │ + └──── new evidence ────┘ +``` + +The existing artifacts each retain a narrower authority: + +- **Linear:** issue state and hard dependency truth. +- **COORDINATION.md:** topology, soft edges, seams and registry integrity. +- **SPEC-LEDGER.md:** implementation against settled obligations. +- **ADRs/specs:** durable design truth. +- **New strategic surface:** current objective, execution strategy, priority and confidence. + +### What the central surface should contain + +#### 1. Milestone contract + +- Outcome being pursued. +- Observable proof. +- Deadline and audience. +- Explicitly excluded outcomes. +- Which product claims must be honest versus merely demonstrated narrowly. + +#### 2. Current system model + +Not “tickets completed,” but: + +- what genuinely works end-to-end; +- which layers are tracer-only; +- which responsibilities are absent; +- external facts and constraints; +- assumptions with confidence and supporting evidence. + +#### 3. Current strategic bet + +A concise theory such as: + +> Preserve the three-register architecture, prove one CPS review-and-revise runbook concretely, and allow that implementation to determine the generic plugin interface. + +It should state why this bet beats alternatives and what evidence would reverse it. + +#### 4. Proof spine + +Proof obligations, not issues: + +```text +P1 CPS captures derive a model and valid SDCPN with provenance +P2 A reviewer session opens the existing target-document +P3 One scoped correction supersedes evidence and changes the model +P4 Reprojection changes the live Petrinaut net +P5 A provenance question reaches net → model → capture → utterance +P6 The complete path runs through the deployed demo surface +``` + +Each proof carries: + +- certainty; +- missing knowledge; +- acceptance oracle; +- mapped issues; +- dependencies—functional and epistemic; +- replan trigger. + +#### 5. Strategic frontiers + +“Now / next” chosen from the proof spine, with a reason. An issue being unblocked only makes it *eligible*. + +A frontier entry should answer: + +- Why now? +- What uncertainty or capability does it retire? +- What becomes possible after it? +- What is the smallest honest proof? +- Which adjacent work remains deliberately deferred? + +#### 6. Issue projection + +Map issues onto proofs many-to-many. This is where Dora’s tickets are adopted without allowing their initial decomposition to dictate implementation architecture. + +It should expose: + +- duplicate or overlapping tickets; +- tickets that contribute to no current proof; +- proofs with no owned work; +- scope that should move between tickets; +- trade-offs created by sequencing. + +#### 7. Learning and replanning + +Record only consequential shifts: + +- evidence observed; +- assumption promoted, weakened or falsified; +- confidence change; +- resulting strategy or sequence change. + +### Operating protocol + +1. **Orient:** read the strategic surface, then query live issue state. +2. **Select:** choose the frontier with the highest closure or information gain—not the lowest issue number. +3. **Scope:** define the smallest proof-producing slice. +4. **Execute and verify.** +5. **Reconcile:** update evidence, confidence, proof status and issue topology. +6. **Replan when a named trigger fires.** + +I would not design this protocol abstractly first. The September demo should be its first worked instance. We can construct the real strategic surface around the elicitor architecture, use it through at least one replan, and only then extract a reusable schema or skill. + +## User + +Agreed. I don't know yet what this is called; but it's not a roadmap, and not a blueprint, and not the spec either (we can have multiple specs anyway, at different levels) + +It's the thing that tracks objectives, evidence, risk and time -- but strategically, which is to say it continually evaluates the former against the latter: achieving objectives/obligations _UNDER_ constraints, limitations, pressures, unknowns. It consumes specs as one input and uses issues as a planning surface. + +We can model this protocol as we use it. A combination of document structure (perhaps templated?) and perhaps local agent-skills might be necessary, as we go + +## Assistant + +I think the core concept is **steering**. + +- **Steering model** — the current strategic understanding of objectives, position, constraints, evidence, risks and bets. +- **Steering surface** — the document plus tools through which people and agents inspect and update that model. +- **Steering protocol** — the recurring orient → choose → execute → reconcile → replan loop. + +`STEERING.md` would be a plausible provisional name. Unlike a roadmap, steering is explicitly feedback-driven: it continually adjusts the route against observed conditions. + +### Proposed structure + +```md +## Project steering + +### Mission +Outcome, obligations, proof, audience, deadline. + +### Current position +What is proved, tracer-only, absent, contradicted or unknown. + +### Pressures and constraints +Deadline, capacity, external dependencies, non-negotiable invariants. + +### Current strategy +The active bet, why it is preferred, and alternatives rejected for now. + +### Proof spine +The ordered capabilities or claims that must be demonstrated. + +### Active frontiers +The next proof-producing moves, why now, and what they unlock. + +### Risks, assumptions and unknowns +Confidence, evidence, consequence, retirement test and fallback. + +### Commitments and cut lines +Must / should / stretch / defer, with dates or evidence that trigger cuts. + +### Issue projection +Issues mapped onto objectives and proofs; overlaps, gaps and trade-offs. +Links to the live coordination graph rather than mirroring its state. + +### Replan triggers +Events that require reconsidering the strategy. + +### Recent confidence shifts +Only consequential learning; stable truth graduates elsewhere. +``` + +The key vocabulary could be: + +- **Objective:** desired outcome. +- **Obligation:** condition that must remain true. +- **Constraint:** unavailable or prohibited option. +- **Pressure:** fact that changes trade-offs, such as time. +- **Unknown:** material unanswered question. +- **Risk:** uncertain adverse outcome. +- **Bet:** chosen strategy under uncertainty. +- **Proof:** evidence that supports an objective or retires risk. +- **Frontier:** strategically selected next proof—not merely unblocked work. +- **Cut line:** condition under which scope is reduced or fallback selected. + +### Relationship to existing artifacts + +```diagram +Specs / ADRs ───────▶ obligations and design truth +Code / tests ───────▶ implementation evidence +Linear ─────────────▶ work inventory and hard dependencies +COORDINATION.md ────▶ issue topology, seams and registry + │ + ▼ + STEERING.md + strategy and next action +``` + +I would keep `COORDINATION.md` narrow rather than expanding it indefinitely. The steering surface consumes its graph projection while owning priority and rationale. + +### Adoption approach + +Start with the document and run it manually for the September effort. Avoid building a family of skills before the operating loop has been exercised. + +After a few real updates, stable routines could become local skills: + +1. **Orient** — assemble current evidence and identify drift. +2. **Steer** — select or revise the strategic frontier. +3. **Reconcile** — incorporate completed work and confidence shifts. +4. **Pressure-test** — challenge the proof spine, assumptions and cut lines. + +“Steering” is my strongest candidate, but I would treat the name as provisional until we use the model on the current elicitor plan. + +## User + +I like it. Let's run it on the current plan, both the explict (existing) parts and the implicit/projected ones per your observations in this thread. Let the September Demo effort's own content be the driver of the document structure, at least on this first pass (don't let our imagined headings and ontologies become forms to be filled for their own sake). Run it all past the elicitor when you're done for a sanity and comprehensiveness check WRT our findings and decisions above + +## Assistant + +*(cancelled)* + +I’ll create the first steering artifact as an evidence-backed September execution model, not a generic template. It will reconcile the existing coordination/spec/issue material with the architectural gaps established here, while leaving Linear state unchanged. + +I’ll then audit it against the actual elicitor flow and its missing feedback loops. The current Brunch agent cannot itself perform that strategic review, so I’m interpreting “past the elicitor” as a systematic check against the elicitor + +## User + +Sorry I meant "run it all past the oracle when you're done..." above, not the "elicitor" + +## Assistant + +Understood—I’ll draft the steering artifact, self-review it against the elicitor architecture and live plan, then ask Oracle for an independent sanity and comprehensiveness review before finalizing it. + +## Assistant + +I’m turning the discussion into a live steering model, not a generic planning template. Its center will be the September reviewer loop, with the current architecture and issue graph treated as evidence and constraints rather than as the plan itself. + +**Tool Use:** `shell_command` + +```json +{ + "command": "rg -n \"captureStore\\.read|captureStore|targetDocumentIdFor|conversationId|supersedes|active.*head|proposal\" packages/binding-flue/src/index.ts packages/core/src apps/brunch-agent/src/petrinaut-chat.ts 2>/dev/null | head -160", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "rg -n \"client tool|tool-result|tool result|brunch_ask|readPetrinaut|write|apply|Petrinaut\" libs/@hashintel/brunch-agent/packages/transport-aisdk/src apps/brunch-agent/src apps/petrinaut-website/src 2>/dev/null | head -200", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "rg -n \"ElicitationPack|completion|cards|schema|fold|demand|projection\" libs/@hashintel/brunch-agent/packages/core/src libs/@hashintel/brunch-agent/packages/plugin-gherkin/src | head -220", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "git status --short -- docs/INDEX.md docs/planning/_shared/COORDINATION.md docs/planning/_shared/STEERING.md; printf '%s\\n' '--- all worktree status ---'; git status --short", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CeZJSBoqePV9R2KWIqc` + +``` +{ + "output": "apps/brunch-agent/src/petrinaut-chat.ts:33:const targetDocumentIdFor = (conversationId: string): string =>\napps/brunch-agent/src/petrinaut-chat.ts:34: `petrinaut-local:${conversationId}`;\napps/brunch-agent/src/petrinaut-chat.ts:37: conversationId: string,\napps/brunch-agent/src/petrinaut-chat.ts:41: const agent = init(GherkinElicitor, { id: conversationId });\napps/brunch-agent/src/petrinaut-chat.ts:44: initialData: { targetDocumentId: targetDocumentIdFor(conversationId) },\napps/brunch-agent/src/petrinaut-chat.ts:64: input.conversationId,\napps/brunch-agent/src/petrinaut-chat.ts:74: input.conversationId,\napps/brunch-agent/src/petrinaut-chat.ts:75: targetDocumentIdFor(input.conversationId),\napps/brunch-agent/src/petrinaut-chat.ts:78: await session.historyReader.peek(input.conversationId),\napps/brunch-agent/src/petrinaut-chat.ts:89: input.conversationId,\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CeZJSg2bY9mqNZsXPSL` + +``` +{ + "output": "libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:136: * Ask-return support. Absent, every tool-result follow-up stays refused\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:179: readonly reason: \"tool-result-follow-up-not-supported\";\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:196: reason: \"tool-result-follow-up-not-supported\",\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:261: * Classify one tool-result follow-up POST. A human answer submitted through\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:263: * machine tool result: exactly one submitted `brunch_ask` output on the\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:265: * Petrinaut mutation outputs, the synthetic diagnostics message — remains\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:587: execute: async ({ writer }) => {\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:592: // panel as an awaiting client tool, and the harness's own output\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:600: writer.write({\nlibs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts:626: writer.write(toUiChunk(wireEvent));\napps/petrinaut-website/src/main/app/brunch-demo/brunch-petrinaut.tsx:8:import { Petrinaut, type ViewportAction } from \"@hashintel/petrinaut/ui\";\napps/petrinaut-website/src/main/app/brunch-demo/brunch-petrinaut.tsx:14: PetrinautDocHandle,\napps/petrinaut-website/src/main/app/brunch-demo/brunch-petrinaut.tsx:21:const BrunchPetrinautWithHandle = ({\napps/petrinaut-website/src/main/app/brunch-demo/brunch-petrinaut.tsx:32: const [handle] = useState(() =>\napps/petrinaut-website/src/main/app/brunch-demo/brunch-petrinaut.tsx:46: \napps/brunch-agent/src/petrinaut-chat.ts:1:/** Application composition for Petrinaut's stock AI SDK chat transport. */\napps/petrinaut-website/src/main/app/brunch-demo/brunch-frame-parsers.ts:50: * Brunch execution-plan shape into a read-only Petrinaut SDCPN for rendering.\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:2: attachPetrinautOptimizationRunStream,\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:3: createPetrinautOptimizerClient,\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:4: PetrinautOptimizerHttpError,\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:9: PetrinautOptimization,\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:10: PetrinautOptimizationEvent,\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:12:import type { PetrinautOptimizerFetch } from \"@local/petrinaut-optimizer-client\";\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:15: * Dev-proxy base for the local Petrinaut Optimizer: `vite.config.ts` rewrites\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:27: * Stamp the duck-typed classification fields Petrinaut's optimization\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:33: error instanceof PetrinautOptimizerHttpError\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:66: error instanceof PetrinautOptimizerHttpError\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:72:/** Create the local-only Petrinaut capability backed directly by Python. */\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:73:export const createPetrinautOptOptimization = (\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:74: fetchImpl: PetrinautOptimizerFetch = fetch,\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:75:): PetrinautOptimization => {\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:76: const client = createPetrinautOptimizerClient(\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:100: let events: AsyncIterable;\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.ts:102: ({ events } = await attachPetrinautOptimizationRunStream({\napps/petrinaut-website/src/main/app/brunch-demo/brunch-status-page.tsx:58: Back to Petrinaut\napps/petrinaut-website/src/main/app/brunch-demo/brunch-protocol.ts:45: * This is intentionally not Petrinaut's full SDCPN document format. It only\napps/petrinaut-website/src/main/app/brunch-demo/brunch-protocol.ts:53: * creating a read-only handle with Petrinaut extensions disabled.\napps/petrinaut-website/src/main/app/brunch-demo/brunch-protocol.ts:56: * Brunch/Petrinaut protocol once that protocol is owned in Petrinaut Core.\napps/brunch-agent/src/routes.ts:4:/** Stock `DefaultChatTransport` endpoint used by Petrinaut's local panel. */\napps/petrinaut-website/src/main/app/brunch-demo/brunch-route.ts:2: * This is temporary, until Petrinaut Demo app gets a real Router.\napps/brunch-agent/src/agents/gherkin-elicitor.ts:54: * demo shell is chartered to mount this library alongside the Petrinaut\napps/petrinaut-website/src/main/app/optimization-demo/optimization-demo-app.tsx:2:import { PetrinautOptOptimizationProvider } from \"./petrinaut-opt-optimization-provider\";\napps/petrinaut-website/src/main/app/optimization-demo/optimization-demo-app.tsx:5: \napps/petrinaut-website/src/main/app/optimization-demo/optimization-demo-app.tsx:7: \napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.test.ts:3:import { createPetrinautOptOptimization } from \"./petrinaut-opt-optimization\";\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.test.ts:5:import type { PetrinautOptimizationInput } from \"@hashintel/petrinaut-core\";\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.test.ts:10:} as PetrinautOptimizationInput;\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.test.ts:12:describe(\"createPetrinautOptOptimization\", () => {\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.test.ts:33: const optimization = createPetrinautOptOptimization(fetchImpl);\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization.test.ts:72: const optimization = createPetrinautOptOptimization(fetchImpl);\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization-provider.tsx:1:import { PetrinautOptimizationContext } from \"@hashintel/petrinaut/react\";\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization-provider.tsx:3:import { createPetrinautOptOptimization } from \"./petrinaut-opt-optimization\";\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization-provider.tsx:7:const petrinautOptOptimization = createPetrinautOptOptimization();\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization-provider.tsx:9:/** Direct Petrinaut Opt integration for the local demo website only. */\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization-provider.tsx:10:export const PetrinautOptOptimizationProvider: FC = ({\napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization-provider.tsx:13: \napps/petrinaut-website/src/main/app/optimization-demo/petrinaut-opt-optimization-provider.tsx:15: \napps/petrinaut-website/src/main/app/local-storage-demo/brunch-ask-interactive-tool.tsx:12: definePetrinautAiInteractiveTool,\napps/petrinaut-website/src/main/app/local-storage-demo/brunch-ask-interactive-tool.tsx:143:export const brunchAskInteractiveTool = definePetrinautAiInteractiveTool({\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:7: type PetrinautDocHandle,\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:8: type PetrinautHandleCapabilities,\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:13: Petrinaut,\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:14: type PetrinautAiChatTransport,\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:15: type PetrinautAiMessage,\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:74:} satisfies PetrinautHandleCapabilities;\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:76:const createHandle = (net: SDCPNInLocalStorage): PetrinautDocHandle =>\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:83:const petrinautAiChatTransport: PetrinautAiChatTransport =\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:100: handle: PetrinautDocHandle;\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:112: * Local-storage demo shell for Petrinaut.\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:115: * Petrinaut document handle owns the currently open net's live editable state.\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:263: onMessages: (messages: PetrinautAiMessage[]) => {\napps/petrinaut-website/src/main/app/local-storage-demo/local-storage-demo-app.tsx:299: ;\napps/petrinaut-website/src/main/app/local-storage-demo/walkthrough/walkthrough-steps.tsx:28: Welcome to Petrinaut\napps/petrinaut-website/src/main/app/local-storage-demo/walkthrough/walkthrough-steps.tsx:34: Petrinaut is a workshop for building, simulating, and\napps/petrinaut-website/src/main/app/local-storage-demo/walkthrough/walkthrough-steps.tsx:46: videoAlt: \"The Petrinaut editor with an example net on the canvas\",\napps/petrinaut-website/src/main/app/local-storage-demo/walkthrough/walkthrough-steps.tsx:59: Petrinaut lets you run experiments on complex\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CeZJT4MsLJLaJGxncm4` + +``` +{ + "output": "libs/@hashintel/brunch-agent/packages/plugin-gherkin/src/index.ts:51: schema: StatementNotedProposal,\nlibs/@hashintel/brunch-agent/packages/core/src/testing/index.ts:41: schema: fixtureProposalSchema,\nlibs/@hashintel/brunch-agent/packages/core/src/session-log.ts:12: /** Stable identity supplied by the substrate's public projection. */\nlibs/@hashintel/brunch-agent/packages/core/src/session-log.ts:24: /** Substrate projection identity, distinct from the harness session id. */\nlibs/@hashintel/brunch-agent/packages/core/src/sweep-protocol.ts:22: proposals: v.array(plugin.proposalCatalog[0].schema),\nlibs/@hashintel/brunch-agent/packages/core/src/sweep-protocol.ts:227: `Use only the declared proposal schema: ${plugin.proposalNames.join(\", \")}. Do not add parsed structure or undeclared proposal types.`,\nlibs/@hashintel/brunch-agent/packages/core/src/sweep-protocol.ts:297: \"Projection and validation are read-time operations; do not treat sweep completion as a stored derived result.\",\nlibs/@hashintel/brunch-agent/packages/core/src/capture-store.ts:294:// Range ordering belongs to this schema rather than to any one caller: every\nlibs/@hashintel/brunch-agent/packages/core/src/capture-store.ts:746: // States what the schema checked, and no more: the spans are structurally\nlibs/@hashintel/brunch-agent/packages/core/src/capture-store.ts:748: // having been resolved against an entry projection.\nlibs/@hashintel/brunch-agent/packages/core/src/capture-store.ts:1111: // Through the same schema a persisted issue is read with, so a command\nlibs/@hashintel/brunch-agent/packages/core/src/capture-store.ts:1131: // than in the schema: a closed conflict's captures are legitimately\nlibs/@hashintel/brunch-agent/packages/core/src/plugin.ts:11: * target has stressed it, so nothing in this scaffold ratifies the SDK export\nlibs/@hashintel/brunch-agent/packages/core/src/plugin.ts:29: readonly schema: v.GenericSchema;\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CeZJTSUcr5qWmnMmPHy` + +``` +{ + "output": "--- all worktree status ---\n M libs/@hashintel/brunch-agent/docs/agents/git-workflow.md\n M libs/@hashintel/brunch-agent/docs/agents/issue-writing.md\n M libs/@hashintel/brunch-agent/docs/agents/legibility.md\n M libs/@hashintel/brunch-agent/docs/planning/_shared/hash-monorepo-import-plan.md\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "sed -n '1,240p' packages/core/src/plugin.ts; sed -n '180,340p' packages/core/src/sweep-protocol.ts", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "rg -n \"captureStore|sweep|archive|read\\(\" packages/binding-flue/src/index.ts; sed -n '300,560p' packages/binding-flue/src/index.ts", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "sed -n '1,120p' ../../../apps/brunch-agent/src/petrinaut-chat.ts; sed -n '240,290p' packages/transport-aisdk/src/index.ts; sed -n '120,210p' packages/transport-aisdk/src/index.ts", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "sed -n '1,120p' packages/plugin-gherkin/src/index.ts; sed -n '1,170p' ../../../apps/brunch-agent/src/agents/gherkin-elicitor.ts", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CeZZ7NzVgHV9ojR89cd` + +``` +{ + "output": "import * as v from \"valibot\";\n\nimport type { CaptureInputProposal } from \"./capture-store\";\n\n/**\n * The plugin descriptor — identity only, at this stage.\n *\n * The plugin's real surface is its packs and the four operations (spec §6.1,\n * §11.1). Those are **deliberately absent here**: spec §13's two-targets rule\n * says the trivial target must not freeze the plugin contract before the hard\n * target has stressed it, so nothing in this scaffold ratifies the SDK export\n * surface. What the descriptor fixes now is only what the topology needs —\n * that a plugin declares which target-domain it defines, and does so through\n * Valibot like every other boundary in the system (spec §12.4).\n */\nexport const PluginDescriptor = v.object({\n /** Package-level identity, matching the `plugin-*` role prefix (spec §12.2). */\n name: v.pipe(\n v.string(),\n v.regex(/^plugin-[a-z][a-z0-9-]*$/, \"expected a `plugin-` name\"),\n ),\n /** The artifact family this plugin elicits — gherkin scenarios, assurance arguments. */\n targetDomain: v.pipe(v.string(), v.nonEmpty()),\n});\n\nexport interface PluginProposalType {\n readonly name: string;\n readonly description: string;\n readonly schema: v.GenericSchema;\n}\n\nexport type Plugin = v.InferOutput & {\n /** FE-1392's declared floor; FE-1393 grows the catalog and SDK around it. */\n readonly proposalCatalog: readonly [PluginProposalType];\n};\n\n/**\n * Declare a plugin. Inversion of control (spec §4): the plugin declares and\n * registers; the harness discovers, orders, and invokes. Nothing a plugin\n * declares can reach persistence — the storage port is harness-defined and\n * binding-implemented, and plugins are storage-blind (spec §9.6).\n */\nexport function definePlugin(descriptor: Plugin): Plugin {\n const identity = v.parse(PluginDescriptor, descriptor);\n const [proposal, ...extraProposals] = descriptor.proposalCatalog;\n if (!proposal || extraProposals.length > 0) {\n throw new TypeError(\n \"This slice requires exactly one declared proposal type.\",\n );\n }\n const name = v.parse(v.pipe(v.string(), v.nonEmpty()), proposal.name);\n const description = v.parse(\n v.pipe(v.string(), v.nonEmpty()),\n proposal.description,\n );\n return {\n ...identity,\n proposalCatalog: [{ ...proposal, name, description }],\n };\n}\n ...parsedState,\n lastCheckedUserEntryId: parsedState.sweptThroughUserEntryId,\n });\n};\n\nconst renderEntry = (entry: SweepSessionEntry): readonly string[] => {\n const rendered: string[] = [];\n for (const affordance of entry.affordances ?? []) {\n rendered.push(`[assistant ask] ${affordance.markdown}`);\n }\n if (entry.text.length > 0) {\n const label = isTrueUserEntry(entry) ? \"user\" : entry.kind;\n rendered.push(`[${label}] ${entry.text}`);\n }\n return rendered;\n};\n\nconst renderTail = (tail: readonly SweepSessionEntry[]): string =>\n tail.flatMap(renderEntry).join(\"\\n\");\n\nexport interface SettlementCheckSignal {\n readonly type: \"settlement-check\";\n readonly tagName: \"settlement-check\";\n readonly body: string;\n}\n\nexport const buildSettlementCheckSignal = (\n tail: readonly SweepSessionEntry[],\n): SettlementCheckSignal => ({\n type: \"settlement-check\",\n tagName: \"settlement-check\",\n body: [\n \"The harness computed this unswept conversation tail:\",\n renderTail(tail),\n `Judge whether this range has settled. If it has, call ${toolName(\"sweep\")}. Declining is legal; continue the interview when the topic is still open.`,\n ].join(\"\\n\\n\"),\n});\n\nexport const buildSweepExtractionPrompt = (\n plugin: {\n readonly targetDomain: string;\n readonly proposalNames: readonly string[];\n },\n tail: readonly SweepSessionEntry[],\n): string =>\n [\n `Extract capture proposals for the ${plugin.targetDomain} target from this settled conversation range.`,\n `Use only the declared proposal schema: ${plugin.proposalNames.join(\", \")}. Do not add parsed structure or undeclared proposal types.`,\n \"Every user-grounded proposal must cite one or more exact verbatim quotes from the user lines below. Never supply entry ids, ranges, pointers, or evidence sources; the harness resolves those.\",\n \"The declared verbatim interior must preserve what was said without paraphrase or normalization. Return an empty proposal list when no honest capture is available.\",\n renderTail(tail),\n ].join(\"\\n\\n\");\n\nexport interface SweepRepairSignal {\n readonly type: \"sweep-repair\";\n readonly tagName: \"sweep-repair\";\n readonly body: string;\n}\n\nexport const buildSweepRepairSignal = (\n refusal: Pick | SweepRefusalFact,\n): SweepRepairSignal => ({\n type: \"sweep-repair\",\n tagName: \"sweep-repair\",\n body: `The sweep was refused: ${refusal.message} Repair the proposal and call ${toolName(\"sweep\")} again. Declining is legal.`,\n});\n\nexport const pendingSweepRepair = (\n entries: readonly SweepSessionEntry[],\n): SweepRefusalFact | null => {\n let pending: SweepRefusalFact | null = null;\n for (const entry of entries) {\n if (entry.sweepRepairSignal) pending = null;\n if (entry.sweepResult?.status === \"refused\" && entry.sweepResult.refusal) {\n pending = entry.sweepResult.refusal;\n } else if (entry.sweepResult && entry.sweepResult.status !== \"refused\") {\n pending = null;\n }\n }\n return pending;\n};\n\nexport interface UnaccountedAskAdvisory {\n readonly type: \"unaccounted-ask\";\n readonly affordanceId: string;\n readonly question: string;\n readonly message: string;\n}\n\nexport const computeUnaccountedAskAdvisories = (\n tail: readonly SweepSessionEntry[],\n capturedUserEntryIds: ReadonlySet,\n): readonly UnaccountedAskAdvisory[] => {\n const accountedAffordanceIds = new Set(\n tail.flatMap((entry) =>\n entry.replyToAffordanceId === undefined ||\n !capturedUserEntryIds.has(entry.id)\n ? []\n : [entry.replyToAffordanceId],\n ),\n );\n return tail.flatMap((entry) =>\n (entry.affordances ?? [])\n .filter((affordance) => !accountedAffordanceIds.has(affordance.id))\n .map((affordance) => ({\n type: \"unaccounted-ask\" as const,\n affordanceId: affordance.id,\n question: affordance.markdown,\n message:\n \"The swept range contains an ask with no affordance-bound capture.\",\n })),\n );\n};\n\nexport const settlementProtocolInstructionFragments = (): readonly string[] => [\n \"When the harness reports an unswept tail, judge whether that range has settled. Declining is legal.\",\n `When it has settled, call ${toolName(\"sweep\")}. The harness privately extracts quote-anchored proposals, refreshes durable history, applies them atomically, and advances the swept high-water mark only on success.`,\n \"Projection and validation are read-time operations; do not treat sweep completion as a stored derived result.\",\n];\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CeZZ7m3yMGGMRQHGE53` + +``` +{ + "output": "45: sweepableRange,\n78: readonly captureStore: CaptureStore;\n100: \"sweepHighWater\",\n104: let sweepState = parseSweepState(storedSweepState);\n139: name: toolName(\"sweep\"),\n141: \"Apply or replay the settled conversation prefix. The harness privately extracts quote-anchored captures, refreshes durable history immediately before atomic application, and advances sweep state only on success.\",\n152: const range = sweepableRange(historyAtJudgment);\n159: \"extract-sweep-proposals\",\n178: // archive write makes every quote resolvable before the store sees it.\n181: await session.historyReader.read(session.sessionId),\n184: const applied = await step.do(\"apply-sweep\", () =>\n185: session.captureStore.execute(\n187: type: \"apply-sweep\",\n196: sweepState = reopenSweepAfterRefusal(sweepState);\n197: setSweepState(sweepState);\n203: sweepState = advanceSweepHighWater(sweepState, throughUserEntryId);\n204: setSweepState(sweepState);\n206: session.captureStore,\n246: state: sweepState,\n251: sweepState = decision.nextState;\n252: setSweepState(sweepState);\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CeZZ8SSapF1CCmTDc8k` + +``` +{ + "output": "/** Application composition for Petrinaut's stock AI SDK chat transport. */\n\nimport { init } from \"@flue/runtime\";\n\nimport {\n decideAskReplyAdmission,\n pendingAskAffordanceId,\n} from \"@hashintel/brunch-agent\";\nimport {\n createFlueReplyProjector,\n projectFlueHistoryForSweep,\n} from \"@hashintel/brunch-agent-binding-flue\";\nimport {\n createAiSdkChatHandler,\n type HarnessReplyEvent,\n type TransportInspectionEvent,\n} from \"@hashintel/brunch-agent-transport-aisdk\";\n\nimport { GherkinElicitor } from \"./agents/gherkin-elicitor.ts\";\nimport { createGherkinElicitationSession } from \"./elicitation-session.ts\";\n\nconst inspect =\n process.env.BRUNCH_TRANSPORT_AISDK_INSPECT === \"1\"\n ? (event: TransportInspectionEvent): void => {\n // This is an opt-in shell diagnostic stream. It is never dispatched\n // into Flue and therefore cannot become elicitation evidence.\n console.log(`TRANSPORT_AISDK ${JSON.stringify(event)}`);\n }\n : undefined;\n\n// FE-1439 replaces this local one-conversation/one-document identity\n// with principal-owned private session lookup. Keep it opaque here.\nconst targetDocumentIdFor = (conversationId: string): string =>\n `petrinaut-local:${conversationId}`;\n\nconst streamElicitorTurn = async (\n conversationId: string,\n dispatch: { readonly message: string; readonly idempotencyKey: string },\n emit: (event: HarnessReplyEvent) => void,\n): Promise => {\n const agent = init(GherkinElicitor, { id: conversationId });\n const receipt = await agent.dispatch({\n ...dispatch,\n initialData: { targetDocumentId: targetDocumentIdFor(conversationId) },\n });\n const projector = createFlueReplyProjector({\n submissionId: receipt.submissionId,\n emit,\n });\n await agent.read(receipt, { onEvent: (chunk) => projector.accept(chunk) });\n};\n\nexport const petrinautChatHandler = createAiSdkChatHandler({\n allowedOrigins: (\n process.env.BRUNCH_PETRINAUT_ORIGINS ??\n \"http://127.0.0.1:4915,http://localhost:4915\"\n )\n .split(\",\")\n .map((origin) => origin.trim())\n .filter((origin) => origin.length > 0),\n inspect,\n runTurn: (input, emit) =>\n streamElicitorTurn(\n input.conversationId,\n { message: input.userMessage.text, idempotencyKey: input.idempotencyKey },\n emit,\n ),\n askReply: {\n // Admission consults durable Flue history, not request-shaped claims: the\n // submission resumes the conversation only when its tool-call id\n // correlates with the one ask still awaiting a reply.\n async admit(input) {\n const session = createGherkinElicitationSession(\n input.conversationId,\n targetDocumentIdFor(input.conversationId),\n );\n const entries = projectFlueHistoryForSweep(\n await session.historyReader.peek(input.conversationId),\n );\n return decideAskReplyAdmission(\n pendingAskAffordanceId(entries),\n input.ask.toolCallId,\n );\n },\n // The admitted answer is a fresh user dispatch (spec §7.4); the binding\n // binds it to the pending affordance, making it the user-affordance reply.\n run: (input, emit) =>\n streamElicitorTurn(\n input.conversationId,\n { message: input.ask.answer, idempotencyKey: input.idempotencyKey },\n emit,\n ),\n },\n});\n \"text\" in part &&\n typeof part.text === \"string\",\n )\n .map((part) => part.text)\n .join(\"\");\n return text.length > 0 ? text : undefined;\n};\n\ntype ParsedTransportRequest =\n | { readonly kind: \"initial\"; readonly value: HarnessTurnInput }\n | { readonly kind: \"ask-reply\"; readonly value: HarnessAskReplyInput }\n | { readonly kind: \"refused\"; readonly refusal: TransportRequestRefusal };\n\nconst isAnsweredAskPart = (\n part: NonNullable[number],\n): boolean =>\n ((part.type === \"dynamic-tool\" && part.toolName === ASK_TOOL_NAME) ||\n part.type === `tool-${ASK_TOOL_NAME}`) &&\n part.state === \"output-available\";\n\n/**\n * Classify one tool-result follow-up POST. A human answer submitted through\n * the registered ask component travels tool-output-shaped but is not a\n * machine tool result: exactly one submitted `brunch_ask` output on the\n * referenced assistant message is a candidate reply. Everything else —\n * Petrinaut mutation outputs, the synthetic diagnostics message — remains\n * the machine-input protocol this transport still refuses (FE-1438 owns it).\n */\nconst parseAskReplyTurn = (body: PanelPostBody): ParsedTransportRequest => {\n if (\n typeof body.id !== \"string\" ||\n body.id.length === 0 ||\n typeof body.messageId !== \"string\" ||\n body.messageId.length === 0 ||\n body.trigger !== \"submit-message\" ||\n !Array.isArray(body.messages)\n ) {\n return {\n kind: \"refused\",\n refusal: transportRequestRefusals.invalidChatRequest,\n };\n }\n\n const message = body.messages.find(\n (candidate) =>\n candidate.id === body.messageId && candidate.role === \"assistant\",\n );\n const askParts = (message?.parts ?? []).filter(isAnsweredAskPart);\n if (askParts.length === 0) {\n return {\n kind: \"refused\",\n readonly type: \"ask-reply-admitted\";\n readonly requestId: string;\n readonly conversationId: string;\n readonly toolCallId: string;\n }\n | {\n readonly type: \"ask-reply-refused\";\n readonly requestId: string;\n readonly conversationId: string;\n readonly toolCallId: string;\n readonly reason: \"no-pending-ask\" | \"different-ask-pending\";\n };\n\nexport interface AiSdkChatHandlerOptions {\n readonly runTurn: HarnessTurnRunner;\n /**\n * Ask-return support. Absent, every tool-result follow-up stays refused\n * (the FE-1436 negative contract); present, exactly the pending ask's\n * correlated submission resumes the conversation.\n */\n readonly askReply?: AskReplyHandler;\n /** Exact browser origins allowed to call this endpoint across origins. */\n readonly allowedOrigins?: readonly string[];\n /** Opt-in diagnostic sink. Events are metadata only and never re-enter the conversation. */\n readonly inspect?: (event: TransportInspectionEvent) => void;\n}\n\nconst panelPartSchema = v.looseObject({\n type: v.optional(v.unknown()),\n text: v.optional(v.unknown()),\n toolName: v.optional(v.unknown()),\n toolCallId: v.optional(v.unknown()),\n state: v.optional(v.unknown()),\n output: v.optional(v.unknown()),\n});\n\nconst panelMessageSchema = v.looseObject({\n id: v.optional(v.unknown()),\n role: v.optional(v.unknown()),\n parts: v.optional(v.array(panelPartSchema)),\n});\n\nconst panelPostBodySchema = v.looseObject({\n id: v.optional(v.unknown()),\n messageId: v.optional(v.unknown()),\n messages: v.optional(v.array(panelMessageSchema)),\n trigger: v.optional(v.unknown()),\n});\n\ntype PanelMessage = v.InferOutput;\ntype PanelPostBody = v.InferOutput;\n\ntype TransportRequestRefusal =\n | {\n readonly reason: \"invalid-chat-request\";\n readonly status: 400;\n readonly error: \"invalid_chat_request\";\n }\n | {\n readonly reason: \"tool-result-follow-up-not-supported\";\n readonly status: 422;\n readonly error: \"tool_result_follow_up_not_supported\";\n }\n | {\n readonly reason: \"invalid-ask-submission\";\n readonly status: 400;\n readonly error: \"invalid_ask_submission\";\n };\n\nconst transportRequestRefusals = {\n invalidChatRequest: {\n reason: \"invalid-chat-request\",\n status: 400,\n error: \"invalid_chat_request\",\n },\n toolResultFollowUpNotSupported: {\n reason: \"tool-result-follow-up-not-supported\",\n status: 422,\n error: \"tool_result_follow_up_not_supported\",\n },\n invalidAskSubmission: {\n reason: \"invalid-ask-submission\",\n status: 400,\n error: \"invalid_ask_submission\",\n },\n} as const satisfies Record;\n\nconst askReplyRefusalErrors = {\n \"no-pending-ask\": \"ask_not_pending\",\n \"different-ask-pending\": \"ask_mismatch\",\n} as const;\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CeZZ8wgHAAtTub6xUHz` + +``` +{ + "output": "/**\n * `@hashintel/brunch-agent-plugin-gherkin` — the gherkin target-domain (spec §13.1).\n *\n * The tracer target: cheap enough to wire end-to-end first, and deliberately\n * trivial, so it must not be the plugin that freezes the contract (spec §13's\n * two-targets-on-each-axis rule). Its packs, `project`, and `validate` land\n * with their own slice.\n *\n * **This package resolves `@hashintel/brunch-agent` and nothing else** — never the binding,\n * never Flue. Target policy has no business knowing which substrate it is\n * running on, and it is storage-blind besides (spec §9.6).\n */\n\nimport * as v from \"valibot\";\n\nimport { definePlugin } from \"@hashintel/brunch-agent\";\n\nconst nonEmptyString = v.pipe(v.string(), v.nonEmpty());\nconst evidenceQuote = v.strictObject({ excerpt: nonEmptyString });\n\nconst StatementNotedProposal = v.pipe(\n v.strictObject({\n evidence: v.pipe(v.array(evidenceQuote), v.minLength(1)),\n epistemicStatus: v.literal(\"explicit\"),\n confidence: v.picklist([\"firm\", \"hedged\", \"speculative\"]),\n content: v.strictObject({\n value: v.strictObject({\n type: v.literal(\"statement-noted\"),\n interior: v.strictObject({ verbatim: nonEmptyString }),\n }),\n }),\n }),\n v.check(\n (proposal) =>\n proposal.evidence.some(\n (evidence) =>\n evidence.excerpt === proposal.content.value.interior.verbatim,\n ),\n \"The verbatim interior must equal one cited user quote.\",\n ),\n);\n\nexport const gherkin = definePlugin({\n name: \"plugin-gherkin\",\n targetDomain: \"gherkin\",\n proposalCatalog: [\n {\n name: \"statement-noted\",\n description:\n \"Record one condition-shaped statement at the verbatim grade floor, with no parsed structure.\",\n schema: StatementNotedProposal,\n },\n ],\n});\n\"use agent\";\n/**\n * The gherkin elicitor (spec §12.5: one agent per target).\n *\n * Named as a noun — the thing, not the act — and read target-first, so the\n * family sorts together as targets multiply: `gherkin-elicitor`,\n * `assurance-elicitor`.\n *\n * The product is the harness library in a thin host-authored agent — Flue's\n * build-time scan makes the alternative structurally unavailable, since a\n * library cannot ship a pre-registered agent (spec §12.1). So this module is\n * deliberately thin: it mounts harness capability and holds no elicitation\n * semantics of its own.\n *\n * Three recorded Flue constraints are honoured here by construction (spec §10):\n * the `'use agent'` directive is the file's first statement; `agentName` is a\n * pinned string literal, because conversation storage keys on it; and the tool\n * set is static, because prompt-cache economics forbid per-question tool\n * swapping.\n */\n\nimport { useInitialData, useModel, type AgentProps } from \"@flue/runtime\";\nimport * as v from \"valibot\";\n\nimport { useElicitation } from \"@hashintel/brunch-agent-binding-flue\";\nimport { gherkin } from \"@hashintel/brunch-agent-plugin-gherkin\";\n\nimport { createGherkinElicitationSession } from \"../elicitation-session.ts\";\n\n/**\n * One definition for the agent and the faux provider alike: the two must name\n * the same model id, and drift fails at resolution only if both sides resolve\n * the same string (Flue patterns audit, 2026-08-17).\n */\nexport const GHERKIN_MODEL_ID = \"claude-haiku-4-5\";\n\nexport function GherkinElicitor(props: AgentProps) {\n useModel(`anthropic/${GHERKIN_MODEL_ID}`);\n const initialData = useInitialData<{ targetDocumentId: string }>();\n return useElicitation(\n gherkin,\n createGherkinElicitationSession(props.id, initialData.targetDocumentId),\n );\n}\n\n/**\n * Pinned, and never to be edited: conversation storage keys on this literal,\n * so changing it orphans every existing conversation. Flue requires a string\n * literal here because build targets derive durable identifiers from it before\n * any user code runs.\n *\n * Product-prefixed on purpose, and this is the one place the prefix is not\n * cosmetic. Agent identities are global per application, and the September\n * demo shell is chartered to mount this library alongside the Petrinaut\n * libraries — a bare `gherkin-elicitor` could collide with another library's\n * agent, and the collision would land on durable conversation storage.\n *\n * The exported symbol stays the shorter `GherkinElicitor` because it reads\n * better at the mount site; `agentName` exists precisely to let durable\n * identity and source-level name differ.\n */\nGherkinElicitor.agentName = \"brunch-gherkin-elicitor\";\n\n/**\n * Session→document binding (spec §9.1, adjudication L4): a new session's\n * `initialData` carries the target-document id, validated once at creation and\n * immutable thereafter — Flue's own lane for a target descriptor. Dispatching\n * to an existing conversation id resumes that session against the current state\n * of its target-document.\n */\nGherkinElicitor.initialData = v.object({\n targetDocumentId: v.pipe(v.string(), v.nonEmpty()),\n});\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "sed -n '1,275p' packages/binding-flue/src/index.ts", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CeZeseLZ2GAIwyJ0ck0` + +``` +{ + "output": "/**\n * `@hashintel/brunch-agent-binding-flue` — the Flue binding.\n *\n * One binding per substrate. It implements the substrate-capability list\n * (spec §10), owns the local capture-store/session-log storage-port\n * implementation (spec §9.6), and is the\n * only shell allowed to know Flue's dialect: **the harness imports no\n * substrate; a binding imports both** (spec §4).\n *\n * Every time mechanism wants to land in here, the second-binding test applies\n * (spec §14.2): genuinely substrate-specific, or mechanism leaking into Flue's\n * dialect?\n */\n\nimport {\n useAgentFinish,\n useAgentStart,\n useDataWriter,\n useDelivery,\n usePersistentState,\n useTool,\n} from \"@flue/runtime\";\nimport * as v from \"valibot\";\n\nimport {\n ASK_TOOL_DESCRIPTION,\n AskInput,\n FreeTextAffordance,\n advanceSweepHighWater,\n askProtocolInstructionFragments,\n buildSettlementCheckSignal,\n buildReplyBindingSignalPayload,\n buildSweepExtractionPrompt,\n buildSweepRepairSignal,\n computeUnaccountedAskAdvisories,\n createSweepExtractionResultSchema,\n createInitialSweepState,\n decidePendingAffordance,\n decideSettlementTrigger,\n mintAskAffordance,\n parseSweepState,\n pendingSweepRepair,\n reopenSweepAfterRefusal,\n settlementProtocolInstructionFragments,\n sweepableRange,\n toolName,\n type CaptureStore,\n type FreeTextAffordanceValue,\n type Plugin,\n type SweepState,\n} from \"@hashintel/brunch-agent\";\n\nimport { capturedUserEntryIdsForSession } from \"./capture-accounting\";\nimport {\n projectFlueHistoryForSweep,\n type FlueHistoryReader,\n} from \"./history-reader\";\n\nconst SweepToolOutput = v.looseObject({\n status: v.picklist([\"no-settled-range\", \"refused\", \"applied\"]),\n});\n\nexport { CAPABILITIES, type Capability, type Provision } from \"./capabilities\";\nexport {\n createFlueHistoryReader,\n projectFlueHistoryForSweep,\n type FlueHistoryReaderOptions,\n} from \"./history-reader\";\nexport {\n createFlueReplyProjector,\n type FlueReplyProjector,\n type FlueReplyProjectorOptions,\n} from \"./reply-projector\";\nexport { createLocalCaptureStore } from \"./local-capture-store\";\n\nexport interface ElicitationSession {\n readonly sessionId: string;\n readonly captureStore: CaptureStore;\n readonly historyReader: FlueHistoryReader;\n}\n\n/**\n * Mount the elicitation harness in a Flue agent.\n *\n * Flue has no ask-the-user primitive, so the harness owns the turn-suspension\n * protocol: a `terminate: true` ask tool, the pending affordance in\n * per-session state, and the answer arriving as a fresh dispatch (spec §7.4).\n */\nexport function useElicitation(\n plugin: Plugin,\n session: ElicitationSession,\n): string {\n const delivery = useDelivery();\n const [pending, setPending] =\n usePersistentState(\n \"pendingAffordance\",\n null,\n );\n const [storedSweepState, setSweepState] = usePersistentState(\n \"sweepHighWater\",\n createInitialSweepState(),\n );\n let pendingAtFinish = pending;\n let sweepState = parseSweepState(storedSweepState);\n const extractionResult = createSweepExtractionResultSchema(plugin);\n const writeAffordance = useDataWriter(\"affordance\", {\n schema: FreeTextAffordance,\n });\n\n useAgentStart((ctx) => {\n if (delivery.kind !== \"user\" || pending === null) return;\n\n pendingAtFinish = null;\n setPending(null);\n ctx.append({ kind: \"signal\", ...buildReplyBindingSignalPayload(pending) });\n });\n\n useTool({\n name: toolName(\"ask\"),\n description: ASK_TOOL_DESCRIPTION,\n input: AskInput,\n output: FreeTextAffordance,\n run({ data, toolCallId }) {\n const affordance = mintAskAffordance(data.question, toolCallId);\n\n setPending((current) => {\n const decision = decidePendingAffordance(current, affordance);\n if (!decision.ok) throw new Error(decision.reason);\n pendingAtFinish = decision.pending;\n return decision.pending;\n });\n writeAffordance(affordance);\n\n return { output: affordance, terminate: true };\n },\n });\n\n useTool({\n name: toolName(\"sweep\"),\n description:\n \"Apply or replay the settled conversation prefix. The harness privately extracts quote-anchored captures, refreshes durable history immediately before atomic application, and advances sweep state only on success.\",\n input: v.strictObject({}),\n output: SweepToolOutput,\n harness: true,\n durable: true,\n async run({ harness, signal, step }) {\n const historyAtJudgment = await step.do(\"read-settled-range\", async () =>\n projectFlueHistoryForSweep(\n await session.historyReader.peek(session.sessionId),\n ),\n );\n const range = sweepableRange(historyAtJudgment);\n const throughUserEntryId = range.at(-1)?.id;\n if (!throughUserEntryId) {\n return { output: { status: \"no-settled-range\" as const } };\n }\n\n const extraction = await step.do(\n \"extract-sweep-proposals\",\n async () =>\n (\n await harness.prompt(\n buildSweepExtractionPrompt(\n {\n targetDomain: plugin.targetDomain,\n proposalNames: plugin.proposalCatalog.map(\n (proposal) => proposal.name,\n ),\n },\n range,\n ),\n { result: extractionResult, signal },\n )\n ).data,\n );\n\n // This read is intentionally adjacent to application: its binding-owned\n // archive write makes every quote resolvable before the store sees it.\n await step.do(\"refresh-history-before-apply\", async () =>\n projectFlueHistoryForSweep(\n await session.historyReader.read(session.sessionId),\n ),\n );\n const applied = await step.do(\"apply-sweep\", () =>\n session.captureStore.execute(\n {\n type: \"apply-sweep\",\n // The plugin schema narrows the existing envelope here; the store\n // repeats envelope validation and owns anchoring at apply.\n proposals: extraction.proposals,\n },\n { sessionId: session.sessionId },\n ),\n );\n if (!applied.ok) {\n sweepState = reopenSweepAfterRefusal(sweepState);\n setSweepState(sweepState);\n return {\n output: { status: \"refused\" as const, refusal: applied.refusal },\n };\n }\n\n sweepState = advanceSweepHighWater(sweepState, throughUserEntryId);\n setSweepState(sweepState);\n const accountedEntryIds = await capturedUserEntryIdsForSession(\n session.captureStore,\n applied.snapshot,\n session.sessionId,\n );\n return {\n output: {\n status: \"applied\" as const,\n appliedCaptureIds:\n \"appliedCaptureIds\" in applied.value\n ? applied.value.appliedCaptureIds\n : [],\n skippedDedupKeys:\n \"skippedDedupKeys\" in applied.value\n ? applied.value.skippedDedupKeys\n : [],\n advisories: [\n ...(\"advisories\" in applied.value ? applied.value.advisories : []),\n ...computeUnaccountedAskAdvisories(range, accountedEntryIds),\n ],\n },\n };\n },\n });\n\n useAgentFinish(async (ctx) => {\n // useAgentFinish also fires on terminate:true asks. The callback's local\n // view is updated by ask/reply callbacks in this render, so it observes the\n // live slot rather than the render-time persistent-state snapshot.\n if (pendingAtFinish !== null) return;\n\n const entries = projectFlueHistoryForSweep(\n await session.historyReader.peek(session.sessionId),\n );\n const repair = pendingSweepRepair(entries);\n if (repair) {\n ctx.append({ kind: \"signal\", ...buildSweepRepairSignal(repair) });\n return;\n }\n const decision = decideSettlementTrigger({\n entries,\n state: sweepState,\n pendingAffordance: false,\n });\n if (decision.action !== \"nudge\") return;\n\n sweepState = decision.nextState;\n setSweepState(sweepState);\n ctx.append({\n kind: \"signal\",\n ...buildSettlementCheckSignal(decision.tail),\n });\n });\n\n return [\n ...askProtocolInstructionFragments(plugin.targetDomain),\n ...settlementProtocolInstructionFragments(),\n ].join(\"\\n\\n\");\n}\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `apply_patch` + +```json +{ + "patchText": "*** Begin Patch\n*** Add File: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n+# Brunch steering model\n+\n+This is the current strategic understanding of Brunch: what outcome matters now, what the system\n+can actually do, which beliefs remain weak, and where to spend the next unit of time. Its immediate\n+decision horizon is the September demo, but it steers the whole context rather than one package or\n+one Linear map.\n+\n+This is not a roadmap, a specification, or an issue mirror. Specifications and accepted ADRs define\n+obligations and settled architecture. Linear is canonical for issue state, hierarchy, and hard\n+blockers. [COORDINATION](./COORDINATION.md) projects this strategy onto the mechanically available\n+work. This document owns the judgment between them: which objective to pursue under the current\n+time, evidence, risk, and product pressure; what to defer; and what new evidence would change that\n+choice. It may expose a conflict with a specification or ADR, but cannot silently override one.\n+\n+The document remains live. A steering pass orients from current evidence, chooses a frontier,\n+executes to a named proof, reconciles the result with specifications and issues, then replans only\n+where the evidence changed. Git carries the history; this file carries only the current model. Its\n+shape is intentionally specific to the present effort. Do not extract a generic template or skill\n+until a second real planning cycle shows which parts recur.\n+\n+## The September outcome\n+\n+As of **2026-08-24**, the working constraint is roughly two human weeks. The event date and final\n+business use case are not yet recorded here; Dora's confirmation is a decision gate, not an excuse\n+to leave the technical spine vague.\n+\n+FE-1476 (the September demo delivery) supplies the working scenario:\n+\n+1. A reviewer opens a prebuilt cyber-physical-process requirements model and its generated SDCPN in\n+ Petrinaut.\n+2. The reviewer selects or describes a net element and asks why it was modelled that way.\n+3. Brunch traces the answer through the requirements model and captures to an exact source\n+ utterance.\n+4. The reviewer scopes one correction and conducts three to five focused chat turns.\n+5. New or superseding captures change the elicited model; reprojection changes the corresponding\n+ part of the live net without rebuilding unrelated parts.\n+6. The resulting artifact is handed to the existing optimisation experiment flow.\n+\n+This is a **review-and-revise** demonstration. It does not need to prove that Brunch can elicit an\n+entire CPS model from a blank conversation. It does need to prove a closed semantic and interaction\n+loop. A chat transcript beside a static fixture, an unexplained net mutation, or a test that injects\n+wiring absent from the deployed entrypoint does not satisfy the outcome.\n+\n+The proof spine is therefore:\n+\n+```text\n+source utterance\n+ -> active typed capture\n+ -> folded CPS requirements model\n+ -> SDCPN element + provenance\n+ -> reviewer question and scoped correction\n+ -> superseding capture\n+ -> changed folded model\n+ -> changed live SDCPN\n+ -> optimisation handoff\n+```\n+\n+## Where the system actually stands\n+\n+The package topology is in place and the implemented tracer is real, but the September loop is not\n+an incremental extension of an almost-finished product. Most of the contract-bearing middle is\n+absent.\n+\n+| Surface | Evidence now | September consequence |\n+| --- | --- | --- |\n+| Ask, suspend, return | A user answer to `brunch_ask` survives the AI SDK/Flue boundary and resumes durable history. | Reuse; do not redesign the ask protocol. |\n+| Settlement and capture | A settled range is privately swept into quote-anchored captures and applied atomically. Supersession and active-head validation exist in the store. | Preserve as the evidence foundation, but expose active state to the controller. |\n+| Plugin SDK | The exported `Plugin` is deliberately only identity plus exactly one proposal type. Gherkin captures one verbatim statement. | There is no implemented fold, demand runner, model, projection, or useful hard-target plugin to extend. |\n+| Elicitation control | The agent receives general ask/sweep instructions. Sweep extraction sees a conversation range and proposal names only. No production path reads the active capture set or a derived model back into the interview. | Brunch cannot yet choose a next question from what it has learned or conduct a targeted correction. |\n+| CPS semantics | The three-register design and provisional two-schema/two-table plugin contract are desk-designed. No `plugin-cps` exists. | The critical semantic path must be built against a concrete CPS case, not inferred from Gherkin completeness. |\n+| Correction | The store can represent supersession, but extraction cannot see active capture IDs, model issues, or the target region; Gherkin cannot propose a supersession. | Targeted re-elicitation is structurally unreachable despite the storage mechanics being present. |\n+| Petrinaut transport | Local panel streaming and human ask-return work. Machine client-tool-result follow-ups are explicitly refused pending FE-1438 (the client-tool round-trip). | The agent cannot yet apply a projection to the live document and receive the result. |\n+| Session target | The current application derives `targetDocumentId` from `conversationId`. | A new reviewer session cannot address a pre-existing elicitation target without changing this identity boundary. |\n+| Demo website | The production website still uses its stock assistant route. The `/brunch` Actual Mode is a separate read-only fixture/SSE surface. | Local tracer proof must not be mistaken for deployed integration. |\n+\n+The decisive reading is that the current design is not too rigorous in its preservation of\n+evidence, correction, or register boundaries. It is too broad and too generic for the remaining\n+time. Completing generic plugin machinery, a second target, a full CPS ontology, and a cold-start\n+interviewer before crossing the real reviewer loop would optimize the library while leaving the\n+demo hollow.\n+\n+## The strategic bet\n+\n+Build the smallest honest **CPS review-and-revise loop** through all three registers and the real\n+Petrinaut entrypoint. Let that concrete implementation discover the minimum plugin interface, then\n+generalize only what the CPS case and existing Gherkin case both need.\n+\n+This is not permission to take another thin tracer as the definition of done. The vertical proof is\n+contract-bearing: it includes model assembly, provenance, targeted correction, reprojection,\n+application, and the deployed route. Breadth inside each layer may be narrow; no layer in that loop\n+may be a fixture masquerading as production wiring.\n+\n+The bet preserves these load-bearing decisions:\n+\n+- Captures remain the durable, source-grounded assertion register.\n+- Every semantic inference happens at write time and is recorded as a contestable capture.\n+- The elicited model is a pure fold over active captures and every model part names its supporting\n+ capture IDs.\n+- SDCPN projection consumes the elicited model without rereading the transcript or making hidden\n+ semantic judgments.\n+- Petrinaut application and diagnostics are separate from semantic projection: the application may\n+ use client tools to apply a projected artifact, but it does not become the authority that invents\n+ the model.\n+- A correction supersedes or adds assertions and re-runs the fold and projection; it does not patch\n+ an unexplained net element directly.\n+\n+FE-1480 (requirements-model-to-SDCPN inference) challenges the third and fourth decisions by\n+assuming the projection itself requires LLM inference. That assumption is unresolved. If a worked\n+CPS case proves that the register-2 model is insufficient for pure projection, the honest choices\n+are to record the missing semantic judgment as a capture before folding or to amend ADR-0003 (the\n+three-register IR) explicitly. Hiding inference inside a read-time projection is not an available\n+shortcut.\n+\n+## The elicitor architecture under this load\n+\n+The discussion began with four parts; the current model has five responsibilities across the\n+harness and plugin layers, plus one per-engagement input. The missing responsibility is the\n+controller that closes the loop between captured evidence and the next move.\n+\n+| Responsibility | Owner | What it contains | State and September obligation |\n+| --- | --- | --- | --- |\n+| Strategy repertoire | Harness | Orientations, motivations, conversational licences, interviewing techniques, and question-formulation guidance. | Partly researched, not operationally selected. Implement only the techniques used by the review-and-revise runbook. |\n+| Evidence engine | Harness | Archive, settlement sweep, quote anchoring, durable captures, issues, conflict, supersession, and provenance primitives. | Strongest implemented layer. Add the active-model/issues read path needed by control and correction; do not broaden storage semantics without evidence. |\n+| Elicitation controller | Harness | Reads the engagement brief, active folded model and issues, current runbook, and strategy repertoire; chooses `ask`, `propose`, `contrast`, `validate`, `project`, `explain`, or `stop`. | Absent. Build the narrow controller loop needed to explain and revise one selected region. |\n+| Domain contract | Plugin | Proposal and model schemas; identity, fold, grade, demand, diagnostics, projection, and provenance rules for one target domain. | Designed but unimplemented. Build the CPS subset exercised by the fixture and correction; let it pressure the generic interface. |\n+| Job runbooks | Plugin | Named jobs over the same domain: objectives, entry conditions, trajectories, demand/completion rules, checks, stopping, revision, boundaries, and handoff. | Absent. Implement `review-and-revise`; defer a complete cold-start runbook. |\n+\n+The **engagement brief** is dynamic input, not plugin policy: target document, participant role,\n+objective, scope, known constraints, allowed actions, and time budget for this run. For September it\n+binds a reviewer to an existing target and one revisable region.\n+\n+A separate free-form “next-question ledger” should not become another authority. Most of it is a\n+derived control trace:\n+\n+```text\n+runbook demand -> model gap or issue -> candidate move -> chosen move -> concrete ask\n+```\n+\n+Persist only what replay, audit, or explicit user commitment requires. The controller must be able\n+to explain its chosen move from the runbook and active model; it must not accumulate an independent\n+shadow plan.\n+\n+The September `review-and-revise` runbook is provisionally:\n+\n+```text\n+entry:\n+ existing target + folded requirements model + projected net + reviewer scope\n+trajectory:\n+ orient -> select -> explain provenance -> frame correction\n+ -> ask/validate (3-5 turns) -> show semantic and net delta -> confirm -> hand off\n+done:\n+ scoped demands are met at the declared grade\n+ no open conflict blocks the selected projection\n+ reviewer confirms the intended delta\n+ every changed net element retains provenance\n+boundary:\n+ do not expand into cold-start elicitation or unrelated net repair\n+```\n+\n+## Proof frontiers and execution order\n+\n+The work has four frontiers. They are ordered by learning dependency, not by which ticket is\n+currently unblocked. The semantic and experience lanes start in parallel after Frontier 0, then\n+join as early as possible; they are not two long independent streams to integrate at the end.\n+\n+### Frontier 0 — make the demo claim decidable\n+\n+Confirm the business use case, freeze one representative prebuilt requirements-model/net fixture,\n+and name the optimisation handoff artifact. On that fixture, settle the FE-1480 authority question:\n+which steps are write-time semantic capture, pure model fold, pure SDCPN projection, and document\n+application?\n+\n+**Proof:** one reviewed worked transformation in which every SDCPN element needed by the scenario\n+traces to model fields and captures, with every non-mechanical judgment assigned to a write-time\n+producer. If this cannot be drawn honestly, implementation should not freeze an interface.\n+\n+### Frontier 1 — close the CPS semantic loop\n+\n+Implement only the CPS proposal kinds, model slots, identity/fold rules, demands, projection, and\n+provenance exercised by the fixture and one realistic correction. Carry capture IDs through every\n+derived layer. Make active model issues and selected-region context available to the controller.\n+\n+**Proof:** from the production fold/projection APIs, one source-grounded supersession changes the\n+expected model field and corresponding SDCPN elements, leaves an unrelated region stable, and\n+answers both forward and reverse provenance queries. A YAML or Markdown rendering of the model is\n+enough for inspection at this frontier.\n+\n+### Frontier 2 — close the reviewer control loop\n+\n+Allow a new conversation to bind to an existing target document. Admit the machine client-tool\n+results needed to apply and diagnose a net change. Mount the narrow `review-and-revise` runbook and\n+controller so that the active model and selected region, rather than the raw transcript alone,\n+drive three to five questions.\n+\n+**Proof:** through the real Brunch HTTP handler and Petrinaut panel, a reviewer selects the prepared\n+region, receives a grounded explanation, submits a scoped correction, and sees the returned apply\n+result resume the same durable session. No test-only injection supplies the target or tool wiring.\n+\n+### Frontier 3 — converge on the deployed demo\n+\n+Wire provider/mode routing, browser principal and private session lookup, remote transport,\n+deployment gates, and the optimisation handoff. Rehearse the exact scenario with a clean browser\n+against the deployed demo surface.\n+\n+**Proof:** a screen-recordable run completes the six September beats, survives one reload, exposes\n+the before/after requirements-model delta, and hands the resulting SDCPN to the optimisation flow.\n+Diagnostics show the source capture and projection identities needed to investigate a failure.\n+\n+## What is deliberately cut\n+\n+Until the proof spine is closed:\n+\n+- Do not freeze a broad declarative plugin SDK or require a second hard target. Extract the shared\n+ contract after CPS has stressed it.\n+- Do not make the Gherkin artifact path a prerequisite for the CPS demo.\n+- Do not build a full requirements-graph UI. FE-1481's YAML or Markdown export is the selected\n+ fallback; a UI earns time only if the core loop is already green.\n+- Do not build a complete cold-start CPS interview, general target gallery, every affordance type,\n+ voice input, surprising-scenario generation, or broad telemetry vocabulary.\n+- Do not implement a comprehensive CPS ontology. Support the fixture, the correction, and the\n+ optimisation handoff while keeping the data model honest about what it omits.\n+- Do not bypass provenance or write-time semantics to make a visually convincing net mutation.\n+\n+These are sequencing cuts, not claims that the deferred obligations are unimportant.\n+\n+## Issue projection\n+\n+The PM-authored issues are adopted here as the September delivery decomposition. Linear has not yet\n+been changed; its current unparented state is recorded in COORDINATION until an explicitly approved\n+registry update. The recommended hierarchy is FE-1357 (September planning and plugin design) →\n+FE-1476 (September delivery) → FE-1477 through FE-1482.\n+\n+| Issue | Strategic role | Reconciliation with existing work |\n+| --- | --- | --- |\n+| FE-1476 — prepare the September demo | Outcome owner and acceptance narrative. | Child of FE-1357 while that map remains active; owns rehearsal and handoff rather than implementation details. |\n+| FE-1477 — route Petrinaut AI and Brunch | Experience-lane entry and mode selection. | Product acceptance overlaps FE-1440 (ship the elicitor in the demo site). Keep one implementation owner; do not build two switches. |\n+| FE-1478 — trace a generated net to requirements | Provenance acceptance through registers 3 → 2 → 1 → utterance. | Must shape Frontier 1 from its first model/projection types, not arrive as post-hoc metadata. |\n+| FE-1479 — targeted re-elicitation | Convergence issue for the reviewer loop. | Consumes FE-1438's machine client-tool/application path, FE-1439's session ownership, and the CPS correction path; it does not own a second mutation mechanism. |\n+| FE-1480 — infer requirements model to SDCPN | Authority and projection decision, then the production projector. | Must be reconciled with ADR-0003 before implementation. FE-1438 owns browser application, not hidden semantic projection. |\n+| FE-1481 — expose the requirements model | Inspection fallback and demo delta surface. | Select YAML/Markdown first. Defer FE-1442's broader live capture/completion UI unless the proof spine closes early. |\n+| FE-1482 — add the CPS plugin | Semantic-lane owner and concrete pressure on the plugin boundary. | Pulls the demo-critical slices from FE-1402 (completion), FE-1403 (CPS guidance), FE-1406 (strategies), and FE-1431 (declarative contract). FE-1393 remains the generic/Gherkin path and no longer gates September. |\n+\n+Other consequences for the old graph:\n+\n+- FE-1387 (second target and plugin-contract freeze) follows the CPS proof instead of preceding the\n+ demo.\n+- FE-1331 (start from create-new-net) is outside the current reviewer-against-existing-target\n+ scenario.\n+- FE-1438, FE-1439, FE-1440, FE-1423 (pre-remote gates), and FE-1441 (deployment) remain real\n+ implementation obligations; the new issues state user outcomes rather than replacing these\n+ substrate and release seams.\n+- FE-1402, FE-1403, FE-1406, and FE-1431 should produce only what the CPS runbook and domain\n+ contract consume. Their old standalone completion must not become a hidden prerequisite.\n+\n+## Beliefs, risks, and replan conditions\n+\n+| Current belief | Confidence and evidence | Replan when |\n+| --- | --- | --- |\n+| A bounded review-and-revise scenario can carry the September product claim without cold-start elicitation. | Medium. It is the written FE-1476 scenario, but Dora has not confirmed the use case. | The confirmed use case requires model creation rather than review, or the optimisation handoff requires fields absent from the fixture. |\n+| A concrete CPS implementation will discover a better minimum plugin contract faster than completing the generic design first. | Medium-high. Gherkin deliberately under-stresses the interface; CPS is the first real consumer. | The first worked CPS transformation cannot be expressed without a reusable harness primitive that must precede it. Build that primitive, then return immediately to the vertical proof. |\n+| Register 2 can be rich enough for pure SDCPN projection. | Low-medium. ADR-0003 requires it, but no real fold or projector exists and FE-1480 asserts non-determinism. | The worked transformation identifies an unavoidable semantic choice not represented in captures/model. Record it earlier or explicitly revisit the ADR. |\n+| Three to five turns can produce a meaningful scoped correction. | Low. No CPS runbook has been rehearsed. | Two rehearsals exceed the budget or require unrelated context. Narrow the region, preload explicit context, or revise the demo claim rather than script fake success. |\n+| The proven ask suspension can extend to document-application client tools. | Medium-low. The suspension spike succeeded, but the production transport intentionally refuses machine tool-result follow-ups. | The first tool round-trip cannot preserve correlation, durability, or non-user evidence semantics. Treat this as a critical integration blocker, not a UI detail. |\n+| The production website and remote server can be joined inside the timebox. | Medium-low. Local host seams exist; provider routing, session ownership, deployment, and release gates do not yet converge. | A deployable path is not proved by the end of Frontier 2. Preserve the real semantic loop and seek an explicit demo-surface decision rather than quietly falling back to test-only wiring. |\n+| Requirements-model UI is unnecessary for comprehension. | Medium. The reviewer needs inspectability, but FE-1481 explicitly permits export. | Rehearsal shows that provenance and delta cannot be understood from chat plus a structured export. |\n+\n+## Current choice\n+\n+Stop treating “unblocked” as “next.” The next strategic move is to run Frontier 0 immediately and\n+open Frontiers 1 and 2 in parallel: one worked CPS semantic slice and one existing-target reviewer\n+session/tool-return slice. Join them at the earliest correction, then drive the same bones through\n+provider routing and deployment. The generic Gherkin/plugin-freeze path and broad UI work wait for\n+that join.\n+\n+Revisit this choice as soon as Dora confirms the use case, the FE-1480 worked transformation lands,\n+or either parallel frontier fails its first proof. A steering pass that only updates ticket status\n+does not change this document; a new fact that changes the objective, proof spine, authority\n+boundary, or cut line does.\n*** Update File: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/INDEX.md\n@@\n | Document | Status | Linear | Digest |\n | -------------------------------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n | [COORDINATION](planning/_shared/COORDINATION.md) | active | cross-project; maintained by arc-close | Current sequencing recommendation, soft cross-map edges, unresolved seams, and exceptional roots; hard blockers, state, and hierarchy remain in Linear |\n | [hash-monorepo-import-plan](planning/_shared/hash-monorepo-import-plan.md) | active until FE-1437 lands | FE-1437 | Native HASH assimilation plan: preserved history and child package workspaces under one Brunch context root, explicit authority cutover, exhaustive repository-material disposition, toolchain port, boundary gates, and verification |\n | [SPEC-LEDGER](planning/_shared/SPEC-LEDGER.md) | active until milestone-one closure | FE-1383 | Obligation-level status and evidence ledger for the elicitation-kernel specification; settles when the milestone closes |\n+| [STEERING](planning/_shared/STEERING.md) | active | FE-1357 / FE-1476 | Current objective-driven strategy for the September CPS review-and-revise proof: evidence, architectural pressure, proof frontiers, cuts, issue projection, risks, and replan conditions |\n | [flue-architecture-cheatsheet](planning/_shared/flue-architecture-cheatsheet.md) | active | commented on FE-1383; feeds docs/agents/flue-routing.md | Architect's consolidation of all 21 Flue guide pages: direct structured generation uses `harness.prompt`; model-delegated work uses `useSubagent`; three-lane boundary summary and ranked divergence risks; reconciled against installed Flue 2.0.3 source |\n | [topology](planning/_shared/topology.md) | active | ratified → ADR-0002; N1 discharged by FE-1422 + FE-1392; local N5 implemented by FE-1391; N3 amended by FE-1437 | Pseudo-style verification of the package/app tree against the three-lane model and spec §12.2: portable ask/sweep protocols, Flue binding wiring, package boundaries, and application-only Brunch–Petrinaut composition |\n*** Update File: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n@@\n-This is the cross-map coordination surface for the `brunch-agent` project. FE-1383 owns the\n-milestone-one harness build; FE-1357 owns the September demo and process-model plugin design.\n-Linear is canonical for issue state, parentage, and hard `blocks` relations. This file owns\n-only the judgment Linear cannot express: the current project-wide recommendation, soft edges,\n-unresolved seams, and exceptional roots.\n+This is the cross-map coordination surface for the `brunch-agent` project. FE-1383 owns the\n+milestone-one harness build; FE-1357 owns the September demo and process-model plugin design.\n+Linear is canonical for issue state, parentage, and hard `blocks` relations. The\n+[steering model](./STEERING.md) chooses the current objective, proof frontiers, and cuts under\n+pressure. This file projects that strategy onto mechanically available work: the current\n+project-wide recommendation, soft edges, unresolved seams, and exceptional roots.\n@@\n ## Current sequencing recommendation\n \n-As of **2026-08-21**, the FE-1437 authority cutover has been executed: the full brunch-lite\n-history is imported on `ln/fe-1437-hash-monorepo-import` in `hashintel/hash` (frozen standalone\n-SHA `43a0022918861846344b96a32cb94f92e2ee96ae`), every import gate re-verified. `hashintel/hash`\n-is authoritative; the standalone repository accepts no further implementation work. FE-1437\n-closes when the branch lands on `main` (squash merge, per convention). Part of FE-1440's website\n-wiring (the Brunch interactive-tool panel in `apps/petrinaut-website`) travelled with the import\n-branch; FE-1440 was trimmed on 2026-08-21 to the remaining mode wiring (mode switch, browser\n-identifier bootstrap, remote transport swap). After landing, advance FE-1438 (client-tool round-trip)\n-beside FE-1393 (plugin SDK and first projection); FE-1439 (private durable sessions) proceeds in\n-parallel. The integration stream joins at FE-1440 and deployment follows at FE-1441 (which also\n-waits on FE-1423's pre-exposure gates), while the harness stream reaches its contract-freeze\n-decision at FE-1387. FE-1402/FE-1403 form a parallel content/evaluation stream, without\n-displacing the two convergence edges.\n+As of **2026-08-24**, FE-1476 (the September demo delivery) changes the recommendation from generic\n+package completion to a concrete CPS review-and-revise proof. After FE-1437 (the monorepo import)\n+lands, open two fronts in parallel. The semantic front starts FE-1482 (the CPS plugin) against one\n+worked fixture and settles FE-1480's requirements-model-to-SDCPN authority boundary before it\n+implements a projector; FE-1478 (net-to-requirements provenance) is part of that spine from its\n+first types. The experience front advances FE-1438 (machine client-tool round-trip) and FE-1439\n+(private sessions) far enough for a new reviewer conversation to target an existing document,\n+while FE-1477/FE-1440 share one provider-routing implementation. Join the fronts at FE-1479\n+(targeted re-elicitation), then drive the same path through FE-1423's pre-exposure gates and\n+FE-1441 deployment.\n+\n+FE-1393's generic Gherkin artifact and FE-1387's second-target contract freeze no longer gate the\n+September proof. FE-1402, FE-1403, FE-1406, and FE-1431 supply only the completion, guidance,\n+strategy, and contract slices the CPS `review-and-revise` runbook consumes. FE-1481 selects\n+YAML/Markdown export as the requirements-model inspection floor; broad UI follows only if the\n+closed loop is already proved.\n@@\n nodes:\n FE-1437 [executed, landing] # history imported; HASH authoritative; PR pending\n- FE-1438 [next] # client-tool round-trip\n- FE-1439 [next, parallel] # private durable sessions\n- FE-1440 [join, partly landed] # website elicitor mode; panel wiring on import branch\n- FE-1441 [post-landing] # HASH deployment\n- FE-1393 [next] # plugin SDK + first projection\n- FE-1387 [after-FE-1393] # second pack + contract freeze\n- FE-1395 [coordination] # full affordance set\n- FE-1402 [parallel, content] # completion contract\n- FE-1403 [parallel, content] # interviewing guidance\n- FE-1404 [after-content] # armed baseline\n+ FE-1476 [objective] # September reviewer demo\n+ FE-1482 [next, semantic] # concrete CPS plugin + review/revise runbook\n+ FE-1480 [decision, semantic] # model/projection authority, then projector\n+ FE-1478 [semantic proof] # provenance through all three registers\n+ FE-1438 [next, experience] # machine client-tool round-trip + application\n+ FE-1439 [next, experience] # existing-target reviewer session ownership\n+ FE-1477/FE-1440 [experience] # one provider-routing implementation\n+ FE-1479 [join] # targeted correction changes the live net\n+ FE-1481 [fallback] # structured model export before UI\n+ FE-1441 [deployed proof] # HASH deployment\n \n edges:\n FE-1449 -[hard]-> FE-1438\n- FE-1392 -[hard]-> FE-1393\n FE-1438, FE-1439,\n FE-1437 -[hard]-> FE-1440\n FE-1437, FE-1439,\n FE-1423 -[hard]-> FE-1441\n- FE-1393 -[hard]-> FE-1387\n- FE-1402, FE-1403 -[hard]-> FE-1404\n- FE-1395 -[coord]-> FE-1438\n FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439, FE-1393\n- FE-1387 -[input]-> FE-1440\n+ FE-1480 decision -[input]-> FE-1482, FE-1478\n+ FE-1402, FE-1403,\n+ FE-1406, FE-1431 -[input]-> FE-1482\n+ FE-1482, FE-1478,\n+ FE-1438, FE-1439 -[input]-> FE-1479\n+ FE-1479, FE-1440 -[input]-> FE-1441\n ```\n@@\n ## Open seams\n \n-- **Contract freeze — FE-1387.** The process-model target must stress the plugin contract before\n- it freezes. FE-1393 makes the contract programmable; FE-1387 remains the cross-map hinge.\n+- **Projection authority — FE-1480.** The ticket assumes non-deterministic LLM inference from the\n+ requirements model to SDCPN, while ADR-0003 requires write-time-only semantic inference and a\n+ pure projection. A worked CPS transformation must assign every judgment to capture, fold,\n+ projection, or document application before the interface freezes.\n+- **Controller and runbook.** The harness does not read the folded model or open issues back into\n+ the agent, and no plugin defines a job trajectory or stopping rule. FE-1482 must exercise the\n+ narrow `review-and-revise` loop; FE-1406 and FE-1402/FE-1403 are inputs, not parallel products.\n+- **Reviewer target identity — FE-1439 × FE-1479.** The current host derives target-document\n+ identity from conversation identity. September requires a new reviewer conversation against an\n+ existing target without weakening owner isolation.\n+- **Contract freeze — FE-1387.** The CPS target must stress the plugin contract before it freezes.\n+ The freeze follows the September semantic proof rather than gating it.\n@@\n ## Exceptional roots\n@@\n - **FE-1406 — design reusable elicitation strategies.** The cross-map home for the\n harness-shipped generic strategy quiver; intentionally independent of either delivery map.\n+- **FE-1472 — evaluate the nested Anthropic SDK pin.** Unrelated triage root; no owning delivery\n+ map has been chosen.\n+- **FE-1476 — prepare the September demo.** Temporary delivery root pending the recommended fold\n+ under FE-1357.\n+- **FE-1477 through FE-1482 — September outcome slices.** PM-authored issues adopted by the\n+ steering model but not yet folded in Linear. The recommended parent is FE-1476; overlaps and\n+ ownership boundaries are recorded in STEERING's issue projection before external mutation.\n*** End Patch" +} +``` + +## User + +**Tool Result:** `TU-034CebqF6NebEylhcnTlux` + +``` +{ + "files": [ + { + "uri": "file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/docs/planning/_shared/STEERING.md", + "diff": "Index: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n===================================================================\n--- /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n+++ /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n@@ -0,0 +1,278 @@\n+# Brunch steering model\n+\n+This is the current strategic understanding of Brunch: what outcome matters now, what the system\n+can actually do, which beliefs remain weak, and where to spend the next unit of time. Its immediate\n+decision horizon is the September demo, but it steers the whole context rather than one package or\n+one Linear map.\n+\n+This is not a roadmap, a specification, or an issue mirror. Specifications and accepted ADRs define\n+obligations and settled architecture. Linear is canonical for issue state, hierarchy, and hard\n+blockers. [COORDINATION](./COORDINATION.md) projects this strategy onto the mechanically available\n+work. This document owns the judgment between them: which objective to pursue under the current\n+time, evidence, risk, and product pressure; what to defer; and what new evidence would change that\n+choice. It may expose a conflict with a specification or ADR, but cannot silently override one.\n+\n+The document remains live. A steering pass orients from current evidence, chooses a frontier,\n+executes to a named proof, reconciles the result with specifications and issues, then replans only\n+where the evidence changed. Git carries the history; this file carries only the current model. Its\n+shape is intentionally specific to the present effort. Do not extract a generic template or skill\n+until a second real planning cycle shows which parts recur.\n+\n+## The September outcome\n+\n+As of **2026-08-24**, the working constraint is roughly two human weeks. The event date and final\n+business use case are not yet recorded here; Dora's confirmation is a decision gate, not an excuse\n+to leave the technical spine vague.\n+\n+FE-1476 (the September demo delivery) supplies the working scenario:\n+\n+1. A reviewer opens a prebuilt cyber-physical-process requirements model and its generated SDCPN in\n+ Petrinaut.\n+2. The reviewer selects or describes a net element and asks why it was modelled that way.\n+3. Brunch traces the answer through the requirements model and captures to an exact source\n+ utterance.\n+4. The reviewer scopes one correction and conducts three to five focused chat turns.\n+5. New or superseding captures change the elicited model; reprojection changes the corresponding\n+ part of the live net without rebuilding unrelated parts.\n+6. The resulting artifact is handed to the existing optimisation experiment flow.\n+\n+This is a **review-and-revise** demonstration. It does not need to prove that Brunch can elicit an\n+entire CPS model from a blank conversation. It does need to prove a closed semantic and interaction\n+loop. A chat transcript beside a static fixture, an unexplained net mutation, or a test that injects\n+wiring absent from the deployed entrypoint does not satisfy the outcome.\n+\n+The proof spine is therefore:\n+\n+```text\n+source utterance\n+ -> active typed capture\n+ -> folded CPS requirements model\n+ -> SDCPN element + provenance\n+ -> reviewer question and scoped correction\n+ -> superseding capture\n+ -> changed folded model\n+ -> changed live SDCPN\n+ -> optimisation handoff\n+```\n+\n+## Where the system actually stands\n+\n+The package topology is in place and the implemented tracer is real, but the September loop is not\n+an incremental extension of an almost-finished product. Most of the contract-bearing middle is\n+absent.\n+\n+| Surface | Evidence now | September consequence |\n+| --- | --- | --- |\n+| Ask, suspend, return | A user answer to `brunch_ask` survives the AI SDK/Flue boundary and resumes durable history. | Reuse; do not redesign the ask protocol. |\n+| Settlement and capture | A settled range is privately swept into quote-anchored captures and applied atomically. Supersession and active-head validation exist in the store. | Preserve as the evidence foundation, but expose active state to the controller. |\n+| Plugin SDK | The exported `Plugin` is deliberately only identity plus exactly one proposal type. Gherkin captures one verbatim statement. | There is no implemented fold, demand runner, model, projection, or useful hard-target plugin to extend. |\n+| Elicitation control | The agent receives general ask/sweep instructions. Sweep extraction sees a conversation range and proposal names only. No production path reads the active capture set or a derived model back into the interview. | Brunch cannot yet choose a next question from what it has learned or conduct a targeted correction. |\n+| CPS semantics | The three-register design and provisional two-schema/two-table plugin contract are desk-designed. No `plugin-cps` exists. | The critical semantic path must be built against a concrete CPS case, not inferred from Gherkin completeness. |\n+| Correction | The store can represent supersession, but extraction cannot see active capture IDs, model issues, or the target region; Gherkin cannot propose a supersession. | Targeted re-elicitation is structurally unreachable despite the storage mechanics being present. |\n+| Petrinaut transport | Local panel streaming and human ask-return work. Machine client-tool-result follow-ups are explicitly refused pending FE-1438 (the client-tool round-trip). | The agent cannot yet apply a projection to the live document and receive the result. |\n+| Session target | The current application derives `targetDocumentId` from `conversationId`. | A new reviewer session cannot address a pre-existing elicitation target without changing this identity boundary. |\n+| Demo website | The production website still uses its stock assistant route. The `/brunch` Actual Mode is a separate read-only fixture/SSE surface. | Local tracer proof must not be mistaken for deployed integration. |\n+\n+The decisive reading is that the current design is not too rigorous in its preservation of\n+evidence, correction, or register boundaries. It is too broad and too generic for the remaining\n+time. Completing generic plugin machinery, a second target, a full CPS ontology, and a cold-start\n+interviewer before crossing the real reviewer loop would optimize the library while leaving the\n+demo hollow.\n+\n+## The strategic bet\n+\n+Build the smallest honest **CPS review-and-revise loop** through all three registers and the real\n+Petrinaut entrypoint. Let that concrete implementation discover the minimum plugin interface, then\n+generalize only what the CPS case and existing Gherkin case both need.\n+\n+This is not permission to take another thin tracer as the definition of done. The vertical proof is\n+contract-bearing: it includes model assembly, provenance, targeted correction, reprojection,\n+application, and the deployed route. Breadth inside each layer may be narrow; no layer in that loop\n+may be a fixture masquerading as production wiring.\n+\n+The bet preserves these load-bearing decisions:\n+\n+- Captures remain the durable, source-grounded assertion register.\n+- Every semantic inference happens at write time and is recorded as a contestable capture.\n+- The elicited model is a pure fold over active captures and every model part names its supporting\n+ capture IDs.\n+- SDCPN projection consumes the elicited model without rereading the transcript or making hidden\n+ semantic judgments.\n+- Petrinaut application and diagnostics are separate from semantic projection: the application may\n+ use client tools to apply a projected artifact, but it does not become the authority that invents\n+ the model.\n+- A correction supersedes or adds assertions and re-runs the fold and projection; it does not patch\n+ an unexplained net element directly.\n+\n+FE-1480 (requirements-model-to-SDCPN inference) challenges the third and fourth decisions by\n+assuming the projection itself requires LLM inference. That assumption is unresolved. If a worked\n+CPS case proves that the register-2 model is insufficient for pure projection, the honest choices\n+are to record the missing semantic judgment as a capture before folding or to amend ADR-0003 (the\n+three-register IR) explicitly. Hiding inference inside a read-time projection is not an available\n+shortcut.\n+\n+## The elicitor architecture under this load\n+\n+The discussion began with four parts; the current model has five responsibilities across the\n+harness and plugin layers, plus one per-engagement input. The missing responsibility is the\n+controller that closes the loop between captured evidence and the next move.\n+\n+| Responsibility | Owner | What it contains | State and September obligation |\n+| --- | --- | --- | --- |\n+| Strategy repertoire | Harness | Orientations, motivations, conversational licences, interviewing techniques, and question-formulation guidance. | Partly researched, not operationally selected. Implement only the techniques used by the review-and-revise runbook. |\n+| Evidence engine | Harness | Archive, settlement sweep, quote anchoring, durable captures, issues, conflict, supersession, and provenance primitives. | Strongest implemented layer. Add the active-model/issues read path needed by control and correction; do not broaden storage semantics without evidence. |\n+| Elicitation controller | Harness | Reads the engagement brief, active folded model and issues, current runbook, and strategy repertoire; chooses `ask`, `propose`, `contrast`, `validate`, `project`, `explain`, or `stop`. | Absent. Build the narrow controller loop needed to explain and revise one selected region. |\n+| Domain contract | Plugin | Proposal and model schemas; identity, fold, grade, demand, diagnostics, projection, and provenance rules for one target domain. | Designed but unimplemented. Build the CPS subset exercised by the fixture and correction; let it pressure the generic interface. |\n+| Job runbooks | Plugin | Named jobs over the same domain: objectives, entry conditions, trajectories, demand/completion rules, checks, stopping, revision, boundaries, and handoff. | Absent. Implement `review-and-revise`; defer a complete cold-start runbook. |\n+\n+The **engagement brief** is dynamic input, not plugin policy: target document, participant role,\n+objective, scope, known constraints, allowed actions, and time budget for this run. For September it\n+binds a reviewer to an existing target and one revisable region.\n+\n+A separate free-form “next-question ledger” should not become another authority. Most of it is a\n+derived control trace:\n+\n+```text\n+runbook demand -> model gap or issue -> candidate move -> chosen move -> concrete ask\n+```\n+\n+Persist only what replay, audit, or explicit user commitment requires. The controller must be able\n+to explain its chosen move from the runbook and active model; it must not accumulate an independent\n+shadow plan.\n+\n+The September `review-and-revise` runbook is provisionally:\n+\n+```text\n+entry:\n+ existing target + folded requirements model + projected net + reviewer scope\n+trajectory:\n+ orient -> select -> explain provenance -> frame correction\n+ -> ask/validate (3-5 turns) -> show semantic and net delta -> confirm -> hand off\n+done:\n+ scoped demands are met at the declared grade\n+ no open conflict blocks the selected projection\n+ reviewer confirms the intended delta\n+ every changed net element retains provenance\n+boundary:\n+ do not expand into cold-start elicitation or unrelated net repair\n+```\n+\n+## Proof frontiers and execution order\n+\n+The work has four frontiers. They are ordered by learning dependency, not by which ticket is\n+currently unblocked. The semantic and experience lanes start in parallel after Frontier 0, then\n+join as early as possible; they are not two long independent streams to integrate at the end.\n+\n+### Frontier 0 — make the demo claim decidable\n+\n+Confirm the business use case, freeze one representative prebuilt requirements-model/net fixture,\n+and name the optimisation handoff artifact. On that fixture, settle the FE-1480 authority question:\n+which steps are write-time semantic capture, pure model fold, pure SDCPN projection, and document\n+application?\n+\n+**Proof:** one reviewed worked transformation in which every SDCPN element needed by the scenario\n+traces to model fields and captures, with every non-mechanical judgment assigned to a write-time\n+producer. If this cannot be drawn honestly, implementation should not freeze an interface.\n+\n+### Frontier 1 — close the CPS semantic loop\n+\n+Implement only the CPS proposal kinds, model slots, identity/fold rules, demands, projection, and\n+provenance exercised by the fixture and one realistic correction. Carry capture IDs through every\n+derived layer. Make active model issues and selected-region context available to the controller.\n+\n+**Proof:** from the production fold/projection APIs, one source-grounded supersession changes the\n+expected model field and corresponding SDCPN elements, leaves an unrelated region stable, and\n+answers both forward and reverse provenance queries. A YAML or Markdown rendering of the model is\n+enough for inspection at this frontier.\n+\n+### Frontier 2 — close the reviewer control loop\n+\n+Allow a new conversation to bind to an existing target document. Admit the machine client-tool\n+results needed to apply and diagnose a net change. Mount the narrow `review-and-revise` runbook and\n+controller so that the active model and selected region, rather than the raw transcript alone,\n+drive three to five questions.\n+\n+**Proof:** through the real Brunch HTTP handler and Petrinaut panel, a reviewer selects the prepared\n+region, receives a grounded explanation, submits a scoped correction, and sees the returned apply\n+result resume the same durable session. No test-only injection supplies the target or tool wiring.\n+\n+### Frontier 3 — converge on the deployed demo\n+\n+Wire provider/mode routing, browser principal and private session lookup, remote transport,\n+deployment gates, and the optimisation handoff. Rehearse the exact scenario with a clean browser\n+against the deployed demo surface.\n+\n+**Proof:** a screen-recordable run completes the six September beats, survives one reload, exposes\n+the before/after requirements-model delta, and hands the resulting SDCPN to the optimisation flow.\n+Diagnostics show the source capture and projection identities needed to investigate a failure.\n+\n+## What is deliberately cut\n+\n+Until the proof spine is closed:\n+\n+- Do not freeze a broad declarative plugin SDK or require a second hard target. Extract the shared\n+ contract after CPS has stressed it.\n+- Do not make the Gherkin artifact path a prerequisite for the CPS demo.\n+- Do not build a full requirements-graph UI. FE-1481's YAML or Markdown export is the selected\n+ fallback; a UI earns time only if the core loop is already green.\n+- Do not build a complete cold-start CPS interview, general target gallery, every affordance type,\n+ voice input, surprising-scenario generation, or broad telemetry vocabulary.\n+- Do not implement a comprehensive CPS ontology. Support the fixture, the correction, and the\n+ optimisation handoff while keeping the data model honest about what it omits.\n+- Do not bypass provenance or write-time semantics to make a visually convincing net mutation.\n+\n+These are sequencing cuts, not claims that the deferred obligations are unimportant.\n+\n+## Issue projection\n+\n+The PM-authored issues are adopted here as the September delivery decomposition. Linear has not yet\n+been changed; its current unparented state is recorded in COORDINATION until an explicitly approved\n+registry update. The recommended hierarchy is FE-1357 (September planning and plugin design) →\n+FE-1476 (September delivery) → FE-1477 through FE-1482.\n+\n+| Issue | Strategic role | Reconciliation with existing work |\n+| --- | --- | --- |\n+| FE-1476 — prepare the September demo | Outcome owner and acceptance narrative. | Child of FE-1357 while that map remains active; owns rehearsal and handoff rather than implementation details. |\n+| FE-1477 — route Petrinaut AI and Brunch | Experience-lane entry and mode selection. | Product acceptance overlaps FE-1440 (ship the elicitor in the demo site). Keep one implementation owner; do not build two switches. |\n+| FE-1478 — trace a generated net to requirements | Provenance acceptance through registers 3 → 2 → 1 → utterance. | Must shape Frontier 1 from its first model/projection types, not arrive as post-hoc metadata. |\n+| FE-1479 — targeted re-elicitation | Convergence issue for the reviewer loop. | Consumes FE-1438's machine client-tool/application path, FE-1439's session ownership, and the CPS correction path; it does not own a second mutation mechanism. |\n+| FE-1480 — infer requirements model to SDCPN | Authority and projection decision, then the production projector. | Must be reconciled with ADR-0003 before implementation. FE-1438 owns browser application, not hidden semantic projection. |\n+| FE-1481 — expose the requirements model | Inspection fallback and demo delta surface. | Select YAML/Markdown first. Defer FE-1442's broader live capture/completion UI unless the proof spine closes early. |\n+| FE-1482 — add the CPS plugin | Semantic-lane owner and concrete pressure on the plugin boundary. | Pulls the demo-critical slices from FE-1402 (completion), FE-1403 (CPS guidance), FE-1406 (strategies), and FE-1431 (declarative contract). FE-1393 remains the generic/Gherkin path and no longer gates September. |\n+\n+Other consequences for the old graph:\n+\n+- FE-1387 (second target and plugin-contract freeze) follows the CPS proof instead of preceding the\n+ demo.\n+- FE-1331 (start from create-new-net) is outside the current reviewer-against-existing-target\n+ scenario.\n+- FE-1438, FE-1439, FE-1440, FE-1423 (pre-remote gates), and FE-1441 (deployment) remain real\n+ implementation obligations; the new issues state user outcomes rather than replacing these\n+ substrate and release seams.\n+- FE-1402, FE-1403, FE-1406, and FE-1431 should produce only what the CPS runbook and domain\n+ contract consume. Their old standalone completion must not become a hidden prerequisite.\n+\n+## Beliefs, risks, and replan conditions\n+\n+| Current belief | Confidence and evidence | Replan when |\n+| --- | --- | --- |\n+| A bounded review-and-revise scenario can carry the September product claim without cold-start elicitation. | Medium. It is the written FE-1476 scenario, but Dora has not confirmed the use case. | The confirmed use case requires model creation rather than review, or the optimisation handoff requires fields absent from the fixture. |\n+| A concrete CPS implementation will discover a better minimum plugin contract faster than completing the generic design first. | Medium-high. Gherkin deliberately under-stresses the interface; CPS is the first real consumer. | The first worked CPS transformation cannot be expressed without a reusable harness primitive that must precede it. Build that primitive, then return immediately to the vertical proof. |\n+| Register 2 can be rich enough for pure SDCPN projection. | Low-medium. ADR-0003 requires it, but no real fold or projector exists and FE-1480 asserts non-determinism. | The worked transformation identifies an unavoidable semantic choice not represented in captures/model. Record it earlier or explicitly revisit the ADR. |\n+| Three to five turns can produce a meaningful scoped correction. | Low. No CPS runbook has been rehearsed. | Two rehearsals exceed the budget or require unrelated context. Narrow the region, preload explicit context, or revise the demo claim rather than script fake success. |\n+| The proven ask suspension can extend to document-application client tools. | Medium-low. The suspension spike succeeded, but the production transport intentionally refuses machine tool-result follow-ups. | The first tool round-trip cannot preserve correlation, durability, or non-user evidence semantics. Treat this as a critical integration blocker, not a UI detail. |\n+| The production website and remote server can be joined inside the timebox. | Medium-low. Local host seams exist; provider routing, session ownership, deployment, and release gates do not yet converge. | A deployable path is not proved by the end of Frontier 2. Preserve the real semantic loop and seek an explicit demo-surface decision rather than quietly falling back to test-only wiring. |\n+| Requirements-model UI is unnecessary for comprehension. | Medium. The reviewer needs inspectability, but FE-1481 explicitly permits export. | Rehearsal shows that provenance and delta cannot be understood from chat plus a structured export. |\n+\n+## Current choice\n+\n+Stop treating “unblocked” as “next.” The next strategic move is to run Frontier 0 immediately and\n+open Frontiers 1 and 2 in parallel: one worked CPS semantic slice and one existing-target reviewer\n+session/tool-return slice. Join them at the earliest correction, then drive the same bones through\n+provider routing and deployment. The generic Gherkin/plugin-freeze path and broad UI work wait for\n+that join.\n+\n+Revisit this choice as soon as Dora confirms the use case, the FE-1480 worked transformation lands,\n+or either parallel frontier fails its first proof. A steering pass that only updates ticket status\n+does not change this document; a new fact that changes the objective, proof spine, authority\n+boundary, or cut line does.\n", + "type": "add", + "additions": 278, + "deletions": 0 + }, + { + "uri": "file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/docs/INDEX.md", + "diff": "Index: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/INDEX.md\n===================================================================\n--- /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/INDEX.md\n+++ /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/INDEX.md\n@@ -70,8 +70,9 @@\n | -------------------------------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n | [COORDINATION](planning/_shared/COORDINATION.md) | active | cross-project; maintained by arc-close | Current sequencing recommendation, soft cross-map edges, unresolved seams, and exceptional roots; hard blockers, state, and hierarchy remain in Linear |\n | [hash-monorepo-import-plan](planning/_shared/hash-monorepo-import-plan.md) | active until FE-1437 lands | FE-1437 | Native HASH assimilation plan: preserved history and child package workspaces under one Brunch context root, explicit authority cutover, exhaustive repository-material disposition, toolchain port, boundary gates, and verification |\n | [SPEC-LEDGER](planning/_shared/SPEC-LEDGER.md) | active until milestone-one closure | FE-1383 | Obligation-level status and evidence ledger for the elicitation-kernel specification; settles when the milestone closes |\n+| [STEERING](planning/_shared/STEERING.md) | active | FE-1357 / FE-1476 | Current objective-driven strategy for the September CPS review-and-revise proof: evidence, architectural pressure, proof frontiers, cuts, issue projection, risks, and replan conditions |\n | [flue-architecture-cheatsheet](planning/_shared/flue-architecture-cheatsheet.md) | active | commented on FE-1383; feeds docs/agents/flue-routing.md | Architect's consolidation of all 21 Flue guide pages: direct structured generation uses `harness.prompt`; model-delegated work uses `useSubagent`; three-lane boundary summary and ranked divergence risks; reconciled against installed Flue 2.0.3 source |\n | [topology](planning/_shared/topology.md) | active | ratified → ADR-0002; N1 discharged by FE-1422 + FE-1392; local N5 implemented by FE-1391; N3 amended by FE-1437 | Pseudo-style verification of the package/app tree against the three-lane model and spec §12.2: portable ask/sweep protocols, Flue binding wiring, package boundaries, and application-only Brunch–Petrinaut composition |\n \n ## planning/legibility-sweep (FE-1401 arc records)\n", + "type": "update", + "additions": 1, + "deletions": 0 + }, + { + "uri": "file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md", + "diff": "Index: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n===================================================================\n--- /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n+++ /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n@@ -1,33 +1,37 @@\n # Project coordination\n \n This is the cross-map coordination surface for the `brunch-agent` project. FE-1383 owns the\n milestone-one harness build; FE-1357 owns the September demo and process-model plugin design.\n-Linear is canonical for issue state, parentage, and hard `blocks` relations. This file owns\n-only the judgment Linear cannot express: the current project-wide recommendation, soft edges,\n-unresolved seams, and exceptional roots.\n+Linear is canonical for issue state, parentage, and hard `blocks` relations. The\n+[steering model](./STEERING.md) chooses the current objective, proof frontiers, and cuts under\n+pressure. This file projects that strategy onto mechanically available work: the current\n+project-wide recommendation, soft edges, unresolved seams, and exceptional roots.\n \n Before revising the recommendation, run\n `turbo run linear:graph --filter '@hashintel/brunch-agent'`. Its compact projection supplies the\n factual open-issue DAG; read the relevant issue bodies for semantic content, then infer the smallest\n honest recommendation. Do not paste the generated graph here or mirror issue status.\n \n ## Current sequencing recommendation\n \n-As of **2026-08-21**, the FE-1437 authority cutover has been executed: the full brunch-lite\n-history is imported on `ln/fe-1437-hash-monorepo-import` in `hashintel/hash` (frozen standalone\n-SHA `43a0022918861846344b96a32cb94f92e2ee96ae`), every import gate re-verified. `hashintel/hash`\n-is authoritative; the standalone repository accepts no further implementation work. FE-1437\n-closes when the branch lands on `main` (squash merge, per convention). Part of FE-1440's website\n-wiring (the Brunch interactive-tool panel in `apps/petrinaut-website`) travelled with the import\n-branch; FE-1440 was trimmed on 2026-08-21 to the remaining mode wiring (mode switch, browser\n-identifier bootstrap, remote transport swap). After landing, advance FE-1438 (client-tool round-trip)\n-beside FE-1393 (plugin SDK and first projection); FE-1439 (private durable sessions) proceeds in\n-parallel. The integration stream joins at FE-1440 and deployment follows at FE-1441 (which also\n-waits on FE-1423's pre-exposure gates), while the harness stream reaches its contract-freeze\n-decision at FE-1387. FE-1402/FE-1403 form a parallel content/evaluation stream, without\n-displacing the two convergence edges.\n+As of **2026-08-24**, FE-1476 (the September demo delivery) changes the recommendation from generic\n+package completion to a concrete CPS review-and-revise proof. After FE-1437 (the monorepo import)\n+lands, open two fronts in parallel. The semantic front starts FE-1482 (the CPS plugin) against one\n+worked fixture and settles FE-1480's requirements-model-to-SDCPN authority boundary before it\n+implements a projector; FE-1478 (net-to-requirements provenance) is part of that spine from its\n+first types. The experience front advances FE-1438 (machine client-tool round-trip) and FE-1439\n+(private sessions) far enough for a new reviewer conversation to target an existing document,\n+while FE-1477/FE-1440 share one provider-routing implementation. Join the fronts at FE-1479\n+(targeted re-elicitation), then drive the same path through FE-1423's pre-exposure gates and\n+FE-1441 deployment.\n \n+FE-1393's generic Gherkin artifact and FE-1387's second-target contract freeze no longer gate the\n+September proof. FE-1402, FE-1403, FE-1406, and FE-1431 supply only the completion, guidance,\n+strategy, and contract slices the CPS `review-and-revise` runbook consumes. FE-1481 selects\n+YAML/Markdown export as the requirements-model inspection floor; broad UI follows only if the\n+closed loop is already proved.\n+\n ```text\n legend:\n -[hard]-> native Linear blocker\n -[coord]-> either order; do not implement concurrently\n@@ -35,31 +39,32 @@\n -[state-gate]-> condition in the world, not an issue edge\n \n nodes:\n FE-1437 [executed, landing] # history imported; HASH authoritative; PR pending\n- FE-1438 [next] # client-tool round-trip\n- FE-1439 [next, parallel] # private durable sessions\n- FE-1440 [join, partly landed] # website elicitor mode; panel wiring on import branch\n- FE-1441 [post-landing] # HASH deployment\n- FE-1393 [next] # plugin SDK + first projection\n- FE-1387 [after-FE-1393] # second pack + contract freeze\n- FE-1395 [coordination] # full affordance set\n- FE-1402 [parallel, content] # completion contract\n- FE-1403 [parallel, content] # interviewing guidance\n- FE-1404 [after-content] # armed baseline\n+ FE-1476 [objective] # September reviewer demo\n+ FE-1482 [next, semantic] # concrete CPS plugin + review/revise runbook\n+ FE-1480 [decision, semantic] # model/projection authority, then projector\n+ FE-1478 [semantic proof] # provenance through all three registers\n+ FE-1438 [next, experience] # machine client-tool round-trip + application\n+ FE-1439 [next, experience] # existing-target reviewer session ownership\n+ FE-1477/FE-1440 [experience] # one provider-routing implementation\n+ FE-1479 [join] # targeted correction changes the live net\n+ FE-1481 [fallback] # structured model export before UI\n+ FE-1441 [deployed proof] # HASH deployment\n \n edges:\n FE-1449 -[hard]-> FE-1438\n- FE-1392 -[hard]-> FE-1393\n FE-1438, FE-1439,\n FE-1437 -[hard]-> FE-1440\n FE-1437, FE-1439,\n FE-1423 -[hard]-> FE-1441\n- FE-1393 -[hard]-> FE-1387\n- FE-1402, FE-1403 -[hard]-> FE-1404\n- FE-1395 -[coord]-> FE-1438\n FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439, FE-1393\n- FE-1387 -[input]-> FE-1440\n+ FE-1480 decision -[input]-> FE-1482, FE-1478\n+ FE-1402, FE-1403,\n+ FE-1406, FE-1431 -[input]-> FE-1482\n+ FE-1482, FE-1478,\n+ FE-1438, FE-1439 -[input]-> FE-1479\n+ FE-1479, FE-1440 -[input]-> FE-1441\n ```\n \n Hard-edge truth remains in Linear. The graph above is a deliberately focused recommendation,\n not a second issue database.\n@@ -89,10 +94,20 @@\n explicit approval from Lu.\n \n ## Open seams\n \n-- **Contract freeze — FE-1387.** The process-model target must stress the plugin contract before\n- it freezes. FE-1393 makes the contract programmable; FE-1387 remains the cross-map hinge.\n+- **Projection authority — FE-1480.** The ticket assumes non-deterministic LLM inference from the\n+ requirements model to SDCPN, while ADR-0003 requires write-time-only semantic inference and a\n+ pure projection. A worked CPS transformation must assign every judgment to capture, fold,\n+ projection, or document application before the interface freezes.\n+- **Controller and runbook.** The harness does not read the folded model or open issues back into\n+ the agent, and no plugin defines a job trajectory or stopping rule. FE-1482 must exercise the\n+ narrow `review-and-revise` loop; FE-1406 and FE-1402/FE-1403 are inputs, not parallel products.\n+- **Reviewer target identity — FE-1439 × FE-1479.** The current host derives target-document\n+ identity from conversation identity. September requires a new reviewer conversation against an\n+ existing target without weakening owner isolation.\n+- **Contract freeze — FE-1387.** The CPS target must stress the plugin contract before it freezes.\n+ The freeze follows the September semantic proof rather than gating it.\n - **Absence locator.** An absence capture carries no payload, but the fold needs a field-specific\n coordinate (anchor × slot). The plugin-contract spec records three worked cases; any envelope\n amendment belongs to the harness side of this seam.\n - **Structured-tap evidence — FE-1395 × capture store.** `resolve-conflict` currently rejects\n@@ -119,4 +134,11 @@\n - **FE-1334 — offer the user a surprising scenario of their model.** A validation gesture with\n no owning map yet; closest to the motif/quiver strategy work.\n - **FE-1406 — design reusable elicitation strategies.** The cross-map home for the\n harness-shipped generic strategy quiver; intentionally independent of either delivery map.\n+- **FE-1472 — evaluate the nested Anthropic SDK pin.** Unrelated triage root; no owning delivery\n+ map has been chosen.\n+- **FE-1476 — prepare the September demo.** Temporary delivery root pending the recommended fold\n+ under FE-1357.\n+- **FE-1477 through FE-1482 — September outcome slices.** PM-authored issues adopted by the\n+ steering model but not yet folded in Linear. The recommended parent is FE-1476; overlaps and\n+ ownership boundaries are recorded in STEERING's issue projection before external mutation.\n", + "type": "update", + "additions": 55, + "deletions": 33 + } + ], + "summary": "add: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md (+278/-0)\nupdate: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/INDEX.md (+1/-0)\nupdate: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md (+55/-33)" +} +``` + +## Assistant + +The first pass is now written and wired into the existing control surface. Before I treat it as settled, I’m checking whether it actually preserves the key distinction we reached: concrete end-to-end contract proof first, without weakening the evidence/register architecture or turning the new ticket list into the strategy. + +**Tool Use:** `oracle` + +```json +{ + "task": "Review the current uncommitted steering/control-surface diff for the September Brunch demo. Intended outcome: @docs/planning/_shared/STEERING.md must be an objective-driven strategic model (not a roadmap/template or issue mirror) that captures this session's findings: the current implementation ends at durable captures; the missing controller/model/projection/correction loops are the critical architecture; the September scenario is a prebuilt CPS model reviewed for provenance then corrected in 3–5 turns; build a concrete CPS review-and-revise path before generic plugin breadth; preserve write-time semantics, pure fold, pure projection, provenance, and real-entrypoint verification; treat FE-1480's LLM-projection premise as unresolved; and adopt/fold FE-1476–FE-1482 into the old graph without making Linear writes. @docs/planning/_shared/COORDINATION.md should remain the compact sequencing projection, and @docs/INDEX.md should register the new control document. Read the current diff plus @docs/adr/0003-three-register-ir.md, @docs/adr/0004-in-petrinaut-staging-and-the-monorepo-import.md, @docs/planning/process-model-elicitation/plugin-contract-spec.md, @docs/planning/process-model-elicitation/petrinaut-integration-spec.md, and relevant source if needed. Determine whether the steering model is strategically comprehensive and internally coherent under the roughly two-week constraint. Report only concrete high-impact omissions, contradictions, unjustified commitments, or sequencing errors, with the smallest correction for each. Explicitly assess whether the proof frontiers close the real semantic and deployed interaction loops rather than repeating the project's tracer-as-done failure. Ignore copyediting and unrelated repository findings." +} +``` + +## User + +**Tool Result:** `TU-034CefPqdFOcX5VtYmUwLi` + +``` +## Verdict + +The steering document does what the outcome asked: it is an objective-driven strategic model, not a roadmap or issue mirror; it captures the durable-captures ceiling, the missing controller/model/projection/correction loops, the review-and-revise scenario, the CPS-before-breadth bet, the preserved invariants, the FE-1480 open question, and the no-Linear-writes issue adoption. COORDINATION correctly demotes itself to a projection of STEERING, and INDEX registers the new document. I verified the load-bearing status-table claims against source: `targetDocumentId` is derived from `conversationId` ([petrinaut-chat.ts#L33-L44](file:///Users/lunelson/Code/hashintel/hash/apps/brunch-agent/src/petrinaut-chat.ts#L33-L44)), the transport refuses machine tool-result follow-ups pending FE-1438 ([transport-aisdk/src/index.ts#L261-L291](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/packages/transport-aisdk/src/index.ts#L261-L291)), and `Plugin` is identity plus exactly one proposal type ([core/src/plugin.ts#L32-L35](file:///Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/packages/core/src/plugin.ts#L32-L35)). + +Three findings should change the text before it ships. All are S-sized doc edits. + +## Blocking findings + +**1. The sweep — the declared single point of semantic failure — has no proof owner in the frontiers.** +The proof spine's arrow `reviewer question and scoped correction -> superseding capture` is the write-time sweep, which ADR-0003 and the plugin-contract spec (strain 7) name as the single point of semantic failure, and which the status table itself says cannot currently see active capture IDs or propose a supersession. Yet no frontier proof asserts it. Frontier 1's proof ("one source-grounded supersession changes the expected model field") can be passed with a hand-inserted superseding capture; Frontier 2's proof ("submits a scoped correction, and sees the returned apply result") can be passed by a controller that changes the projection without any superseding capture at all — its "no test-only injection" clause covers *wiring*, not *semantic extraction*. That is exactly the tracer-as-done shape the document warns against, surviving one layer deeper. +**Smallest fix:** one sentence added to the Frontier 2 proof (and mirrored in Frontier 1's join expectation): the applied net delta must trace to a superseding capture produced by the production sweep from the reviewer's actual utterance — not injected by the test or fabricated by the controller. + +**2. Frontier 0 doesn't constrain how the prebuilt fixture gets its register-1 content.** +Demo beat 3 is "captures to an exact source utterance," but a "prebuilt requirements-model/net fixture" authored directly at register 2 or 3 has no genuine source utterances — forward/reverse provenance queries would run against fabricated evidence, violating the doc's own "no layer may be a fixture masquerading as production wiring" rule at the layer the demo most depends on. Frontier 0 says "freeze one fixture" without stating this constraint. +**Smallest fix:** add to Frontier 0 that the fixture is a valid store state — source conversation plus captures produced through (or validated against) the production capture/fold path — not a hand-authored register-2/3 artifact, so that both provenance directions and the correction supersession run on real data. + +**3. FE-1331's deferral silently contradicts accepted ADR-0004.** +ADR-0004's consequences explicitly state "FE-1331 (start elicitation from create-new-net) is **un-deferred** — in-Petrinaut initiation is now the September topology, not the post-September one." STEERING says FE-1331 "is outside the current reviewer-against-existing-target scenario," and COORDINATION's exceptional-roots entry re-defers it — neither names the ADR. STEERING's own charter says it "may expose a conflict with a specification or ADR, but cannot silently override one," and this is a silent override: the review-and-revise scenario reverses ADR-0004's initiation-topology consequence. +**Smallest fix:** in the issue-projection bullet, name the conflict explicitly ("ADR-0004 un-deferred FE-1331; the FE-1476 scenario re-defers it — exposed conflict pending a dated ADR-0004 amendment or Dora's use-case confirmation") rather than treating the deferral as unremarkable. + +## Non-blocking follow-ups + +- **Controller's F1 dependency is implicit.** Frontier 2 mounts a controller that reads "the active model and selected region," which only exists once Frontier 1's read path lands; the frontiers "start in parallel" text could let F2 stall on it unnoticed. One clause noting that F2's controller-mounting step waits on F1's active-model read path (while session binding and tool-result admission proceed independently) would make the parallelism honest. +- **The petrinaut-integration-spec's user stories are now partially stale** (cold-start framing: "interview me about my process before building," "watch the net appear"). STEERING doesn't need to amend it, but a reconciliation note belongs on the next arc-close pass so the `active` spec doesn't contradict the demo claim. +- The other files in this diff (git-workflow, issue-writing, legibility protocol additions; import-plan `gt` wording) are unrelated to the steering model and raise no concerns. + +## Tracer-as-done assessment + +Apart from finding 1, the frontiers genuinely close the loops rather than repeating the failure: Frontier 1 proves semantic purity and bidirectional provenance at the production fold/projection APIs; Frontier 2 explicitly requires the real HTTP handler and panel with no test-only target or tool wiring; Frontier 3 requires a clean-browser run against the deployed surface, a reload survival, and the optimisation handoff. The status table's "Demo website" row and the belief-table replan condition ("seek an explicit demo-surface decision rather than quietly falling back to test-only wiring") show the failure mode is understood. Findings 1 and 2 are the two remaining seams where a fixture or hand-authored capture could still stand in for the real semantic path; closing them in the text closes the loop definition completely. +``` + +## Assistant + +The Oracle found two places where a “green” proof could still cheat: a hand-authored prebuilt model could fake provenance, and a hand-inserted supersession could fake correction. It also caught a real conflict with ADR-0004 around the create-new-net entrypoint. I’m tightening those acceptance boundaries rather than adding more plan structure. + +**Tool Use:** `apply_patch` + +```json +{ + "patchText": "*** Begin Patch\n*** Update File: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n@@\n Confirm the business use case, freeze one representative prebuilt requirements-model/net fixture,\n and name the optimisation handoff artifact. On that fixture, settle the FE-1480 authority question:\n which steps are write-time semantic capture, pure model fold, pure SDCPN projection, and document\n application?\n+\n+The prebuilt fixture must be a valid register-1 store state with a source conversation and\n+quote-anchored captures produced through, or independently validated against, the production\n+capture/fold path. A hand-authored register-2 model or register-3 net cannot prove provenance and\n+cannot serve as the correction baseline.\n \n **Proof:** one reviewed worked transformation in which every SDCPN element needed by the scenario\n traces to model fields and captures, with every non-mechanical judgment assigned to a write-time\n producer. If this cannot be drawn honestly, implementation should not freeze an interface.\n@@\n **Proof:** from the production fold/projection APIs, one source-grounded supersession changes the\n expected model field and corresponding SDCPN elements, leaves an unrelated region stable, and\n answers both forward and reverse provenance queries. A YAML or Markdown rendering of the model is\n-enough for inspection at this frontier.\n+enough for inspection at this frontier. The proving proposal must have the shape the production\n+sweep will emit; the cross-frontier join is not accepted until that sweep produces it from the\n+reviewer's actual utterance rather than a test inserting it directly.\n@@\n Allow a new conversation to bind to an existing target document. Admit the machine client-tool\n results needed to apply and diagnose a net change. Mount the narrow `review-and-revise` runbook and\n controller so that the active model and selected region, rather than the raw transcript alone,\n drive three to five questions.\n+\n+Session binding and client-tool admission may proceed in parallel with Frontier 1. Mounting the\n+controller against active model/issues waits for Frontier 1's production read path; do not replace\n+that dependency with request-shaped model context.\n \n **Proof:** through the real Brunch HTTP handler and Petrinaut panel, a reviewer selects the prepared\n region, receives a grounded explanation, submits a scoped correction, and sees the returned apply\n-result resume the same durable session. No test-only injection supplies the target or tool wiring.\n+result resume the same durable session. The net delta must trace to a superseding capture produced\n+by the production sweep from the reviewer's utterance, not one inserted by the test or fabricated\n+by the controller. No test-only injection supplies the target or tool wiring.\n@@\n-- FE-1331 (start from create-new-net) is outside the current reviewer-against-existing-target\n- scenario.\n+- FE-1331 (start from create-new-net) is outside the current reviewer-against-existing-target\n+ scenario, but ADR-0004 explicitly un-deferred it as September topology. The FE-1476 scenario\n+ therefore creates an exposed conflict pending Dora's confirmation and, if review-and-revise\n+ stands, a dated ADR-0004 amendment; this steering document does not silently re-defer it.\n - FE-1438, FE-1439, FE-1440, FE-1423 (pre-remote gates), and FE-1441 (deployment) remain real\n implementation obligations; the new issues state user outcomes rather than replacing these\n substrate and release seams.\n - FE-1402, FE-1403, FE-1406, and FE-1431 should produce only what the CPS runbook and domain\n contract consume. Their old standalone completion must not become a hidden prerequisite.\n+- The active Petrinaut integration spec still describes a cold-start interview in some user\n+ stories. Reconcile those stories with the confirmed scenario rather than treating this plan as a\n+ silent specification amendment.\n*** Update File: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n@@\n-- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** Deferred post-September\n- consumer topology; returns after in-Petrinaut staging proves itself.\n+- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** ADR-0004 un-deferred this as\n+ September topology, while FE-1476's new reviewer scenario starts from an existing target. Keep\n+ the conflict visible until Dora confirms the use case and the ADR is amended if necessary.\n*** End Patch" +} +``` + +## User + +**Tool Result:** `TU-034CejRiYoQEn9tyZlBKRM` + +``` +{ + "files": [ + { + "uri": "file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/docs/planning/_shared/STEERING.md", + "diff": "Index: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n===================================================================\n--- /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n+++ /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n@@ -169,8 +169,13 @@\n and name the optimisation handoff artifact. On that fixture, settle the FE-1480 authority question:\n which steps are write-time semantic capture, pure model fold, pure SDCPN projection, and document\n application?\n \n+The prebuilt fixture must be a valid register-1 store state with a source conversation and\n+quote-anchored captures produced through, or independently validated against, the production\n+capture/fold path. A hand-authored register-2 model or register-3 net cannot prove provenance and\n+cannot serve as the correction baseline.\n+\n **Proof:** one reviewed worked transformation in which every SDCPN element needed by the scenario\n traces to model fields and captures, with every non-mechanical judgment assigned to a write-time\n producer. If this cannot be drawn honestly, implementation should not freeze an interface.\n \n@@ -182,20 +187,28 @@\n \n **Proof:** from the production fold/projection APIs, one source-grounded supersession changes the\n expected model field and corresponding SDCPN elements, leaves an unrelated region stable, and\n answers both forward and reverse provenance queries. A YAML or Markdown rendering of the model is\n-enough for inspection at this frontier.\n+enough for inspection at this frontier. The proving proposal must have the shape the production\n+sweep will emit; the cross-frontier join is not accepted until that sweep produces it from the\n+reviewer's actual utterance rather than a test inserting it directly.\n \n ### Frontier 2 — close the reviewer control loop\n \n Allow a new conversation to bind to an existing target document. Admit the machine client-tool\n results needed to apply and diagnose a net change. Mount the narrow `review-and-revise` runbook and\n controller so that the active model and selected region, rather than the raw transcript alone,\n drive three to five questions.\n \n+Session binding and client-tool admission may proceed in parallel with Frontier 1. Mounting the\n+controller against active model/issues waits for Frontier 1's production read path; do not replace\n+that dependency with request-shaped model context.\n+\n **Proof:** through the real Brunch HTTP handler and Petrinaut panel, a reviewer selects the prepared\n region, receives a grounded explanation, submits a scoped correction, and sees the returned apply\n-result resume the same durable session. No test-only injection supplies the target or tool wiring.\n+result resume the same durable session. The net delta must trace to a superseding capture produced\n+by the production sweep from the reviewer's utterance, not one inserted by the test or fabricated\n+by the controller. No test-only injection supplies the target or tool wiring.\n \n ### Frontier 3 — converge on the deployed demo\n \n Wire provider/mode routing, browser principal and private session lookup, remote transport,\n@@ -244,14 +257,19 @@\n \n - FE-1387 (second target and plugin-contract freeze) follows the CPS proof instead of preceding the\n demo.\n - FE-1331 (start from create-new-net) is outside the current reviewer-against-existing-target\n- scenario.\n+ scenario, but ADR-0004 explicitly un-deferred it as September topology. The FE-1476 scenario\n+ therefore creates an exposed conflict pending Dora's confirmation and, if review-and-revise\n+ stands, a dated ADR-0004 amendment; this steering document does not silently re-defer it.\n - FE-1438, FE-1439, FE-1440, FE-1423 (pre-remote gates), and FE-1441 (deployment) remain real\n implementation obligations; the new issues state user outcomes rather than replacing these\n substrate and release seams.\n - FE-1402, FE-1403, FE-1406, and FE-1431 should produce only what the CPS runbook and domain\n contract consume. Their old standalone completion must not become a hidden prerequisite.\n+- The active Petrinaut integration spec still describes a cold-start interview in some user\n+ stories. Reconcile those stories with the confirmed scenario rather than treating this plan as a\n+ silent specification amendment.\n \n ## Beliefs, risks, and replan conditions\n \n | Current belief | Confidence and evidence | Replan when |\n", + "type": "update", + "additions": 21, + "deletions": 3 + }, + { + "uri": "file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md", + "diff": "Index: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n===================================================================\n--- /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n+++ /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n@@ -128,10 +128,11 @@\n ## Exceptional roots\n \n These project issues intentionally have no parent and are roots under the registry rule:\n \n-- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** Deferred post-September\n- consumer topology; returns after in-Petrinaut staging proves itself.\n+- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** ADR-0004 un-deferred this as\n+ September topology, while FE-1476's new reviewer scenario starts from an existing target. Keep\n+ the conflict visible until Dora confirms the use case and the ADR is amended if necessary.\n - **FE-1334 — offer the user a surprising scenario of their model.** A validation gesture with\n no owning map yet; closest to the motif/quiver strategy work.\n - **FE-1406 — design reusable elicitation strategies.** The cross-map home for the\n harness-shipped generic strategy quiver; intentionally independent of either delivery map.\n", + "type": "update", + "additions": 3, + "deletions": 2 + } + ], + "summary": "update: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md (+21/-3)\nupdate: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md (+3/-2)" +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "cat docs/planning/_shared/STEERING.md", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "cat docs/planning/_shared/COORDINATION.md", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "sed -n '63,80p' docs/INDEX.md; git diff --check -- libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CejrJFCxLm7ojcPqke4` + +``` +{ + "output": "# Brunch steering model\n\nThis is the current strategic understanding of Brunch: what outcome matters now, what the system\ncan actually do, which beliefs remain weak, and where to spend the next unit of time. Its immediate\ndecision horizon is the September demo, but it steers the whole context rather than one package or\none Linear map.\n\nThis is not a roadmap, a specification, or an issue mirror. Specifications and accepted ADRs define\nobligations and settled architecture. Linear is canonical for issue state, hierarchy, and hard\nblockers. [COORDINATION](./COORDINATION.md) projects this strategy onto the mechanically available\nwork. This document owns the judgment between them: which objective to pursue under the current\ntime, evidence, risk, and product pressure; what to defer; and what new evidence would change that\nchoice. It may expose a conflict with a specification or ADR, but cannot silently override one.\n\nThe document remains live. A steering pass orients from current evidence, chooses a frontier,\nexecutes to a named proof, reconciles the result with specifications and issues, then replans only\nwhere the evidence changed. Git carries the history; this file carries only the current model. Its\nshape is intentionally specific to the present effort. Do not extract a generic template or skill\nuntil a second real planning cycle shows which parts recur.\n\n## The September outcome\n\nAs of **2026-08-24**, the working constraint is roughly two human weeks. The event date and final\nbusiness use case are not yet recorded here; Dora's confirmation is a decision gate, not an excuse\nto leave the technical spine vague.\n\nFE-1476 (the September demo delivery) supplies the working scenario:\n\n1. A reviewer opens a prebuilt cyber-physical-process requirements model and its generated SDCPN in\n Petrinaut.\n2. The reviewer selects or describes a net element and asks why it was modelled that way.\n3. Brunch traces the answer through the requirements model and captures to an exact source\n utterance.\n4. The reviewer scopes one correction and conducts three to five focused chat turns.\n5. New or superseding captures change the elicited model; reprojection changes the corresponding\n part of the live net without rebuilding unrelated parts.\n6. The resulting artifact is handed to the existing optimisation experiment flow.\n\nThis is a **review-and-revise** demonstration. It does not need to prove that Brunch can elicit an\nentire CPS model from a blank conversation. It does need to prove a closed semantic and interaction\nloop. A chat transcript beside a static fixture, an unexplained net mutation, or a test that injects\nwiring absent from the deployed entrypoint does not satisfy the outcome.\n\nThe proof spine is therefore:\n\n```text\nsource utterance\n -> active typed capture\n -> folded CPS requirements model\n -> SDCPN element + provenance\n -> reviewer question and scoped correction\n -> superseding capture\n -> changed folded model\n -> changed live SDCPN\n -> optimisation handoff\n```\n\n## Where the system actually stands\n\nThe package topology is in place and the implemented tracer is real, but the September loop is not\nan incremental extension of an almost-finished product. Most of the contract-bearing middle is\nabsent.\n\n| Surface | Evidence now | September consequence |\n| --- | --- | --- |\n| Ask, suspend, return | A user answer to `brunch_ask` survives the AI SDK/Flue boundary and resumes durable history. | Reuse; do not redesign the ask protocol. |\n| Settlement and capture | A settled range is privately swept into quote-anchored captures and applied atomically. Supersession and active-head validation exist in the store. | Preserve as the evidence foundation, but expose active state to the controller. |\n| Plugin SDK | The exported `Plugin` is deliberately only identity plus exactly one proposal type. Gherkin captures one verbatim statement. | There is no implemented fold, demand runner, model, projection, or useful hard-target plugin to extend. |\n| Elicitation control | The agent receives general ask/sweep instructions. Sweep extraction sees a conversation range and proposal names only. No production path reads the active capture set or a derived model back into the interview. | Brunch cannot yet choose a next question from what it has learned or conduct a targeted correction. |\n| CPS semantics | The three-register design and provisional two-schema/two-table plugin contract are desk-designed. No `plugin-cps` exists. | The critical semantic path must be built against a concrete CPS case, not inferred from Gherkin completeness. |\n| Correction | The store can represent supersession, but extraction cannot see active capture IDs, model issues, or the target region; Gherkin cannot propose a supersession. | Targeted re-elicitation is structurally unreachable despite the storage mechanics being present. |\n| Petrinaut transport | Local panel streaming and human ask-return work. Machine client-tool-result follow-ups are explicitly refused pending FE-1438 (the client-tool round-trip). | The agent cannot yet apply a projection to the live document and receive the result. |\n| Session target | The current application derives `targetDocumentId` from `conversationId`. | A new reviewer session cannot address a pre-existing elicitation target without changing this identity boundary. |\n| Demo website | The production website still uses its stock assistant route. The `/brunch` Actual Mode is a separate read-only fixture/SSE surface. | Local tracer proof must not be mistaken for deployed integration. |\n\nThe decisive reading is that the current design is not too rigorous in its preservation of\nevidence, correction, or register boundaries. It is too broad and too generic for the remaining\ntime. Completing generic plugin machinery, a second target, a full CPS ontology, and a cold-start\ninterviewer before crossing the real reviewer loop would optimize the library while leaving the\ndemo hollow.\n\n## The strategic bet\n\nBuild the smallest honest **CPS review-and-revise loop** through all three registers and the real\nPetrinaut entrypoint. Let that concrete implementation discover the minimum plugin interface, then\ngeneralize only what the CPS case and existing Gherkin case both need.\n\nThis is not permission to take another thin tracer as the definition of done. The vertical proof is\ncontract-bearing: it includes model assembly, provenance, targeted correction, reprojection,\napplication, and the deployed route. Breadth inside each layer may be narrow; no layer in that loop\nmay be a fixture masquerading as production wiring.\n\nThe bet preserves these load-bearing decisions:\n\n- Captures remain the durable, source-grounded assertion register.\n- Every semantic inference happens at write time and is recorded as a contestable capture.\n- The elicited model is a pure fold over active captures and every model part names its supporting\n capture IDs.\n- SDCPN projection consumes the elicited model without rereading the transcript or making hidden\n semantic judgments.\n- Petrinaut application and diagnostics are separate from semantic projection: the application may\n use client tools to apply a projected artifact, but it does not become the authority that invents\n the model.\n- A correction supersedes or adds assertions and re-runs the fold and projection; it does not patch\n an unexplained net element directly.\n\nFE-1480 (requirements-model-to-SDCPN inference) challenges the third and fourth decisions by\nassuming the projection itself requires LLM inference. That assumption is unresolved. If a worked\nCPS case proves that the register-2 model is insufficient for pure projection, the honest choices\nare to record the missing semantic judgment as a capture before folding or to amend ADR-0003 (the\nthree-register IR) explicitly. Hiding inference inside a read-time projection is not an available\nshortcut.\n\n## The elicitor architecture under this load\n\nThe discussion began with four parts; the current model has five responsibilities across the\nharness and plugin layers, plus one per-engagement input. The missing responsibility is the\ncontroller that closes the loop between captured evidence and the next move.\n\n| Responsibility | Owner | What it contains | State and September obligation |\n| --- | --- | --- | --- |\n| Strategy repertoire | Harness | Orientations, motivations, conversational licences, interviewing techniques, and question-formulation guidance. | Partly researched, not operationally selected. Implement only the techniques used by the review-and-revise runbook. |\n| Evidence engine | Harness | Archive, settlement sweep, quote anchoring, durable captures, issues, conflict, supersession, and provenance primitives. | Strongest implemented layer. Add the active-model/issues read path needed by control and correction; do not broaden storage semantics without evidence. |\n| Elicitation controller | Harness | Reads the engagement brief, active folded model and issues, current runbook, and strategy repertoire; chooses `ask`, `propose`, `contrast`, `validate`, `project`, `explain`, or `stop`. | Absent. Build the narrow controller loop needed to explain and revise one selected region. |\n| Domain contract | Plugin | Proposal and model schemas; identity, fold, grade, demand, diagnostics, projection, and provenance rules for one target domain. | Designed but unimplemented. Build the CPS subset exercised by the fixture and correction; let it pressure the generic interface. |\n| Job runbooks | Plugin | Named jobs over the same domain: objectives, entry conditions, trajectories, demand/completion rules, checks, stopping, revision, boundaries, and handoff. | Absent. Implement `review-and-revise`; defer a complete cold-start runbook. |\n\nThe **engagement brief** is dynamic input, not plugin policy: target document, participant role,\nobjective, scope, known constraints, allowed actions, and time budget for this run. For September it\nbinds a reviewer to an existing target and one revisable region.\n\nA separate free-form “next-question ledger” should not become another authority. Most of it is a\nderived control trace:\n\n```text\nrunbook demand -> model gap or issue -> candidate move -> chosen move -> concrete ask\n```\n\nPersist only what replay, audit, or explicit user commitment requires. The controller must be able\nto explain its chosen move from the runbook and active model; it must not accumulate an independent\nshadow plan.\n\nThe September `review-and-revise` runbook is provisionally:\n\n```text\nentry:\n existing target + folded requirements model + projected net + reviewer scope\ntrajectory:\n orient -> select -> explain provenance -> frame correction\n -> ask/validate (3-5 turns) -> show semantic and net delta -> confirm -> hand off\ndone:\n scoped demands are met at the declared grade\n no open conflict blocks the selected projection\n reviewer confirms the intended delta\n every changed net element retains provenance\nboundary:\n do not expand into cold-start elicitation or unrelated net repair\n```\n\n## Proof frontiers and execution order\n\nThe work has four frontiers. They are ordered by learning dependency, not by which ticket is\ncurrently unblocked. The semantic and experience lanes start in parallel after Frontier 0, then\njoin as early as possible; they are not two long independent streams to integrate at the end.\n\n### Frontier 0 — make the demo claim decidable\n\nConfirm the business use case, freeze one representative prebuilt requirements-model/net fixture,\nand name the optimisation handoff artifact. On that fixture, settle the FE-1480 authority question:\nwhich steps are write-time semantic capture, pure model fold, pure SDCPN projection, and document\napplication?\n\nThe prebuilt fixture must be a valid register-1 store state with a source conversation and\nquote-anchored captures produced through, or independently validated against, the production\ncapture/fold path. A hand-authored register-2 model or register-3 net cannot prove provenance and\ncannot serve as the correction baseline.\n\n**Proof:** one reviewed worked transformation in which every SDCPN element needed by the scenario\ntraces to model fields and captures, with every non-mechanical judgment assigned to a write-time\nproducer. If this cannot be drawn honestly, implementation should not freeze an interface.\n\n### Frontier 1 — close the CPS semantic loop\n\nImplement only the CPS proposal kinds, model slots, identity/fold rules, demands, projection, and\nprovenance exercised by the fixture and one realistic correction. Carry capture IDs through every\nderived layer. Make active model issues and selected-region context available to the controller.\n\n**Proof:** from the production fold/projection APIs, one source-grounded supersession changes the\nexpected model field and corresponding SDCPN elements, leaves an unrelated region stable, and\nanswers both forward and reverse provenance queries. A YAML or Markdown rendering of the model is\nenough for inspection at this frontier. The proving proposal must have the shape the production\nsweep will emit; the cross-frontier join is not accepted until that sweep produces it from the\nreviewer's actual utterance rather than a test inserting it directly.\n\n### Frontier 2 — close the reviewer control loop\n\nAllow a new conversation to bind to an existing target document. Admit the machine client-tool\nresults needed to apply and diagnose a net change. Mount the narrow `review-and-revise` runbook and\ncontroller so that the active model and selected region, rather than the raw transcript alone,\ndrive three to five questions.\n\nSession binding and client-tool admission may proceed in parallel with Frontier 1. Mounting the\ncontroller against active model/issues waits for Frontier 1's production read path; do not replace\nthat dependency with request-shaped model context.\n\n**Proof:** through the real Brunch HTTP handler and Petrinaut panel, a reviewer selects the prepared\nregion, receives a grounded explanation, submits a scoped correction, and sees the returned apply\nresult resume the same durable session. The net delta must trace to a superseding capture produced\nby the production sweep from the reviewer's utterance, not one inserted by the test or fabricated\nby the controller. No test-only injection supplies the target or tool wiring.\n\n### Frontier 3 — converge on the deployed demo\n\nWire provider/mode routing, browser principal and private session lookup, remote transport,\ndeployment gates, and the optimisation handoff. Rehearse the exact scenario with a clean browser\nagainst the deployed demo surface.\n\n**Proof:** a screen-recordable run completes the six September beats, survives one reload, exposes\nthe before/after requirements-model delta, and hands the resulting SDCPN to the optimisation flow.\nDiagnostics show the source capture and projection identities needed to investigate a failure.\n\n## What is deliberately cut\n\nUntil the proof spine is closed:\n\n- Do not freeze a broad declarative plugin SDK or require a second hard target. Extract the shared\n contract after CPS has stressed it.\n- Do not make the Gherkin artifact path a prerequisite for the CPS demo.\n- Do not build a full requirements-graph UI. FE-1481's YAML or Markdown export is the selected\n fallback; a UI earns time only if the core loop is already green.\n- Do not build a complete cold-start CPS interview, general target gallery, every affordance type,\n voice input, surprising-scenario generation, or broad telemetry vocabulary.\n- Do not implement a comprehensive CPS ontology. Support the fixture, the correction, and the\n optimisation handoff while keeping the data model honest about what it omits.\n- Do not bypass provenance or write-time semantics to make a visually convincing net mutation.\n\nThese are sequencing cuts, not claims that the deferred obligations are unimportant.\n\n## Issue projection\n\nThe PM-authored issues are adopted here as the September delivery decomposition. Linear has not yet\nbeen changed; its current unparented state is recorded in COORDINATION until an explicitly approved\nregistry update. The recommended hierarchy is FE-1357 (September planning and plugin design) →\nFE-1476 (September delivery) → FE-1477 through FE-1482.\n\n| Issue | Strategic role | Reconciliation with existing work |\n| --- | --- | --- |\n| FE-1476 — prepare the September demo | Outcome owner and acceptance narrative. | Child of FE-1357 while that map remains active; owns rehearsal and handoff rather than implementation details. |\n| FE-1477 — route Petrinaut AI and Brunch | Experience-lane entry and mode selection. | Product acceptance overlaps FE-1440 (ship the elicitor in the demo site). Keep one implementation owner; do not build two switches. |\n| FE-1478 — trace a generated net to requirements | Provenance acceptance through registers 3 → 2 → 1 → utterance. | Must shape Frontier 1 from its first model/projection types, not arrive as post-hoc metadata. |\n| FE-1479 — targeted re-elicitation | Convergence issue for the reviewer loop. | Consumes FE-1438's machine client-tool/application path, FE-1439's session ownership, and the CPS correction path; it does not own a second mutation mechanism. |\n| FE-1480 — infer requirements model to SDCPN | Authority and projection decision, then the production projector. | Must be reconciled with ADR-0003 before implementation. FE-1438 owns browser application, not hidden semantic projection. |\n| FE-1481 — expose the requirements model | Inspection fallback and demo delta surface. | Select YAML/Markdown first. Defer FE-1442's broader live capture/completion UI unless the proof spine closes early. |\n| FE-1482 — add the CPS plugin | Semantic-lane owner and concrete pressure on the plugin boundary. | Pulls the demo-critical slices from FE-1402 (completion), FE-1403 (CPS guidance), FE-1406 (strategies), and FE-1431 (declarative contract). FE-1393 remains the generic/Gherkin path and no longer gates September. |\n\nOther consequences for the old graph:\n\n- FE-1387 (second target and plugin-contract freeze) follows the CPS proof instead of preceding the\n demo.\n- FE-1331 (start from create-new-net) is outside the current reviewer-against-existing-target\n scenario, but ADR-0004 explicitly un-deferred it as September topology. The FE-1476 scenario\n therefore creates an exposed conflict pending Dora's confirmation and, if review-and-revise\n stands, a dated ADR-0004 amendment; this steering document does not silently re-defer it.\n- FE-1438, FE-1439, FE-1440, FE-1423 (pre-remote gates), and FE-1441 (deployment) remain real\n implementation obligations; the new issues state user outcomes rather than replacing these\n substrate and release seams.\n- FE-1402, FE-1403, FE-1406, and FE-1431 should produce only what the CPS runbook and domain\n contract consume. Their old standalone completion must not become a hidden prerequisite.\n- The active Petrinaut integration spec still describes a cold-start interview in some user\n stories. Reconcile those stories with the confirmed scenario rather than treating this plan as a\n silent specification amendment.\n\n## Beliefs, risks, and replan conditions\n\n| Current belief | Confidence and evidence | Replan when |\n| --- | --- | --- |\n| A bounded review-and-revise scenario can carry the September product claim without cold-start elicitation. | Medium. It is the written FE-1476 scenario, but Dora has not confirmed the use case. | The confirmed use case requires model creation rather than review, or the optimisation handoff requires fields absent from the fixture. |\n| A concrete CPS implementation will discover a better minimum plugin contract faster than completing the generic design first. | Medium-high. Gherkin deliberately under-stresses the interface; CPS is the first real consumer. | The first worked CPS transformation cannot be expressed without a reusable harness primitive that must precede it. Build that primitive, then return immediately to the vertical proof. |\n| Register 2 can be rich enough for pure SDCPN projection. | Low-medium. ADR-0003 requires it, but no real fold or projector exists and FE-1480 asserts non-determinism. | The worked transformation identifies an unavoidable semantic choice not represented in captures/model. Record it earlier or explicitly revisit the ADR. |\n| Three to five turns can produce a meaningful scoped correction. | Low. No CPS runbook has been rehearsed. | Two rehearsals exceed the budget or require unrelated context. Narrow the region, preload explicit context, or revise the demo claim rather than script fake success. |\n| The proven ask suspension can extend to document-application client tools. | Medium-low. The suspension spike succeeded, but the production transport intentionally refuses machine tool-result follow-ups. | The first tool round-trip cannot preserve correlation, durability, or non-user evidence semantics. Treat this as a critical integration blocker, not a UI detail. |\n| The production website and remote server can be joined inside the timebox. | Medium-low. Local host seams exist; provider routing, session ownership, deployment, and release gates do not yet converge. | A deployable path is not proved by the end of Frontier 2. Preserve the real semantic loop and seek an explicit demo-surface decision rather than quietly falling back to test-only wiring. |\n| Requirements-model UI is unnecessary for comprehension. | Medium. The reviewer needs inspectability, but FE-1481 explicitly permits export. | Rehearsal shows that provenance and delta cannot be understood from chat plus a structured export. |\n\n## Current choice\n\nStop treating “unblocked” as “next.” The next strategic move is to run Frontier 0 immediately and\nopen Frontiers 1 and 2 in parallel: one worked CPS semantic slice and one existing-target reviewer\nsession/tool-return slice. Join them at the earliest correction, then drive the same bones through\nprovider routing and deployment. The generic Gherkin/plugin-freeze path and broad UI work wait for\nthat join.\n\nRevisit this choice as soon as Dora confirms the use case, the FE-1480 worked transformation lands,\nor either parallel frontier fails its first proof. A steering pass that only updates ticket status\ndoes not change this document; a new fact that changes the objective, proof spine, authority\nboundary, or cut line does.\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CejrKhsqzE7ZBmXWT1H` + +``` +{ + "output": "# Project coordination\n\nThis is the cross-map coordination surface for the `brunch-agent` project. FE-1383 owns the\nmilestone-one harness build; FE-1357 owns the September demo and process-model plugin design.\nLinear is canonical for issue state, parentage, and hard `blocks` relations. The\n[steering model](./STEERING.md) chooses the current objective, proof frontiers, and cuts under\npressure. This file projects that strategy onto mechanically available work: the current\nproject-wide recommendation, soft edges, unresolved seams, and exceptional roots.\n\nBefore revising the recommendation, run\n`turbo run linear:graph --filter '@hashintel/brunch-agent'`. Its compact projection supplies the\nfactual open-issue DAG; read the relevant issue bodies for semantic content, then infer the smallest\nhonest recommendation. Do not paste the generated graph here or mirror issue status.\n\n## Current sequencing recommendation\n\nAs of **2026-08-24**, FE-1476 (the September demo delivery) changes the recommendation from generic\npackage completion to a concrete CPS review-and-revise proof. After FE-1437 (the monorepo import)\nlands, open two fronts in parallel. The semantic front starts FE-1482 (the CPS plugin) against one\nworked fixture and settles FE-1480's requirements-model-to-SDCPN authority boundary before it\nimplements a projector; FE-1478 (net-to-requirements provenance) is part of that spine from its\nfirst types. The experience front advances FE-1438 (machine client-tool round-trip) and FE-1439\n(private sessions) far enough for a new reviewer conversation to target an existing document,\nwhile FE-1477/FE-1440 share one provider-routing implementation. Join the fronts at FE-1479\n(targeted re-elicitation), then drive the same path through FE-1423's pre-exposure gates and\nFE-1441 deployment.\n\nFE-1393's generic Gherkin artifact and FE-1387's second-target contract freeze no longer gate the\nSeptember proof. FE-1402, FE-1403, FE-1406, and FE-1431 supply only the completion, guidance,\nstrategy, and contract slices the CPS `review-and-revise` runbook consumes. FE-1481 selects\nYAML/Markdown export as the requirements-model inspection floor; broad UI follows only if the\nclosed loop is already proved.\n\n```text\nlegend:\n -[hard]-> native Linear blocker\n -[coord]-> either order; do not implement concurrently\n -[input]-> semantic input, not a blocker\n -[state-gate]-> condition in the world, not an issue edge\n\nnodes:\n FE-1437 [executed, landing] # history imported; HASH authoritative; PR pending\n FE-1476 [objective] # September reviewer demo\n FE-1482 [next, semantic] # concrete CPS plugin + review/revise runbook\n FE-1480 [decision, semantic] # model/projection authority, then projector\n FE-1478 [semantic proof] # provenance through all three registers\n FE-1438 [next, experience] # machine client-tool round-trip + application\n FE-1439 [next, experience] # existing-target reviewer session ownership\n FE-1477/FE-1440 [experience] # one provider-routing implementation\n FE-1479 [join] # targeted correction changes the live net\n FE-1481 [fallback] # structured model export before UI\n FE-1441 [deployed proof] # HASH deployment\n\nedges:\n FE-1449 -[hard]-> FE-1438\n FE-1438, FE-1439,\n FE-1437 -[hard]-> FE-1440\n FE-1437, FE-1439,\n FE-1423 -[hard]-> FE-1441\n FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439, FE-1393\n FE-1480 decision -[input]-> FE-1482, FE-1478\n FE-1402, FE-1403,\n FE-1406, FE-1431 -[input]-> FE-1482\n FE-1482, FE-1478,\n FE-1438, FE-1439 -[input]-> FE-1479\n FE-1479, FE-1440 -[input]-> FE-1441\n```\n\nHard-edge truth remains in Linear. The graph above is a deliberately focused recommendation,\nnot a second issue database.\n\n## Repository handoff threshold\n\nFE-1437 (the monorepo import; [execution plan](./hash-monorepo-import-plan.md)) was the authority\ncutover, not a general freeze on harness work. It was crossed on 2026-08-21:\n\n```text\nbrunch-lite authoritative (until 2026-08-21)\n FE-1434 + FE-1435 verdicts landed\n FE-1388/1389/1390/1399 review stack merged\n |\n v\n == FE-1437 import (executed) ==\n |\n v\nhashintel/hash authoritative (now)\n FE-1440 website wiring + FE-1441 deployment\n```\n\nThe standalone repository is frozen at SHA `43a0022918861846344b96a32cb94f92e2ee96ae` and is\nread-only reference material. All further work — including FE-1438 and FE-1439, which were not\nimport gates — happens in `hashintel/hash`. Do not run both repositories as writable authorities.\nClosing out the standalone repository's shared state (archival, access) is deferred and requires\nexplicit approval from Lu.\n\n## Open seams\n\n- **Projection authority — FE-1480.** The ticket assumes non-deterministic LLM inference from the\n requirements model to SDCPN, while ADR-0003 requires write-time-only semantic inference and a\n pure projection. A worked CPS transformation must assign every judgment to capture, fold,\n projection, or document application before the interface freezes.\n- **Controller and runbook.** The harness does not read the folded model or open issues back into\n the agent, and no plugin defines a job trajectory or stopping rule. FE-1482 must exercise the\n narrow `review-and-revise` loop; FE-1406 and FE-1402/FE-1403 are inputs, not parallel products.\n- **Reviewer target identity — FE-1439 × FE-1479.** The current host derives target-document\n identity from conversation identity. September requires a new reviewer conversation against an\n existing target without weakening owner isolation.\n- **Contract freeze — FE-1387.** The CPS target must stress the plugin contract before it freezes.\n The freeze follows the September semantic proof rather than gating it.\n- **Absence locator.** An absence capture carries no payload, but the fold needs a field-specific\n coordinate (anchor × slot). The plugin-contract spec records three worked cases; any envelope\n amendment belongs to the harness side of this seam.\n- **Structured-tap evidence — FE-1395 × capture store.** `resolve-conflict` currently rejects\n `user-affordance-payload` evidence. FE-1395 must decide the transport fact before the store\n rule can settle.\n- **Guidance placement — FE-1403 × FE-1406.** Plugin cards and the harness-shipped generic\n strategy quiver share authoring methods but not ownership. Packages export; hosts register.\n- **Telemetry vocabulary — FE-1385 × FE-1404 × FE-1423.** The probe surface, experiment\n accounting, and remote telemetry should share span vocabulary rather than invent it three\n times.\n- **Living-prototype charter.** The deployed elicitor as a cumulative record of proved and\n unproved behavior remains pre-charter until the infrastructure conversation settles.\n\nSettled seam decisions still governing open work: FE-1392 established the plugin-declared\nverbatim proposal floor, and ask accounting remains a read-time relation rather than an envelope\nfield. ADR-0003 keeps field-level structure below the capture's single epistemic status.\n\n## Exceptional roots\n\nThese project issues intentionally have no parent and are roots under the registry rule:\n\n- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** ADR-0004 un-deferred this as\n September topology, while FE-1476's new reviewer scenario starts from an existing target. Keep\n the conflict visible until Dora confirms the use case and the ADR is amended if necessary.\n- **FE-1334 — offer the user a surprising scenario of their model.** A validation gesture with\n no owning map yet; closest to the motif/quiver strategy work.\n- **FE-1406 — design reusable elicitation strategies.** The cross-map home for the\n harness-shipped generic strategy quiver; intentionally independent of either delivery map.\n- **FE-1472 — evaluate the nested Anthropic SDK pin.** Unrelated triage root; no owning delivery\n map has been chosen.\n- **FE-1476 — prepare the September demo.** Temporary delivery root pending the recommended fold\n under FE-1357.\n- **FE-1477 through FE-1482 — September outcome slices.** PM-authored issues adopted by the\n steering model but not yet folded in Linear. The recommended parent is FE-1476; overlaps and\n ownership boundaries are recorded in STEERING's issue projection before external mutation.\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CejrLBy1mv7nq81RC0k` + +``` +{ + "output": "sed: docs/INDEX.md: No such file or directory\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "sed -n '63,80p' docs/INDEX.md", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "git diff --check -- libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md; git diff --stat -- libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "git diff -- libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md | sed -n '1,340p'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034Cek53htAlJQWEntJALf` + +``` +{ + "output": "| [notes/deep-read-fe-1389](planning/process-model-elicitation/notes/deep-read-fe-1389.md) | active | FE-1401 / findings in FE-1420 | Deep-read of the walking skeleton: builder's account, spec-discharge table (issues 10/13 capabilities discharged; markdown floor contradicted in the UI), 12 findings; source of PR #10's backfilled record |\n| [notes/deep-read-fe-1390](planning/process-model-elicitation/notes/deep-read-fe-1390.md) | active | FE-1401 / probes on FE-1419 | Deep-read of the capture store: spec-discharge table, write-time tiering assessment (penciled item 7), the FE-1405 status-arity answer, and live-probed confirmation of FE-1419's capture-store claims plus one new aliasing hole; source of PR #11's backfilled record |\n| [plugin-contract-spec](planning/process-model-elicitation/plugin-contract-spec.md) | active | FE-1431 (spec issue); decided on FE-1405 | Provisional spec: a plugin is two schemas and two tables (model schema, proposal catalog, fold table, demand table) over the three-register IR (ADR-0003) — harness-machinery typology, standard-interiors library, grade-as-narrowing, derived fold rules; strains 4–7 and envelope pressure #2 held open with owners |\n\n## planning/\\_shared (cross-effort control documents)\n\n| Document | Status | Linear | Digest |\n| -------------------------------------------------------------------------------- | ---------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| [COORDINATION](planning/_shared/COORDINATION.md) | active | cross-project; maintained by arc-close | Current sequencing recommendation, soft cross-map edges, unresolved seams, and exceptional roots; hard blockers, state, and hierarchy remain in Linear |\n| [hash-monorepo-import-plan](planning/_shared/hash-monorepo-import-plan.md) | active until FE-1437 lands | FE-1437 | Native HASH assimilation plan: preserved history and child package workspaces under one Brunch context root, explicit authority cutover, exhaustive repository-material disposition, toolchain port, boundary gates, and verification |\n| [SPEC-LEDGER](planning/_shared/SPEC-LEDGER.md) | active until milestone-one closure | FE-1383 | Obligation-level status and evidence ledger for the elicitation-kernel specification; settles when the milestone closes |\n| [STEERING](planning/_shared/STEERING.md) | active | FE-1357 / FE-1476 | Current objective-driven strategy for the September CPS review-and-revise proof: evidence, architectural pressure, proof frontiers, cuts, issue projection, risks, and replan conditions |\n| [flue-architecture-cheatsheet](planning/_shared/flue-architecture-cheatsheet.md) | active | commented on FE-1383; feeds docs/agents/flue-routing.md | Architect's consolidation of all 21 Flue guide pages: direct structured generation uses `harness.prompt`; model-delegated work uses `useSubagent`; three-lane boundary summary and ranked divergence risks; reconciled against installed Flue 2.0.3 source |\n| [topology](planning/_shared/topology.md) | active | ratified → ADR-0002; N1 discharged by FE-1422 + FE-1392; local N5 implemented by FE-1391; N3 amended by FE-1437 | Pseudo-style verification of the package/app tree against the three-lane model and spec §12.2: portable ask/sweep protocols, Flue binding wiring, package boundaries, and application-only Brunch–Petrinaut composition |\n\n## planning/legibility-sweep (FE-1401 arc records)\n\n| Document | Status | Linear | Digest |\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034Cek55eiK2UBnapC75mu` + +``` +{ + "output": " libs/@hashintel/brunch-agent/docs/INDEX.md | 1 +\n .../docs/planning/_shared/COORDINATION.md | 93 ++++++++++++++--------\n 2 files changed, 59 insertions(+), 35 deletions(-)\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034Cek56pKeADZNxtxu42g` + +``` +{ + "output": "diff --git a/libs/@hashintel/brunch-agent/docs/INDEX.md b/libs/@hashintel/brunch-agent/docs/INDEX.md\nindex ca6ea309c0..b0834155a7 100644\n--- a/libs/@hashintel/brunch-agent/docs/INDEX.md\n+++ b/libs/@hashintel/brunch-agent/docs/INDEX.md\n@@ -71,6 +71,7 @@ _(empty — items settle out via the arc-close inbox sweep)_\n | [COORDINATION](planning/_shared/COORDINATION.md) | active | cross-project; maintained by arc-close | Current sequencing recommendation, soft cross-map edges, unresolved seams, and exceptional roots; hard blockers, state, and hierarchy remain in Linear |\n | [hash-monorepo-import-plan](planning/_shared/hash-monorepo-import-plan.md) | active until FE-1437 lands | FE-1437 | Native HASH assimilation plan: preserved history and child package workspaces under one Brunch context root, explicit authority cutover, exhaustive repository-material disposition, toolchain port, boundary gates, and verification |\n | [SPEC-LEDGER](planning/_shared/SPEC-LEDGER.md) | active until milestone-one closure | FE-1383 | Obligation-level status and evidence ledger for the elicitation-kernel specification; settles when the milestone closes |\n+| [STEERING](planning/_shared/STEERING.md) | active | FE-1357 / FE-1476 | Current objective-driven strategy for the September CPS review-and-revise proof: evidence, architectural pressure, proof frontiers, cuts, issue projection, risks, and replan conditions |\n | [flue-architecture-cheatsheet](planning/_shared/flue-architecture-cheatsheet.md) | active | commented on FE-1383; feeds docs/agents/flue-routing.md | Architect's consolidation of all 21 Flue guide pages: direct structured generation uses `harness.prompt`; model-delegated work uses `useSubagent`; three-lane boundary summary and ranked divergence risks; reconciled against installed Flue 2.0.3 source |\n | [topology](planning/_shared/topology.md) | active | ratified → ADR-0002; N1 discharged by FE-1422 + FE-1392; local N5 implemented by FE-1391; N3 amended by FE-1437 | Pseudo-style verification of the package/app tree against the three-lane model and spec §12.2: portable ask/sweep protocols, Flue binding wiring, package boundaries, and application-only Brunch–Petrinaut composition |\n \ndiff --git a/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md b/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\nindex 54e343fb83..8c2d3d1ca4 100644\n--- a/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n+++ b/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n@@ -2,9 +2,10 @@\n \n This is the cross-map coordination surface for the `brunch-agent` project. FE-1383 owns the\n milestone-one harness build; FE-1357 owns the September demo and process-model plugin design.\n-Linear is canonical for issue state, parentage, and hard `blocks` relations. This file owns\n-only the judgment Linear cannot express: the current project-wide recommendation, soft edges,\n-unresolved seams, and exceptional roots.\n+Linear is canonical for issue state, parentage, and hard `blocks` relations. The\n+[steering model](./STEERING.md) chooses the current objective, proof frontiers, and cuts under\n+pressure. This file projects that strategy onto mechanically available work: the current\n+project-wide recommendation, soft edges, unresolved seams, and exceptional roots.\n \n Before revising the recommendation, run\n `turbo run linear:graph --filter '@hashintel/brunch-agent'`. Its compact projection supplies the\n@@ -13,19 +14,22 @@ honest recommendation. Do not paste the generated graph here or mirror issue sta\n \n ## Current sequencing recommendation\n \n-As of **2026-08-21**, the FE-1437 authority cutover has been executed: the full brunch-lite\n-history is imported on `ln/fe-1437-hash-monorepo-import` in `hashintel/hash` (frozen standalone\n-SHA `43a0022918861846344b96a32cb94f92e2ee96ae`), every import gate re-verified. `hashintel/hash`\n-is authoritative; the standalone repository accepts no further implementation work. FE-1437\n-closes when the branch lands on `main` (squash merge, per convention). Part of FE-1440's website\n-wiring (the Brunch interactive-tool panel in `apps/petrinaut-website`) travelled with the import\n-branch; FE-1440 was trimmed on 2026-08-21 to the remaining mode wiring (mode switch, browser\n-identifier bootstrap, remote transport swap). After landing, advance FE-1438 (client-tool round-trip)\n-beside FE-1393 (plugin SDK and first projection); FE-1439 (private durable sessions) proceeds in\n-parallel. The integration stream joins at FE-1440 and deployment follows at FE-1441 (which also\n-waits on FE-1423's pre-exposure gates), while the harness stream reaches its contract-freeze\n-decision at FE-1387. FE-1402/FE-1403 form a parallel content/evaluation stream, without\n-displacing the two convergence edges.\n+As of **2026-08-24**, FE-1476 (the September demo delivery) changes the recommendation from generic\n+package completion to a concrete CPS review-and-revise proof. After FE-1437 (the monorepo import)\n+lands, open two fronts in parallel. The semantic front starts FE-1482 (the CPS plugin) against one\n+worked fixture and settles FE-1480's requirements-model-to-SDCPN authority boundary before it\n+implements a projector; FE-1478 (net-to-requirements provenance) is part of that spine from its\n+first types. The experience front advances FE-1438 (machine client-tool round-trip) and FE-1439\n+(private sessions) far enough for a new reviewer conversation to target an existing document,\n+while FE-1477/FE-1440 share one provider-routing implementation. Join the fronts at FE-1479\n+(targeted re-elicitation), then drive the same path through FE-1423's pre-exposure gates and\n+FE-1441 deployment.\n+\n+FE-1393's generic Gherkin artifact and FE-1387's second-target contract freeze no longer gate the\n+September proof. FE-1402, FE-1403, FE-1406, and FE-1431 supply only the completion, guidance,\n+strategy, and contract slices the CPS `review-and-revise` runbook consumes. FE-1481 selects\n+YAML/Markdown export as the requirements-model inspection floor; broad UI follows only if the\n+closed loop is already proved.\n \n ```text\n legend:\n@@ -36,29 +40,30 @@ legend:\n \n nodes:\n FE-1437 [executed, landing] # history imported; HASH authoritative; PR pending\n- FE-1438 [next] # client-tool round-trip\n- FE-1439 [next, parallel] # private durable sessions\n- FE-1440 [join, partly landed] # website elicitor mode; panel wiring on import branch\n- FE-1441 [post-landing] # HASH deployment\n- FE-1393 [next] # plugin SDK + first projection\n- FE-1387 [after-FE-1393] # second pack + contract freeze\n- FE-1395 [coordination] # full affordance set\n- FE-1402 [parallel, content] # completion contract\n- FE-1403 [parallel, content] # interviewing guidance\n- FE-1404 [after-content] # armed baseline\n+ FE-1476 [objective] # September reviewer demo\n+ FE-1482 [next, semantic] # concrete CPS plugin + review/revise runbook\n+ FE-1480 [decision, semantic] # model/projection authority, then projector\n+ FE-1478 [semantic proof] # provenance through all three registers\n+ FE-1438 [next, experience] # machine client-tool round-trip + application\n+ FE-1439 [next, experience] # existing-target reviewer session ownership\n+ FE-1477/FE-1440 [experience] # one provider-routing implementation\n+ FE-1479 [join] # targeted correction changes the live net\n+ FE-1481 [fallback] # structured model export before UI\n+ FE-1441 [deployed proof] # HASH deployment\n \n edges:\n FE-1449 -[hard]-> FE-1438\n- FE-1392 -[hard]-> FE-1393\n FE-1438, FE-1439,\n FE-1437 -[hard]-> FE-1440\n FE-1437, FE-1439,\n FE-1423 -[hard]-> FE-1441\n- FE-1393 -[hard]-> FE-1387\n- FE-1402, FE-1403 -[hard]-> FE-1404\n- FE-1395 -[coord]-> FE-1438\n FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439, FE-1393\n- FE-1387 -[input]-> FE-1440\n+ FE-1480 decision -[input]-> FE-1482, FE-1478\n+ FE-1402, FE-1403,\n+ FE-1406, FE-1431 -[input]-> FE-1482\n+ FE-1482, FE-1478,\n+ FE-1438, FE-1439 -[input]-> FE-1479\n+ FE-1479, FE-1440 -[input]-> FE-1441\n ```\n \n Hard-edge truth remains in Linear. The graph above is a deliberately focused recommendation,\n@@ -90,8 +95,18 @@ explicit approval from Lu.\n \n ## Open seams\n \n-- **Contract freeze — FE-1387.** The process-model target must stress the plugin contract before\n- it freezes. FE-1393 makes the contract programmable; FE-1387 remains the cross-map hinge.\n+- **Projection authority — FE-1480.** The ticket assumes non-deterministic LLM inference from the\n+ requirements model to SDCPN, while ADR-0003 requires write-time-only semantic inference and a\n+ pure projection. A worked CPS transformation must assign every judgment to capture, fold,\n+ projection, or document application before the interface freezes.\n+- **Controller and runbook.** The harness does not read the folded model or open issues back into\n+ the agent, and no plugin defines a job trajectory or stopping rule. FE-1482 must exercise the\n+ narrow `review-and-revise` loop; FE-1406 and FE-1402/FE-1403 are inputs, not parallel products.\n+- **Reviewer target identity — FE-1439 × FE-1479.** The current host derives target-document\n+ identity from conversation identity. September requires a new reviewer conversation against an\n+ existing target without weakening owner isolation.\n+- **Contract freeze — FE-1387.** The CPS target must stress the plugin contract before it freezes.\n+ The freeze follows the September semantic proof rather than gating it.\n - **Absence locator.** An absence capture carries no payload, but the fold needs a field-specific\n coordinate (anchor × slot). The plugin-contract spec records three worked cases; any envelope\n amendment belongs to the harness side of this seam.\n@@ -114,9 +129,17 @@ field. ADR-0003 keeps field-level structure below the capture's single epistemic\n \n These project issues intentionally have no parent and are roots under the registry rule:\n \n-- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** Deferred post-September\n- consumer topology; returns after in-Petrinaut staging proves itself.\n+- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** ADR-0004 un-deferred this as\n+ September topology, while FE-1476's new reviewer scenario starts from an existing target. Keep\n+ the conflict visible until Dora confirms the use case and the ADR is amended if necessary.\n - **FE-1334 — offer the user a surprising scenario of their model.** A validation gesture with\n no owning map yet; closest to the motif/quiver strategy work.\n - **FE-1406 — design reusable elicitation strategies.** The cross-map home for the\n harness-shipped generic strategy quiver; intentionally independent of either delivery map.\n+- **FE-1472 — evaluate the nested Anthropic SDK pin.** Unrelated triage root; no owning delivery\n+ map has been chosen.\n+- **FE-1476 — prepare the September demo.** Temporary delivery root pending the recommended fold\n+ under FE-1357.\n+- **FE-1477 through FE-1482 — September outcome slices.** PM-authored issues adopted by the\n+ steering model but not yet folded in Linear. The recommended parent is FE-1476; overlaps and\n+ ownership boundaries are recorded in STEERING's issue projection before external mutation.\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `apply_patch` + +```json +{ + "patchText": "*** Begin Patch\n*** Update File: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n@@\n- FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439, FE-1393\n+ FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439\n@@\n-These project issues intentionally have no parent and are roots under the registry rule:\n+These project issues currently have no parent. Some are intentional roots; the temporary or\n+unresolved roots are named here until their Linear parentage is settled:\n*** End Patch" +} +``` + +## User + +**Tool Result:** `TU-034CekGiiRgw1pZ1J1qAGT` + +``` +{ + "files": [ + { + "uri": "file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md", + "diff": "Index: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n===================================================================\n--- /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n+++ /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n@@ -56,9 +56,9 @@\n FE-1438, FE-1439,\n FE-1437 -[hard]-> FE-1440\n FE-1437, FE-1439,\n FE-1423 -[hard]-> FE-1441\n- FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439, FE-1393\n+ FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439\n FE-1480 decision -[input]-> FE-1482, FE-1478\n FE-1402, FE-1403,\n FE-1406, FE-1431 -[input]-> FE-1482\n FE-1482, FE-1478,\n@@ -126,9 +126,10 @@\n field. ADR-0003 keeps field-level structure below the capture's single epistemic status.\n \n ## Exceptional roots\n \n-These project issues intentionally have no parent and are roots under the registry rule:\n+These project issues currently have no parent. Some are intentional roots; the temporary or\n+unresolved roots are named here until their Linear parentage is settled:\n \n - **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** ADR-0004 un-deferred this as\n September topology, while FE-1476's new reviewer scenario starts from an existing target. Keep\n the conflict visible until Dora confirms the use case and the ADR is amended if necessary.\n", + "type": "update", + "additions": 3, + "deletions": 2 + } + ], + "summary": "update: /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md (+3/-2)" +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "sed -n '44,74p' docs/planning/_shared/COORDINATION.md; sed -n '120,155p' docs/planning/_shared/COORDINATION.md", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CekNwpeOY5YQMx9PhLB` + +``` +{ + "output": " FE-1482 [next, semantic] # concrete CPS plugin + review/revise runbook\n FE-1480 [decision, semantic] # model/projection authority, then projector\n FE-1478 [semantic proof] # provenance through all three registers\n FE-1438 [next, experience] # machine client-tool round-trip + application\n FE-1439 [next, experience] # existing-target reviewer session ownership\n FE-1477/FE-1440 [experience] # one provider-routing implementation\n FE-1479 [join] # targeted correction changes the live net\n FE-1481 [fallback] # structured model export before UI\n FE-1441 [deployed proof] # HASH deployment\n\nedges:\n FE-1449 -[hard]-> FE-1438\n FE-1438, FE-1439,\n FE-1437 -[hard]-> FE-1440\n FE-1437, FE-1439,\n FE-1423 -[hard]-> FE-1441\n FE-1437 branch on main -[state-gate]-> FE-1438, FE-1439\n FE-1480 decision -[input]-> FE-1482, FE-1478\n FE-1402, FE-1403,\n FE-1406, FE-1431 -[input]-> FE-1482\n FE-1482, FE-1478,\n FE-1438, FE-1439 -[input]-> FE-1479\n FE-1479, FE-1440 -[input]-> FE-1441\n```\n\nHard-edge truth remains in Linear. The graph above is a deliberately focused recommendation,\nnot a second issue database.\n\n## Repository handoff threshold\n\nFE-1437 (the monorepo import; [execution plan](./hash-monorepo-import-plan.md)) was the authority\n times.\n- **Living-prototype charter.** The deployed elicitor as a cumulative record of proved and\n unproved behavior remains pre-charter until the infrastructure conversation settles.\n\nSettled seam decisions still governing open work: FE-1392 established the plugin-declared\nverbatim proposal floor, and ask accounting remains a read-time relation rather than an envelope\nfield. ADR-0003 keeps field-level structure below the capture's single epistemic status.\n\n## Exceptional roots\n\nThese project issues currently have no parent. Some are intentional roots; the temporary or\nunresolved roots are named here until their Linear parentage is settled:\n\n- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** ADR-0004 un-deferred this as\n September topology, while FE-1476's new reviewer scenario starts from an existing target. Keep\n the conflict visible until Dora confirms the use case and the ADR is amended if necessary.\n- **FE-1334 — offer the user a surprising scenario of their model.** A validation gesture with\n no owning map yet; closest to the motif/quiver strategy work.\n- **FE-1406 — design reusable elicitation strategies.** The cross-map home for the\n harness-shipped generic strategy quiver; intentionally independent of either delivery map.\n- **FE-1472 — evaluate the nested Anthropic SDK pin.** Unrelated triage root; no owning delivery\n map has been chosen.\n- **FE-1476 — prepare the September demo.** Temporary delivery root pending the recommended fold\n under FE-1357.\n- **FE-1477 through FE-1482 — September outcome slices.** PM-authored issues adopted by the\n steering model but not yet folded in Linear. The recommended parent is FE-1476; overlaps and\n ownership boundaries are recorded in STEERING's issue projection before external mutation.\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "jq -r '.scripts | to_entries[] | select(.key|test(\"^(lint|test|build|fix:format)\")) | \"\\(.key)=\\(.value)\"' package.json | sed -n '1,160p'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "yarn oxfmt --help | sed -n '1,180p'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "git status --short; printf '%s\\n' '--- manifest'; git status --short -- libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "find docs/inbox -maxdepth 1 -type f -not -name '.DS_Store' -not -name '.gitkeep' -print 2>/dev/null; printf '%s\\n' '--- spec ledger references to affected obligations'; rg -n \"FE-147|FE-148|CPS|projection|Petrinaut|plugin\" docs/planning/_shared/SPEC-LEDGER.md | head -100", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CekYfG1MyOTg5hrDmVz` + +``` +{ + "output": "fix:format=oxfmt --write\nlint=npm-run-all --continue-on-error \"lint:*\"\nlint:constraints=yarn constraints\nlint:eslint=CARGO_TERM_PROGRESS_WHEN=never turbo --continue=always lint:eslint --\nlint:format=oxfmt --check\nlint:license-in-workspaces=yarn workspace @local/repo-chores exe scripts/check-license-in-workspaces.ts\nlint:markdownlint=mise exec --env dev markdownlint-cli2 -- markdownlint-cli2\nlint:skill=yarn agents:skill-management validate\nlint:taplo=taplo fmt --check\nlint:tsc=mise run lint:tsc\nlint:yarn-deduplicate=yarn dedupe --strategy highest --check\ntest=npm-run-all --continue-on-error \"test:*\"\ntest:integration=CARGO_TERM_PROGRESS_WHEN=never turbo run test:integration --env-mode=loose --\ntest:playwright=CARGO_TERM_PROGRESS_WHEN=never turbo run test:integration --env-mode=loose --filter @tests/hash-playwright --\ntest:unit=CARGO_TERM_PROGRESS_WHEN=never turbo run test:unit --env-mode=loose --\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CekYg2JVLrzgKw7ueZr` + +``` +{ + "output": "Usage: [-c=PATH] [PATH]...\n\nMode Options:\n --init Initialize `.oxfmtrc.json` with default values\n --migrate=SOURCE Migrate configuration to `.oxfmtrc.json` from specified source\n Available sources: prettier, biome\n --lsp Start language server protocol (LSP) server\n --stdin-filepath=PATH Specify the file name to use to infer which parser to use\n\nOutput Options:\n --write Format and write files in place (default)\n --check Check if files are formatted, also show statistics\n --list-different List files that would be changed\n\nConfig Options\n -c, --config=PATH Path to the configuration file (.json, .jsonc, .ts, .mts, .cts, .js,\n .mjs, .cjs)\n --disable-nested-config Do not search for configuration files in subdirectories\n\nIgnore Options\n --ignore-path=PATH Path to ignore file(s). Can be specified multiple times. If not\n specified, .gitignore and .prettierignore in the current directory are\n used.\n --with-node-modules Format code in node_modules directory (skipped by default)\n\nRuntime Options\n --no-error-on-unmatched-pattern Do not exit with error when pattern is unmatched\n --threads=INT Number of threads to use. Set to 1 for using only 1 CPU core.\n\nAvailable positional items:\n PATH Single file, path or list of paths. Glob patterns are also supported.\n (Be sure to quote them, otherwise your shell may expand them before\n passing.) Exclude patterns with `!` prefix like `'!**/fixtures/*.js'`\n are also supported. If not provided, current working directory is used.\n\nAvailable options:\n -h, --help Prints help information\n -V, --version Prints version information\n\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CekYgQWoicWIdAeBogw` + +``` +{ + "output": " M libs/@hashintel/brunch-agent/docs/INDEX.md\n M libs/@hashintel/brunch-agent/docs/agents/git-workflow.md\n M libs/@hashintel/brunch-agent/docs/agents/issue-writing.md\n M libs/@hashintel/brunch-agent/docs/agents/legibility.md\n M libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n M libs/@hashintel/brunch-agent/docs/planning/_shared/hash-monorepo-import-plan.md\n?? libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n--- manifest\n M libs/@hashintel/brunch-agent/docs/INDEX.md\n M libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\n?? libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CekYgod3wfyc7qMtIAB` + +``` +{ + "output": "--- spec ledger references to affected obligations\n20:| Shell separation: plugins→core only; core imports no substrate; binding imports both | §4, §12.2 | **discharged** | boundary gates (FE-1388/FE-1399, `test/boundaries.test.ts`); `workspacePackages()` derives groups from manifest; `plugin-gherkin` imports `@brunch/core` only |\n21:| Package topology | §12.2 | **partial** | `core` (+`testing` subpath), `binding-flue`, `transport-aisdk`, `plugin-gherkin`, `apps/brunch-agent` exist; `plugin-assurance` pending. FE-1437 imported them to their native HASH destinations and preserved the existing dependency boundaries. Topology pin derives from §12.2 itself (FE-1400 `ef00201`); FE-1436 adds the transport-only dependency gate. |\n26:| Host-authored thin agent calling `useElicitation(plugin, session)` | §12.1 | **discharged** | `apps/brunch-agent/src/agents/gherkin-elicitor.ts`; FE-1392 adds host-owned immutable session/document and transport wiring |\n29:| Remote-parity constraints (pinned agentName, storage outside plugin, no dynamic agents) | §12.5 | **discharged** | pinned-identity gates (FE-1399/FE-1400); storage port in binding (FE-1390) |\n40:| Confidence qualitative, never a scalar | §5 | **partial** | non-empty string only; `\"0.93\"` accepted. Vocabulary is settled by the plugin-contract spec as `firm | hedged | speculative`; its proposed store refusal rule for numeric-parsing strings remains to implement |\n43:| One epistemic status per capture | §5 | **discharged**, with named friction | Status is the proposal union's discriminant, coupled to provenance shape — per-field status is unrepresentable, and payload-smuggling it breaks dedup identity. This was FE-1405's central input (deep-read FE-1390, tiering section); the arc consumed it _without_ amendment — one status per capture survives, and the structure that wanted per-field status lives below it in proposal interiors (ADR-0003, plugin-contract spec) |\n49:| `project` + typed loss report; `validate`; optional `reconcile`; purity (C2) | §6.1 | **pending** | FE-1392 adds only the plugin-declared `statement-noted` verbatim proposal floor; operations remain FE-1393 |\n52:| Duplicate detection free for flat-record plugins | §6.2 | **partial** | near-identical advisory fires for string payloads only; a flat record gets none |\n55:| Cadence as policy (§6.4) | §6.4 | **partial** | FE-1392 makes successful sweep the cadence boundary and keeps projection/validation read-time-only, leaving sweep outcome unchanged. Concrete operations remain absent until FE-1393 |\n90:| Only the true user's side is evidence; injected entries structurally non-user | §9.4 | **partial** | FE-1391 verifies role/purpose against the public projection, refuses signal/advisory text, and classifies affordance replies only from the harness-owned reply-binding signal. The kickoff remains a machine-authored `user` entry until FE-1420/FE-1385 move it to `useInitialData`; FE-1396 still owns briefing-never-evidence |\n92:| Storage port: harness-defined, binding-implemented, plugin-blind (C1) | §9.6 | **discharged for the local target** | core owns capture/archive/anchoring semantics; `binding-flue` owns the file implementation; plugins cannot import the binding (FE-1390 + FE-1391) |\n94:| Compaction vs. durable log | §9.7 | **partial — source-settled, behavioral pin open** | Flue 2.0.3's append-only stream contract and implementation show compaction appends a canonical record, rewrites only model context, preserves the public message projection, and leaves `state_write` reduction untouched. The source-read record reshapes FE-1386 to one upgrade pin; `test/open-gaps.ts` remains until behavioral proof lands |\n101:| Caps 6–8, incl. entry-projection read | §10 | **discharged** | FE-1391 supplies the public reader/archive. FE-1392 uses direct structured `harness.prompt` inside a durable tool whose peek/extract/refresh/apply boundaries use `step.do`; the mounted runtime pins same-response finish-hook steering and refresh-before-apply |\n107:| Plugin ownership: packs, forms, validators | §11.1 | **partial** | `plugin-gherkin` now owns its one FE-1392 proposal declaration/schema and target identity; packs, forms, validators, fold, and demand table remain FE-1393/FE-1387 work |\n109:| Smallest honest plugin as a standing bar | §11.3 | **partial** | `statement-noted.test.ts` and the core plugin fixture encode the one-type verbatim floor and reject undeclared parsed/pointer shape; the standing bar must grow with FE-1393's operations |\n122:| Invariants 3, 8 (projection loss, equivalent projection) | §14.1 | **pending** | no `project` exists |\n124:| Gating tests (reprojection, minimal pairs, black-box authoring) | §14.3 | **pending** | — |\n", + "exitCode": 0 +} +``` + +## Assistant + +The reviewed plan now makes the production sweep itself part of “done”: the correction must originate in the reviewer’s utterance and become a real superseding capture. It also requires the prebuilt demo baseline to begin from valid source conversation/capture state, not a hand-authored model with decorative provenance. I’m moving through the package’s verification and control-surface closeout now. + +**Tool Use:** `shell_command` + +```json +{ + "command": "yarn markdownlint-cli2 libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md && turbo run lint:eslint --filter '@hashintel/brunch-agent'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 60000 +} +``` + +## User + +**Tool Result:** `TU-034CekpIOxnYwkta6op8sD` + +``` +{ + "output": "Usage Error: Couldn't find a script named \"markdownlint-cli2\".\n\n$ yarn run [--inspect] [--inspect-brk] [-T,--top-level] [-B,--binaries-only] [--require #0] ...\n", + "exitCode": 1 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "mise exec --env dev markdownlint-cli2 -- markdownlint-cli2 libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md && turbo run lint:eslint --filter '@hashintel/brunch-agent'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 60000 +} +``` + +## User + +**Tool Result:** `TU-034Cel1wEvg9lhiTrj1jis` + +``` +{ + "output": "markdownlint-cli2 v0.22.1 (markdownlint v0.40.0)\nFinding: libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md *.md **/*.md **/*.mdc !**/LICENSE*.md !**/AGENTS*.md !node_modules/** !target/** !**/_temp/** !**/_ai/** !**/.cursor/plans/** !libs/@hashintel/ds-components/** !libs/@hashintel/ds-helpers/** !libs/@hashintel/brunch-agent/docs/**\nLinting: 256 file(s)\nSummary: 0 error(s)\nturbo 2.6.3\n\n• Packages in scope: @hashintel/brunch-agent\n• Running lint:eslint in 1 packages\n• Remote caching disabled\n@local/eslint:build: cache miss, executing 721d5b9a378f6a70\n@hashintel/brunch-agent:lint:eslint: cache miss, executing 59f21353e1c3ce33\n@hashintel/brunch-agent:lint:eslint: Found 0 warnings and 0 errors.\n@hashintel/brunch-agent:lint:eslint: Finished in 651ms on 29 files with 110 rules using 16 threads.\n\n Tasks: 2 successful, 2 total\nCached: 0 cached, 2 total\n Time: 5.875s \n\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "yarn oxfmt --check libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 60000 +} +``` + +## User + +**Tool Result:** `TU-034CelM4ZMYxG1P5RAJY93` + +``` +{ + "output": "(node:57738) [MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type of file:///Users/lunelson/Code/hashintel/hash/oxfmt.config.ts?cache=1787567470038 is not specified and it doesn't parse as CommonJS.\nReparsing as ES module because module syntax was detected. This incurs a performance overhead.\nTo eliminate this warning, add \"type\": \"module\" to /Users/lunelson/Code/hashintel/hash/package.json.\n(Use `node --trace-warnings ...` to show where the warning was created)\nChecking formatting...\n\nExpected at least one target file. All matched files may have been excluded by ignore rules.\n", + "exitCode": 2 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "yarn bin prettier || true; yarn bin markdownlint-cli2 || true; rg -n \"brunch-agent/docs|\\.md\" oxfmt.config.ts .prettierignore 2>/dev/null | head -80", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CelVd9SekIht8fTjx82` + +``` +{ + "output": "Usage Error: Couldn't find a binary named \"prettier\" for package \"hash@workspace:.\"\n\n$ yarn bin [-v,--verbose] [--json] [name]\nUsage Error: Couldn't find a binary named \"markdownlint-cli2\" for package \"hash@workspace:.\"\n\n$ yarn bin [-v,--verbose] [--json] [name]\noxfmt.config.ts:61: \"**/LICENSE*.md\",\noxfmt.config.ts:64: \"libs/@hashintel/brunch-agent/docs/**\",\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "turbo run lint:tsc --filter '@hashintel/brunch-agent'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 60000 +} +``` + +## User + +**Tool Result:** `TU-034Celf5ywUscVmI5cF36u` + +``` +{ + "output": "turbo 2.6.3\n\n• Packages in scope: @hashintel/brunch-agent\n• Running lint:tsc in 1 packages\n• Remote caching disabled\n@hashintel/brunch-agent:lint:tsc: cache miss, executing 50584d5be80cc7ec\n\n Tasks: 1 successful, 1 total\nCached: 0 cached, 1 total\n Time: 2.681s \n\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "turbo run test:unit --filter '@hashintel/brunch-agent'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 60000 +} +``` + +## User + +**Tool Result:** `TU-034CelqMiYvo5Mj62t4N5A` + +``` +{ + "output": "turbo 2.6.3\n\n• Packages in scope: @hashintel/brunch-agent\n• Running test:unit in 1 packages\n• Remote caching disabled\n@hashintel/brunch-agent:test:unit: cache miss, executing d4c5393b6af87011\n@hashintel/brunch-agent:test:unit: \n@hashintel/brunch-agent:test:unit: RUN v4.1.10 /Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent/packages/core\n@hashintel/brunch-agent:test:unit: \n@hashintel/brunch-agent:test:unit: ✓ test/architecture/boundaries.test.ts (29 tests) 33ms\n@hashintel/brunch-agent:test:unit: ✓ test/naming.test.ts (11 tests) 3ms\n@hashintel/brunch-agent:test:unit: ✓ test/capture-store.test.ts (24 tests) 21ms\n@hashintel/brunch-agent:test:unit: ✓ test/anchoring.test.ts (6 tests) 4ms\n@hashintel/brunch-agent:test:unit: ✓ test/session-log.test.ts (4 tests) 8ms\n@hashintel/brunch-agent:test:unit: ✓ test/sweep-protocol.test.ts (9 tests) 3ms\n@hashintel/brunch-agent:test:unit: ✓ test/architecture/workspace.test.ts (7 tests) 3ms\n@hashintel/brunch-agent:test:unit: ✓ test/architecture/linear-project-graph.test.ts (2 tests) 14ms\n@hashintel/brunch-agent:test:unit: ✓ test/architecture/docs-index.test.ts (7 tests) 12ms\n@hashintel/brunch-agent:test:unit: ✓ test/ask-protocol.test.ts (9 tests) 2ms\n@hashintel/brunch-agent:test:unit: stderr | test/architecture/open-gaps.test.ts\n@hashintel/brunch-agent:test:unit: \n@hashintel/brunch-agent:test:unit: ⚠ 3 verification gaps are open (spec §14.5 and friends):\n@hashintel/brunch-agent:test:unit: · restart-durability — FE-1396 (spec §14.5)\n@hashintel/brunch-agent:test:unit: · compaction-vs-durable-history — FE-1386 (spec §9.7, §14.5)\n@hashintel/brunch-agent:test:unit: · interpretation-render-plugin-seam — FE-1394 (spec §7.6, §14.5)\n@hashintel/brunch-agent:test:unit: Closing one means deleting its entry in the commit that lands its proof.\n@hashintel/brunch-agent:test:unit: \n@hashintel/brunch-agent:test:unit: \n@hashintel/brunch-agent:test:unit: ✓ test/architecture/open-gaps.test.ts (2 tests) 1ms\n@hashintel/brunch-agent:test:unit: ✓ test/architecture/baseline-runner.test.ts (4 tests) 1867ms\n@hashintel/brunch-agent:test:unit: ✓ checkpoints a truncated expert reply and stops before another interviewer call 756ms\n@hashintel/brunch-agent:test:unit: ✓ resume regenerates a trailing truncated expert reply before continuing 636ms\n@hashintel/brunch-agent:test:unit: ✓ continues a truncated final delivery without sending checkpoint metadata 311ms\n@hashintel/brunch-agent:test:unit: \n@hashintel/brunch-agent:test:unit: Test Files 12 passed (12)\n@hashintel/brunch-agent:test:unit: Tests 114 passed (114)\n@hashintel/brunch-agent:test:unit: Start at 12:31:31\n@hashintel/brunch-agent:test:unit: Duration 2.08s (transform 76ms, setup 0ms, import 155ms, tests 1.97s, environment 0ms)\n@hashintel/brunch-agent:test:unit: \n\n Tasks: 1 successful, 1 total\nCached: 0 cached, 1 total\n Time: 4.748s \n\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "turbo run build --filter '@hashintel/brunch-agent'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 60000 +} +``` + +## User + +**Tool Result:** `TU-034Cem7UfNqOgfA1Uva9tF` + +``` +{ + "output": "turbo 2.6.3\n\n• Packages in scope: @hashintel/brunch-agent\n• Running build in 1 packages\n• Remote caching disabled\n@hashintel/brunch-agent:build: cache bypass, force executing d9f7ac2bc077ccba\n@hashintel/brunch-agent:build: vite v8.1.0 building client environment for production...\n@hashintel/brunch-agent:build: \u001b[2K\r@hashintel/brunch-agent:build: transforming...✓ 13 modules transformed.\n@hashintel/brunch-agent:build: rendering chunks...\n@hashintel/brunch-agent:build: computing gzip size...\n@hashintel/brunch-agent:build: dist/client-tools.js 0.12 kB │ gzip: 0.12 kB\n@hashintel/brunch-agent:build: dist/storage.js 0.20 kB │ gzip: 0.15 kB\n@hashintel/brunch-agent:build: dist/plugin-BlyisbcK.js 0.68 kB │ gzip: 0.41 kB │ map: 3.09 kB\n@hashintel/brunch-agent:build: dist/testing/index.js 0.69 kB │ gzip: 0.41 kB │ map: 2.13 kB\n@hashintel/brunch-agent:build: dist/naming-DhqH8ada.js 0.78 kB │ gzip: 0.48 kB │ map: 4.29 kB\n@hashintel/brunch-agent:build: dist/session-log-1mbM2HlS.js 6.44 kB │ gzip: 2.22 kB │ map: 20.44 kB\n@hashintel/brunch-agent:build: dist/index.js 25.31 kB │ gzip: 7.67 kB │ map: 80.29 kB\n@hashintel/brunch-agent:build: \n@hashintel/brunch-agent:build: ✓ built in 23ms\n\n Tasks: 1 successful, 1 total\nCached: 0 cached, 1 total\n Time: 2.689s \n\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `skill` + +```json +{ + "name": "arc-close", + "arguments": "Close the steering-model control-surface arc. Manifest: docs/planning/_shared/STEERING.md, docs/planning/_shared/COORDINATION.md, docs/INDEX.md. Do not mutate Linear or unrelated worktree files." +} +``` + +## User + +**Tool Result:** `TU-034CemKIXqnng601WefzlI` + +``` +{ + "content": [ + { + "text": "\n# arc-close Skill\n\n\nRead `docs/agents/arc-close.md` from the Brunch context root and execute its five steps in order.\nThis wrapper carries no duplicate procedure. Report the required checks and whether each\nconditional control surface changed; never persist a no-op evaluation.\n\n\nARGUMENTS: Close the steering-model control-surface arc. Manifest: docs/planning/_shared/STEERING.md, docs/planning/_shared/COORDINATION.md, docs/INDEX.md. Do not mutate Linear or unrelated worktree files.\n\nBase directory for this skill: file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/.agents/skills/arc-close\nRelative paths in this skill (e.g., scripts/, reference/) are relative to this base directory.\n", + "type": "text" + } + ] +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "turbo run linear:graph --filter '@hashintel/brunch-agent' 2>/dev/null | sed -n '/project brunch-agent/,$p'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 60000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "git diff --check -- libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md; if rg -n '[[:blank:]]+$' libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md; then exit 1; fi; printf '%s\\n' 'no whitespace errors'", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "printf '%s\\n' '--- inbox'; find docs/inbox -maxdepth 1 -type f -not -name '.DS_Store' -not -name '.gitkeep' -print 2>/dev/null; printf '%s\\n' '--- manifest status'; git status --short -- docs/INDEX.md docs/planning/_shared/COORDINATION.md docs/planning/_shared/STEERING.md; printf '%s\\n' '--- unrelated status retained'; git status --short -- docs/agents/git-workflow.md docs/agents/issue-writing.md docs/agents/legibility.md docs/planning/_shared/hash-monorepo-import-plan.md", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CemaoZZtzEmqq2jtwmT` + +``` +{ + "output": "@hashintel/brunch-agent:linear:graph: project brunch-agent open=35 hard=16\n@hashintel/brunch-agent:linear:graph: legend: L=hard-dependency layer; p=parent; <=blocked by; =>blocks; *=outside project\n@hashintel/brunch-agent:linear:graph: L0 FE-1331 [Todo root] | Start elicitation from Petrinaut's create-new-net flow\n@hashintel/brunch-agent:linear:graph: L0 FE-1334 [Todo root] | Offer user a surprising scenario of their model\n@hashintel/brunch-agent:linear:graph: L0 FE-1357 [In progress root] | Plan the September elicitation demo and plugin specification\n@hashintel/brunch-agent:linear:graph: L0 FE-1383 [In progress root] | Build the first complete elicitation interview\n@hashintel/brunch-agent:linear:graph: L0 FE-1386 [Backlog p:FE-1383] | Test durable history across transcript compaction\n@hashintel/brunch-agent:linear:graph: L0 FE-1393 [Todo p:FE-1383] =>FE-1384,FE-1387,FE-1394 | Produce the first Gherkin artifact through the plugin SDK\n@hashintel/brunch-agent:linear:graph: L0 FE-1395 [Todo p:FE-1383] =>FE-1385 | Add choices, questionnaires, and explicit absence replies\n@hashintel/brunch-agent:linear:graph: L0 FE-1402 [Next up p:FE-1357] =>FE-1404 | Define and rehearse the elicitation completion contract\n@hashintel/brunch-agent:linear:graph: L0 FE-1403 [Next up p:FE-1357] =>FE-1404 | Assemble and test the CPS interview guidance\n@hashintel/brunch-agent:linear:graph: L0 FE-1406 [Next up root] | Design reusable elicitation strategies\n@hashintel/brunch-agent:linear:graph: L0 FE-1407 [Next up p:FE-1357] | Catalogue elicitor failures that published measures miss\n@hashintel/brunch-agent:linear:graph: L0 FE-1420 [Next up p:FE-1383] | Make affordance handling safe under retries and abandonment\n@hashintel/brunch-agent:linear:graph: L0 FE-1431 [Todo p:FE-1357] | Define declarative plugin authoring\n@hashintel/brunch-agent:linear:graph: L0 FE-1437 [Ready for review p:FE-1433] =>FE-1440,FE-1441 | Move brunch-agent into hashintel/hash with its history\n@hashintel/brunch-agent:linear:graph: L0 FE-1438 [Todo p:FE-1433] =>FE-1440 | Build and repair Petrinaut nets through client tools\n@hashintel/brunch-agent:linear:graph: L0 FE-1439 [Todo p:FE-1433] =>FE-1440,FE-1441 | Keep elicitation sessions private and durable per browser\n@hashintel/brunch-agent:linear:graph: L0 FE-1448 [Ready for review p:FE-1433] | Let Petrinaut hosts render interactive chat tools\n@hashintel/brunch-agent:linear:graph: L0 FE-1472 [Triage root] | Evaluate the cost of pinning bedrock-sdk's nested Anthropic SDK\n@hashintel/brunch-agent:linear:graph: L0 FE-1476 [Todo root] | Prepare September demo\n@hashintel/brunch-agent:linear:graph: L0 FE-1477 [Next up root] | Define the routing logic between Petrinaut AI and the brunch elicitor\n@hashintel/brunch-agent:linear:graph: L0 FE-1478 [Todo root] | Provide provenance from a generated net back to the requirements graph\n@hashintel/brunch-agent:linear:graph: L0 FE-1479 [Todo root] | Update a section of the net through targeted re-elicitation\n@hashintel/brunch-agent:linear:graph: L0 FE-1480 [Todo root] | Infer requirements graph to SDCPN in Petrinaut editor\n@hashintel/brunch-agent:linear:graph: L0 FE-1481 [Todo root] | Show the requirements graph in UI OR export as YAML or Markdown\n@hashintel/brunch-agent:linear:graph: L0 FE-1482 [Next up root] | Add Cyber-physical process modelling plugin to brunch agent\n@hashintel/brunch-agent:linear:graph: L1 FE-1384 [Backlog p:FE-1383] <=FE-1393 | Generate replay tests for the harness rules\n@hashintel/brunch-agent:linear:graph: L1 FE-1387 [Backlog p:FE-1383] <=FE-1393 | Choose a second target and stabilize the plugin interface\n@hashintel/brunch-agent:linear:graph: L1 FE-1394 [Todo p:FE-1383] <=FE-1393 =>FE-1385,FE-1396 | Preserve conflicts until the user resolves them\n@hashintel/brunch-agent:linear:graph: L1 FE-1404 [Next up p:FE-1357] <=FE-1402,FE-1403 | Run the third baseline with completion and interview guidance\n@hashintel/brunch-agent:linear:graph: L1 FE-1440 [Todo p:FE-1433] <=FE-1437,FE-1438,FE-1439 =>FE-1442 | Ship the elicitor in demo.petrinaut.org’s chat panel\n@hashintel/brunch-agent:linear:graph: L2 FE-1385 [Backlog p:FE-1383] <=FE-1394,FE-1395 | Expand the dev app into a target gallery and diagnostic view\n@hashintel/brunch-agent:linear:graph: L2 FE-1396 [Todo p:FE-1383] <=FE-1394 =>FE-1423 | Restore interview context after resume and restart\n@hashintel/brunch-agent:linear:graph: L2 FE-1442 [Todo p:FE-1433] <=FE-1440 | Show live captures and completion accounting in the demo\n@hashintel/brunch-agent:linear:graph: L3 FE-1423 [Todo p:FE-1357] <=FE-1396 =>FE-1441 | Require safe remote access to the elicitor server\n@hashintel/brunch-agent:linear:graph: L4 FE-1441 [Todo p:FE-1433] <=FE-1423,FE-1437,FE-1439 | Deploy the elicitor server behind the remote-release checks\n@hashintel/brunch-agent:linear:graph: cycles: none\n\n Tasks: 1 successful, 1 total\nCached: 0 cached, 1 total\n Time: 3.73s \n\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034Cemap9xVYDSej2U9SVL` + +``` +{ + "output": "no whitespace errors\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034Cemape2wKP2Oug8G2WK` + +``` +{ + "output": "--- inbox\n--- manifest status\n M docs/INDEX.md\n M docs/planning/_shared/COORDINATION.md\n?? docs/planning/_shared/STEERING.md\n--- unrelated status retained\n M docs/agents/git-workflow.md\n M docs/agents/issue-writing.md\n M docs/agents/legibility.md\n M docs/planning/_shared/hash-monorepo-import-plan.md\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "git add libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md && git status --short && printf '%s\\n' '--- staged paths' && git diff --cached --name-only", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034Cemxbk8eOgW09TrYLmd` + +``` +{ + "output": "M libs/@hashintel/brunch-agent/docs/INDEX.md\n M libs/@hashintel/brunch-agent/docs/agents/git-workflow.md\n M libs/@hashintel/brunch-agent/docs/agents/issue-writing.md\n M libs/@hashintel/brunch-agent/docs/agents/legibility.md\nM libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\nA libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n M libs/@hashintel/brunch-agent/docs/planning/_shared/hash-monorepo-import-plan.md\n--- staged paths\nlibs/@hashintel/brunch-agent/docs/INDEX.md\nlibs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\nlibs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "git diff --cached --check && git diff --cached --stat && git commit -m \"Add September steering model\"", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 60000 +} +``` + +## User + +**Tool Result:** `TU-034CenBB5thhw0PWVBUWVn` + +``` +{ + "output": " libs/@hashintel/brunch-agent/docs/INDEX.md | 1 +\n .../docs/planning/_shared/COORDINATION.md | 98 ++++---\n .../brunch-agent/docs/planning/_shared/STEERING.md | 296 +++++++++++++++++++++\n 3 files changed, 358 insertions(+), 37 deletions(-)\n╭──────────────────────────────────────╮\n│ 🥊 lefthook v2.0.0 hook: pre-commit │\n╰──────────────────────────────────────╯\n│ yarn (skip) no matching staged files\n│ toml (skip) no files for inspection\n│ sqlfluff (skip) no files for inspection\n│ rust (skip) no files for inspection\n┃ oxfmt ❯ \n\n(node:65832) [MODULE_TYPELESS_PACKAGE_JSON] Warning: Module type of file:///Users/lunelson/Code/hashintel/hash/oxfmt.config.ts?cache=1787567541808 is not specified and it doesn't parse as CommonJS.\r\nReparsing as ES module because module syntax was detected. This incurs a performance overhead.\r\nTo eliminate this warning, add \"type\": \"module\" to /Users/lunelson/Code/hashintel/hash/package.json.\r\n(Use `node --trace-warnings ...` to show where the warning was created)\r\nExpected at least one target file. All matched files may have been excluded by ignore rules.\r\n\n┃ markdownlint ❯ \n\nmarkdownlint-cli2 v0.22.1 (markdownlint v0.40.0)\r\nFinding: libs/@hashintel/brunch-agent/docs/INDEX.md libs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md !**/LICENSE*.md !**/AGENTS*.md !node_modules/** !target/** !**/_temp/** !**/_ai/** !**/.cursor/plans/** !libs/@hashintel/ds-components/** !libs/@hashintel/ds-helpers/** !libs/@hashintel/brunch-agent/docs/**\r\nLinting: 0 file(s)\r\nSummary: 0 error(s)\r\n\n \n ────────────────────────────────────\nsummary: (done in 0.93 seconds) \n✔️ oxfmt (0.40 seconds)\n✔️ markdownlint (0.85 seconds)\n[ln/fe-xxxx-whats-next d4e61bb23b] Add September steering model\n 3 files changed, 358 insertions(+), 37 deletions(-)\n create mode 100644 libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "git status --short; git show --stat --oneline --summary HEAD", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "git show --format= --name-only HEAD; git show --format= --check HEAD", + "workdir": "/Users/lunelson/Code/hashintel/hash", + "timeout_ms": 10000 +} +``` + +**Tool Use:** `shell_command` + +```json +{ + "command": "nl -ba docs/planning/_shared/STEERING.md | sed -n '1,330p' | tail -20; nl -ba docs/planning/_shared/COORDINATION.md | sed -n '1,170p' | tail -45", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CenRkjCL9VDpfTx9Umd` + +``` +{ + "output": " M libs/@hashintel/brunch-agent/docs/agents/git-workflow.md\n M libs/@hashintel/brunch-agent/docs/agents/issue-writing.md\n M libs/@hashintel/brunch-agent/docs/agents/legibility.md\n M libs/@hashintel/brunch-agent/docs/planning/_shared/hash-monorepo-import-plan.md\nd4e61bb23b Add September steering model\n libs/@hashintel/brunch-agent/docs/INDEX.md | 1 +\n .../docs/planning/_shared/COORDINATION.md | 98 ++++---\n .../brunch-agent/docs/planning/_shared/STEERING.md | 296 +++++++++++++++++++++\n 3 files changed, 358 insertions(+), 37 deletions(-)\n create mode 100644 libs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CenRl7UIjQsnLZeIYR3` + +``` +{ + "output": "libs/@hashintel/brunch-agent/docs/INDEX.md\nlibs/@hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md\nlibs/@hashintel/brunch-agent/docs/planning/_shared/STEERING.md\n", + "exitCode": 0 +} +``` + +**Tool Result:** `TU-034CenRltj53l8AQQst4wC` + +``` +{ + "output": " 277\t| A bounded review-and-revise scenario can carry the September product claim without cold-start elicitation. | Medium. It is the written FE-1476 scenario, but Dora has not confirmed the use case. | The confirmed use case requires model creation rather than review, or the optimisation handoff requires fields absent from the fixture. |\n 278\t| A concrete CPS implementation will discover a better minimum plugin contract faster than completing the generic design first. | Medium-high. Gherkin deliberately under-stresses the interface; CPS is the first real consumer. | The first worked CPS transformation cannot be expressed without a reusable harness primitive that must precede it. Build that primitive, then return immediately to the vertical proof. |\n 279\t| Register 2 can be rich enough for pure SDCPN projection. | Low-medium. ADR-0003 requires it, but no real fold or projector exists and FE-1480 asserts non-determinism. | The worked transformation identifies an unavoidable semantic choice not represented in captures/model. Record it earlier or explicitly revisit the ADR. |\n 280\t| Three to five turns can produce a meaningful scoped correction. | Low. No CPS runbook has been rehearsed. | Two rehearsals exceed the budget or require unrelated context. Narrow the region, preload explicit context, or revise the demo claim rather than script fake success. |\n 281\t| The proven ask suspension can extend to document-application client tools. | Medium-low. The suspension spike succeeded, but the production transport intentionally refuses machine tool-result follow-ups. | The first tool round-trip cannot preserve correlation, durability, or non-user evidence semantics. Treat this as a critical integration blocker, not a UI detail. |\n 282\t| The production website and remote server can be joined inside the timebox. | Medium-low. Local host seams exist; provider routing, session ownership, deployment, and release gates do not yet converge. | A deployable path is not proved by the end of Frontier 2. Preserve the real semantic loop and seek an explicit demo-surface decision rather than quietly falling back to test-only wiring. |\n 283\t| Requirements-model UI is unnecessary for comprehension. | Medium. The reviewer needs inspectability, but FE-1481 explicitly permits export. | Rehearsal shows that provenance and delta cannot be understood from chat plus a structured export. |\n 284\t\n 285\t## Current choice\n 286\t\n 287\tStop treating “unblocked” as “next.” The next strategic move is to run Frontier 0 immediately and\n 288\topen Frontiers 1 and 2 in parallel: one worked CPS semantic slice and one existing-target reviewer\n 289\tsession/tool-return slice. Join them at the earliest correction, then drive the same bones through\n 290\tprovider routing and deployment. The generic Gherkin/plugin-freeze path and broad UI work wait for\n 291\tthat join.\n 292\t\n 293\tRevisit this choice as soon as Dora confirms the use case, the FE-1480 worked transformation lands,\n 294\tor either parallel frontier fails its first proof. A steering pass that only updates ticket status\n 295\tdoes not change this document; a new fact that changes the objective, proof spine, authority\n 296\tboundary, or cut line does.\n 102\t- **Controller and runbook.** The harness does not read the folded model or open issues back into\n 103\t the agent, and no plugin defines a job trajectory or stopping rule. FE-1482 must exercise the\n 104\t narrow `review-and-revise` loop; FE-1406 and FE-1402/FE-1403 are inputs, not parallel products.\n 105\t- **Reviewer target identity — FE-1439 × FE-1479.** The current host derives target-document\n 106\t identity from conversation identity. September requires a new reviewer conversation against an\n 107\t existing target without weakening owner isolation.\n 108\t- **Contract freeze — FE-1387.** The CPS target must stress the plugin contract before it freezes.\n 109\t The freeze follows the September semantic proof rather than gating it.\n 110\t- **Absence locator.** An absence capture carries no payload, but the fold needs a field-specific\n 111\t coordinate (anchor × slot). The plugin-contract spec records three worked cases; any envelope\n 112\t amendment belongs to the harness side of this seam.\n 113\t- **Structured-tap evidence — FE-1395 × capture store.** `resolve-conflict` currently rejects\n 114\t `user-affordance-payload` evidence. FE-1395 must decide the transport fact before the store\n 115\t rule can settle.\n 116\t- **Guidance placement — FE-1403 × FE-1406.** Plugin cards and the harness-shipped generic\n 117\t strategy quiver share authoring methods but not ownership. Packages export; hosts register.\n 118\t- **Telemetry vocabulary — FE-1385 × FE-1404 × FE-1423.** The probe surface, experiment\n 119\t accounting, and remote telemetry should share span vocabulary rather than invent it three\n 120\t times.\n 121\t- **Living-prototype charter.** The deployed elicitor as a cumulative record of proved and\n 122\t unproved behavior remains pre-charter until the infrastructure conversation settles.\n 123\t\n 124\tSettled seam decisions still governing open work: FE-1392 established the plugin-declared\n 125\tverbatim proposal floor, and ask accounting remains a read-time relation rather than an envelope\n 126\tfield. ADR-0003 keeps field-level structure below the capture's single epistemic status.\n 127\t\n 128\t## Exceptional roots\n 129\t\n 130\tThese project issues currently have no parent. Some are intentional roots; the temporary or\n 131\tunresolved roots are named here until their Linear parentage is settled:\n 132\t\n 133\t- **FE-1331 — start elicitation from Petrinaut's create-new-net flow.** ADR-0004 un-deferred this as\n 134\t September topology, while FE-1476's new reviewer scenario starts from an existing target. Keep\n 135\t the conflict visible until Dora confirms the use case and the ADR is amended if necessary.\n 136\t- **FE-1334 — offer the user a surprising scenario of their model.** A validation gesture with\n 137\t no owning map yet; closest to the motif/quiver strategy work.\n 138\t- **FE-1406 — design reusable elicitation strategies.** The cross-map home for the\n 139\t harness-shipped generic strategy quiver; intentionally independent of either delivery map.\n 140\t- **FE-1472 — evaluate the nested Anthropic SDK pin.** Unrelated triage root; no owning delivery\n 141\t map has been chosen.\n 142\t- **FE-1476 — prepare the September demo.** Temporary delivery root pending the recommended fold\n 143\t under FE-1357.\n 144\t- **FE-1477 through FE-1482 — September outcome slices.** PM-authored issues adopted by the\n 145\t steering model but not yet folded in Linear. The recommended parent is FE-1476; overlaps and\n 146\t ownership boundaries are recorded in STEERING's issue projection before external mutation.\n", + "exitCode": 0 +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "rg -n '^## |^### ' docs/planning/_shared/STEERING.md; rg -n '^## |^### ' docs/planning/_shared/COORDINATION.md; rg -n '\\[STEERING\\]' docs/INDEX.md", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CenaJhj5wq8tcm8LEb5` + +``` +{ + "output": "21:## The September outcome\n58:## Where the system actually stands\n82:## The strategic bet\n114:## The elicitor architecture under this load\n160:## Proof frontiers and execution order\n166:### Frontier 0 — make the demo claim decidable\n182:### Frontier 1 — close the CPS semantic loop\n195:### Frontier 2 — close the reviewer control loop\n212:### Frontier 3 — converge on the deployed demo\n222:## What is deliberately cut\n239:## Issue projection\n273:## Beliefs, risks, and replan conditions\n285:## Current choice\n15:## Current sequencing recommendation\n72:## Repository handoff threshold\n96:## Open seams\n128:## Exceptional roots\n74:| [STEERING](planning/_shared/STEERING.md) | active | FE-1357 / FE-1476 | Current objective-driven strategy for the September CPS review-and-revise proof: evidence, architectural pressure, proof frontiers, cuts, issue projection, risks, and replan conditions |\n", + "exitCode": 0 +} +``` + +## Assistant + +Created and committed the [Brunch steering model](file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/docs/planning/_shared/STEERING.md#L1-L296), including: + +- September objective, architecture inventory, strategic bet, proof frontiers, cuts, risks, and issue projection. +- Updated [coordination sequencing](file:///Users/lunelson/Code/hashintel/hash/libs/%40hashintel/brunch-agent/docs/planning/_shared/COORDINATION.md#L15-L69). +- Oracle-reviewed acceptance criteria preventing fake provenance or hand-inserted corrections. +- Explicit FE-1480/ADR-0003 and FE-1331/ADR-0004 conflicts. + +No Linear changes were made. Verification passed: lint, type-check, 114 tests, build, documentation index/link gates. + +Commit: `d4e61bb23b` (`Add September steering model`) + +The next substantive discussion should be Frontier 0: the CPS fixture and FE-1480 authority boundary. + +## User + +OK this is very helpful. A few thoughts: + +- a more compact overview, in nested bullet-list or perhaps tree form, collecting issues to the frontiers they support, and calling out where more issues might need to be mapped, would be helpful +- the proof obligations list must also call out legibility: a proof without a legible surface, and ideally a human witness, is the proverbial tree that falls in the forest with nobody around to hear it. This is the legibility protocol, which I need in order to maintain my shared understanding +- your confidence assignments in the "beliefs..." table are mostly what I would assign as well; I would say my low-confidence hovers around the following two cuts that you made, mainly because I'm not confident that belief row 1 will hold, i.e. we will not be asked to show a cold-start elicitation + +> - Do not build a complete cold-start CPS interview, general target gallery, every affordance type, voice input, surprising-scenario generation, or broad telemetry vocabulary. +> - Do not implement a comprehensive CPS ontology. Support the fixture, the correction, and the optimisation handoff while keeping the data model honest about what it omits. + +Let's talk about Frontier 0 next. (ASIDE: we have an unclear topology of planning docs now, in terms of canonicality, order-of-reading, authority, scope; and we have several documents which are effectively stale and should move to `docs/_archive/` or be deleted + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "cat docs/agents/legibility.md", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CfkNUto2uMtzB5jmd3F` + +``` +{ + "output": "# Legibility protocol: render, read the strain, reconcile\n\nHow work arcs with significant agent-generated output close: produce legibility artifacts that\naid review and re-establish shared understanding between the humans and the agents carrying the\nwork. Companion to `documentation.md` (which governs where documents live; this file governs\nhow understanding is checked and kept).\n\nThe protocol serves one thesis, the same one the CI gates and the capture store serve in code:\n**no claim without a way for it to fail.** A document read in its own register can nod along\nwith itself; re-rendered into a different register, every claim must survive translation, and\nthe places where it doesn't are findings.\n\n## The move: render and read the strain\n\nAt the close of an arc, re-render its central artifact into another register and instruct the\nrenderer to report **every place the source resisted plain rendering** — a dangling referent, a\nterm defined nowhere, a prohibition citing nothing, a causal claim whose causality had to be\ninferred. The strain report _is_ the review yield; the rendering itself is a byproduct (often a\nuseful one — a teammate-readable account).\n\nRun renderings as fork subagents carrying the strain-report instruction, so the main thread\nreviews the findings instead of doing the translation. Instrumenting the collection raises the\nyield: the ir-design plain rendering returned seven strain points where an uninstrumented\nround-2 read of the FE-1374 spec renderings had found four by accident (each of which fed a\nreal spec change — the practice predates its name).\n\n## The register dial\n\nThe register is a dial, not a single target. One practice, several grades — pick the cheapest\ngrade that can still fail:\n\n- **Plain prose** (Google/GOV.UK style): the default. Catches undefined terms, uncited rules,\n compressed allusions.\n- **STE grade** (controlled vocabulary, one instruction per sentence): for sources whose claims\n are dense or load-bearing enough that plain prose can still paper over them. Costs more;\n earns it when the source will govern implementation.\n- **Worked examples** (FE-1397's form): re-render a _definition_ into concrete instances and\n check what breaks. The strongest grade for type systems and contracts — a definition that\n survives three worked designs at different thicknesses has been tested, not admired.\n\n## Filings are render-and-read material too\n\nA sweep's own capture — its tickets, its accrual comments, its penciled directions — is itself\na rendering of the session's understanding, and gets the same treatment: expect a challenge\npass over the filings before the arc closes. The FE-1405/FE-1406 round came from re-reading the\nfirst round's own text (\"shapes-to-fill\" quoted back); the gaps were real and had been deepened\nby the filings meant to close them.\n\n## Point findings may reveal a recurrent class\n\nA point finding is evidence of a possible fault class, not proof that the whole codebase shares\nit. Promote the finding to an audit only when recurrence is plausible, the class is cheaply\nsearchable, and missed instances could fail silently. Search both the mechanical family and the\nownership boundaries where the same contract may be reimplemented. Keep finding and fixing as\nseparate steps so a human can confirm the class and scope before repair begins.\n\nWhen the class is confirmed, make its categorical part executable as a boundary or regression\ncheck. Put any judgment that cannot be mechanized into review guidance. Do not widen a one-off\nfinding into a repository sweep merely for symmetry.\n\n## Consolidation: capture-as-we-go, reconcile-before-landing\n\nCapture channels (accrual comments, pencil lists, strain appendices, handoffs) guard against\nevaporation, not fragmentation. Two rules keep the yield coherent:\n\n- **Every capture channel names its consolidation target** — accruals reconcile into the\n owning control surface, pencils graduate to issues or planning documents, and strain reports\n become document fixes. A channel with no named target is a leak with a delay.\n- **An arc is not closed until consolidation runs.** The closing step reconciles what the\n captures established into the durable artifacts (coordination, ledger, docs, issues) — a\n handoff note alone is a deferral, not a deposit.\n\n## Deposit: work describes itself at authoring time\n\nProse backfill is remediation, not workflow. A branch's commit message and PR body carry its\nsemantics when it lands — the record must not abstain exactly where description is most needed\n(FE-1390 landed 1,392 lines with an empty body; the deep-read that repaired it cost more than\nwriting it at authoring time would have). The same rule for tooling: a skill output written\ninto `docs/` passes through the documentation protocol — an `INDEX.md` row or an `AGENTS.md`\npointer — like any other document.\n\nReflections belong in work products, marked as `> **Reflection:**` blockquotes, distinct from\nthe captured facts — insight left only in chat evaporates with the context that produced it.\n", + "exitCode": 0 +} +``` + +## Assistant + +Agreed on all three adjustments. + +The two cuts should become **conditional bets**, not commitments: + +- Default to review-and-revise until Frontier 0 confirms whether cold-start is a demo obligation. +- Build a **minimum coherent CPS semantic closure**, not merely a fixture-shaped subset. It must support the demo, provenance, correction, completion, and optimisation handoff while explicitly inventorying omissions. + +A compact frontier map could look like: + +```text +FE-1476 September outcome +├─ Frontier 0 — make the claim decidable +│ ├─ FE-1480 projection-authority decision +│ ├─ FE-1478 provenance acceptance criteria +│ ├─ FE-1482 CPS semantic scope +│ ├─ FE-1402 completion criteria +│ ├─ FE-1331 cold-start conflict +│ └─ Missing mappings +│ ├─ confirmed demo claim/use case +│ ├─ valid source/capture fixture +│ ├─ optimisation handoff contract +│ └─ witnessed worked-example review +│ +├─ Frontier 1 — CPS semantic loop +│ ├─ FE-1482 CPS plugin +│ ├─ FE-1480 SDCPN projection +│ ├─ FE-1478 provenance +│ ├─ FE-1481 structured legibility surface +│ ├─ FE-1402 completion input +│ ├─ FE-1431 plugin-contract input +│ └─ Missing mappings +│ ├─ active-model/issues read path +│ └─ CPS semantic-coverage oracle +│ +├─ Frontier 2 — reviewer control loop +│ ├─ FE-1479 targeted re-elicitation +│ ├─ FE-1438 client-tool return/application +│ ├─ FE-1439 existing-target session identity +│ ├─ FE-1394 supersession/conflict behavior +│ ├─ FE-1403 / FE-1406 guidance and strategies +│ └─ Missing mappings +│ ├─ controller implementation +│ ├─ review-and-revise runbook +│ └─ selected-region identity +│ +└─ Frontier 3 — deployed witnessed proof + ├─ FE-1477 / FE-1440 routing and website integration + ├─ FE-1423 exposure gates + ├─ FE-1441 deployment + ├─ FE-1476 rehearsal and acceptance + └─ Missing mappings + ├─ optimisation-flow integration + └─ witnessed demo/legibility deposit +``` + +Each frontier’s proof should become a three-part bundle: + +1. **Executable evidence** — the behavior succeeds and can fail honestly. +2. **Legible rendering** — translate it into another register and record the strain. +3. **Human witness and deposit** — a named person reviews it; findings reconcile into the governing artifact. + +For example, Frontier 1 is not proved merely because projection tests pass. A human must be able to follow: + +```text +utterance → capture → model field → SDCPN element +``` + +…and understand the before/after correction without reading implementation code. + +For Frontier 0, I suggest four decisions: + +1. **What claim must the demo support?** + - Review/revise only + - Bootstrap one bounded region from cold start + - Elicit an entire model from cold start + +2. **What semantic closure is necessary?** + - Every demonstrated net construct has a model/capture source. + - Every runbook demand has a representable slot or issue. + - Optimisation inputs are represented. + - Omitted CPS concepts and their consequences are legible. + +3. **Where does inference belong?** + Work one concrete capture → model → SDCPN transformation and allocate every judgment to capture, fold, projection, or application. + +4. **Who witnesses it?** + Ideally you for architectural legibility, Dora for the product claim, and Chris/Yannis for the optimisation handoff. + +My first question is therefore: **what is the strongest cold-start claim you think stakeholders may expect—one bounded region, a recognisable partial model, or the complete process?** + +On the planning-doc aside: agreed. We need scoped authority rather than a single total order: + +```text +How we work AGENTS + protocols +Settled truth CONTEXT + ADRs + active specs +What matters now STEERING +What runs next COORDINATION + Linear +Why we believe it planning/reference records +``` + +Several records currently blur those roles. After Frontier 0, I’d run a separate inventory that classifies each document as current authority, supporting evidence, historical record, superseded/archive, or deletable—with link and Linear-reference repair before moving anything. + +## User + +Good. That kind of projection is much more legible and usable for me. Long-lived active documents like STEERING.md should also be designed with only as much prose as they need, in such a way as to aid rapid comprehension and reduce VCS churn and conflicts. legible artifacts can be of various forms, and would in at least some cases follow patterns such as dictated for prototyping in `ds-prototype`; but should not be throwaway, rather collected as documentation snapshots of decision/design, and even as regression oracles. + +To your question: I think it's safe to assume that time constraints for a live demo preclude eliciting a complete model *during the live demo*; but that doesn't mean that attendees will not ask to try it out, and it's also possible that external factors or stakeholder decisions will change the focus/substance of the demo with short notice, so I think an implementation that is reasonably capable of a full model elicitation, which works better than a "baseline" (see our earlier comparisons, where we had claude code elicit based on a bare flat prompt), has to be considered important, but it takes time and the judgement of the quality of the output takes time. It's the more bounded scenarios where we want it to be clear (legible) that the elicitation process results in consequent change + +## Assistant + +**Tool Use:** `skill` + +```json +{ + "name": "dogsled:ds-prototype", + "arguments": "Use its artifact and proof conventions as a reference while shaping persistent legibility artifacts for Brunch Frontier 0; do not build a prototype yet." +} +``` + +## User + +**Tool Result:** `TU-034CfzGWw83L0SzcJU5WFJ` + +``` +{ + "content": [ + { + "text": "\n# ds-prototype Skill\n\n\n\n\n# Prototype\n\nA prototype is **throwaway code that answers a question**. The question decides the shape.\n\n## Pick a branch\n\nIdentify which question is being answered — from the user's prompt, the surrounding code, or by asking if the user is around:\n\n- **\"Does this logic / state model feel right?\"** → [LOGIC.md](LOGIC.md). Build a single shareable HTML file — free-play buttons plus tabbed guided walkthroughs — that pushes the state machine through cases that are hard to reason about on paper, and that a non-developer can drive.\n- **\"What should this look like?\"** → [UI.md](UI.md). Generate several radically different UI variations on a single route, switchable via a URL search param and a floating bottom bar.\n\nThe two branches produce very different artifacts — getting this wrong wastes the whole prototype. If the question is genuinely ambiguous and the user isn't reachable, default to whichever branch better matches the surrounding code (a backend module → logic; a page or component → UI) and state the assumption at the top of the prototype.\n\n## Rules that apply to both\n\nUse /ds-subtraction after you understand the question — the first sufficient prototype, not a smaller product.\n\n1. **Throwaway from day one, and clearly marked as such.** Locate the prototype code close to where it will actually be used (next to the module or page it's prototyping for) so context is obvious — but name it so a casual reader can see it's a prototype, not production. For throwaway UI routes, obey whatever routing convention the project already uses; don't invent a new top-level structure.\n2. **Trivial to run.** A UI prototype starts from one command in the project's task runner — `pnpm `, `python `, `bun `, etc. A logic demo is a single HTML file the user double-clicks. Either way, no thinking required to start it.\n3. **No persistence by default.** State lives in memory. Persistence is the thing the prototype is _checking_, not something it should depend on. If the question explicitly involves a database, hit a scratch DB or a local file with a clear \"PROTOTYPE — wipe me\" name.\n4. **Skip the polish.** No tests, no error handling beyond what makes the prototype _runnable_, no abstractions. The point is to learn something fast.\n5. **Surface the state.** After every action (logic) or on every variant switch (UI), print or render the full relevant state so the user can see what changed.\n6. **Capture it when done.** Fold any validated decision into the real code, then capture the prototype itself as a **primary source**: commit it to a throwaway branch, out of main, and leave a context pointer to that branch on the implementation issue. Capture the answer too — the verdict and the question it settled — in the issue or a commit. The main branch keeps only the validated decision.\n\n\nARGUMENTS: Use its artifact and proof conventions as a reference while shaping persistent legibility artifacts for Brunch Frontier 0; do not build a prototype yet.\n\nBase directory for this skill: file:///Users/lunelson/.config/amp/plugins/dogsled/skills/ds-prototype\nRelative paths in this skill (e.g., scripts/, reference/) are relative to this base directory.\n\n\n/Users/lunelson/.config/amp/plugins/dogsled/skills/ds-prototype/LOGIC.md\n/Users/lunelson/.config/amp/plugins/dogsled/skills/ds-prototype/UI.md\n/Users/lunelson/.config/amp/plugins/dogsled/skills/ds-prototype/agents/openai.yaml\n\n", + "type": "text" + } + ] +} +``` + +## Assistant + +**Tool Use:** `shell_command` + +```json +{ + "command": "cat /Users/lunelson/.config/amp/plugins/dogsled/skills/ds-prototype/LOGIC.md", + "workdir": "/Users/lunelson/Code/hashintel/hash/libs/@hashintel/brunch-agent", + "timeout_ms": 10000 +} +``` + +## User + +**Tool Result:** `TU-034CfzOJwx7qDvtPhxnrcK` + +``` +{ + "output": "# Logic Prototype\n\nA single, self-contained HTML file — a **shareable demo** — that lets anyone drive a state model by clicking buttons. Use this when the question is about **business logic, state transitions, or data shape** — the kind of thing that looks reasonable on paper but only feels wrong once you push it through real cases.\n\nBecause it's one file with nothing to install, you can hand it to a non-developer — a designer, a PM, a domain expert — and let them feel the model for themselves. So it speaks their language, not the code's.\n\n## When this is the right shape\n\n- \"I'm not sure if this state machine handles the edge case where X then Y.\"\n- \"Does this data model actually let me represent the case where...\"\n- \"I want to feel out what the API should look like before writing it.\"\n- Anything where someone wants to **press buttons and watch state change**.\n\nIf the question is \"what should this look like\" — wrong branch. Use [UI.md](UI.md).\n\n## Process\n\n### 1. State the question\n\nBefore writing code, write down what state model and what question you're prototyping. One paragraph, at the top of the demo (in a visible intro, not just a comment). A logic prototype that answers the wrong question is pure waste — make the question explicit so it can be checked later, whether the user is watching now or returning to it AFK.\n\n### 2. Isolate the logic in a portable module\n\nPut the actual logic — the bit that's answering the question — in a single `