Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .spec/planning/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ The plan aligns to:
36. [Phase 42 - Conversation Persistence And Product Convergence](./phase-42-conversation-persistence-and-product-convergence.md): persist append-only conversation history and snapshots, preserve bounded short-term context across steering, and converge the conversation model with factory work, docs, and rollout defaults.
37. [Phase 43 - Conversation Runtime Deltas And Clarification Recovery](./phase-43-conversation-runtime-deltas-and-clarification-recovery.md): make `tool_result.submit` and `turn.resume` first-class coordinator behaviors, surface progressive tool and turn updates, and keep clarification loops recoverable through the event-driven conversation model.
38. [Phase 44 - Managed Repo Conversation Surface Adoption](./phase-44-managed-repo-conversation-surface-adoption.md): adopt the durable conversation model into the managed-repository detail route through product-owned workspace helpers, bounded repo-detail interaction, and current-truth coverage.
39. [Phase 45 - Governed Run Conversation Surface Adoption](./phase-45-governed-run-conversation-surface-adoption.md): adopt the durable conversation model into governed run detail through work-item conversation helpers, bounded run-detail interaction, and current-truth coverage.

## Shared Conventions
- Numbering:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Phase 45 - Governed Run Conversation Surface Adoption

<!-- covers: package.jido_code.spec_led_workspace -->
<!-- covers: architecture.conversation_orchestration.conversation_is_repo_and_work_scoped -->
<!-- covers: architecture.conversation_orchestration.ui_delivery_is_event_driven_and_reconnectable -->
<!-- covers: architecture.conversation_orchestration.degraded_mode_falls_back_to_persisted_state -->
<!-- covers: architecture.conversation_orchestration.governed_run_routes_host_work_conversations -->

Back to index: [README](./README.md)

## Relevant Shared APIs / Interfaces
- `../specs/conversation_orchestration.spec.md`
- `../specs/frontend_architecture.spec.md`
- `../decisions/jido_code.interruptible_conversation_orchestration.md`
- `lib/jido_code/conversations.ex`
- `lib/jido_code/agent_workspace.ex`
- `lib/jido_code/workbench/run_conversation.ex`
- `lib/jido_code_web/live/run_detail_live.ex`
- `test/jido_code/phase_forty_five_integration_test.exs`
- `test/jido_code_web/live/run_detail_live_test.exs`

## Relevant Assumptions / Defaults
- Phases 39 through 44 established the canonical conversation scope, interrupt model, event stream, persistence contract, clarification recovery path, and managed-repository route adoption.
- The governed run detail route already hosts the canonical `Run`, linked `WorkItem`, governance records, and bounded memory context, so work-item conversation adoption should follow that same product-owned route pattern instead of forcing operators back to repo detail or a chat-only page.
- Run detail should only continue canonical durable work through the existing `WorkItem` link. If a run lacks governed work scope, the route should stay explicit about that gap instead of inventing run-local chat state.
- When live delivery degrades, the operator still needs the latest durable work conversation snapshot and explicit continuity messaging rather than a blank or runtime-leaking UI.

[x] 45 Phase 45 - Governed Run Conversation Surface Adoption
Adopt the durable conversation model into the governed run operator surface through work-item conversation helpers, bounded run-detail interaction, and spec-aligned integration coverage.

[x] 45.1 Section - Work Conversation Workspace And Product Boundary
Add the work-item-scoped lookup and opening APIs needed so governed run surfaces use a product-owned conversation boundary instead of reaching into raw persistence or runtime topology.

[x] 45.1.1 Task - Expose work conversation lookup and opening through bounded product entrypoints
Make it possible for run-detail surfaces to find, reuse, or start the right governed work conversation without duplicating conversation-domain policy in the UI.

[x] 45.1.1.1 Subtask - Add latest-work-item conversation lookup on the conversation domain for governed run surfaces.
[x] 45.1.1.2 Subtask - Add AgentWorkspace conversation helpers for work-item-scoped opening, snapshot lookup, event replay, and command admission.
[x] 45.1.1.3 Subtask - Introduce a product-owned `RunConversation` boundary that decides when run-detail routes should resume the latest active work conversation versus open a fresh one.

