diff --git a/.yoi/tickets/00001KXKJGYGD/item.md b/.yoi/tickets/00001KXKJGYGD/item.md index 2a21f341..0577b18d 100644 --- a/.yoi/tickets/00001KXKJGYGD/item.md +++ b/.yoi/tickets/00001KXKJGYGD/item.md @@ -2,7 +2,7 @@ title: 'Remove workflow tracking and workflow resources' state: 'inprogress' created_at: '2026-07-15T19:02:13Z' -updated_at: '2026-07-15T20:45:12Z' +updated_at: '2026-07-15T21:04:19Z' assignee: null queued_by: 'workspace-panel' queued_at: '2026-07-15T19:54:36Z' diff --git a/.yoi/tickets/00001KXKJGYGD/thread.md b/.yoi/tickets/00001KXKJGYGD/thread.md index 3cc8eb49..f9c1fe73 100644 --- a/.yoi/tickets/00001KXKJGYGD/thread.md +++ b/.yoi/tickets/00001KXKJGYGD/thread.md @@ -151,4 +151,35 @@ Validation: - nix build .#yoi --no-link -> exit 0 +--- + + + +## 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 + + --- diff --git a/crates/ticket/src/config.rs b/crates/ticket/src/config.rs index 494671fe..43b005e0 100644 --- a/crates/ticket/src/config.rs +++ b/crates/ticket/src/config.rs @@ -1115,7 +1115,7 @@ launch_prompt = "$workspace/ticket/reviewer/launch" for role in TicketRole::ALL { assert!(scaffold.contains(&format!("[ticket.roles.{role}]"))); assert!(scaffold.contains(&format!( - "[ticket.roles.{role}]\nprofile = \"{}\"\nworkflow = \"{}\"", + "[ticket.roles.{role}]\nprofile = \"{}\"", role.default_profile() ))); } diff --git a/crates/tui/src/app.rs b/crates/tui/src/app.rs index 8cf99af6..03058a33 100644 --- a/crates/tui/src/app.rs +++ b/crates/tui/src/app.rs @@ -3324,7 +3324,7 @@ mod completion_flow_tests { } #[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 item = serde_json::json!({ "kind": "workflow", @@ -3333,10 +3333,7 @@ mod completion_flow_tests { }); app.handle_worker_event(Event::SystemItem { item }); - assert!(matches!( - app.blocks.as_slice(), - [Block::SystemMessage { text }] if text == "[Workflow /build]\nRun the build" - )); + assert!(app.blocks.is_empty()); } #[test] diff --git a/crates/worker/src/discovery.rs b/crates/worker/src/discovery.rs index ccfa08bd..7c5b381b 100644 --- a/crates/worker/src/discovery.rs +++ b/crates/worker/src/discovery.rs @@ -1064,8 +1064,6 @@ fn discovery_error_to_tool_error(error: WorkerDiscoveryError) -> ToolError { #[cfg(test)] mod tests { use super::*; - use std::sync::Mutex; - use manifest::{Permission, ScopeRule}; use protocol::stream::JsonLineWriter; use protocol::{Alert, AlertLevel, AlertSource}; @@ -1077,6 +1075,7 @@ mod tests { use tokio::net::UnixListener; use crate::runtime::dir::RuntimeDir; + use crate::runtime::worker_allocation::test_util::RuntimeDirSandbox; #[derive(Clone)] struct FailTargetPeerStore { @@ -1118,18 +1117,13 @@ mod tests { } } - static ENV_LOCK: Mutex<()> = Mutex::new(()); - #[tokio::test(flavor = "current_thread")] async fn state_backed_visibility_and_restore_planning() { - let _env = ENV_LOCK.lock().unwrap(); let root = TempDir::new().unwrap(); let store_dir = root.path().join("store"); let runtime_base = root.path().join("runtime"); std::fs::create_dir_all(&runtime_base).unwrap(); - unsafe { - std::env::set_var("YOI_RUNTIME_DIR", &runtime_base); - } + let _runtime_sandbox = RuntimeDirSandbox::new(&runtime_base); let store = FsWorkerStore::new(&store_dir).unwrap(); let session_id = new_session_id(); diff --git a/crates/worker/src/runtime/worker_allocation.rs b/crates/worker/src/runtime/worker_allocation.rs index 53694e52..1eb3874b 100644 --- a/crates/worker/src/runtime/worker_allocation.rs +++ b/crates/worker/src/runtime/worker_allocation.rs @@ -12,7 +12,7 @@ mod mutate; mod table; #[cfg(test)] -mod test_util; +pub(crate) mod test_util; pub use conflict::{ ConflictOwner, find_conflict_owner, find_conflict_owners, is_within_effective_write, diff --git a/docs/manifest.toml b/docs/manifest.toml index 1d542488..16de2c7e 100644 --- a/docs/manifest.toml +++ b/docs/manifest.toml @@ -281,8 +281,8 @@ permission = "write" # ===== [skills] ============================================================= -# 外部 Agent Skills (`SKILL.md`) を Workflow として読み込むディレクトリ群。 -# セクション省略 = 何もロードしない (implicit な `$config_dir/skills/` 検索や +# 外部 Agent Skills (`SKILL.md`) の候補ディレクトリ群。 +# セクション省略 = 何も使用しない (implicit な `$config_dir/skills/` 検索や # builtin probe は存在しない)。 # [skills] # diff --git a/web/workspace/src/lib/generated/protocol.ts b/web/workspace/src/lib/generated/protocol.ts index ba692217..d59209fd 100644 --- a/web/workspace/src/lib/generated/protocol.ts +++ b/web/workspace/src/lib/generated/protocol.ts @@ -79,7 +79,7 @@ message: string, */ 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", /** diff --git a/web/workspace/src/lib/workspace/console/composer-command.test.ts b/web/workspace/src/lib/workspace/console/composer-command.test.ts index d9ee89b9..a2aa9cd3 100644 --- a/web/workspace/src/lib/workspace/console/composer-command.test.ts +++ b/web/workspace/src/lib/workspace/console/composer-command.test.ts @@ -24,8 +24,7 @@ Deno.test("parseSigilSegments converts TUI-style references", () => { { kind: "file_ref", path: "src/main.rs" }, { kind: "text", content: " then " }, { kind: "knowledge_ref", slug: "memory" }, - { kind: "text", content: " and " }, - { kind: "workflow_invoke", slug: "workflow" }, + { kind: "text", content: " and /workflow" }, ]); }); diff --git a/web/workspace/src/lib/workspace/console/composer-command.ts b/web/workspace/src/lib/workspace/console/composer-command.ts index ffd0ec3b..d8f40c5b 100644 --- a/web/workspace/src/lib/workspace/console/composer-command.ts +++ b/web/workspace/src/lib/workspace/console/composer-command.ts @@ -161,7 +161,7 @@ function invalidUsage(name: string): ComposerCommandResult { export function parseSigilSegments(input: string): Segment[] { const segments: Segment[] = []; - const pattern = /(^|\s)([@#/])([^\s]+)/g; + const pattern = /(^|\s)([@#])([^\s]+)/g; let cursor = 0; let match: RegExpExecArray | null; while ((match = pattern.exec(input)) !== null) { @@ -187,8 +187,6 @@ function sigilSegment(sigil: string, value: string): Segment { return { kind: "file_ref", path: value }; case "#": return { kind: "knowledge_ref", slug: value }; - case "/": - return { kind: "workflow_invoke", slug: value }; default: return { kind: "text", content: `${sigil}${value}` }; } diff --git a/web/workspace/src/lib/workspace/console/model.ts b/web/workspace/src/lib/workspace/console/model.ts index 1d449fe6..e1a5278a 100644 --- a/web/workspace/src/lib/workspace/console/model.ts +++ b/web/workspace/src/lib/workspace/console/model.ts @@ -319,8 +319,6 @@ export function segmentsToText(segments: Segment[]): string { return `@file ${segment.path}`; case "knowledge_ref": return `@knowledge ${segment.slug}`; - case "workflow_invoke": - return `/${segment.slug}`; case "unknown": return "[unknown segment]"; }