fix: remove remaining workflow invoke surfaces

This commit is contained in:
Keisuke Hirata 2026-07-16 06:04:19 +09:00
parent d801b2698b
commit d30dca2d99
No known key found for this signature in database
11 changed files with 43 additions and 26 deletions

View File

@ -2,7 +2,7 @@
title: 'Remove workflow tracking and workflow resources' title: 'Remove workflow tracking and workflow resources'
state: 'inprogress' state: 'inprogress'
created_at: '2026-07-15T19:02:13Z' created_at: '2026-07-15T19:02:13Z'
updated_at: '2026-07-15T20:45:12Z' updated_at: '2026-07-15T21:04:19Z'
assignee: null assignee: null
queued_by: 'workspace-panel' queued_by: 'workspace-panel'
queued_at: '2026-07-15T19:54:36Z' queued_at: '2026-07-15T19:54:36Z'

View File

@ -151,4 +151,35 @@ Validation:
- nix build .#yoi --no-link -> exit 0 - nix build .#yoi --no-link -> exit 0
---
<!-- event: implementation_report author: hare at: 2026-07-15T21:04:19Z -->
## Implementation report
Follow-up fixes for external review blockers.
Summary:
- Removed stale web `workflow_invoke` protocol/model/composer/test behavior; slash-prefixed text now remains plain text in the web console composer.
- Updated the generated TypeScript protocol surface to match the Rust protocol without WorkflowInvoke.
- Removed remaining role workflow scaffold test expectation.
- Replaced the stale TUI live workflow SystemItem rendering test with a legacy workflow SystemItem ignore-path test.
- Removed stale docs/config wording that advertised loading Skills as Workflows.
- Stabilized the Worker discovery restore-planning test by sharing the runtime-dir sandbox used by allocation tests, so the required full worker test command is not affected by global runtime-dir test races.
Validation:
- rg "ActiveWorkflow|active_workflow|Active workflow" -> no matches (exit 1)
- rg "resources/workflows|\\.yoi/workflow|workflow invocation|Resident workflows|workflow_invoke" -> no matches (exit 1)
- git diff --check -> exit 0
- cargo test -p ticket --lib scaffold_config_includes_backend_and_all_fixed_roles -- --nocapture -> exit 0
- cargo test -p tui --lib live_legacy_workflow_system_item_is_ignored -- --nocapture -> exit 0
- cargo test -p session-store --lib --tests -> exit 0
- cargo test -p worker --lib --tests -> exit 0
- cargo test -p yoi --tests -> exit 0
- cd web/workspace && deno task check && deno task test -> exit 0
- cargo check -p yoi -> exit 0
- yoi ticket doctor -> exit 0
- nix build .#yoi --no-link -> exit 0
--- ---

View File

@ -1115,7 +1115,7 @@ launch_prompt = "$workspace/ticket/reviewer/launch"
for role in TicketRole::ALL { for role in TicketRole::ALL {
assert!(scaffold.contains(&format!("[ticket.roles.{role}]"))); assert!(scaffold.contains(&format!("[ticket.roles.{role}]")));
assert!(scaffold.contains(&format!( assert!(scaffold.contains(&format!(
"[ticket.roles.{role}]\nprofile = \"{}\"\nworkflow = \"{}\"", "[ticket.roles.{role}]\nprofile = \"{}\"",
role.default_profile() role.default_profile()
))); )));
} }

View File