[x] 45.2 Section - Governed Run Detail Conversation Adoption
Host a bounded governed work conversation panel on the run detail route so operators can continue canonical work without leaving the governed surface.

[x] 45.2.1 Task - Render the governed work conversation panel on run detail
Add the run-detail route panel, transcript, controls, and degraded continuity messaging using the existing event-driven conversation model.

[x] 45.2.1.1 Subtask - Load the latest work-item conversation projection during run-detail route handling and subscribe to its event stream when LiveView is connected.
[x] 45.2.1.2 Subtask - Let operators open the governed work conversation, submit turns, resume clarification, and pause, resume, or stop active work from the same run-detail route.
[x] 45.2.1.3 Subtask - Keep the route bounded and product-readable by rendering recent transcript, execution state, and degraded messaging rather than raw runtime internals.

[x] 45.3 Section - Phase 45 Integration Tests And Spec Convergence
Verify the new run-detail conversation adoption path stays aligned with the conversation spec, product workspace boundary, and LiveView surface behavior.

[x] 45.3.1 Task - Run conversation boundary scenarios
Prove the product-owned run conversation boundary reuses the right work-item conversation state and exposes snapshots through AgentWorkspace instead of bypassing the conversation contract.

[x] 45.3.1.1 Subtask - Add integration coverage proving run-detail conversation opening reuses the latest active work-item conversation.
[x] 45.3.1.2 Subtask - Add integration coverage proving AgentWorkspace work-item conversation helpers expose snapshots and command admission for the run-detail surface.
[x] 45.3.1.3 Subtask - Keep run-detail conversation loading durable when the route rehydrates from the latest snapshot.

[x] 45.3.2 Task - Governed run route truth scenarios
Keep the current-truth spec workspace and route-level LiveView behavior aligned after governed run conversation adoption lands.

[x] 45.3.2.1 Subtask - Update run-detail LiveView coverage to assert the governed work conversation panel, transcript, and clarification flow.
[x] 45.3.2.2 Subtask - Update the conversation spec surface and verification targets to include the run-detail conversation adoption files.
[x] 45.3.2.3 Subtask - Verify the planning index and Phase 45 document remain coherent after governed run conversation adoption lands.
54 changes: 53 additions & 1 deletion .spec/specs/conversation_orchestration.spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ durable work scope, interruptible execution, and event-driven UI delivery.
id: architecture.conversation_orchestration
kind: feature
status: active
summary: Jido.Code treats productive coding conversations as managed-repository and usually work-item-scoped mixed-initiative sessions coordinated through explicit control and work commands, append-only sequenced event streams, durable snapshots, bounded shared context, cancellable tool jobs, and event-driven LiveView plus PubSub delivery with reconnectable degraded fallbacks, including bounded managed-repository route adoption rather than snapshot polling or ad hoc FIFO chat handling.
summary: Jido.Code treats productive coding conversations as managed-repository and usually work-item-scoped mixed-initiative sessions coordinated through explicit control and work commands, append-only sequenced event streams, durable snapshots, bounded shared context, cancellable tool jobs, and event-driven LiveView plus PubSub delivery with reconnectable degraded fallbacks, including bounded managed-repository and governed-run route adoption rather than snapshot polling or ad hoc FIFO chat handling.
decisions:
- jido_code.factory_control_plane_and_runtime_overlay
- jido_code.jido_agent_os_integration
Expand All @@ -24,16 +24,20 @@ surface:
- lib/jido_code/agent_workspace.ex
- lib/jido_code/operations/synthesis.ex
- lib/jido_code/workbench/project_conversation.ex
- lib/jido_code/workbench/run_conversation.ex
- lib/jido_code_web/live/project_detail_live.ex
- lib/jido_code_web/live/run_detail_live.ex
- lib/jido_code_web/live/demos/chat_live.ex
- lib/jido_code_web/live/forge/show_live.ex
- lib/jido_code/forge/pubsub.ex
- lib/jido_code/orchestration/run_pubsub.ex
- test/jido_code/phase_forty_five_integration_test.exs
- test/jido_code/phase_forty_four_integration_test.exs
- test/jido_code/phase_forty_one_integration_test.exs
- test/jido_code/phase_forty_two_integration_test.exs
- test/jido_code_web/live/demos/chat_live_test.exs
- test/jido_code_web/live/project_detail_live_test.exs
- test/jido_code_web/live/run_detail_live_test.exs
```

## Requirements
Expand Down Expand Up @@ -103,6 +107,11 @@ surface:
statement: Managed-repository operator routes should be able to open, resume, and guide bounded repo-scoped conversations through product-owned workspace and service boundaries without forcing the operator onto a separate chat-only surface.
priority: should
stability: proposed

- id: architecture.conversation_orchestration.governed_run_routes_host_work_conversations
statement: Governed run routes should be able to open, resume, and guide bounded work-item-scoped conversations through product-owned workspace and service boundaries when the run already carries canonical governed work, without forcing the operator back to repo detail or onto a separate chat-only surface.
priority: should
stability: proposed
```

