Skip to content

fix(flows): keep seeded build turn propose-only (#4596) - #4607

Merged
senamakel merged 2 commits into
tinyhumansai:mainfrom
CodeGhost21:fix/4596-seeded-build-propose-only
Jul 6, 2026
Merged

senamakel merged 2 commits into
tinyhumansai:mainfrom
CodeGhost21:fix/4596-seeded-build-propose-only

Conversation

@CodeGhost21

@CodeGhost21 CodeGhost21 commented Jul 6, 2026 •

Copy link
Copy Markdown
Member

Summary

  • Restores the "copilot only PROPOSES" invariant for the Flows prompt-bar seeded build turn, so rejecting the proposal no longer leaves a persisted graph behind.
  • Rewrites the workflow_builder build directive to explicitly forbid save_workflow on the seeded turn; realigns the system prompt, agent descriptor, RPC schema description, and save_workflow tool comment so every doc surface says the same thing.
  • No frontend behavior change — mode: 'build' still fires; the server just no longer asks the agent to persist.
  • Adds a regression test (build_is_propose_only_and_injects_flow_id_as_context) that guards against every historical auto-save phrasing coming back.

Problem

Flagged as P1 by chatgpt-codex-connector on PR #4578 and filed as #4596.

The Flows prompt bar's instant-create path did two real writes:

  1. WorkflowPromptBar.tsx calls createFlow(...) (persists a blank flow), then navigates to /flows/:id with state.copilotBuild.
  2. WorkflowCopilotPanel.tsx:161-169 sees buildSeed and sends mode: 'build'. builder_prompt.rs's old DIRECTIVE_BUILD_AND_SAVE explicitly told the agent to save_workflow onto that flow id after dry-run. save_workflow → flows_update → the graph is persisted before Accept/Reject ever renders.

Reject (WorkflowCopilotPanel.tsx:214-218) only did onReject() + clearProposal() — pure local overlay state; no RPC. So a user who rejected or closed the panel was left with a persisted flow they never approved. If the graph carried a schedule / app_event trigger and the user later enabled the flow, that trigger would arm.

The invariant on WorkflowCopilotPanel.tsx:19-20 — "the copilot only PROPOSES. Accept applies to the UNSAVED local draft (no flows_update); persistence stays behind the canvas's own Save" — had already been silently violated by the build mode addition.

Solution

Bring build mode back inside the propose-only invariant. Persistence stays a user-explicit action (Accept in the review card, then the canvas's own Save). Two options were considered:

  • A. Make build propose-only (chosen) — small footprint, restores the stated invariant, matches every other authoring turn.
  • B. Add a revert path on Reject/close — would need snapshot-of-blank tracking, disarm-triggers RPC, cover close-tab / route-away / lost-socket edge cases. Materially more code + more failure modes for a UX win the invariant explicitly rejected.

Chose A.

Changes

  • src/openhuman/flows/agents/workflow_builder/builder_prompt.rs
    • Rename DIRECTIVE_BUILD_AND_SAVE → DIRECTIVE_BUILD_PROPOSE_ONLY. New directive explicitly says "Do NOT save_workflow in this turn: I will Accept the proposal explicitly and the canvas's Save persists it."
    • BuildMode::Build branch of render_prompt still injects flow_id as future-turn context (user may later ask "save it" / "run it"), but the injection line now labels it: "kept for future turns — do not save_workflow it here".
    • Updated module-level doc + BuildMode::Build variant doc to reference Rejecting a seeded flow build leaves the graph persisted #4596 and the propose-only contract.
    • Test build_asks_to_save_onto_flow_id → build_is_propose_only_and_injects_flow_id_as_context. Asserts (a) Do NOT save_workflow appears; (b) none of the four historical auto-save phrasings (then SAVE, with save_workflow, SAVE it onto, save_workflow onto) survive; (c) flow_9 + END-TO-END still land.
  • src/openhuman/flows/agents/workflow_builder/prompt.md
    • Rewrote the "Saving your work" section. Old header ("finish the job — don't hand it back") is replaced with "only on the user's explicit ask". New body: every authoring turn is propose-only; save_workflow runs only when the user explicitly asks ("save this"); explains why auto-saving on a flow_id would leave the graph persisted even on Reject.
  • src/openhuman/flows/agents/workflow_builder/agent.toml
    • when_to_use no longer tells the router the agent "may also SAVE the built graph" on flow-id delegation. Persistence stays with the user's Accept + Save; save_workflow / run_flow are on explicit user ask only.
  • src/openhuman/flows/schemas.rs
  • src/openhuman/tools/ops.rs
    • Comment on SaveWorkflowTool registration was defending an auto-save carve-out for the prompt bar. Rewrote to reflect explicit-ask usage.
  • app/src/components/flows/WorkflowCopilotPanel.tsx
    • Comment on the auto-send for buildSeed (~line 154) now describes a "build → dry-run → PROPOSE" arc and points at Rejecting a seeded flow build leaves the graph persisted #4596. mode: 'build' still fires (naming preserved) so the server can still distinguish "seeded from prompt bar" from a plain revise and inject the flow_id as context. No API break.
  • app/src/components/flows/WorkflowCopilotPanel.test.tsx
    • Comment-only update. Existing arg.request.mode === 'build' assertion still holds.

What was deliberately not changed

  • save_workflow remains in the agent's named tools list — revise mode legitimately uses it on user ask.
  • No new revert RPC, no snapshot-of-blank tracking, no trigger-disarm logic — Option B was rejected.
  • No frontend behavior change.

Submission Checklist

  • Tests added or updated — Rust regression test build_is_propose_only_and_injects_flow_id_as_context covers both the happy path (directive still injects flow_id and END-TO-END framing) and the failure path (four historical auto-save phrasings are asserted absent).
  • Diff coverage ≥ 80% — the only executable-code change is the directive/text rendering in BuildMode::Build, fully covered by the new + existing builder_prompt tests. cargo test --lib openhuman::flows::agents::workflow_builder — 9 passed. Frontend edits are comment-only.
  • Coverage matrix updated — N/A: behavior-only change restoring a documented invariant; no new feature row.
  • All affected feature IDs listed under ## Related — N/A: behavior-only change, no matrix rows added/removed/renamed.
  • No new external network dependencies introduced.
  • Manual smoke checklist updated — N/A: bug fix restoring propose-only; the Flows seeded-build path smoke step is unchanged from the reviewer's perspective (Accept still applies, Save still persists).
  • Linked issue closed via Closes #4596 in ## Related.

Impact

  • Runtime/platform: desktop only (Flows canvas + prompt bar). Backend directive change affects the workflow_builder agent's turn behavior. No mobile/CLI impact.
  • Performance: none.
  • Security: removes an auto-persistence path the user did not explicitly consent to — small positive.
  • Migration/compat: none. No schema, RPC surface, or wire-format change. mode: 'build' still accepted; only its rendered directive changes.
  • UX: users who prompt-bar-seed a flow now see a proposal only; they must click Accept + Save to persist, exactly like every other copilot turn.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

Commit & Branch

  • Branch: fix/4596-seeded-build-propose-only
  • Commit SHA: 44f459007 (rebased onto latest origin/main and includes one incidental Prettier autofix — see Follow-up TODOs below).

Validation Run

  • pnpm --filter openhuman-app format:check — Prettier clean on touched frontend files (WorkflowCopilotPanel.tsx, WorkflowCopilotPanel.test.tsx).
  • pnpm typecheck — N/A: no TS surface changed (only comments); frontend tests compile + pass via vitest run.
  • Focused tests:
    • Rust: cargo test --lib openhuman::flows::agents::workflow_builder → 9 passed.
    • Rust: cargo test --lib openhuman::flows::schemas → 19 passed (no cascade from schema description edit).
    • Vitest: all 129 tests in app/src/components/flows/* pass (WorkflowCopilotPanel.test.tsx, WorkflowPromptBar.test.tsx, and 14 more).
  • Rust fmt/check — cargo fmt --check clean; cargo check clean (no new warnings introduced).
  • Tauri fmt/check — N/A: no Tauri host code changed.

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: the workflow_builder agent no longer auto-save_workflows onto the prompt-bar-seeded flow. mode: 'build' becomes propose-only, matching create/revise/repair.
  • User-visible effect: rejecting or closing a seeded build proposal now leaves the flow's persisted graph untouched (blank, as created). Accepting still applies the diff to the local draft; the canvas's Save still persists. One extra click (Save) after Accept for users who want to keep the built graph — matching the rest of the canvas.

Parity Contract

  • Legacy behavior preserved: mode: 'build' still accepted at the RPC surface with the same request shape ({ mode, instruction, graph, flow_id }) and validate() still rejects a missing/blank flow_id. save_workflow tool is still registered and still callable when the user explicitly asks the agent to save.
  • Guard/fallback/dispatch parity checks: the frontend mode: 'revise' fallback in WorkflowCopilotPanel.tsx:168 (used when flowId is somehow missing) is unchanged.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none found.
  • Canonical PR: this one.
  • Resolution: N/A.

Summary by CodeRabbit

  • New Features

    • Workflow building guidance now keeps new builds proposal-only until you explicitly Accept and then Save.
    • Build and instant-create now follow a build → dry-run → propose arc; persistence requires explicit user action.
  • Bug Fixes

    • Prevented workflows from being auto-saved during the initial build flow, reducing unintended persistence.
    • Improved clarity of fallback behavior when no flow ID is available.
  • Tests

    • Updated and extended tests to verify the “do not auto-save” contract and related runtime expectations.

@CodeGhost21
CodeGhost21 requested a review from a team July 6, 2026 21:20
@coderabbitai

coderabbitai Bot commented Jul 6, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR updates frontend comments, agent policy text, server prompt directives, schema wording, and tests to state that BuildMode::Build is propose-only and does not auto-persist. Saving is now described as requiring explicit user Accept + Save.

Changes

Propose-only build persistence contract

Layer / File(s) Summary
Frontend panel comments on build-seed flow
app/src/components/flows/WorkflowCopilotPanel.tsx, app/src/components/flows/WorkflowCopilotPanel.test.tsx
Comments reworded to describe the build → dry-run → propose flow and note that mode: 'build' does not persist the graph.
Agent usage policy
src/openhuman/flows/agents/workflow_builder/agent.toml
when_to_use now limits saving and test-running to explicit user requests and forbids independent persistence or flow creation.
Server prompt directive and validation docs
src/openhuman/flows/agents/workflow_builder/builder_prompt.rs
Module docs, BuildMode::Build docs, validation docs, and the build prompt directive were updated to prohibit save_workflow during the build turn.
Regression test for propose-only build prompt
src/openhuman/flows/agents/workflow_builder/builder_prompt.rs
The build prompt test now checks for Do NOT save_workflow and absence of prior auto-save wording.
Prompt guide, schema, and tool documentation updates
src/openhuman/flows/agents/workflow_builder/prompt.md, src/openhuman/flows/schemas.rs, src/openhuman/tools/ops.rs
Supporting docs now describe propose-only build behavior and user-gated persistence.

Estimated code review effort: 2 (Simple) | ~15 minutes

Possibly related issues

Possibly related PRs

Suggested labels: bug

Suggested reviewers: sanil-23, M3gA-Mind

Poem

A rabbit hops with careful glee,
No save till you say, “Yes, let it be!”
Build, dry-run, propose — then wait,
Accept and Save to seal the gate. 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive The summary shows the propose-only prompt fix, but it doesn't demonstrate reject/close coverage or confirm the no-persist behavior end to end. Add a test that rejects or closes a seeded build and verifies no graph persists, or show the rollback/disarm path if persistence remains possible.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The changed files all support the seeded-build persistence fix; no clearly unrelated feature work appears in the summary.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: keeping the seeded build turn propose-only.

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 94aacd4aaa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +104 to +105
dry_run_workflow, then return the proposal for me to review. Do NOT save_workflow in this turn: I will \
Accept the proposal explicitly and the canvas's Save persists it. Do not enable, disable, or run_flow \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Remove the remaining auto-save tool instruction

This turn-level prohibition is undermined because the workflow builder system prompt still appends the model-visible tool list, and SaveWorkflowTool::description() still tells the agent to use save_workflow after the user asked it to “build/update a workflow” (src/openhuman/flows/builder_tools.rs:1243-1247). In the prompt-bar build path that exact condition is true and a flow_id is present, so the agent still receives a conflicting instruction that can persist the graph before Accept/Reject; please update the actual tool description (or hide the tool for seeded build turns), not just the registry comment.

Useful? React with 👍 / 👎.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 6, 2026
The Flows prompt bar's instant-create path routed through
WorkflowCopilotPanel with `mode: 'build'`, whose server directive told
the workflow_builder agent to `save_workflow` onto the freshly-created
flow before Accept/Reject rendered. Reject then only cleared the local
overlay — the persisted graph stayed on disk (and a schedule/app_event
trigger would arm if the user later enabled the flow), violating the
copilot's stated "propose only" invariant.

Restore the invariant by making `build` mode propose-only, matching the
existing `create`/`revise`/`repair` contract:

- Rewrite DIRECTIVE_BUILD_AND_SAVE -> DIRECTIVE_BUILD_PROPOSE_ONLY and
  forbid `save_workflow` on the seeded turn explicitly.
- Keep the flow_id injected as future-turn context (the user may later
  ask the agent to save/test it).
- Realign the workflow_builder system prompt (`prompt.md`), the router
  descriptor (`agent.toml`), the `flows.build` RPC schema description,
  and the `save_workflow` tool comment so every doc surface says the
  same thing: `save_workflow` runs only on the user's explicit ask.
- Frontend `WorkflowCopilotPanel` needs no behavior change — `mode:
  'build'` still fires (naming preserved) but the server no longer
  asks the agent to persist. Comments updated to match.

Regression test `build_is_propose_only_and_injects_flow_id_as_context`
asserts the new directive forbids `save_workflow` and that none of the
four historical auto-save phrasings survive.

Closes tinyhumansai#4596
Landed unformatted on origin/main via tinyhumansai#4604 ("Fix/conversation
timeline anchoring and dedup"). Blocking `pnpm --filter openhuman-app
format:check` in `pr-quality.yml` on this PR. Two mechanical wraps —
no code change:

- Inline an `expect.objectContaining` literal.
- Wrap a long `expect(...).toBe('')` chain across three lines.

Not part of the tinyhumansai#4596 fix; included here purely to unblock CI.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Rejecting a seeded flow build leaves the graph persisted

2 participants