@ -3324,7 +3324,7 @@ mod completion_flow_tests {
} }
#[test] #[test]
fn live_system_item_workflow_appends_system_message_block() { fn live_legacy_workflow_system_item_is_ignored() {
let mut app = App::new("test".into()); let mut app = App::new("test".into());
let item = serde_json::json!({ let item = serde_json::json!({
"kind": "workflow", "kind": "workflow",
@ -3333,10 +3333,7 @@ mod completion_flow_tests {
}); });
app.handle_worker_event(Event::SystemItem { item }); app.handle_worker_event(Event::SystemItem { item });
assert!(matches!( assert!(app.blocks.is_empty());
app.blocks.as_slice(),
[Block::SystemMessage { text }] if text == "[Workflow /build]\nRun the build"
));
} }
#[test] #[test]

View File

@ -1064,8 +1064,6 @@ fn discovery_error_to_tool_error(error: WorkerDiscoveryError) -> ToolError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use std::sync::Mutex;
use manifest::{Permission, ScopeRule}; use manifest::{Permission, ScopeRule};
use protocol::stream::JsonLineWriter; use protocol::stream::JsonLineWriter;
use protocol::{Alert, AlertLevel, AlertSource}; use protocol::{Alert, AlertLevel, AlertSource};
@ -1077,6 +1075,7 @@ mod tests {
use tokio::net::UnixListener; use tokio::net::UnixListener;
use crate::runtime::dir::RuntimeDir; use crate::runtime::dir::RuntimeDir;
use crate::runtime::worker_allocation::test_util::RuntimeDirSandbox;
#[derive(Clone)] #[derive(Clone)]
struct FailTargetPeerStore { struct FailTargetPeerStore {
@ -1118,18 +1117,13 @@ mod tests {
} }
} }
static ENV_LOCK: Mutex<()> = Mutex::new(());
#[tokio::test(flavor = "current_thread")] #[tokio::test(flavor = "current_thread")]
async fn state_backed_visibility_and_restore_planning() { async fn state_backed_visibility_and_restore_planning() {
let _env = ENV_LOCK.lock().unwrap();
let root = TempDir::new().unwrap(); let root = TempDir::new().unwrap();
let store_dir = root.path().join("store"); let store_dir = root.path().join("store");
let runtime_base = root.path().join("runtime"); let runtime_base = root.path().join("runtime");
std::fs::create_dir_all(&runtime_base).unwrap(); std::fs::create_dir_all(&runtime_base).unwrap();
unsafe { let _runtime_sandbox = RuntimeDirSandbox::new(&runtime_base);
std::env::set_var("YOI_RUNTIME_DIR", &runtime_base);
}
let store = FsWorkerStore::new(&store_dir).unwrap(); let store = FsWorkerStore::new(&store_dir).unwrap();
let session_id = new_session_id(); let session_id = new_session_id();

View File

@ -12,7 +12,7 @@ mod mutate;
mod table; mod table;
#[cfg(test)] #[cfg(test)]
mod test_util; pub(crate) mod test_util;
pub use conflict::{ pub use conflict::{
ConflictOwner, find_conflict_owner, find_conflict_owners, is_within_effective_write, ConflictOwner, find_conflict_owner, find_conflict_owners, is_within_effective_write,

View File

@ -281,8 +281,8 @@ permission = "write"
# ===== [skills] ============================================================= # ===== [skills] =============================================================
# 外部 Agent Skills (`SKILL.md`) を Workflow として読み込むディレクトリ群。 # 外部 Agent Skills (`SKILL.md`) の候補ディレクトリ群。
# セクション省略 = 何もロードしない (implicit な `$config_dir/skills/` 検索や # セクション省略 = 何も使用しない (implicit な `$config_dir/skills/` 検索や
# builtin probe は存在しない)。 # builtin probe は存在しない)。
# [skills] # [skills]
# #

View File

@ -79,7 +79,7 @@ message: string,
*/ */
timestamp_ms: number, }; timestamp_ms: number, };
export type Segment = { "kind": "text", content: string, } | { "kind": "paste", id: number, chars: number, lines: number, content: string, } | { "kind": "file_ref", path: string, } | { "kind": "knowledge_ref", slug: string, } | { "kind": "workflow_invoke", slug: string, } | { "kind": "unknown" }; export type Segment = { "kind": "text", content: string, } | { "kind": "paste", id: number, chars: number, lines: number, content: string, } | { "kind": "file_ref", path: string, } | { "kind": "knowledge_ref", slug: string, } | { "kind": "unknown" };
export type WorkerEvent = { "kind": "turn_ended", worker_name: string, } | { "kind": "errored", worker_name: string, message: string, } | { "kind": "shut_down", worker_name: string, } | { "kind": "scope_sub_delegated", export type WorkerEvent = { "kind": "turn_ended", worker_name: string, } | { "kind": "errored", worker_name: string, message: string, } | { "kind": "shut_down", worker_name: string, } | { "kind": "scope_sub_delegated",
/** /**

View File

@ -24,8 +24,7 @@ Deno.test("parseSigilSegments converts TUI-style references", () => {
{ kind: "file_ref", path: "src/main.rs" }, { kind: "file_ref", path: "src/main.rs" },
{ kind: "text", content: " then " }, { kind: "text", content: " then " },
{ kind: "knowledge_ref", slug: "memory" }, { kind: "knowledge_ref", slug: "memory" },
{ kind: "text", content: " and " }, { kind: "text", content: " and /workflow" },
{ kind: "workflow_invoke", slug: "workflow" },
]); ]);
}); });

View File

@ -161,7 +161,7 @@ function invalidUsage(name: string): ComposerCommandResult {
export function parseSigilSegments(input: string): Segment[] { export function parseSigilSegments(input: string): Segment[] {
const segments: Segment[] = []; const segments: Segment[] = [];
const pattern = /(^|\s)([@#/])([^\s]+)/g; const pattern = /(^|\s)([@#])([^\s]+)/g;
let cursor = 0; let cursor = 0;
let match: RegExpExecArray | null; let match: RegExpExecArray | null;
while ((match = pattern.exec(input)) !== null) { while ((match = pattern.exec(input)) !== null) {
@ -187,8 +187,6 @@ function sigilSegment(sigil: string, value: string): Segment {
return { kind: "file_ref", path: value }; return { kind: "file_ref", path: value };
case "#": case "#":
return { kind: "knowledge_ref", slug: value }; return { kind: "knowledge_ref", slug: value };
case "/":
return { kind: "workflow_invoke", slug: value };
default: default:
return { kind: "text", content: `${sigil}${value}` }; return { kind: "text", content: `${sigil}${value}` };
} }

View File

@ -319,8 +319,6 @@ export function segmentsToText(segments: Segment[]): string {
return `@file ${segment.path}`; return `@file ${segment.path}`;
case "knowledge_ref": case "knowledge_ref":
return `@knowledge ${segment.slug}`; return `@knowledge ${segment.slug}`;
case "workflow_invoke":
return `/${segment.slug}`;
case "unknown": case "unknown":
return "[unknown segment]"; return "[unknown segment]";
} }