## Scenarios
Expand Down Expand Up @@ -206,6 +215,21 @@ surface:
- The product-owned route boundary reuses the latest active repo-scoped conversation when one already exists.
- The route loads the latest durable snapshot and recent events through bounded workspace helpers.
- Live delivery stays event-driven while degraded continuity still renders the latest durable conversation state.

- id: architecture.conversation_orchestration.scenario_run_detail_route_reuses_work_item_conversation
covers:
- architecture.conversation_orchestration.conversation_is_repo_and_work_scoped
- architecture.conversation_orchestration.ui_delivery_is_event_driven_and_reconnectable
- architecture.conversation_orchestration.degraded_mode_falls_back_to_persisted_state
- architecture.conversation_orchestration.governed_run_routes_host_work_conversations
given:
- A governed run detail route needs to show the latest bounded conversation state for the run's canonical work item.
when:
- The operator opens or resumes the governed work conversation from that route.
then:
- The product-owned route boundary reuses the latest active work-item-scoped conversation when one already exists.
- The route loads the latest durable snapshot and recent events through bounded workspace helpers.
- Live delivery stays event-driven while degraded continuity still renders the latest durable conversation state.
```

## Verification
Expand Down Expand Up @@ -302,6 +326,13 @@ surface:
- architecture.conversation_orchestration.degraded_mode_falls_back_to_persisted_state
- architecture.conversation_orchestration.managed_repo_routes_host_repo_conversations

- kind: source_file
target: lib/jido_code/workbench/run_conversation.ex
covers:
- architecture.conversation_orchestration.conversation_is_repo_and_work_scoped
- architecture.conversation_orchestration.degraded_mode_falls_back_to_persisted_state
- architecture.conversation_orchestration.governed_run_routes_host_work_conversations

- kind: source_file
target: test/jido_code/phase_forty_integration_test.exs
covers:
Expand Down Expand Up @@ -340,6 +371,13 @@ surface:
- architecture.conversation_orchestration.coordinator_owns_turn_admission_and_state
- architecture.conversation_orchestration.managed_repo_routes_host_repo_conversations

- kind: source_file
target: test/jido_code/phase_forty_five_integration_test.exs
covers:
- architecture.conversation_orchestration.conversation_is_repo_and_work_scoped
- architecture.conversation_orchestration.coordinator_owns_turn_admission_and_state
- architecture.conversation_orchestration.governed_run_routes_host_work_conversations

- kind: source_file
target: lib/jido_code_web/live/forge/show_live.ex
covers:
Expand All @@ -359,6 +397,13 @@ surface:
- architecture.conversation_orchestration.degraded_mode_falls_back_to_persisted_state
- architecture.conversation_orchestration.managed_repo_routes_host_repo_conversations

- kind: source_file
target: lib/jido_code_web/live/run_detail_live.ex
covers:
- architecture.conversation_orchestration.ui_delivery_is_event_driven_and_reconnectable
- architecture.conversation_orchestration.degraded_mode_falls_back_to_persisted_state
- architecture.conversation_orchestration.governed_run_routes_host_work_conversations

- kind: source_file
target: test/jido_code_web/live/demos/chat_live_test.exs
covers:
Expand All @@ -372,6 +417,13 @@ surface:
- architecture.conversation_orchestration.degraded_mode_falls_back_to_persisted_state
- architecture.conversation_orchestration.managed_repo_routes_host_repo_conversations

- kind: source_file
target: test/jido_code_web/live/run_detail_live_test.exs
covers:
- architecture.conversation_orchestration.ui_delivery_is_event_driven_and_reconnectable
- architecture.conversation_orchestration.degraded_mode_falls_back_to_persisted_state
- architecture.conversation_orchestration.governed_run_routes_host_work_conversations

- kind: source_file
target: lib/jido_code/forge/pubsub.ex
covers:
Expand Down
26 changes: 26 additions & 0 deletions lib/jido_code/agent_workspace.ex
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,16 @@ defmodule JidoCode.AgentWorkspace do
Conversations.latest_for_managed_repo(managed_repo_id, actor: conversation_actor(opts))
end

@doc """
Returns the latest work-item-scoped conversation for the governed work item, if any.
"""
@spec latest_work_item_conversation(work_item_id(), keyword()) ::
{:ok, Conversations.Conversation.t() | nil} | {:error, term()}
def latest_work_item_conversation(work_item_id, opts \\ [])
when is_binary(work_item_id) and is_list(opts) do
Conversations.latest_for_work_item(work_item_id, actor: conversation_actor(opts))
end

@doc """
Opens a repo-scoped conversation and returns its initial snapshot.
"""
Expand All @@ -272,6 +282,22 @@ defmodule JidoCode.AgentWorkspace do
)
end

@doc """
Opens a work-item-scoped conversation and returns its initial snapshot.
"""
@spec open_work_item_conversation(managed_repo_id(), work_item_id(), map(), keyword()) ::
{:ok, map()} | {:error, term()}
def open_work_item_conversation(managed_repo_id, work_item_id, attrs \\ %{}, opts \\ [])
when is_binary(managed_repo_id) and is_binary(work_item_id) and is_map(attrs) and is_list(opts) do
ConversationDriver.start_conversation(
attrs
|> Map.put("managed_repo_id", managed_repo_id)
|> Map.put("work_item_id", work_item_id)
|> Map.put_new("attach_mode", :existing_work_item)
|> Map.put_new("actor", conversation_actor(opts))
)
end

@doc """
Returns the current snapshot for a conversation.
"""
Expand Down
19 changes: 19 additions & 0 deletions lib/jido_code/conversations.ex
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,25 @@ defmodule JidoCode.Conversations do
end
end

@spec latest_for_work_item(String.t(), keyword()) :: {:ok, Conversation.t() | nil} | {:error, term()}
def latest_for_work_item(work_item_id, opts \\ [])
when is_binary(work_item_id) and is_list(opts) do
actor = normalize_actor(Keyword.get(opts, :actor))

case Conversation.read(
query: [
filter: [work_item_id: work_item_id],
sort: [last_activity_at: :desc, inserted_at: :desc],
limit: 1
],
actor: actor
) do
{:ok, [%Conversation{} = conversation | _rest]} -> {:ok, conversation}
{:ok, []} -> {:ok, nil}
{:error, reason} -> {:error, reason}
end
end

@spec steer_work(Conversation.t(), map(), keyword()) :: {:ok, steer_result()} | {:error, term()}
def steer_work(%Conversation{} = conversation, %{} = payload, opts \\ []) when is_list(opts) do
actor = normalize_actor(Keyword.get(opts, :actor))
Expand Down
Loading
Loading