Compare commits
182
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
159704dc6f | ||
|
|
6492f10f42 | ||
|
|
a525ba4d01 | ||
|
|
c261aea021 | ||
|
|
8d4fee231b | ||
|
|
307d38453f | ||
|
|
d2a8a79ac6 | ||
|
|
6c8998878d | ||
|
|
41283c8dd9 | ||
|
|
fa29cc2c95 | ||
|
|
7a4fd97526 | ||
|
|
103077dfae | ||
|
|
cd2006305e | ||
|
|
a453c6e2da | ||
|
|
16247ce7c5 | ||
|
|
b9e786e106 | ||
|
|
ccd4d83d43 | ||
|
|
3a9ac1b1b7 | ||
|
|
f2c51ffe39 | ||
|
|
ef17955369 | ||
|
|
62e467c035 | ||
|
|
4950749c5d | ||
|
|
dc2f8b409d | ||
|
|
d2aa92a729 | ||
|
|
86017a5abc | ||
|
|
799998639a | ||
|
|
755d460f0d | ||
|
|
07f9793bc6 | ||
|
|
89a40db79e | ||
|
|
84a8423611 | ||
|
|
8e79c1dc96 | ||
|
|
000afbbe19 | ||
|
|
db1a2f567b | ||
|
|
bdd05dce4d | ||
|
|
4e138b7e36 | ||
|
|
1839acb3d0 | ||
|
|
f26c7e0d09 | ||
|
|
437ef5b56b | ||
|
|
7d64b443f2 | ||
|
|
449745ee24 | ||
|
|
e66efc746f | ||
|
|
436bcc812d | ||
|
|
6086099fe4 | ||
|
|
390f468471 | ||
|
|
ef1d8d9af2 | ||
|
|
ceb7b95096 | ||
|
|
237c985f2c | ||
|
|
66c5be16f8 | ||
|
|
bedbb670e4 | ||
|
|
0591fd528c | ||
|
|
19ff3724ed | ||
|
|
741d71327a | ||
|
|
27117f3246 | ||
|
|
1b5a39dbc9 | ||
|
|
f65f0e3b8f | ||
|
|
e2df9f9493 | ||
|
|
959b497135 | ||
|
|
ef08b873ce | ||
|
|
2f975808bb | ||
|
|
273f10e954 | ||
|
|
f349738257 | ||
|
|
577bf75051 | ||
|
|
79df31ccf6 | ||
|
|
72812878c0 | ||
|
|
cea115ecd9 | ||
|
|
4c3b15d8d6 | ||
|
|
45d21ac032 | ||
|
|
4e713fce19 | ||
|
|
428b7d0fef | ||
|
|
5ddc8dceac | ||
|
|
f901b9bee3 | ||
|
|
2f9604a12f | ||
|
|
893122781d | ||
|
|
f367d73231 | ||
|
|
5fa480904d | ||
|
|
0618de21eb | ||
|
|
d5012d3e16 | ||
|
|
28d53aadf2 | ||
|
|
4fb75ec324 | ||
|
|
091ee764a4 | ||
|
|
439f967cb8 | ||
|
|
80d6861aba | ||
|
|
d2ec533585 | ||
|
|
b52b7c963c | ||
|
|
89910a1a29 | ||
|
|
7ee2b78bbb | ||
|
|
0b2ce6ca1f | ||
|
|
bca8ba6ed9 | ||
|
|
5c9331e848 | ||
|
|
bb6bc9f6a1 | ||
|
|
845817d3bf | ||
|
|
1d98921a45 | ||
|
|
7ede927d5a | ||
|
|
6081448a7e | ||
|
|
70162d5001 | ||
|
|
b975812c18 | ||
|
|
1251c0ca70 | ||
|
|
dd40c41f45 | ||
|
|
428d255b27 | ||
|
|
38d25582b2 | ||
|
|
cdc0a5da33 | ||
|
|
c96cc49d0a | ||
|
|
9bd1550715 | ||
|
|
81fa035a1c | ||
|
|
371fd7c6e5 | ||
|
|
d231f41300 | ||
|
|
97555bb5a1 | ||
|
|
d62ab6e1de | ||
|
|
217a4828d7 | ||
|
|
bc2b8513f7 | ||
|
|
73122c10fd | ||
|
|
b84db7fac7 | ||
|
|
911df3df77 | ||
|
|
acf1f5fb53 | ||
|
|
1044b39c3f | ||
|
|
a729d68600 | ||
|
|
b83886554f | ||
|
|
5a8bcebdf4 | ||
|
|
a479d3e32d | ||
|
|
f399d7383c | ||
|
|
e8e019eb76 | ||
|
|
3c2fd5d760 | ||
|
|
1ca5663298 | ||
|
|
b28d64c3c6 | ||
|
|
76c800542c | ||
|
|
cca073f8aa | ||
|
|
c0f4c184ca | ||
|
|
8c8fb01426 | ||
|
|
052408392d | ||
|
|
cfb215ab0c | ||
|
|
3501e0dffe | ||
|
|
af683af2d2 | ||
|
|
90b1a1fccb | ||
|
|
5954021cc5 | ||
|
|
108088d811 | ||
|
|
ca2ad18ded | ||
|
|
d2e6a2a1a7 | ||
|
|
e275a80f4c | ||
|
|
2745f3d516 | ||
|
|
8f7b87a29e | ||
|
|
2a7b659be4 | ||
|
|
3dd680683c | ||
|
|
49c9e19074 | ||
|
|
ddd2f86e26 | ||
|
|
fac79dc962 | ||
|
|
71a39002fb | ||
|
|
58904c441a | ||
|
|
1e812b793b | ||
|
|
ff8aa6bcbf | ||
|
|
2b213a8add | ||
|
|
021aca8d5e | ||
|
|
21b14ba440 | ||
|
|
5c242d9620 | ||
|
|
31565c9b9e | ||
|
|
99f31e0055 | ||
|
|
4cda83b748 | ||
|
|
13e76d3544 | ||
|
|
85b6d9f027 | ||
|
|
8daf9eacb7 | ||
|
|
48672e4317 | ||
|
|
eb998f0ad4 | ||
|
|
9cbb5b9b71 | ||
|
|
108666664a | ||
|
|
5abf16f9e6 | ||
|
|
78c98a34d1 | ||
|
|
68f1ddbd5a | ||
|
|
71284cdc92 | ||
|
|
03ad525fcc | ||
|
|
af9e940873 | ||
|
|
b547203fde | ||
|
|
9728b533b4 | ||
|
|
9c4d1559fd | ||
|
|
e0ec8ce78a | ||
|
|
9de04f7266 | ||
|
|
eea26f9174 | ||
|
|
0b1e9fdc5b | ||
|
|
277af3dec3 | ||
|
|
3bfd1ca07d | ||
|
|
0e635ba6b4 | ||
|
|
017ac70876 | ||
|
|
a13fb6933b | ||
|
|
6f68bb8d95 |
@@ -2,8 +2,8 @@
|
||||
title: "Plugin platform roadmap"
|
||||
state: "active"
|
||||
created_at: "2026-06-19T13:18:58Z"
|
||||
updated_at: "2026-06-19T13:18:58Z"
|
||||
linked_tickets: ["00001KV5R5V2S", "00001KV5W3PHA", "00001KV5W3PHW", "00001KV5W3PJ3", "00001KVFD3YSV", "00001KVFDX9AF", "00001KVFDX9AY", "00001KVG0HR96"]
|
||||
updated_at: "2026-06-24T19:55:00Z"
|
||||
linked_tickets: ["00001KV5R5V2S", "00001KV5W3PHA", "00001KV5W3PHW", "00001KV5W3PJ3", "00001KVFD3YSV", "00001KVFDX9AF", "00001KVFDX9AY", "00001KVG0HR96", "00001KVXHVCR5", "00001KVXK0WD3", "00001KVXK0WDH", "00001KVXK0WDQ", "00001KVXK0WDX", "00001KVXK0WE4", "00001KVXK0WEA"]
|
||||
---
|
||||
|
||||
## Goal
|
||||
@@ -42,10 +42,10 @@ Research of common Wasm extension systems points to the same pattern: mature sys
|
||||
- Package presence never registers a Tool/Hook, executes Wasm, starts a Service, reads files, opens network, or injects context.
|
||||
- Explicit enablement and Plugin grants are required before registration/execution/host API use.
|
||||
- Tool calls/results continue through ordinary ToolRegistry and Worker history paths.
|
||||
- Treat Component Model as the preferred future Plugin runtime shape.
|
||||
- Treat Component Model as the active Plugin runtime shape before public release.
|
||||
- New typed Plugin host APIs should be designed in WIT-compatible terms.
|
||||
- `runtime.kind = "wasm-component"` should become the preferred runtime once implemented.
|
||||
- Current `yoi-plugin-wasm-1` raw core-Wasm ABI remains a compatibility / migration bridge until Component Model execution and authoring are validated.
|
||||
- `runtime.kind = "wasm-component"` is the current Plugin runtime authority for new work.
|
||||
- The earlier `yoi-plugin-wasm-1` raw core-Wasm compatibility bridge is retired from the active roadmap because Plugin has not been publicly released and compatibility would preserve the wrong boundary.
|
||||
- Sequence the platform in usable layers:
|
||||
1. Package discovery / explicit enablement / digest-pinned restore. Completed foundation.
|
||||
2. Tool surface registration. Completed foundation.
|
||||
@@ -53,30 +53,49 @@ Research of common Wasm extension systems points to the same pattern: mature sys
|
||||
4. Permission grants. Completed foundation.
|
||||
5. Read-only Plugin CLI inspection (`yoi plugin list/show`) for debugging discovery/enablement/grants/runtime metadata.
|
||||
6. `https` and `fs` host APIs for Tool Plugins, grant-gated and WIT-compatible.
|
||||
7. Component Model runtime migration and authoring model.
|
||||
8. Guest SDK/PDK, examples, `check`/`pack`/`new` authoring tooling.
|
||||
9. Service / Ingress / WebSocket or inbound HTTP only after Tool + host API foundations are stable.
|
||||
7. Remove the raw core-Wasm compatibility bridge and reject legacy runtime manifests.
|
||||
8. Component Model runtime and authoring model become the only active Plugin runtime path.
|
||||
9. Guest SDK/PDK, examples, `check`/`pack`/`new` authoring tooling target Component Model only.
|
||||
10. Service / Ingress runtime is developed as host-managed lifecycle, event queue, output command, and diagnostics slices.
|
||||
11. WebSocket support for long-lived integrations is host-owned connection driver + ingress event delivery + output command, not Plugin-owned polling with `recv(timeout)`.
|
||||
- Keep Discord-style bridge goals split into two stages.
|
||||
- Outbound Discord/webhook Tool is possible after `https`.
|
||||
- Bidirectional Discord bridge requires Service + Ingress + WebSocket or inbound HTTP and host routing policy.
|
||||
|
||||
## Current implementation split
|
||||
|
||||
The broad Plugin runtime redesign is tracked by `00001KVXHVCR5` as context only; implementation should proceed through concrete Tickets instead of routing that umbrella as a single coding task.
|
||||
|
||||
1. `00001KVXK0WD3` Remove legacy raw WASM Plugin runtime.
|
||||
- Deletes the active `LegacyToolAdapter` / raw-Wasm execution path.
|
||||
2. `00001KVXK0WDH` Reject legacy Plugin runtime in manifest and CLI diagnostics.
|
||||
- Makes `plugin.toml`, `yoi plugin check/list/show`, docs, and fixtures reflect Component Model only runtime authority.
|
||||
3. `00001KVXK0WDQ` Define Plugin Service lifecycle and ingress queue runtime.
|
||||
- Adds host-managed lifecycle, bounded queue, serial dispatch, backpressure, timeout, and diagnostics.
|
||||
4. `00001KVXK0WDX` Add Plugin service output command model.
|
||||
- Lets service handlers request side effects as grant-checked commands rather than ambient authority.
|
||||
5. `00001KVXK0WE4` Add host-owned WebSocket driver for Plugin services.
|
||||
- Converts incoming WS frames into ingress events and sends outbound frames through output commands.
|
||||
6. `00001KVXK0WEA` Update Plugin WIT PDK templates for service event runtime.
|
||||
- Aligns authoring API, WIT, PDK, templates, and docs with the new event/command execution model.
|
||||
|
||||
## Success criteria / exit conditions
|
||||
|
||||
- Users can inspect Plugin discovery/enablement/grant/runtime state through a read-only CLI without executing Plugin code.
|
||||
- Plugin authors can build a Tool Plugin without writing raw memory/pointer ABI plumbing.
|
||||
- Tool Plugins can safely call grant-gated `https` and `fs` host APIs.
|
||||
- Component Model support is available or a documented migration path is active, with WIT-compatible host API types and measured packaging/runtime impact.
|
||||
- Component Model is the only active Plugin runtime path, with WIT-compatible host API types and measured packaging/runtime impact.
|
||||
- Plugin grants remain authoritative over registration, execution, and host API calls.
|
||||
- Plugin diagnostics explain missing package, invalid manifest, digest/version mismatch, missing grant, rejected schema, runtime mismatch, and unsupported host API cases safely.
|
||||
- Existing raw core-Wasm Plugin tests either remain passing or have an explicit compatibility/deprecation decision.
|
||||
- Documentation covers package format, runtime kinds, Component Model direction, host API authority, authoring SDK/templates, and operational debugging.
|
||||
- Service/Ingress work starts only after Tool Plugin + host API + diagnostics foundations are usable.
|
||||
- Plugin diagnostics explain missing package, invalid manifest, digest/version mismatch, missing grant, rejected schema, runtime mismatch, legacy runtime rejection, and unsupported host API cases safely.
|
||||
- Raw core-Wasm Plugin compatibility is removed before public release; tests and docs no longer treat it as a current runtime.
|
||||
- Documentation covers package format, Component Model runtime, host API authority, authoring SDK/templates, Service/Ingress event runtime, and operational debugging.
|
||||
- Service/Ingress work is host-managed: services have lifecycle/status, ingress uses bounded queues, side effects are output commands, and WebSocket integrations use host-owned connection drivers.
|
||||
|
||||
## Decision context
|
||||
|
||||
- This Objective is roadmap context, not Ticket authority. Implementation still requires reading concrete Ticket bodies, threads, artifacts, and relations.
|
||||
- Component Model direction supersedes making Yoi's custom raw ABI the long-term authoring interface, but does not require an immediate flag-day rewrite.
|
||||
- Component Model direction supersedes Yoi's custom raw ABI as both long-term and current active Plugin runtime authority before public release.
|
||||
- `https` / `fs` work should avoid choices that conflict with later WIT typed interfaces.
|
||||
- Guest SDK work should either target Component Model directly or keep the raw ABI wrapper clearly transitional.
|
||||
- Guest SDK work targets Component Model directly; raw ABI wrappers are not a supported transitional authoring path.
|
||||
- Plugin and MCP remain separate. Component Model adoption for Plugin does not imply MCP server execution, MCP prompt/resource injection, or MCP trust policy changes.
|
||||
- Plugin surfaces remain Tool / Hook / Service / Ingress; outbound side effects are Tool metadata and host API grants, not a separate surface.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
title: 'Generate Workspace web TypeScript types from protocol crate'
|
||||
state: 'inprogress'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-23T05:13:22Z'
|
||||
updated_at: '2026-06-23T05:42:14Z'
|
||||
updated_at: '2026-06-23T06:22:01Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-23T05:40:01Z'
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
Protocol crate 由来の Workspace web TypeScript type generation を実装し、Orchestrator worktree の `orchestration` branch に統合した。
|
||||
|
||||
主な成果:
|
||||
- `crates/protocol` の `stream` module / tokio dependency を default `stream` feature に分離し、DTO-only build で tokio を不要にした。
|
||||
- Optional `typescript` feature と `ts-rs` による TypeScript export を追加。
|
||||
- Protocol DTOs に `cfg_attr(feature = "typescript", derive(ts_rs::TS))` を追加。
|
||||
- Deterministic generator を追加:
|
||||
- `crates/protocol/src/typescript.rs`
|
||||
- `crates/protocol/examples/generate_typescript.rs`
|
||||
- Drift check を追加:
|
||||
- `cargo test -p protocol --features typescript generated_protocol_types_are_current`
|
||||
- Generated artifact を追加:
|
||||
- `web/workspace/src/lib/generated/protocol.ts`
|
||||
- Workspace web が generated root protocol types を re-export:
|
||||
- `PodProtocolMethod`
|
||||
- `PodProtocolEvent`
|
||||
- `PodProtocolSegment`
|
||||
- Workspace backend extension-point notes に、browser が Pod Unix socket に直接接続せず、将来の backend proxy が Worker identity と method allow/block boundary を enforce する方針を記録。
|
||||
- `Cargo.lock` と `package.nix` cargo hash を更新。
|
||||
|
||||
統合・検証:
|
||||
- Merge commit: `9728b533 merge: protocol typescript generation`
|
||||
- Implementation commit: `a13fb693 protocol: generate workspace TypeScript types`
|
||||
- Reviewer final verdict: approve
|
||||
- Validation passed: `cargo fmt --check`, `git diff --check HEAD^1..HEAD`, `cargo test -p protocol`, `cargo test -p protocol --features typescript generated_protocol_types_are_current`, `cargo test -p protocol --features typescript`, `cargo check -p protocol --target wasm32-unknown-unknown --no-default-features`, `deno task check`, `deno task build`, `cargo run -p yoi -- ticket doctor`, and `nix build .#yoi --no-link`。
|
||||
|
||||
既知の非ブロッキング事項:
|
||||
- `ts-rs` は `#[serde(other)]` on `Segment::Unknown` に warning を出すが、generated artifact には `{ "kind": "unknown" }` が含まれ、current validation は pass。
|
||||
- 一部 `Option<T>` + `skip_serializing_if` fields は TS で optional field ではなく required nullable に出る。将来 UI が該当 field を使う際は注意。
|
||||
@@ -126,3 +126,267 @@ Next action:
|
||||
- Wait for Coder implementation report, then spawn Reviewer read-only for the implementation diff。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:09:42Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Coder implementation report received from `yoi-coder-00001KVSEBF56`.
|
||||
|
||||
Implementation commit:
|
||||
- `a13fb693 protocol: generate workspace TypeScript types`
|
||||
|
||||
Changed areas:
|
||||
- `crates/protocol`
|
||||
- Made `stream` optional behind default feature `stream`。
|
||||
- Added optional `typescript` feature using `ts-rs`。
|
||||
- Added `cfg_attr(feature = "typescript", derive(ts_rs::TS))` to protocol DTOs。
|
||||
- Added deterministic generator module and example:
|
||||
- `crates/protocol/src/typescript.rs`
|
||||
- `crates/protocol/examples/generate_typescript.rs`
|
||||
- Added drift check:
|
||||
- `cargo test -p protocol --features typescript generated_protocol_types_are_current`
|
||||
- `web/workspace`
|
||||
- Added generated TypeScript artifact:
|
||||
- `web/workspace/src/lib/generated/protocol.ts`
|
||||
- Re-exported generated root protocol types from workspace sidebar types:
|
||||
- `PodProtocolMethod`
|
||||
- `PodProtocolEvent`
|
||||
- `PodProtocolSegment`
|
||||
- `crates/workspace-server`
|
||||
- Updated extension-point notes to explicitly preserve no direct browser-to-Pod socket exposure and require future Workspace-server proxy enforcement of Worker identity / method allow-block boundaries。
|
||||
- Packaging/dependencies:
|
||||
- Updated `Cargo.lock`。
|
||||
- Updated `package.nix` `cargoHash`。
|
||||
|
||||
Coder validation reported:
|
||||
- `cargo fmt --check`: passed
|
||||
- `cargo test -p protocol`: passed
|
||||
- `cargo test -p protocol --features typescript generated_protocol_types_are_current`: passed
|
||||
- `cargo test -p protocol --features typescript`: passed
|
||||
- `cargo check -p protocol --target wasm32-unknown-unknown --no-default-features`: passed
|
||||
- `cd web/workspace && deno task check && deno task build`: passed
|
||||
- `cargo run -p yoi -- ticket doctor`: passed
|
||||
- `git diff --check`: passed
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
Generated artifact cleanup:
|
||||
- Only intended generated TypeScript import artifact is tracked。
|
||||
- Orchestrator removed ignored `web/workspace/node_modules/` before Reviewer routing; no ignored frontend artifacts remain under `web/workspace`。
|
||||
|
||||
Orchestrator evidence checked:
|
||||
- Worktree clean on `impl/00001KVSEBF56-protocol-typescript-types` at `a13fb693`。
|
||||
- Diff `746c51c7..HEAD` touches expected protocol/frontend/workspace-server/package files only。
|
||||
- `git diff --check 746c51c7..HEAD`: passed。
|
||||
|
||||
Next action:
|
||||
- Route to read-only Reviewer Pod for acceptance review。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: comment author: yoi-orchestrator at: 2026-06-23T06:10:31Z -->
|
||||
|
||||
## Comment
|
||||
|
||||
Review routing:
|
||||
|
||||
Spawned read-only Reviewer Pod:
|
||||
- `yoi-reviewer-00001KVSEBF56-r1`
|
||||
|
||||
Review target:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVSEBF56-protocol-typescript-types`
|
||||
- Branch: `impl/00001KVSEBF56-protocol-typescript-types`
|
||||
- Baseline: `746c51c7`
|
||||
- Implementation commit: `a13fb693 protocol: generate workspace TypeScript types`
|
||||
- Diff: `746c51c7..a13fb693`
|
||||
|
||||
Reviewer scope:
|
||||
- read-only `/home/hare/Projects/yoi`
|
||||
|
||||
Reviewer focus:
|
||||
- Generated TS shape vs serde wire shape。
|
||||
- `Method` / `Event` / `Segment` coverage。
|
||||
- Deterministic drift check。
|
||||
- `stream` feature gating and wasm/no-default protocol compile。
|
||||
- No direct browser-to-Pod socket implication。
|
||||
- Package/Nix updates。
|
||||
|
||||
Orchestrator will wait for reviewer verdict before integration。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVSEBF56-r1 at: 2026-06-23T06:16:54Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Verdict: `approve`
|
||||
|
||||
確認範囲:
|
||||
- Ticket authority:
|
||||
- `.yoi/tickets/00001KVSEBF56/item.md`
|
||||
- `.yoi/tickets/00001KVSEBF56/thread.md`
|
||||
- Diff `746c51c7..a13fb693`:
|
||||
- `crates/protocol/Cargo.toml`
|
||||
- `crates/protocol/src/lib.rs`
|
||||
- `crates/protocol/src/typescript.rs`
|
||||
- `crates/protocol/examples/generate_typescript.rs`
|
||||
- `web/workspace/src/lib/generated/protocol.ts`
|
||||
- `web/workspace/src/lib/workspace-sidebar/types.ts`
|
||||
- `crates/workspace-server/src/server.rs`
|
||||
- `Cargo.lock`
|
||||
- `package.nix`
|
||||
|
||||
Blocking issues:
|
||||
- None。
|
||||
|
||||
Non-blocking concerns:
|
||||
- `cargo test -p protocol --features typescript` emits `ts-rs` warnings for `#[serde(other)]` on `Segment::Unknown`: `ts-rs failed to parse this attribute. It will be ignored.` The generated artifact still includes `{ "kind": "unknown" }`, and this does not break current validation, but TS generator is not fully understanding serde fallback semantics。
|
||||
- Some `Option<T>` fields with `skip_serializing_if = "Option::is_none"` are generated as required nullable rather than optional nullable, e.g. `RewindTarget.disabled_reason: string | null` and `warning: string | null`. Acceptable for this initial generated-types ticket, but future UI code should be careful because runtime JSON may omit those fields。
|
||||
|
||||
Review findings:
|
||||
- `crates/protocol` remains Rust DTO authority。
|
||||
- `stream` is now an optional default feature:
|
||||
- `default = ["stream"]`
|
||||
- `stream = ["dep:tokio"]`
|
||||
- `tokio` is optional。
|
||||
- DTO-only/no-default protocol build compiles for wasm without `tokio`。
|
||||
- `typescript` feature is optional and uses `ts-rs`。
|
||||
- Generated TS root includes `Method`, `Event`, `Segment`, plus related DTOs such as `PodEvent`, `ScopeRule`, `Greeting`, `InFlight*`, rewind DTOs, completion DTOs, status/result/error enums。
|
||||
- Generated TS file is committed at `web/workspace/src/lib/generated/protocol.ts`。
|
||||
- Workspace web re-exports generated root protocol types as `PodProtocolMethod`, `PodProtocolEvent`, and `PodProtocolSegment`。
|
||||
- Generated TS tagged enums and casing match observed serde wire shape for critical roots:
|
||||
- `Method`: `{ "method": "...", "params": ... }`
|
||||
- `Event`: `{ "event": "...", "data": ... }`
|
||||
- `Segment` / `PodEvent` / `InFlightBlock`: internal `"kind"` tags with snake_case variants。
|
||||
- Drift check `generated_protocol_types_are_current` compares committed generated artifact to deterministic generator output。
|
||||
- Backend proxy stance is represented in Workspace API extension-point notes and does not add direct browser-to-Pod socket access or broad Worker operation UI。
|
||||
|
||||
Reviewer validation:
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check 746c51c7..HEAD`: passed
|
||||
- `cargo test -p protocol`: passed (`40 passed`)
|
||||
- `cargo test -p protocol --features typescript generated_protocol_types_are_current`: passed; emitted non-blocking `ts-rs` warning for `serde(other)`。
|
||||
- `cargo test -p protocol --features typescript`: passed (`41 passed`); emitted same non-blocking warning。
|
||||
- `cargo check -p protocol --target wasm32-unknown-unknown --no-default-features`: passed
|
||||
- `cd web/workspace && deno task check && deno task build`: passed (`svelte-check found 0 errors and 0 warnings`; build succeeded)
|
||||
- `cargo run -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
Generated artifact status:
|
||||
- `web/workspace/src/lib/generated/protocol.ts` remained unchanged after validation。
|
||||
- SHA-256 after validation: `3984a043ded1179545656e5402171c49b2d22b5529aa17f016b675e394b7e553`。
|
||||
|
||||
Worktree status:
|
||||
- Clean on `impl/00001KVSEBF56-protocol-typescript-types` at `a13fb693`。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:20:49Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Reviewer r1 approvalを受けて、実装ブランチを Orchestrator worktree の `orchestration` branch に統合した。
|
||||
|
||||
統合:
|
||||
- Merge commit: `9728b533 merge: protocol typescript generation`
|
||||
- Merged branch: `impl/00001KVSEBF56-protocol-typescript-types`
|
||||
- Implementation commit:
|
||||
- `a13fb693 protocol: generate workspace TypeScript types`
|
||||
|
||||
Orchestrator worktree validation:
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cargo test -p protocol`: passed
|
||||
- `cargo test -p protocol --features typescript generated_protocol_types_are_current`: passed
|
||||
- `cargo test -p protocol --features typescript`: passed
|
||||
- Non-blocking `ts-rs` warning for `#[serde(other)]` on `Segment::Unknown` remains as reviewer noted。
|
||||
- `cargo check -p protocol --target wasm32-unknown-unknown --no-default-features`: passed
|
||||
- `cd web/workspace && rm -rf node_modules .svelte-kit build && deno task check`: passed (`svelte-check found 0 errors and 0 warnings`)
|
||||
- `cd web/workspace && deno task build`: passed
|
||||
- `cargo run -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
Validation generated ignored frontend artifacts in Orchestrator worktree:
|
||||
- `web/workspace/node_modules/`
|
||||
- `web/workspace/.svelte-kit/`
|
||||
- `web/workspace/build/`
|
||||
|
||||
These were removed after validation. Final Orchestrator worktree status after validation cleanup is clean on `orchestration` at `9728b533`。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T06:21:01Z from: inprogress to: done reason: implementation_merged_and_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Reviewer approval、Orchestrator worktree への統合、protocol tests/drift check/wasm no-default check、Deno check/build、Ticket doctor、Nix build が完了したため `done` に遷移する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: hare at: 2026-06-23T06:21:19Z from: done to: closed reason: closed field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を closed にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: close author: hare at: 2026-06-23T06:21:19Z status: closed -->
|
||||
|
||||
## 完了
|
||||
|
||||
Protocol crate 由来の Workspace web TypeScript type generation を実装し、Orchestrator worktree の `orchestration` branch に統合した。
|
||||
|
||||
主な成果:
|
||||
- `crates/protocol` の `stream` module / tokio dependency を default `stream` feature に分離し、DTO-only build で tokio を不要にした。
|
||||
- Optional `typescript` feature と `ts-rs` による TypeScript export を追加。
|
||||
- Protocol DTOs に `cfg_attr(feature = "typescript", derive(ts_rs::TS))` を追加。
|
||||
- Deterministic generator を追加:
|
||||
- `crates/protocol/src/typescript.rs`
|
||||
- `crates/protocol/examples/generate_typescript.rs`
|
||||
- Drift check を追加:
|
||||
- `cargo test -p protocol --features typescript generated_protocol_types_are_current`
|
||||
- Generated artifact を追加:
|
||||
- `web/workspace/src/lib/generated/protocol.ts`
|
||||
- Workspace web が generated root protocol types を re-export:
|
||||
- `PodProtocolMethod`
|
||||
- `PodProtocolEvent`
|
||||
- `PodProtocolSegment`
|
||||
- Workspace backend extension-point notes に、browser が Pod Unix socket に直接接続せず、将来の backend proxy が Worker identity と method allow/block boundary を enforce する方針を記録。
|
||||
- `Cargo.lock` と `package.nix` cargo hash を更新。
|
||||
|
||||
統合・検証:
|
||||
- Merge commit: `9728b533 merge: protocol typescript generation`
|
||||
- Implementation commit: `a13fb693 protocol: generate workspace TypeScript types`
|
||||
- Reviewer final verdict: approve
|
||||
- Validation passed: `cargo fmt --check`, `git diff --check HEAD^1..HEAD`, `cargo test -p protocol`, `cargo test -p protocol --features typescript generated_protocol_types_are_current`, `cargo test -p protocol --features typescript`, `cargo check -p protocol --target wasm32-unknown-unknown --no-default-features`, `deno task check`, `deno task build`, `cargo run -p yoi -- ticket doctor`, and `nix build .#yoi --no-link`。
|
||||
|
||||
既知の非ブロッキング事項:
|
||||
- `ts-rs` は `#[serde(other)]` on `Segment::Unknown` に warning を出すが、generated artifact には `{ "kind": "unknown" }` が含まれ、current validation は pass。
|
||||
- 一部 `Option<T>` + `skip_serializing_if` fields は TS で optional field ではなく required nullable に出る。将来 UI が該当 field を使う際は注意。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:22:01Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Post-close cleanup completed。
|
||||
|
||||
- Stopped child Pods and reclaimed scope:
|
||||
- `yoi-coder-00001KVSEBF56`
|
||||
- `yoi-reviewer-00001KVSEBF56-r1`
|
||||
- Removed ignored frontend validation artifacts from child worktree before worktree removal if present:
|
||||
- `web/workspace/node_modules/`
|
||||
- `web/workspace/.svelte-kit/`
|
||||
- `web/workspace/build/`
|
||||
- Removed implementation worktree:
|
||||
- `/home/hare/Projects/yoi/.worktree/00001KVSEBF56-protocol-typescript-types`
|
||||
- Deleted implementation branch:
|
||||
- `impl/00001KVSEBF56-protocol-typescript-types`
|
||||
- Orchestrator worktree remains clean on `orchestration` at `b547203f`。
|
||||
|
||||
Root/original workspace was not used for merge/validation/cleanup operations。
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"orch-plan-20260623-061132-1","ticket_id":"00001KVSFXY88","kind":"accepted_plan","accepted_plan":{"summary":"Remove redundant Workspace Dashboard title/actionbar key hints and selected-row textual status display while preserving row selection markers and Dashboard keyboard/action semantics, updating render tests accordingly.","branch":"impl/00001KVSFXY88-dashboard-hint-cleanup","worktree":"/home/hare/Projects/yoi/.worktree/00001KVSFXY88-dashboard-hint-cleanup","role_plan":"Orchestrator creates a dedicated child worktree and spawns a narrow-scope Coder. Reviewer will be spawned read-only after Coder reports implementation commit(s). After approval, Orchestrator integrates into `orchestration`, validates TUI tests, records closure, and cleans only the child worktree/branch."},"author":"yoi-orchestrator","at":"2026-06-23T06:11:32Z"}
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
title: 'TUI Dashboard の冗長な key hints と selected-row 状態表示を削る'
|
||||
state: 'queued'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-23T05:40:56Z'
|
||||
updated_at: '2026-06-23T06:08:42Z'
|
||||
updated_at: '2026-06-23T06:33:21Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['tui-ux', 'terminal-layout']
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
TUI Dashboard の冗長な key hints と selected-row textual status display を削除し、Orchestrator worktree の `orchestration` branch に統合した。
|
||||
|
||||
主な成果:
|
||||
- Top title line から `Row selection`, `blank Enter`, `Tab target` などの key hint guidance を削除。
|
||||
- Selected Ticket / Pod / Intake / no-row selected textual status line を blank にした。
|
||||
- Composer bottom actionbar を always-on key hints ではなく notices / diagnostics only に最小化。
|
||||
- Row marker / highlighting rendering は維持。
|
||||
- Keyboard/action behavior は変更していない。
|
||||
- Unused selected-row display-status helper を削除。
|
||||
- Dashboard render/unit tests を新 display contract に更新し、selected row marker の visibility assertion は維持。
|
||||
|
||||
統合・検証:
|
||||
- Merge commit: `5abf16f9 merge: dashboard hint cleanup`
|
||||
- Implementation commit: `03ad525f tui: trim dashboard redundant hints`
|
||||
- Reviewer final verdict: approve
|
||||
- Validation passed: `cargo fmt --check`, `git diff --check HEAD^1..HEAD`, `cargo test -p tui dashboard --lib`, `cargo test -p tui workspace_panel --lib`, and `cargo run -p yoi -- ticket doctor`。
|
||||
|
||||
範囲外:
|
||||
- Console / single-Pod TUI hints は変更していない。
|
||||
- Manual/PTY `yoi panel` visual check は実施していない。Focused render/unit tests を主 validation とした。
|
||||
@@ -13,4 +13,294 @@ LocalTicketBackend によって作成されました。
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-23T06:11:11Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: `implementation_ready_parallel`
|
||||
|
||||
Reason:
|
||||
- Ticket body has concrete Dashboard render targets and acceptance criteria。
|
||||
- No relations / blockers / orchestration plan records exist。
|
||||
- Active work `00001KVSEBF56` (protocol TS generation) and `00001KVSGFM65` (Workspace web Kanban review) are separate from TUI Dashboard render code。
|
||||
- Orchestrator worktree is clean on `orchestration` at `0e635ba6`; target worktree / branch is not present。
|
||||
- Bounded code map confirms relevant functions in `crates/tui/src/dashboard/render.rs`: `draw_title`, `target_status_line`, `actionbar_left_text`, `actionbar_right_text`, `draw_actionbar`, and tests in `crates/tui/src/dashboard/tests.rs`。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Remove redundant Dashboard key hints and selected-row textual status while preserving actual row selection visibility and keyboard behavior。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- This Ticket only changes Dashboard display cleanup。
|
||||
- Console / single-Pod TUI key hints are out of scope。
|
||||
- Do not remove list row selection markers / highlighting / keyboard navigation visibility。
|
||||
- Do not reintroduce direct selected-Pod send。
|
||||
- Companion lifecycle / Orchestrator lifecycle / Ticket workflow semantics must not change。
|
||||
- Existing Dashboard actions must remain: blank Enter row action, text Enter composer-target action, Tab target switching, Esc clear selection, Pod open/attach, Ticket Intake/Queue flows。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Top title line no longer shows key hint guidance such as `Row selection`, `blank Enter`, `Tab target`。
|
||||
- Composer bottom actionbar no longer shows always-on key hint groups, or is minimized to non-redundant notices only。
|
||||
- Selected Ticket / selected Pod / selected Intake Pod / no row selected textual status line is removed or no longer recognized as redundant selected-row status。
|
||||
- List still visibly indicates current selected row。
|
||||
- Related render/unit tests are updated to the new display specification。
|
||||
|
||||
Implementation latitude:
|
||||
- `target_status_line` layout row may be removed, made empty/minimal, or repurposed only if it does not show redundant selected-row status。
|
||||
- Actionbar may be fully removed, notice-only, or otherwise minimized depending on layout/tests。
|
||||
- Keep row markers like `▶` and selected styling unless explicitly escalated。
|
||||
- If layout row removal creates resize/hitbox complications, choose minimal empty/notice behavior and document the tradeoff。
|
||||
|
||||
Escalate if:
|
||||
- Removing status/actionbar rows makes current composer target/action ambiguous enough to require alternative UI。
|
||||
- Row selection marker/visibility also needs removal。
|
||||
- Layout changes cause terminal resize / hitbox / mouse selection side effects that require broader Dashboard layout refactor。
|
||||
|
||||
Validation plan:
|
||||
- `cargo fmt --check`
|
||||
- `cargo test -p tui dashboard --lib`
|
||||
- `cargo test -p tui workspace_panel --lib` if affected by shared tests/helpers。
|
||||
- `git diff --check`
|
||||
- `cargo run -p yoi -- ticket doctor`
|
||||
- Manual/PTY `yoi panel` check if practical, but focused render tests are primary。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T06:11:22Z from: queued to: inprogress reason: human_authorized_unblocked_dashboard_hint_cleanup field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Human authorized queue routing from Workspace Dashboard. Ticket has concrete Dashboard render acceptance criteria and no recorded blockers, so Orchestrator accepts implementation.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:12:36Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation start report:
|
||||
|
||||
- Created child implementation worktree:
|
||||
- `/home/hare/Projects/yoi/.worktree/00001KVSFXY88-dashboard-hint-cleanup`
|
||||
- Created branch:
|
||||
- `impl/00001KVSFXY88-dashboard-hint-cleanup`
|
||||
- Base commit:
|
||||
- `3bfd1ca0 ticket: accept dashboard hint cleanup`
|
||||
- Confirmed tracked Ticket project records are visible in the child worktree。
|
||||
- Confirmed `.yoi/memory` has no tracked/untracked entries in the child worktree check。
|
||||
- Spawned sibling Coder Pod:
|
||||
- `yoi-coder-00001KVSFXY88`
|
||||
- Coder scope:
|
||||
- read: `/home/hare/Projects/yoi`
|
||||
- write: `/home/hare/Projects/yoi/.worktree/00001KVSFXY88-dashboard-hint-cleanup`
|
||||
|
||||
Parallelization note:
|
||||
- Active Workspace web / protocol work is separate from TUI Dashboard rendering. This Ticket should stay limited to `crates/tui/src/dashboard/*` unless tests reveal a narrow shared helper impact。
|
||||
|
||||
Next action:
|
||||
- Wait for Coder implementation report, then spawn Reviewer read-only for the implementation diff。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:28:12Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Coder implementation report received from `yoi-coder-00001KVSFXY88`.
|
||||
|
||||
Implementation commit:
|
||||
- `03ad525f tui: trim dashboard redundant hints`
|
||||
|
||||
Changed areas:
|
||||
- `crates/tui/src/dashboard/render.rs`
|
||||
- Removed top title key-hint guidance。
|
||||
- Made selected-row/composer target status line blank。
|
||||
- Minimized actionbar to notices/diagnostic-only text。
|
||||
- Preserved row marker/highlighting rendering。
|
||||
- `crates/tui/src/dashboard/mod.rs`
|
||||
- Removed now-unused selected-row display-status helper。
|
||||
- `crates/tui/src/dashboard/tests.rs`
|
||||
- Updated render/unit expectations for no redundant hints/status。
|
||||
- Added title guidance cleanup assertion。
|
||||
- Kept assertions that selected rows remain visibly marked。
|
||||
|
||||
Coder validation reported:
|
||||
- `cargo fmt --check`: passed
|
||||
- `cargo test -p tui dashboard --lib`: passed
|
||||
- `cargo test -p tui workspace_panel --lib`: passed
|
||||
- `git diff --check`: passed
|
||||
- `cargo run -p yoi -- ticket doctor`: passed
|
||||
|
||||
Manual/PTY `yoi panel` check:
|
||||
- Not run; focused render/unit tests were used as primary validation。
|
||||
|
||||
Orchestrator evidence checked:
|
||||
- Worktree clean on `impl/00001KVSFXY88-dashboard-hint-cleanup`。
|
||||
- HEAD is `03ad525f`。
|
||||
- Diff `3bfd1ca0..HEAD` touches expected dashboard render/module/tests files only。
|
||||
- `git diff --check 3bfd1ca0..HEAD`: passed。
|
||||
|
||||
Next action:
|
||||
- Route to read-only Reviewer Pod for acceptance review。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: comment author: yoi-orchestrator at: 2026-06-23T06:28:54Z -->
|
||||
|
||||
## Comment
|
||||
|
||||
Review routing:
|
||||
|
||||
Spawned read-only Reviewer Pod:
|
||||
- `yoi-reviewer-00001KVSFXY88-r1`
|
||||
|
||||
Review target:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVSFXY88-dashboard-hint-cleanup`
|
||||
- Branch: `impl/00001KVSFXY88-dashboard-hint-cleanup`
|
||||
- Baseline: `3bfd1ca0`
|
||||
- Implementation commit: `03ad525f tui: trim dashboard redundant hints`
|
||||
- Diff: `3bfd1ca0..03ad525f`
|
||||
|
||||
Reviewer scope:
|
||||
- read-only `/home/hare/Projects/yoi`
|
||||
|
||||
Reviewer focus:
|
||||
- Removal of redundant title/actionbar key hints and selected-row textual status。
|
||||
- Preservation of visible row selection marker/highlighting。
|
||||
- No keyboard behavior/action semantics changes。
|
||||
- Dashboard render tests updated to new display contract。
|
||||
|
||||
Orchestrator will wait for reviewer verdict before integration。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVSFXY88-r1 at: 2026-06-23T06:31:21Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Verdict: `approve`
|
||||
|
||||
確認範囲:
|
||||
- Ticket authority:
|
||||
- `.yoi/tickets/00001KVSFXY88/item.md`
|
||||
- `.yoi/tickets/00001KVSFXY88/thread.md`
|
||||
- Diff `3bfd1ca0..03ad525f`:
|
||||
- `crates/tui/src/dashboard/render.rs`
|
||||
- `crates/tui/src/dashboard/mod.rs`
|
||||
- `crates/tui/src/dashboard/tests.rs`
|
||||
|
||||
Evidence:
|
||||
- Top title guidance was removed; `title_line` now keeps only `workspace dashboard` plus companion/orchestrator status。
|
||||
- `target_status_line` now renders blank, removing selected Ticket / Pod / Intake / no-row textual status。
|
||||
- Actionbar is reduced to sending/refreshing/notices/diagnostic text; always-on key hint groups are gone。
|
||||
- Row marker/highlighting paths remain; tests assert selected row marker strings such as `▶ ready`, `▶ queued`, and ` ▶ live`。
|
||||
- Keyboard/action behavior was not altered in the diff; removed helpers were display-only and no remaining references exist。
|
||||
- No Console/single-Pod TUI files changed。
|
||||
- No direct selected-Pod send was reintroduced; existing dashboard behavior tests still pass。
|
||||
|
||||
Blocking issues:
|
||||
- None。
|
||||
|
||||
Non-blocking concerns:
|
||||
- Manual `yoi panel` PTY visual check was not run; focused render/unit coverage was used as primary validation, as suggested。
|
||||
|
||||
Reviewer validation:
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check 3bfd1ca0..HEAD`: passed
|
||||
- `cargo test -p tui dashboard --lib`: passed (`107 passed`)
|
||||
- `cargo test -p tui workspace_panel --lib`: passed (`23 passed`)
|
||||
- `cargo run -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
|
||||
Worktree status:
|
||||
- Clean on `impl/00001KVSFXY88-dashboard-hint-cleanup` at `03ad525f`。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:32:25Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Reviewer r1 approvalを受けて、実装ブランチを Orchestrator worktree の `orchestration` branch に統合した。
|
||||
|
||||
統合:
|
||||
- Merge commit: `5abf16f9 merge: dashboard hint cleanup`
|
||||
- Merged branch: `impl/00001KVSFXY88-dashboard-hint-cleanup`
|
||||
- Implementation commit:
|
||||
- `03ad525f tui: trim dashboard redundant hints`
|
||||
|
||||
Orchestrator worktree validation:
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cargo test -p tui dashboard --lib`: passed (`107 passed`)
|
||||
- `cargo test -p tui workspace_panel --lib`: passed (`23 passed`)
|
||||
- `cargo run -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
|
||||
Final Orchestrator worktree status after validation is clean on `orchestration` at `5abf16f9`。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T06:32:37Z from: inprogress to: done reason: implementation_merged_and_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Reviewer approval、Orchestrator worktree への統合、focused Dashboard / workspace_panel tests、Ticket doctor が完了したため `done` に遷移する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: hare at: 2026-06-23T06:32:49Z from: done to: closed reason: closed field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を closed にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: close author: hare at: 2026-06-23T06:32:49Z status: closed -->
|
||||
|
||||
## 完了
|
||||
|
||||
TUI Dashboard の冗長な key hints と selected-row textual status display を削除し、Orchestrator worktree の `orchestration` branch に統合した。
|
||||
|
||||
主な成果:
|
||||
- Top title line から `Row selection`, `blank Enter`, `Tab target` などの key hint guidance を削除。
|
||||
- Selected Ticket / Pod / Intake / no-row selected textual status line を blank にした。
|
||||
- Composer bottom actionbar を always-on key hints ではなく notices / diagnostics only に最小化。
|
||||
- Row marker / highlighting rendering は維持。
|
||||
- Keyboard/action behavior は変更していない。
|
||||
- Unused selected-row display-status helper を削除。
|
||||
- Dashboard render/unit tests を新 display contract に更新し、selected row marker の visibility assertion は維持。
|
||||
|
||||
統合・検証:
|
||||
- Merge commit: `5abf16f9 merge: dashboard hint cleanup`
|
||||
- Implementation commit: `03ad525f tui: trim dashboard redundant hints`
|
||||
- Reviewer final verdict: approve
|
||||
- Validation passed: `cargo fmt --check`, `git diff --check HEAD^1..HEAD`, `cargo test -p tui dashboard --lib`, `cargo test -p tui workspace_panel --lib`, and `cargo run -p yoi -- ticket doctor`。
|
||||
|
||||
範囲外:
|
||||
- Console / single-Pod TUI hints は変更していない。
|
||||
- Manual/PTY `yoi panel` visual check は実施していない。Focused render/unit tests を主 validation とした。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:33:21Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Post-close cleanup completed。
|
||||
|
||||
- Stopped child Pods and reclaimed scope:
|
||||
- `yoi-coder-00001KVSFXY88`
|
||||
- `yoi-reviewer-00001KVSFXY88-r1`
|
||||
- Removed implementation worktree:
|
||||
- `/home/hare/Projects/yoi/.worktree/00001KVSFXY88-dashboard-hint-cleanup`
|
||||
- Deleted implementation branch:
|
||||
- `impl/00001KVSFXY88-dashboard-hint-cleanup`
|
||||
- Orchestrator worktree remains clean on `orchestration` at `10866666`。
|
||||
|
||||
Root/original workspace was not used for merge/validation/cleanup operations。
|
||||
|
||||
---
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
title: 'Improve Workspace web ticket Kanban grouping and lazy rows'
|
||||
state: 'inprogress'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-23T05:50:36Z'
|
||||
updated_at: '2026-06-23T06:06:45Z'
|
||||
updated_at: '2026-06-23T06:16:10Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-23T05:53:22Z'
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
Workspace web Repository Ticket Kanban の grouping / lazy rows 改善を統合した。
|
||||
|
||||
主な成果:
|
||||
- Repository Ticket Kanban を `RepositoryTicketKanban.svelte` component に分離。
|
||||
- `planning` + `ready` を display-only group とし、`ready` を `planning` より上に表示。
|
||||
- `queued` + `inprogress` を display-only group とし、`inprogress` を `queued` より上に表示。
|
||||
- `done`, `closed`, `other` は独立 group として維持。
|
||||
- 各 row に original Ticket state を表示。
|
||||
- 各 group の初期表示行数を 30 に cap。
|
||||
- 各 group に独立 scroll area と independent lazy visible count を実装。
|
||||
- High-volume `closed` group が page height を無制限に伸ばさないようにした。
|
||||
- `WorkspacePage.svelte` から inline Kanban logic/markup を削減。
|
||||
- Styling は existing design tokens を使い、backend/API/Ticket lifecycle semantics は変更していない。
|
||||
|
||||
統合・検証:
|
||||
- Merge commit: `eea26f91 merge: kanban lazy rows`
|
||||
- Implementation commit: `6f68bb8d web: group repository ticket kanban rows`
|
||||
- Reviewer final verdict: approve
|
||||
- Validation passed: `git diff --check HEAD^1..HEAD`, `deno task check`, `deno task build`, `cargo run -p yoi -- ticket doctor`, and `nix build .#yoi --no-link`。
|
||||
|
||||
範囲外:
|
||||
- Backend pagination、Ticket state mutation UI、drag/drop Kanban、browser/manual scroll E2E tests は追加していない。
|
||||
@@ -206,3 +206,167 @@ Reviewer focus:
|
||||
Orchestrator will wait for reviewer verdict before integration。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVSGFM65-r1 at: 2026-06-23T06:13:34Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Verdict: `approve`
|
||||
|
||||
確認範囲:
|
||||
- Ticket authority:
|
||||
- `.yoi/tickets/00001KVSGFM65/item.md`
|
||||
- `.yoi/tickets/00001KVSGFM65/thread.md`
|
||||
- Diff `a6f9019e..6f68bb8d`:
|
||||
- `web/workspace/src/lib/workspace-pages/RepositoryTicketKanban.svelte`
|
||||
- `web/workspace/src/lib/workspace-pages/WorkspacePage.svelte`
|
||||
- `web/workspace/src/app.css`
|
||||
|
||||
Review evidence:
|
||||
- Grouping/sort:
|
||||
- `planning` + `ready` are grouped as `ready-planning`, labelled `Ready / Planning`。
|
||||
- `queued` + `inprogress` are grouped as `inprogress-queued`, labelled `In progress / Queued`。
|
||||
- `statePriority()` places `ready` before `planning`, and `inprogress` before `queued`。
|
||||
- Other states:
|
||||
- `done`, `closed`, and `other` remain separate group keys via `state:${state}` / `state:other`。
|
||||
- Per-group lazy state:
|
||||
- `visibleRowsByGroup` is keyed by group key。
|
||||
- Initial visible rows are `INITIAL_VISIBLE_ROWS = 30`。
|
||||
- Scroll handling updates only `[group.key]`。
|
||||
- Near-bottom threshold is `NEAR_BOTTOM_PX = 96`。
|
||||
- High-volume containment:
|
||||
- Each non-empty group row list has its own `.ticket-list-scroll`。
|
||||
- `.ticket-list-scroll` uses `max-height: 34rem; overflow-y: auto;`, so `closed` cannot expand page vertically without bound。
|
||||
- Original row state:
|
||||
- Each ticket row renders `<span class="ticket-state">{ticket.state}</span>`。
|
||||
- Component boundary:
|
||||
- Kanban logic and row rendering moved into `RepositoryTicketKanban.svelte`。
|
||||
- `WorkspacePage.svelte` now delegates with `<RepositoryTicketKanban tickets={repositoryTickets} />`。
|
||||
- Design / boundary:
|
||||
- Styling uses existing CSS tokens such as `var(--space-*)`, `var(--line)`, `var(--text-muted)`, `var(--text-faint)`, `var(--text-strong)`。
|
||||
- No backend/API/protocol TypeScript generation scope touched。
|
||||
- No mutation UI added。
|
||||
|
||||
Blocking issues:
|
||||
- None found。
|
||||
|
||||
Non-blocking concerns:
|
||||
- No browser/manual scroll interaction test was run; validation is by code inspection plus Svelte check/build. Given the ticket’s frontend-only scope and current test tooling, this is acceptable。
|
||||
|
||||
Reviewer validation:
|
||||
- `git diff --check a6f9019e..6f68bb8d`: passed
|
||||
- `git diff --check a6f9019e..HEAD`: passed
|
||||
- `cd web/workspace && rm -rf node_modules .svelte-kit build && deno task check && deno task build`: passed (`svelte-check found 0 errors and 0 warnings`; static build completed)
|
||||
- `cargo run -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
- `cargo test -p yoi-workspace-server`: not run; no backend/API changes were made。
|
||||
|
||||
Generated artifacts:
|
||||
- Ignored validation artifacts present after review:
|
||||
- `target/`
|
||||
- `web/workspace/.svelte-kit/`
|
||||
- `web/workspace/build/`
|
||||
- `web/workspace/node_modules/`
|
||||
- No generated artifacts are tracked。
|
||||
|
||||
Worktree status:
|
||||
- Clean tracked state on `impl/00001KVSGFM65-kanban-lazy-rows` at `6f68bb8d`。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:15:01Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Reviewer r1 approvalを受けて、実装ブランチを Orchestrator worktree の `orchestration` branch に統合した。
|
||||
|
||||
統合:
|
||||
- Merge commit: `eea26f91 merge: kanban lazy rows`
|
||||
- Merged branch: `impl/00001KVSGFM65-kanban-lazy-rows`
|
||||
- Implementation commit:
|
||||
- `6f68bb8d web: group repository ticket kanban rows`
|
||||
|
||||
Orchestrator worktree validation:
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cd web/workspace && rm -rf node_modules .svelte-kit build && deno task check`: passed (`svelte-check found 0 errors and 0 warnings`)
|
||||
- `cd web/workspace && deno task build`: passed
|
||||
- `cargo run -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
Validation generated ignored frontend artifacts in Orchestrator worktree:
|
||||
- `web/workspace/node_modules/`
|
||||
- `web/workspace/.svelte-kit/`
|
||||
- `web/workspace/build/`
|
||||
|
||||
These were removed after validation. Final Orchestrator worktree status after validation cleanup is clean on `orchestration` at `eea26f91`。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T06:15:09Z from: inprogress to: done reason: implementation_merged_and_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Reviewer approval、Orchestrator worktree への統合、Deno check/build、Ticket doctor、Nix build が完了したため `done` に遷移する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: hare at: 2026-06-23T06:15:22Z from: done to: closed reason: closed field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を closed にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: close author: hare at: 2026-06-23T06:15:22Z status: closed -->
|
||||
|
||||
## 完了
|
||||
|
||||
Workspace web Repository Ticket Kanban の grouping / lazy rows 改善を統合した。
|
||||
|
||||
主な成果:
|
||||
- Repository Ticket Kanban を `RepositoryTicketKanban.svelte` component に分離。
|
||||
- `planning` + `ready` を display-only group とし、`ready` を `planning` より上に表示。
|
||||
- `queued` + `inprogress` を display-only group とし、`inprogress` を `queued` より上に表示。
|
||||
- `done`, `closed`, `other` は独立 group として維持。
|
||||
- 各 row に original Ticket state を表示。
|
||||
- 各 group の初期表示行数を 30 に cap。
|
||||
- 各 group に独立 scroll area と independent lazy visible count を実装。
|
||||
- High-volume `closed` group が page height を無制限に伸ばさないようにした。
|
||||
- `WorkspacePage.svelte` から inline Kanban logic/markup を削減。
|
||||
- Styling は existing design tokens を使い、backend/API/Ticket lifecycle semantics は変更していない。
|
||||
|
||||
統合・検証:
|
||||
- Merge commit: `eea26f91 merge: kanban lazy rows`
|
||||
- Implementation commit: `6f68bb8d web: group repository ticket kanban rows`
|
||||
- Reviewer final verdict: approve
|
||||
- Validation passed: `git diff --check HEAD^1..HEAD`, `deno task check`, `deno task build`, `cargo run -p yoi -- ticket doctor`, and `nix build .#yoi --no-link`。
|
||||
|
||||
範囲外:
|
||||
- Backend pagination、Ticket state mutation UI、drag/drop Kanban、browser/manual scroll E2E tests は追加していない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:16:10Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Post-close cleanup completed。
|
||||
|
||||
- Stopped child Pods and reclaimed scope:
|
||||
- `yoi-coder-00001KVSGFM65`
|
||||
- `yoi-reviewer-00001KVSGFM65-r1`
|
||||
- Removed ignored frontend validation artifacts from child worktree before worktree removal if present:
|
||||
- `web/workspace/node_modules/`
|
||||
- `web/workspace/.svelte-kit/`
|
||||
- `web/workspace/build/`
|
||||
- Removed implementation worktree:
|
||||
- `/home/hare/Projects/yoi/.worktree/00001KVSGFM65-kanban-lazy-rows`
|
||||
- Deleted implementation branch:
|
||||
- `impl/00001KVSGFM65-kanban-lazy-rows`
|
||||
- Orchestrator worktree remains clean on `orchestration` at `9de04f72`。
|
||||
|
||||
Root/original workspace was not used for merge/validation/cleanup operations。
|
||||
|
||||
---
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"orch-plan-20260623-065020-1","ticket_id":"00001KVSKGDYS","kind":"accepted_plan","accepted_plan":{"summary":"Add tracked `.yoi/workspace.toml` schema/loader/create-if-missing path for safe local Workspace identity and use persisted workspace id in Workspace APIs/repository/host id derivation, with tests for missing/existing/invalid/no-path-leak behavior.","branch":"impl/00001KVSKGDYS-workspace-identity","worktree":"/home/hare/Projects/yoi/.worktree/00001KVSKGDYS-workspace-identity","role_plan":"Orchestrator creates a dedicated child worktree and spawns a narrow-scope Workspace backend Coder. Reviewer will be spawned read-only after Coder reports implementation commit(s). After approval, Orchestrator integrates into `orchestration`, validates workspace-server/frontend/Nix as needed, records closure, and cleans only the child worktree/branch."},"author":"yoi-orchestrator","at":"2026-06-23T06:50:20Z"}
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: 'Persist local Workspace identity in .yoi/workspace.toml'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-23T06:43:28Z'
|
||||
updated_at: '2026-06-23T07:39:10Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-23T06:47:18Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Workspace server の local dev bootstrap は現在、`workspace_id` を `local:{display}` のように workspace root の basename から導出している。これは暫定 namespace としては分かりやすいが、DB の primary key / Workspace identity としては不適切である。
|
||||
|
||||
問題:
|
||||
|
||||
- `workspace_id` が表示名 / path basename から予測可能に作られている。
|
||||
- 同じ basename の workspace が複数あると衝突しうる。
|
||||
- workspace root の rename / move で identity が変わる。
|
||||
- `local:` namespace と display label が DB PK に混ざっている。
|
||||
- `--workspace .` のような相対 path では display fallback に落ちるなど、初期化責務が `ServerConfig::local_dev` に寄りすぎている。
|
||||
|
||||
Workspace identity は `.yoi/workspace.toml` を local Workspace record として永続化し、未作成なら Workspace backend の初期化処理で払い出す。これにより、DB を再作成しても Workspace identity は維持され、将来の DB authority / hosted Workspace / migration でも扱いやすくなる。
|
||||
|
||||
## 方針
|
||||
|
||||
- `.yoi/workspace.toml` を local Workspace identity の authority とする。
|
||||
- `workspace_id` は path / display name から導出しない。
|
||||
- 新規 local Workspace 初期化時に UUIDv7 を発行して `workspace_id` として保存する。
|
||||
- `display_name` は identity ではなく UI label として保存する。
|
||||
- 初期値は canonicalized workspace root の basename でよい。
|
||||
- 将来的に rename 可能な field として扱う。
|
||||
- `ServerConfig::local_dev` は Workspace ID を生成しない。
|
||||
- CLI/bootstrap 層で workspace root canonicalization と `.yoi/workspace.toml` load-or-init を行い、結果を `ServerConfig` に渡す。
|
||||
- `.yoi/workspace.toml` が壊れている場合は勝手に上書きせず、明示的な error で止める。
|
||||
- 既存 `.yoi/workspace.db` 内の `local:*` workspace row については、初期実装では destructive migration を必須にしない。
|
||||
- 新しい UUIDv7 workspace row を upsert し、古い row は残してよい。
|
||||
- 必要なら後続で cleanup/migration policy を設計する。
|
||||
|
||||
## `.yoi/workspace.toml` v0
|
||||
|
||||
最小 schema:
|
||||
|
||||
```toml
|
||||
workspace_id = "0197..." # UUIDv7 canonical string
|
||||
created_at = "2026-06-23T...Z"
|
||||
display_name = "yoi"
|
||||
```
|
||||
|
||||
Validation:
|
||||
|
||||
- `workspace_id` は UUID として parse できること。
|
||||
- 可能なら UUID version 7 であることを検証する。
|
||||
- `created_at` は RFC3339 UTC timestamp として parse できること。
|
||||
- `display_name` は空文字列でないこと。
|
||||
- unknown fields の扱いは将来拡張を考え、明示的に決める。
|
||||
- v0 では deny でも preserve でもよいが、選択理由を実装に残す。
|
||||
|
||||
## 初期化フロー
|
||||
|
||||
`yoi-workspace-server serve --workspace <path>` の local bootstrap は将来的に以下の責務分離にする。
|
||||
|
||||
1. `--workspace` を canonicalize する。
|
||||
2. workspace root 配下の `.yoi/` を確認し、なければ作成する。
|
||||
3. `.yoi/workspace.toml` を読む。
|
||||
4. 存在しない場合:
|
||||
- UUIDv7 `workspace_id` を発行する。
|
||||
- `created_at` を現在 UTC にする。
|
||||
- `display_name` を canonicalized workspace root basename から作る。
|
||||
- `.yoi/workspace.toml` を atomic-ish に書き込む。
|
||||
5. 存在する場合:
|
||||
- parse / validate する。
|
||||
- 壊れていたら停止し、上書きしない。
|
||||
6. `ServerConfig` には canonicalized workspace root と Workspace identity を渡す。
|
||||
7. SQLite `workspaces` row は `.yoi/workspace.toml` の `workspace_id` / `display_name` で upsert する。
|
||||
8. API `/api/workspace` は DB row / identity record を元に stable id と display name を返す。
|
||||
|
||||
## 実装候補
|
||||
|
||||
- `crates/workspace-server` に Workspace identity loader を追加する。
|
||||
- 例: `workspace_identity.rs` または `identity.rs`。
|
||||
- 型例:
|
||||
|
||||
```rust
|
||||
struct WorkspaceIdentity {
|
||||
workspace_id: Uuid,
|
||||
created_at: DateTime<Utc>,
|
||||
display_name: String,
|
||||
}
|
||||
|
||||
impl WorkspaceIdentity {
|
||||
fn load_or_init(root: &Path) -> Result<Self, WorkspaceIdentityError>;
|
||||
}
|
||||
```
|
||||
|
||||
- `uuid` crate の UUIDv7 support を確認し、必要なら依存 feature を追加する。
|
||||
- TOML parse/write には既存 dependency を優先し、なければ最小 dependency を検討する。
|
||||
- `ServerConfig::local_dev` は `workspace_id` / `display_name` を引数または identity object で受け取る形に寄せる。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Hosted / multi-user Workspace identity の完全設計。
|
||||
- Workspace rename UI。
|
||||
- 既存 `.yoi/workspace.db` の destructive migration。
|
||||
- Ticket / Objective storage の DB authority migration。
|
||||
- `.yoi/workspace.toml` を全 Workspace settings store に拡張すること。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- local Workspace identity が `.yoi/workspace.toml` に永続化される。
|
||||
- `.yoi/workspace.toml` 未作成時、Workspace backend 初期化時に UUIDv7 `workspace_id` が払い出される。
|
||||
- `workspace_id` が path basename / display name から導出されなくなる。
|
||||
- `display_name` は `.yoi/workspace.toml` の field として扱われ、identity と分離されている。
|
||||
- `--workspace .` でも canonicalized workspace root をもとに初期化される。
|
||||
- `.yoi/workspace.toml` が壊れている場合、勝手に再生成/上書きせず error で停止する。
|
||||
- `ServerConfig::local_dev` または同等の bootstrap helper が workspace id を自前生成しない。
|
||||
- SQLite `workspaces` row は `.yoi/workspace.toml` の identity を使って upsert される。
|
||||
- 既存 `local:{display}` 形式は新規 workspace id として生成されない。
|
||||
- `cargo test -p yoi-workspace-server`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,38 @@
|
||||
Local Workspace identity を tracked `.yoi/workspace.toml` に永続化する実装を完了した。
|
||||
|
||||
完了内容:
|
||||
- `.yoi/workspace.toml` を local Workspace identity の authority として追加。
|
||||
- v0 schema は `workspace_id`, `created_at`, `display_name` のみ。
|
||||
- `workspace_id` は UUIDv7 canonical string として検証し、path / display basename から導出しない。
|
||||
- `created_at` は UTC RFC3339 timestamp として検証。
|
||||
- `display_name` は空文字列を拒否。
|
||||
- unknown fields は v0 では明示的に deny。
|
||||
- invalid existing file は fail closed し、自動上書きしない。
|
||||
- missing file 初期化では `OpenOptions::create_new(true)` を使い、既存 file が race で作られた場合は persisted identity を read/parse して返す。
|
||||
- fixed temp file / `path.exists()` + `rename` finalization は使わない。
|
||||
- `ServerConfig::local_dev` は `local:{display}` を生成せず、persisted `WorkspaceIdentity` を受け取る。
|
||||
- SQLite `workspaces` upsert、Workspace API、repository ids、host ids は persisted Workspace id を使う。
|
||||
- legacy `/api/repositories/local` alias は維持。
|
||||
- 既存 `local:*` DB rows の destructive migration はしない。
|
||||
- `.yoi/workspace.toml` は絶対 path / secret / socket / runtime data を含まない安全な project identity record として維持。
|
||||
|
||||
統合:
|
||||
- Implementation: `31565c9b feat: persist workspace identity`
|
||||
- Fix: `49c9e190 fix: return persisted workspace identity`
|
||||
- Merge: `2745f3d5 merge: workspace identity persistence`
|
||||
|
||||
検証:
|
||||
- Reviewer approval: `yoi-reviewer-00001KVSKGDYS-r1`
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cargo test -p yoi-workspace-server`: passed
|
||||
- `cargo check -p yoi-workspace-server`: passed
|
||||
- `cd web/workspace && deno task check && deno task build`: passed
|
||||
- `cargo run -q -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
生成物 cleanup:
|
||||
- orchestration worktree の `target/`, `web/workspace/node_modules/`, `web/workspace/.svelte-kit/`, `web/workspace/build/` を削除済み。
|
||||
|
||||
残作業:
|
||||
- なし。将来必要なら legacy `local:*` row cleanup / migration policy は別 Ticket で扱う。
|
||||
@@ -0,0 +1,536 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-23T06:43:28Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-23T06:44:19Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-23T06:44:19Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-23T06:47:18Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-23T06:49:54Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: `implementation_ready_parallel`
|
||||
|
||||
Reason:
|
||||
- Ticket body has concrete `workspace.toml` semantics, backend/API consistency requirements, migration-safe behavior, tests, and validation criteria。
|
||||
- No relations / blockers / orchestration plan records exist。
|
||||
- Active Dashboard no-auto-selection work is TUI-only and separate from Workspace backend identity persistence, so parallel implementation is acceptable。
|
||||
- Orchestrator worktree is clean on `orchestration` at `13e76d35`; target worktree / branch is not present。
|
||||
- Current Workspace backend has ad-hoc/stable-ish IDs; Ticket asks for tracked local identity at `.yoi/workspace.toml`。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Persist local Workspace identity in tracked `.yoi/workspace.toml` and use it as the stable local Workspace id across backend APIs, repository IDs, host ID derivation, and frontend display where applicable。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- `.yoi/workspace.toml` is tracked project record, not local runtime/secret file。
|
||||
- It should contain only safe project identity fields, e.g. `workspace_id`, `display_name`, `created_at` or equivalent; no absolute paths, user names, socket paths, data-dir paths, tokens, or runtime secrets。
|
||||
- Existing checkouts without the file must remain usable with safe auto-create or fallback behavior。
|
||||
- Workspace id should not change on process restart, repo path move, or sibling worktree checkout when the file is present。
|
||||
- Avoid changing Ticket/Objectives canonical authority。
|
||||
- Do not confuse this with Profile/manifest/override runtime config。
|
||||
- Handle invalid/corrupt `workspace.toml` fail-closed with clear diagnostic; do not silently generate a different id over a bad tracked file unless explicitly safe。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Define `.yoi/workspace.toml` schema and parser/loader.
|
||||
- Add create-if-missing behavior for local workspace server/bootstrap path, or a documented CLI/tool path if auto-create is unsuitable.
|
||||
- Use persisted workspace id in Workspace API responses and any Repository/Host ids derived from workspace id.
|
||||
- Ensure generated file is safe to commit and has no local absolute paths/secrets.
|
||||
- Existing tests updated to deterministic temp workspace identity behavior。
|
||||
- Add tests for missing file creation/fallback, existing stable id, invalid file error, and no local path leakage。
|
||||
- Validation includes workspace-server tests, Deno check/build if frontend output changes, git diff check, Ticket doctor, and Nix build if package/source behavior changes。
|
||||
|
||||
Implementation latitude:
|
||||
- Put parser in `workspace-server` crate if currently only the web backend needs it, or a small shared crate if needed; avoid broad architecture churn。
|
||||
- Workspace id can reuse project-record id allocator if suitable, or a stable slug/uuid/base32 type if already used。
|
||||
- If auto-writing tracked file during server startup is risky, implement explicit ensure function used by tests/bootstrap and document behavior; but Ticket prefers tracked persistence。
|
||||
- Frontend can just display the id returned by existing `/api/workspace` if backend response changes。
|
||||
|
||||
Escalate if:
|
||||
- Creating tracked `.yoi/workspace.toml` from a server process violates current project-record write boundaries。
|
||||
- Workspace id generation requires global registry/coordination beyond local checkout。
|
||||
- Existing code strongly assumes workspace id is derived from path and changing it would break multiple APIs unexpectedly。
|
||||
- Nix/source filtering excludes `.yoi/workspace.toml` unexpectedly and package behavior needs product decision。
|
||||
|
||||
Validation plan:
|
||||
- `cargo fmt --check`
|
||||
- `cargo test -p yoi-workspace-server`
|
||||
- `cargo check -p yoi-workspace-server`
|
||||
- `cd web/workspace && deno task check && deno task build` if frontend-visible changes occur。
|
||||
- `git diff --check`
|
||||
- `cargo run -p yoi -- ticket doctor`
|
||||
- `nix build .#yoi --no-link` if package/source filtering or tracked file behavior changed。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T06:50:08Z from: queued to: inprogress reason: human_authorized_unblocked_workspace_identity_persistence field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Human authorized queue routing from Workspace Dashboard. Ticket has concrete local workspace identity requirements and no recorded blockers, so Orchestrator accepts implementation.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:51:44Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation start report:
|
||||
|
||||
- Created child implementation worktree:
|
||||
- `/home/hare/Projects/yoi/.worktree/00001KVSKGDYS-workspace-identity`
|
||||
- Created branch:
|
||||
- `impl/00001KVSKGDYS-workspace-identity`
|
||||
- Base commit:
|
||||
- `4cda83b7 ticket: accept workspace identity and selection work`
|
||||
- Confirmed tracked Ticket project records are visible in the child worktree。
|
||||
- Confirmed `.yoi/memory` has no tracked/untracked entries in the child worktree check。
|
||||
- Spawned sibling Coder Pod:
|
||||
- `yoi-coder-00001KVSKGDYS`
|
||||
- Coder scope:
|
||||
- read: `/home/hare/Projects/yoi`
|
||||
- write: `/home/hare/Projects/yoi/.worktree/00001KVSKGDYS-workspace-identity`
|
||||
|
||||
Parallelization note:
|
||||
- `00001KVSKJ0EA` is active separately and targets TUI Dashboard selection semantics. This Ticket should stay limited to Workspace backend identity persistence and safe project record behavior。
|
||||
|
||||
Next action:
|
||||
- Wait for Coder implementation report, then spawn Reviewer read-only for the implementation diff。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T07:13:47Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Coder implementation report received from `yoi-coder-00001KVSKGDYS`.
|
||||
|
||||
Implementation commit:
|
||||
- `31565c9b feat: persist workspace identity`
|
||||
|
||||
Changed areas:
|
||||
- Added tracked project identity record:
|
||||
- `.yoi/workspace.toml`
|
||||
- current contents are safe project identity fields only: `workspace_id`, `created_at`, `display_name`。
|
||||
- Added Workspace identity schema/loader:
|
||||
- `crates/workspace-server/src/identity.rs`
|
||||
- strict TOML parser with `workspace_id`, `created_at`, `display_name`。
|
||||
- UUIDv7 validation。
|
||||
- UTC RFC3339 `created_at` validation。
|
||||
- unknown fields rejected。
|
||||
- create-if-missing behavior。
|
||||
- invalid existing file fails closed without rewrite。
|
||||
- tests for missing creation, stable existing identity, invalid file, no path leakage。
|
||||
- Integrated persisted identity into workspace server/bootstrap:
|
||||
- `crates/workspace-server/src/main.rs`
|
||||
- `crates/workspace-server/src/server.rs`
|
||||
- workspace API uses persisted `workspace_id` / display metadata。
|
||||
- Updated repository ID behavior:
|
||||
- `crates/workspace-server/src/repositories.rs`
|
||||
- local repository ids derive from persisted Workspace id。
|
||||
- legacy `/api/repositories/local` remains accepted as an alias。
|
||||
- Host ID derivation now receives persisted Workspace id through existing API flow。
|
||||
- Added dependencies / packaging update:
|
||||
- `crates/workspace-server/Cargo.toml`
|
||||
- `Cargo.lock`
|
||||
- `package.nix` cargo hash。
|
||||
|
||||
Coder validation reported:
|
||||
- `cargo fmt --check`: passed
|
||||
- `cargo test -p yoi-workspace-server`: passed
|
||||
- `cargo check -p yoi-workspace-server`: passed
|
||||
- `cd web/workspace && deno task check && deno task build`: passed
|
||||
- `git diff --check`: passed
|
||||
- `git diff --cached --check`: passed
|
||||
- `cargo run -p yoi -- ticket doctor`: passed
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
Generated artifact cleanup:
|
||||
- Coder removed generated frontend artifacts:
|
||||
- `web/workspace/.svelte-kit`
|
||||
- `web/workspace/build`
|
||||
- `web/workspace/node_modules`
|
||||
- Coder removed generated Rust build cache:
|
||||
- `target`
|
||||
|
||||
Orchestrator evidence checked:
|
||||
- Worktree clean on `impl/00001KVSKGDYS-workspace-identity` at `31565c9b`。
|
||||
- Diff `4cda83b7..HEAD` touches expected Workspace identity/backend/package files and adds `.yoi/workspace.toml`。
|
||||
- `git diff --check 4cda83b7..HEAD`: passed。
|
||||
|
||||
Next action:
|
||||
- Route to read-only Reviewer Pod for acceptance review。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: comment author: yoi-orchestrator at: 2026-06-23T07:14:37Z -->
|
||||
|
||||
## Comment
|
||||
|
||||
Review routing:
|
||||
|
||||
Spawned read-only Reviewer Pod:
|
||||
- `yoi-reviewer-00001KVSKGDYS-r1`
|
||||
|
||||
Review target:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVSKGDYS-workspace-identity`
|
||||
- Branch: `impl/00001KVSKGDYS-workspace-identity`
|
||||
- Baseline: `4cda83b7`
|
||||
- Implementation commit: `31565c9b feat: persist workspace identity`
|
||||
- Diff: `4cda83b7..31565c9b`
|
||||
|
||||
Reviewer scope:
|
||||
- read-only `/home/hare/Projects/yoi`
|
||||
|
||||
Reviewer focus:
|
||||
- Safety and tracked-project-record suitability of `.yoi/workspace.toml`。
|
||||
- Stable persisted id usage in Workspace API / repository / host ids。
|
||||
- Missing/existing/invalid file behavior。
|
||||
- No local path/secret leakage。
|
||||
- Package/Nix updates。
|
||||
|
||||
Orchestrator will wait for reviewer verdict before integration。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-orchestrator at: 2026-06-23T07:24:58Z status: request_changes -->
|
||||
|
||||
## Review: request changes
|
||||
|
||||
Reviewer Pod `yoi-reviewer-00001KVSKGDYS-r1` requested changes.
|
||||
|
||||
Reviewed target:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVSKGDYS-workspace-identity`
|
||||
- Branch: `impl/00001KVSKGDYS-workspace-identity`
|
||||
- Implementation: `31565c9b feat: persist workspace identity`
|
||||
- Diff: `4cda83b7..31565c9b`
|
||||
|
||||
Blocking issue:
|
||||
1. Missing-file create path can return/use an identity that is not the persisted `.yoi/workspace.toml` identity under a local bootstrap race。
|
||||
|
||||
Evidence:
|
||||
- `crates/workspace-server/src/identity.rs` generates a new `WorkspaceIdentity`, calls `identity.write_new(path)?`, and then returns the generated identity。
|
||||
- In `write_new`, if another process creates `workspace.toml` after the initial missing-file path, the code validates the existing file but discards the parsed identity:
|
||||
|
||||
```rust
|
||||
if path.exists() {
|
||||
let _ = fs::remove_file(&tmp);
|
||||
let raw = fs::read_to_string(path)?;
|
||||
return Self::parse_str(&raw, path).map(|_| ());
|
||||
}
|
||||
```
|
||||
|
||||
- The caller still returns the newly generated identity, so a server instance can upsert SQLite / serve Workspace API / repository / host ids using an id that is not the tracked file and will not survive restart。
|
||||
- Related TOCTOU risk: `path.exists()` followed by `fs::rename(tmp, path)` can overwrite a concurrently created file on Unix, and fixed temp path `workspace.toml.tmp` can be clobbered by concurrent creators。
|
||||
|
||||
Required fix direction:
|
||||
- Ensure the returned `WorkspaceIdentity` is always the identity actually persisted or read from `.yoi/workspace.toml`。
|
||||
- Use a no-overwrite / create-new style finalization or equivalent safe retry/read behavior for local bootstrap races。
|
||||
- Add focused test coverage for the race/return-authority behavior if feasible。
|
||||
|
||||
Non-blocking reviewer findings:
|
||||
- `.yoi/workspace.toml` contents look safe to track。
|
||||
- Unknown fields are intentionally denied and documented/tested。
|
||||
- `ServerConfig::local_dev` no longer derives `local:{display}` internally。
|
||||
- Workspace API/store/repository/host plumbing appears correctly based on persisted identity once loaded。
|
||||
- Existing `local:*` rows are not destructively migrated。
|
||||
|
||||
Reviewer validation all passed before request_changes:
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check 4cda83b7..HEAD`
|
||||
- `cargo test -p yoi-workspace-server` (`15 passed`)
|
||||
- `cargo check -p yoi-workspace-server`
|
||||
- `cd web/workspace && deno task check && deno task build`
|
||||
- `cargo run -p yoi -- ticket doctor`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
Reviewer notes generated ignored artifacts from validation remained in worktree:
|
||||
- `target/`
|
||||
- `web/workspace/node_modules/`
|
||||
- `web/workspace/.svelte-kit/`
|
||||
- `web/workspace/build/`
|
||||
|
||||
---
|
||||
|
||||
<!-- event: comment author: yoi-orchestrator at: 2026-06-23T07:25:27Z -->
|
||||
|
||||
## Comment
|
||||
|
||||
Rerouted request-changes feedback to Coder Pod `yoi-coder-00001KVSKGDYS`.
|
||||
|
||||
Requested fix:
|
||||
- `WorkspaceIdentity::load_or_init` must return the identity actually persisted/read from `.yoi/workspace.toml`。
|
||||
- Missing-file creation must handle local bootstrap races without returning an unpersisted generated identity。
|
||||
- Avoid or safely handle TOCTOU / fixed temp-file clobbering around `workspace.toml.tmp`。
|
||||
- Add focused deterministic test coverage if feasible。
|
||||
|
||||
Validation requested after fix:
|
||||
- `cargo fmt --check`
|
||||
- `cargo test -p yoi-workspace-server`
|
||||
- `cargo check -p yoi-workspace-server`
|
||||
- `cd web/workspace && deno task check && deno task build`
|
||||
- `git diff --check`
|
||||
- `git diff --cached --check`
|
||||
- `cargo run -p yoi -- ticket doctor`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
Coder was also asked to remove ignored validation artifacts before reporting。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T07:30:46Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Coder fix report received from `yoi-coder-00001KVSKGDYS` after request_changes。
|
||||
|
||||
New commit:
|
||||
- `49c9e190 fix: return persisted workspace identity`
|
||||
|
||||
Fix summary:
|
||||
- Replaced temp-file + `rename` finalization in `crates/workspace-server/src/identity.rs`。
|
||||
- New creation path uses `OpenOptions::create_new(true)` directly on `.yoi/workspace.toml`。
|
||||
- If creation succeeds, generated identity is written and returned。
|
||||
- If creation fails because the file already exists from a concurrent bootstrap race, the existing file is read/parsed and that persisted identity is returned。
|
||||
- Removed fixed `workspace.toml.tmp` path and the `path.exists()` + `rename` TOCTOU overwrite risk。
|
||||
|
||||
Test coverage:
|
||||
- Added deterministic unit test `create_new_race_returns_existing_persisted_identity`。
|
||||
- Test verifies an already-persisted identity wins over a generated candidate, returned identity matches the file, and the file is not rewritten。
|
||||
- Existing tests for missing creation, stable existing identity, invalid fail-closed behavior, no path leakage, and unknown field rejection remain。
|
||||
|
||||
Coder validation reported:
|
||||
- `cargo fmt --check`: passed
|
||||
- `cargo test -p yoi-workspace-server`: passed
|
||||
- `cargo check -p yoi-workspace-server`: passed
|
||||
- `cd web/workspace && deno task check && deno task build`: passed
|
||||
- `git diff --check`: passed
|
||||
- `git diff --cached --check`: passed
|
||||
- `cargo run -p yoi -- ticket doctor`: passed
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
Cleanup reported:
|
||||
- Removed ignored validation artifacts:
|
||||
- `target/`
|
||||
- `web/workspace/node_modules/`
|
||||
- `web/workspace/.svelte-kit/`
|
||||
- `web/workspace/build/`
|
||||
|
||||
Orchestrator evidence checked:
|
||||
- Worktree clean on `impl/00001KVSKGDYS-workspace-identity` at `49c9e190`。
|
||||
- Diff `4cda83b7..HEAD` still touches expected Workspace identity/backend/package files。
|
||||
- Latest fix commit changes only `crates/workspace-server/src/identity.rs`。
|
||||
- `git diff --check 4cda83b7..HEAD`: passed。
|
||||
- Spot-check of `identity.rs` confirmed `write_new_or_read_existing` returns parsed persisted identity on `AlreadyExists` and no longer uses fixed temp file / rename finalization。
|
||||
|
||||
Next action:
|
||||
- Route back to Reviewer Pod for re-review of request_changes fix。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: comment author: yoi-orchestrator at: 2026-06-23T07:31:34Z -->
|
||||
|
||||
## Comment
|
||||
|
||||
Re-review routing:
|
||||
|
||||
Sent the request_changes fix back to Reviewer Pod:
|
||||
- `yoi-reviewer-00001KVSKGDYS-r1`
|
||||
|
||||
Review target:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVSKGDYS-workspace-identity`
|
||||
- Branch: `impl/00001KVSKGDYS-workspace-identity`
|
||||
- Baseline: `4cda83b7`
|
||||
- Previous implementation: `31565c9b feat: persist workspace identity`
|
||||
- Fix commit: `49c9e190 fix: return persisted workspace identity`
|
||||
- Main review diff: `4cda83b7..49c9e190`
|
||||
- Focus diff: `31565c9b..49c9e190`
|
||||
|
||||
Reviewer was asked to verify the prior blocking issue is fixed and re-run validation including workspace-server tests/checks, web check/build, TicketDoctor, and Nix build。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-orchestrator at: 2026-06-23T07:35:05Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Reviewer Pod `yoi-reviewer-00001KVSKGDYS-r1` approved the request_changes fix and the full implementation.
|
||||
|
||||
Reviewed target:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVSKGDYS-workspace-identity`
|
||||
- Branch: `impl/00001KVSKGDYS-workspace-identity`
|
||||
- Final HEAD: `49c9e190 fix: return persisted workspace identity`
|
||||
- Full diff: `4cda83b7..49c9e190`
|
||||
- Fix diff: `31565c9b..49c9e190`
|
||||
|
||||
Reviewer result:
|
||||
- Prior blocker is fixed。
|
||||
- `write_new_or_read_existing` now uses `OpenOptions::new().write(true).create_new(true).open(path)` for no-overwrite creation。
|
||||
- On successful create, generated identity is written/synced and returned。
|
||||
- On `AlreadyExists`, existing `.yoi/workspace.toml` is read/parsed and the persisted identity is returned。
|
||||
- Fixed temp path and `path.exists() + rename` finalization are gone。
|
||||
- This satisfies the invariant that the returned identity is the persisted/read authority under a local bootstrap race。
|
||||
|
||||
Blocking issues:
|
||||
- なし。
|
||||
|
||||
Non-blocking concern:
|
||||
- Direct final-file `create_new` write can expose an empty/partial file to a concurrent reader during the short write window or after crash/write failure, but this fails closed rather than returning the wrong identity and was not considered blocking for local bootstrap scope。
|
||||
|
||||
Requirement checks:
|
||||
- Missing-file creation writes minimal v0 TOML schema。
|
||||
- Invalid existing file fails closed without overwrite。
|
||||
- Unknown fields remain denied and tested。
|
||||
- UUIDv7 validation is real: UUID parse + version check + canonical lowercase hyphenated form check。
|
||||
- `ServerConfig::local_dev` no longer constructs `local:{display}`。
|
||||
- SQLite `workspaces` upsert uses `.yoi/workspace.toml` identity values。
|
||||
- Repository ids and host ids derive from persisted workspace id。
|
||||
- Legacy `/api/repositories/local` alias remains accepted。
|
||||
- Existing `local:*` DB rows are not destructively migrated。
|
||||
- `.yoi/workspace.toml` remains safe to track and contains only `workspace_id`, `created_at`, `display_name`。
|
||||
|
||||
Reviewer validation:
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check 4cda83b7..HEAD`: passed
|
||||
- `cargo test -p yoi-workspace-server`: passed (`16 passed`)
|
||||
- `cargo check -p yoi-workspace-server`: passed
|
||||
- `cd web/workspace && deno task check && deno task build`: passed
|
||||
- `cargo run -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
Worktree status:
|
||||
- clean for tracked/untracked files at `49c9e190`。
|
||||
- Reviewer validation left only ignored generated artifacts in the child worktree。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T07:38:38Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Merge and validation completed.
|
||||
|
||||
Merged implementation:
|
||||
- Merge commit: `2745f3d5 merge: workspace identity persistence`
|
||||
- Implementation commits:
|
||||
- `31565c9b feat: persist workspace identity`
|
||||
- `49c9e190 fix: return persisted workspace identity`
|
||||
|
||||
Post-merge validation in orchestration worktree:
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cargo test -p yoi-workspace-server`: passed
|
||||
- `cargo check -p yoi-workspace-server`: passed
|
||||
- `cd web/workspace && deno task check && deno task build`: passed (`svelte-check` 0 errors / 0 warnings; build completed)
|
||||
- `cargo run -q -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
Generated artifact cleanup:
|
||||
- Removed validation artifacts from orchestration worktree:
|
||||
- `target/`
|
||||
- `web/workspace/node_modules/`
|
||||
- `web/workspace/.svelte-kit/`
|
||||
- `web/workspace/build/`
|
||||
- `git status --short --branch --ignored` shows only ignored `.yoi/tickets/.ticket-backend.lock`。
|
||||
|
||||
Outcome:
|
||||
- Local Workspace identity now persists in tracked `.yoi/workspace.toml`。
|
||||
- New ids are UUIDv7 and no longer derived from path/display basename。
|
||||
- `.yoi/workspace.toml` parsing validates UUIDv7, UTC RFC3339 timestamp, non-empty display name, canonical id form, and denies unknown fields。
|
||||
- Invalid existing identity files fail closed and are not overwritten。
|
||||
- Missing-file creation returns the identity actually persisted/read, including `AlreadyExists` race handling。
|
||||
- Workspace API / SQLite upsert / repository ids / host ids use the persisted Workspace identity。
|
||||
- Existing legacy `local:*` DB rows are not destructively migrated。
|
||||
- `.yoi/workspace.toml` remains a minimal safe project identity record, not a runtime/settings/secret store。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T07:38:42Z from: inprogress to: done reason: merged_and_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Reviewer approval 後に implementation を orchestration worktree へ merge し、post-merge validation と生成物 cleanup が完了したため done とする。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: hare at: 2026-06-23T07:39:10Z from: done to: closed reason: closed field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を closed にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: close author: hare at: 2026-06-23T07:39:10Z status: closed -->
|
||||
|
||||
## 完了
|
||||
|
||||
Local Workspace identity を tracked `.yoi/workspace.toml` に永続化する実装を完了した。
|
||||
|
||||
完了内容:
|
||||
- `.yoi/workspace.toml` を local Workspace identity の authority として追加。
|
||||
- v0 schema は `workspace_id`, `created_at`, `display_name` のみ。
|
||||
- `workspace_id` は UUIDv7 canonical string として検証し、path / display basename から導出しない。
|
||||
- `created_at` は UTC RFC3339 timestamp として検証。
|
||||
- `display_name` は空文字列を拒否。
|
||||
- unknown fields は v0 では明示的に deny。
|
||||
- invalid existing file は fail closed し、自動上書きしない。
|
||||
- missing file 初期化では `OpenOptions::create_new(true)` を使い、既存 file が race で作られた場合は persisted identity を read/parse して返す。
|
||||
- fixed temp file / `path.exists()` + `rename` finalization は使わない。
|
||||
- `ServerConfig::local_dev` は `local:{display}` を生成せず、persisted `WorkspaceIdentity` を受け取る。
|
||||
- SQLite `workspaces` upsert、Workspace API、repository ids、host ids は persisted Workspace id を使う。
|
||||
- legacy `/api/repositories/local` alias は維持。
|
||||
- 既存 `local:*` DB rows の destructive migration はしない。
|
||||
- `.yoi/workspace.toml` は絶対 path / secret / socket / runtime data を含まない安全な project identity record として維持。
|
||||
|
||||
統合:
|
||||
- Implementation: `31565c9b feat: persist workspace identity`
|
||||
- Fix: `49c9e190 fix: return persisted workspace identity`
|
||||
- Merge: `2745f3d5 merge: workspace identity persistence`
|
||||
|
||||
検証:
|
||||
- Reviewer approval: `yoi-reviewer-00001KVSKGDYS-r1`
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cargo test -p yoi-workspace-server`: passed
|
||||
- `cargo check -p yoi-workspace-server`: passed
|
||||
- `cd web/workspace && deno task check && deno task build`: passed
|
||||
- `cargo run -q -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `nix build .#yoi --no-link`: passed
|
||||
|
||||
生成物 cleanup:
|
||||
- orchestration worktree の `target/`, `web/workspace/node_modules/`, `web/workspace/.svelte-kit/`, `web/workspace/build/` を削除済み。
|
||||
|
||||
残作業:
|
||||
- なし。将来必要なら legacy `local:*` row cleanup / migration policy は別 Ticket で扱う。
|
||||
|
||||
---
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"orch-plan-20260623-064931-1","ticket_id":"00001KVSKJ0EA","kind":"accepted_plan","accepted_plan":{"summary":"Change Workspace Dashboard selection semantics so initial display and reload/background refresh do not auto-select rows; explicit keyboard/mouse selection still works; no-selection + TicketIntake composer submits global/new Intake; add focused tests.","branch":"impl/00001KVSKJ0EA-dashboard-no-auto-selection","worktree":"/home/hare/Projects/yoi/.worktree/00001KVSKJ0EA-dashboard-no-auto-selection","role_plan":"Orchestrator creates a dedicated child worktree and spawns a narrow-scope TUI Coder. Reviewer will be spawned read-only after Coder reports implementation commit(s). After approval, Orchestrator integrates into `orchestration`, validates TUI focused tests, records closure, and cleans only the child worktree/branch."},"author":"yoi-orchestrator","at":"2026-06-23T06:49:31Z"}
|
||||
@@ -0,0 +1,107 @@
|
||||
---
|
||||
title: 'Dashboard reload と初期表示で row を自動選択しない'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-23T06:44:20Z'
|
||||
updated_at: '2026-06-23T07:24:20Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['tui-ux', 'panel-selection', 'reload-state']
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-23T06:47:17Z'
|
||||
---
|
||||
|
||||
## User claims / request snapshot
|
||||
|
||||
- Dashboard で `Esc` を押して row selection を消しても、reload によって頻繁に選択が戻る。
|
||||
- そのため、実使用上は「何も選択していない状態」で composer を global / 新規 Intake として使うのが難しい。
|
||||
- reload で勝手に row selection しないようにしたい。
|
||||
- 追加合意: 初回 `yoi panel` 起動時から未選択にする。
|
||||
|
||||
## Confirmed facts / sources
|
||||
|
||||
- `crates/tui/src/dashboard/mod.rs`
|
||||
- Dashboard は `selected_row: Option<PanelRowKey>` を持ち、`None` の未選択状態が実装上存在する。
|
||||
- `Esc` 経路で `clear_panel_selection()` が呼ばれ、selection を消せる。
|
||||
- reload / snapshot 更新後の selection visibility 補正により、visible row があると selection が戻る可能性がある。
|
||||
- `crates/tui/src/dashboard/tests.rs`
|
||||
- `Esc` が row selection を clear する既存テストがある。
|
||||
- 関連 Ticket:
|
||||
- `00001KTNS1AA8` closed: Panel composer / no-selection / `Esc` semantics の過去文脈。
|
||||
- `00001KTFMMZP0` closed: background reload と selection/composer preservation の過去文脈。
|
||||
|
||||
## Unverified hypotheses
|
||||
|
||||
- 現行の reload 完了時の `ensure_selection_visible()` 系処理が、明示的な no-selection と「まだ selection がない初期/補正状態」を区別していない可能性が高い。
|
||||
- 初期表示時の自動選択も同じ selection visibility 補正または初期化経路に由来している可能性がある。
|
||||
|
||||
## Undecided points / open questions
|
||||
|
||||
- なし。初回表示から未選択にする方針で合意済み。
|
||||
|
||||
## Background
|
||||
|
||||
Dashboard composer は row selection と composer target の組み合わせで挙動が変わる。`TicketIntake` target で Ticket row が選択されていると、入力が既存 Ticket の詳細化 / planning return として扱われる経路がある。一方、ユーザーが global / 新規 Intake として入力したい場合は row selection がない状態を維持できる必要がある。
|
||||
|
||||
現状は `Esc` で selection を消せても、background reload 等で選択が戻るため、ユーザーが意図した no-selection 状態を維持しづらい。
|
||||
|
||||
## Requirements
|
||||
|
||||
- 初回 `yoi panel` 表示時は、Ticket row / Pod row を自動選択しない。
|
||||
- ユーザーが `Esc` で row selection を clear した後、reload / background reload / snapshot 更新が完了しても `selected_row = None` を維持する。
|
||||
- reload によって既存の明示選択がまだ visible な場合は、その selection を維持してよい。
|
||||
- reload によって選択中 row が消えた場合は安全に未選択へ落とす。
|
||||
- Up/Down、mouse click、その他既存の明示的な row selection 操作では従来どおり selection を作れる。
|
||||
- 未選択状態で `TicketIntake` target に非空 composer 入力して Enter した場合、既存 Ticket refinement ではなく global / 新規 Intake launch として扱われる。
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- 初回 `yoi panel` 起動後、visible row があっても row selection はない。
|
||||
- `Esc` で selection を clear した後、panel reload completion を挟んでも selection は復活しない。
|
||||
- 未選択状態で `TicketIntake` target に composer 入力して Enter すると、新規/global Intake handoff になり、既存 Ticket の詳細化 handoff にならない。
|
||||
- keyboard navigation または mouse click により、ユーザーは明示的に row を再選択できる。
|
||||
- 既存の selected-row action、queue/close/open 操作、Ticket workflow state semantics は変えない。
|
||||
- focused tests で少なくとも以下を確認する:
|
||||
- initial Dashboard state has no selected row when rows exist;
|
||||
- `Esc` clear -> reload completion -> still no selected row;
|
||||
- no-selection + `TicketIntake` composer submit routes to global/new Intake rather than selected Ticket refinement.
|
||||
|
||||
## Binding decisions / invariants
|
||||
|
||||
- no-selection は first-class UX state として扱う。
|
||||
- reload は、ユーザーが明示的に作った no-selection state を勝手に解除しない。
|
||||
- 初回表示でも自動選択しない。
|
||||
- composer draft は reload / selection clear によって失わない。
|
||||
- Ticket state transition / lifecycle authority は変更しない。
|
||||
- row click は selection のみを変更し、click だけで action dispatch しない既存方針を維持する。
|
||||
|
||||
## Implementation latitude
|
||||
|
||||
- 実装は `selected_row: Option<PanelRowKey>` に加えて「明示 no-selection」フラグを持つ、または selection visibility 補正の呼び出し条件を整理するなど、局所的に選んでよい。
|
||||
- 初期表示・reload 完了・row 消失・navigation 開始の各経路で、selection を作る責務を明示的 user action に寄せられればよい。
|
||||
- UI 表示文言の小変更は許容するが、この Ticket の主目的は selection semantics の修正であり、広い Dashboard layout redesign は含めない。
|
||||
|
||||
## Readiness
|
||||
|
||||
- readiness: implementation_ready
|
||||
- risk_flags: [tui-ux, panel-selection, reload-state]
|
||||
|
||||
## Escalation conditions
|
||||
|
||||
- 初回未選択にすると keyboard-only navigation や blank Enter action の既存 contract が大きく変わることが判明した場合。
|
||||
- selection visibility 補正が reload 以外の重要な safety/correctness を担っており、単純に止めると stale selection や action 誤爆が起きる場合。
|
||||
- focused tests では確認できず、実端末 `yoi panel` / PTY 経路での挙動確認が必要になった場合。
|
||||
|
||||
## Validation
|
||||
|
||||
- `cargo test -q -p tui workspace_panel`
|
||||
- 必要に応じて Dashboard 関連の focused test 名指定。
|
||||
- 変更範囲に応じて `cargo fmt --check`、`git diff --check`、`cargo check -q`。
|
||||
- terminal delivery / timing に依存する挙動が疑わしい場合は、既存の Panel PTY/E2E 系テストまたは実 `yoi panel` で確認する。
|
||||
|
||||
## Related work
|
||||
|
||||
- `00001KTNS1AA8` — Panel composer / no-selection / `Esc` semantics の関連 closed Ticket。
|
||||
- `00001KTFMMZP0` — Dashboard background reload / selection preservation の関連 closed Ticket。
|
||||
- `crates/tui/src/dashboard/mod.rs`
|
||||
- `crates/tui/src/dashboard/tests.rs`
|
||||
- `crates/tui/src/dashboard/render.rs`
|
||||
@@ -0,0 +1,26 @@
|
||||
Dashboard の row selection を明示的 user action の結果として扱うように修正した。
|
||||
|
||||
完了内容:
|
||||
- 初期表示で visible row があっても自動選択しない。
|
||||
- reload / snapshot reconciliation で `selected_row = None` を勝手に selection へ戻さない。
|
||||
- `Esc` による no-selection が reload を跨いで維持される。
|
||||
- 選択中 row が消えた場合は `None` へ安全に落とす。
|
||||
- keyboard navigation では no-selection から明示的に selection を作成できる。
|
||||
- `list.selected_name` は実際の Pod row selection と同期し、no-selection / non-Pod selection では clear する。
|
||||
- no-selection + `TicketIntake` composer submit が既存 Ticket refinement ではなく global/new Intake route へ進むことを focused test で確認した。
|
||||
|
||||
統合:
|
||||
- Implementation: `5c242d96 fix: keep dashboard row selection explicit`
|
||||
- Merge: `58904c44 merge: dashboard no auto selection`
|
||||
|
||||
検証:
|
||||
- Reviewer approval: `yoi-reviewer-00001KVSKJ0EA-r1`
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cargo test -q -p tui workspace_panel`: passed (`27 passed`)
|
||||
- `cargo test -q -p tui dashboard`: passed (`111 passed`)
|
||||
- reviewer 側追加確認 `cargo test -q -p tui`: passed (`372 passed`)
|
||||
- `cargo run -q -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
|
||||
残作業:
|
||||
- なし。
|
||||
@@ -0,0 +1,313 @@
|
||||
<!-- event: create author: LocalTicketBackend at: 2026-06-23T06:44:20Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: ticket-intake at: 2026-06-23T06:46:36Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
ユーザー合意により ready 化。Ticket は `implementation_ready` で、初回 `yoi panel` 表示時から未選択、`Esc` 後の no-selection を reload が復活させない、未選択 + `TicketIntake` composer submit を global/new Intake に流す、という要件・受け入れ条件・validation が明記されている。未決定点なし。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: ticket-intake at: 2026-06-23T06:46:36Z from: planning to: ready reason: user_requested_ready field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
ユーザーから `readyにして` の明示指示があり、対象 Ticket の item/thread を確認した。要件・受け入れ条件・risk flags・validation が揃っており、Orchestrator が routing 可能なため `ready` に遷移する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-23T06:47:17Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-23T06:49:08Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: `implementation_ready_parallel`
|
||||
|
||||
Reason:
|
||||
- Ticket body has concrete Dashboard selection semantics and focused test requirements。
|
||||
- No relations / blockers / orchestration plan records exist。
|
||||
- Active queued Workspace identity Ticket is backend/workspace-server focused and separate from TUI Dashboard row-selection code, so parallel implementation is acceptable。
|
||||
- Orchestrator worktree is clean on `orchestration` at `13e76d35`; target worktree / branch is not present。
|
||||
- Code map from Ticket body points to `crates/tui/src/dashboard/mod.rs`, `tests.rs`, and `render.rs`。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Treat no-selection as a first-class Dashboard UX state: initial panel display and reload/background refresh must not auto-select rows, while explicit keyboard/mouse selection still works。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- Initial `yoi panel` display should have `selected_row = None` even when rows are visible。
|
||||
- `Esc` clear must persist across reload/snapshot refresh; reload must not recreate selection after explicit no-selection。
|
||||
- If a user explicitly selected a row and it remains visible after reload, that selection may be preserved。
|
||||
- If selected row disappears after reload, fall back safely to no-selection。
|
||||
- Composer draft must survive selection clear/reload。
|
||||
- Existing row actions, queue/close/open operations, Ticket workflow state semantics, and row-click-is-selection-only policy must remain unchanged。
|
||||
- No broad Dashboard layout redesign in this Ticket。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Initial Dashboard state has no selected row when rows exist。
|
||||
- Esc clear -> reload completion -> still no selected row。
|
||||
- No-selection + `TicketIntake` composer submit routes to global/new Intake, not selected Ticket refinement。
|
||||
- Keyboard navigation or mouse click can explicitly create selection again。
|
||||
- Focused tests cover the above semantics。
|
||||
|
||||
Implementation latitude:
|
||||
- Use an explicit no-selection flag or refine selection visibility correction conditions。
|
||||
- The key is to make selection creation happen only from explicit user navigation/click/action paths, not from reload/init visibility correction。
|
||||
|
||||
Escalate if:
|
||||
- Initial no-selection substantially breaks keyboard-only navigation or blank Enter action contract。
|
||||
- Existing selection visibility correction has safety roles that cannot be preserved with a local change。
|
||||
- Real terminal / PTY behavior is required beyond focused tests。
|
||||
|
||||
Validation plan:
|
||||
- `cargo fmt --check`
|
||||
- `cargo test -q -p tui workspace_panel`
|
||||
- Dashboard focused tests as needed。
|
||||
- `git diff --check`
|
||||
- `cargo run -p yoi -- ticket doctor`。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T06:49:18Z from: queued to: inprogress reason: human_authorized_unblocked_dashboard_no_auto_selection field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Human authorized queue routing from Workspace Dashboard. Ticket has concrete Dashboard selection semantics and no recorded blockers, so Orchestrator accepts implementation.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T06:51:32Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation start report:
|
||||
|
||||
- Created child implementation worktree:
|
||||
- `/home/hare/Projects/yoi/.worktree/00001KVSKJ0EA-dashboard-no-auto-selection`
|
||||
- Created branch:
|
||||
- `impl/00001KVSKJ0EA-dashboard-no-auto-selection`
|
||||
- Base commit:
|
||||
- `4cda83b7 ticket: accept workspace identity and selection work`
|
||||
- Confirmed tracked Ticket project records are visible in the child worktree。
|
||||
- Confirmed `.yoi/memory` has no tracked/untracked entries in the child worktree check。
|
||||
- Spawned sibling Coder Pod:
|
||||
- `yoi-coder-00001KVSKJ0EA`
|
||||
- Coder scope:
|
||||
- read: `/home/hare/Projects/yoi`
|
||||
- write: `/home/hare/Projects/yoi/.worktree/00001KVSKJ0EA-dashboard-no-auto-selection`
|
||||
|
||||
Parallelization note:
|
||||
- `00001KVSKGDYS` is active separately and targets Workspace backend identity persistence. This Ticket should stay limited to TUI Dashboard selection semantics。
|
||||
|
||||
Next action:
|
||||
- Wait for Coder implementation report, then spawn Reviewer read-only for the implementation diff。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T07:15:44Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Coder implementation report received from `yoi-coder-00001KVSKJ0EA`.
|
||||
|
||||
Implementation commit:
|
||||
- `5c242d96 fix: keep dashboard row selection explicit`
|
||||
|
||||
Changed areas:
|
||||
- `crates/tui/src/dashboard/mod.rs`
|
||||
- Reload/snapshot reconciliation preserves only an explicitly selected visible row。
|
||||
- Initial/reload visibility correction no longer auto-selects a row。
|
||||
- Stale/disappeared selections fall back to `None`。
|
||||
- `Esc` clear state remains no-selection across reload。
|
||||
- Keyboard navigation from no-selection explicitly creates selection on first visible row。
|
||||
- `list.selected_name` stays aligned with actual Pod row selection and clears for non-Pod/no-selection states。
|
||||
- `crates/tui/src/dashboard/tests.rs`
|
||||
- Added focused coverage for initial visible rows with no selected row。
|
||||
- Added `Esc` clear surviving reload while preserving composer draft。
|
||||
- Added no-selection + `TicketIntake` submit routing to global/new Intake。
|
||||
- Added keyboard navigation creating selection explicitly。
|
||||
- Added reload fallback to no-selection when selected row disappears。
|
||||
- Updated existing Dashboard tests to explicitly select rows where previous behavior depended on auto-selection。
|
||||
|
||||
Coder validation reported:
|
||||
- `cargo fmt --check`: passed
|
||||
- `cargo test -q -p tui workspace_panel`: passed
|
||||
- `cargo test -q -p tui dashboard`: passed
|
||||
- `git diff --check`: passed
|
||||
- `cargo run -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
|
||||
Orchestrator evidence checked:
|
||||
- Worktree clean on `impl/00001KVSKJ0EA-dashboard-no-auto-selection` at `5c242d96`。
|
||||
- Diff `4cda83b7..HEAD` touches expected Dashboard model/tests only。
|
||||
- `git diff --check 4cda83b7..HEAD`: passed。
|
||||
|
||||
Next action:
|
||||
- Route to read-only Reviewer Pod for acceptance review。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: comment author: yoi-orchestrator at: 2026-06-23T07:16:33Z -->
|
||||
|
||||
## Comment
|
||||
|
||||
Review routing:
|
||||
|
||||
Spawned read-only Reviewer Pod:
|
||||
- `yoi-reviewer-00001KVSKJ0EA-r1`
|
||||
|
||||
Review target:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVSKJ0EA-dashboard-no-auto-selection`
|
||||
- Branch: `impl/00001KVSKJ0EA-dashboard-no-auto-selection`
|
||||
- Baseline: `4cda83b7`
|
||||
- Implementation commit: `5c242d96 fix: keep dashboard row selection explicit`
|
||||
- Diff: `4cda83b7..5c242d96`
|
||||
|
||||
Reviewer scope:
|
||||
- read-only `/home/hare/Projects/yoi`
|
||||
|
||||
Reviewer focus:
|
||||
- Initial/reload no-auto-selection semantics。
|
||||
- Esc clear persistence and composer draft preservation。
|
||||
- Explicit keyboard/mouse selection still works。
|
||||
- Stale selection falls back to none。
|
||||
- No-selection TicketIntake composer routing。
|
||||
- `list.selected_name` sync and no stale Pod selection。
|
||||
- No row-action / workflow semantic regressions。
|
||||
|
||||
Orchestrator will wait for reviewer verdict before integration。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-orchestrator at: 2026-06-23T07:23:02Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Reviewer Pod `yoi-reviewer-00001KVSKJ0EA-r1` approved the implementation.
|
||||
|
||||
Reviewed target:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVSKJ0EA-dashboard-no-auto-selection`
|
||||
- Branch: `impl/00001KVSKJ0EA-dashboard-no-auto-selection`
|
||||
- Implementation: `5c242d96 fix: keep dashboard row selection explicit`
|
||||
- Diff: `4cda83b7..5c242d96`
|
||||
|
||||
Reviewer evidence:
|
||||
- 初期表示 / reload path は row selection を自動生成しない。
|
||||
- `selected_row = None` は `Esc` 後も reload/snapshot reconciliation を跨いで維持される。
|
||||
- 明示的な keyboard navigation は no-selection から selection を作成できる。
|
||||
- 明示的 selection は row が visible な間は維持される。
|
||||
- 消えた / stale row selection は `None` へ落ちる。
|
||||
- `list.selected_name` は no-selection / non-Pod selection で clear され、実際の Pod row selection のみで設定される。
|
||||
- no-selection + `TicketIntake` submit は global/new Intake launch へ進む。
|
||||
- mouse click は selection-only のまま。
|
||||
- 差分は Dashboard selection logic と focused tests に限定され、layout / render / workflow semantic の不要変更はない。
|
||||
|
||||
Blocking issues:
|
||||
- なし。
|
||||
|
||||
Non-blocking concerns:
|
||||
- なし。
|
||||
|
||||
Reviewer validation:
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check 4cda83b7..HEAD`: passed
|
||||
- `cargo test -q -p tui workspace_panel`: passed (`27 passed`)
|
||||
- `cargo test -q -p tui dashboard`: passed (`111 passed`)
|
||||
- `cargo run -q -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
- `cargo test -q -p tui`: passed (`372 passed`)
|
||||
|
||||
Worktree status:
|
||||
- clean at `5c242d96`。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T07:24:05Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Merge and validation completed.
|
||||
|
||||
Merged implementation:
|
||||
- Merge commit: `58904c44 merge: dashboard no auto selection`
|
||||
- Implementation commit: `5c242d96 fix: keep dashboard row selection explicit`
|
||||
|
||||
Post-merge validation in orchestration worktree:
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cargo test -q -p tui workspace_panel`: passed (`27 passed`)
|
||||
- `cargo test -q -p tui dashboard`: passed (`111 passed`)
|
||||
- `cargo run -q -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
|
||||
Outcome:
|
||||
- 初期表示と reload/snapshot reconciliation が row selection を自動生成しなくなった。
|
||||
- `Esc` 後の no-selection は reload を跨いで維持される。
|
||||
- 明示的 keyboard navigation による selection 作成は維持された。
|
||||
- `TicketIntake` composer の no-selection submit は global/new Intake route になる。
|
||||
- stale selection は安全に `None` へ落ちる。
|
||||
- Ticket lifecycle / row action semantics は変更していない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T07:24:10Z from: inprogress to: done reason: merged_and_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
実装は reviewer approval 後に orchestration worktree へ merge され、post-merge validation も通過したため done とする。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: hare at: 2026-06-23T07:24:20Z from: done to: closed reason: closed field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を closed にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: close author: hare at: 2026-06-23T07:24:20Z status: closed -->
|
||||
|
||||
## 完了
|
||||
|
||||
Dashboard の row selection を明示的 user action の結果として扱うように修正した。
|
||||
|
||||
完了内容:
|
||||
- 初期表示で visible row があっても自動選択しない。
|
||||
- reload / snapshot reconciliation で `selected_row = None` を勝手に selection へ戻さない。
|
||||
- `Esc` による no-selection が reload を跨いで維持される。
|
||||
- 選択中 row が消えた場合は `None` へ安全に落とす。
|
||||
- keyboard navigation では no-selection から明示的に selection を作成できる。
|
||||
- `list.selected_name` は実際の Pod row selection と同期し、no-selection / non-Pod selection では clear する。
|
||||
- no-selection + `TicketIntake` composer submit が既存 Ticket refinement ではなく global/new Intake route へ進むことを focused test で確認した。
|
||||
|
||||
統合:
|
||||
- Implementation: `5c242d96 fix: keep dashboard row selection explicit`
|
||||
- Merge: `58904c44 merge: dashboard no auto selection`
|
||||
|
||||
検証:
|
||||
- Reviewer approval: `yoi-reviewer-00001KVSKJ0EA-r1`
|
||||
- `cargo fmt --check`: passed
|
||||
- `git diff --check HEAD^1..HEAD`: passed
|
||||
- `cargo test -q -p tui workspace_panel`: passed (`27 passed`)
|
||||
- `cargo test -q -p tui dashboard`: passed (`111 passed`)
|
||||
- reviewer 側追加確認 `cargo test -q -p tui`: passed (`372 passed`)
|
||||
- `cargo run -q -p yoi -- ticket doctor`: passed (`doctor: ok`)
|
||||
|
||||
残作業:
|
||||
- なし。
|
||||
|
||||
---
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"orch-plan-20260623-132129-1","ticket_id":"00001KVSMJJNV","kind":"accepted_plan","accepted_plan":{"summary":"Ticket 00001KVSMJJNV を implementation worktree `.worktree/00001KVSMJJNV-paused-ctrlx-cancel` / branch `work/00001KVSMJJNV-paused-ctrlx-cancel` で開始する。Paused 中の `Ctrl+X` が shutdown ではなく cancel になり、paused turn を破棄して次入力可能にすることが主目的。","branch":"work/00001KVSMJJNV-paused-ctrlx-cancel","worktree":"/home/hare/Projects/yoi/.worktree/00001KVSMJJNV-paused-ctrlx-cancel","role_plan":"Coder Pod: implementation worktree で TUI key handling / controller paused cancel semantics / focused tests を実装し、ローカル commit まで行う。Orchestrator: output/diff/tests を確認後、Reviewer Pod に recorded IntentPacket に基づく review を依頼する。"},"author":"yoi-orchestrator","at":"2026-06-23T13:21:29Z"}
|
||||
@@ -0,0 +1,105 @@
|
||||
---
|
||||
title: 'TUI Console: Paused 中の Ctrl+X で中断ターンをキャンセルできるようにする'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-23T07:02:07Z'
|
||||
updated_at: '2026-06-23T13:56:16Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['tui-keybinding', 'pod-lifecycle']
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-23T08:41:00Z'
|
||||
---
|
||||
|
||||
## User claims / request snapshot
|
||||
|
||||
- TUI Console で、`Ctrl+C` により Pause している状態のとき、`Ctrl+X` でキャンセルできるようにしたい。
|
||||
|
||||
## Confirmed facts / sources
|
||||
|
||||
- 既存 Ticket:
|
||||
- 未完了 Ticket に直接 duplicate は確認できなかった。
|
||||
- `00001KSVP63K8 Support immediate in-flight TUI composer injection` は TUI 実行中入力に関連するが、「Do not interrupt/cancel the current run」が non-goal なので今回の要求とは別件。
|
||||
- `crates/tui/src/console/mod.rs`
|
||||
- 現在の `Ctrl+X` は `PodStatus::Running` のときだけ `Method::Cancel` を返す。
|
||||
- `PodStatus::Paused | PodStatus::Idle` のときは `Method::Shutdown` を返している。
|
||||
- `Ctrl+C` は Running では `Method::Pause`、Idle/Paused では TUI 終了の 2-tap guard として扱われている。
|
||||
- 既存 test `pause_and_cancel_clear_queued_input` は名前上 pause/cancel を扱うが、`Ctrl+C` 後に app status を Paused に更新していないため、Paused 状態での `Ctrl+X` cancel は実質カバーしていない。
|
||||
- `crates/protocol/src/lib.rs`
|
||||
- `Method::Pause` は in-flight turn を止めて Paused に遷移するもの。
|
||||
- コメント上、`Cancel` は破棄して Idle に戻る意味を持ち、Paused は `Resume` または新規 `Run` が可能。
|
||||
- `crates/pod/src/controller.rs`
|
||||
- 非 running 側の `Method::Cancel` は現状 `NotRunning` error を返す経路があるため、TUI keymap 変更だけでなく Paused 状態の cancel semantics を確認・必要なら実装する必要がある。
|
||||
|
||||
## Unverified hypotheses
|
||||
|
||||
- 実装は比較的小さい可能性が高いが、`Paused` 状態で `Method::Cancel` を受け取った時に、Worker/Pod の interrupted state や orphan tool-use cleanup をどう clear するべきかは実装時に確認が必要。
|
||||
- UI 表示は paused hint に `Ctrl+X to cancel` 相当を追加するだけで足りる可能性がある。
|
||||
|
||||
## Undecided points / open questions
|
||||
|
||||
- blocking な未決定点はなし。
|
||||
- Orchestrator/実装者判断で、`Ctrl+X` の Idle 挙動を現状通り `Shutdown` に残すか、Paused のみ `Cancel` に分岐するのがよさそう。
|
||||
|
||||
## Background
|
||||
|
||||
`Ctrl+C` で Pause した turn は resume 可能だが、ユーザーが「やっぱりこの中断 turn は破棄したい」と判断した時に、Console 上の自然な操作として `Ctrl+X` cancel が効くべき。現在は Paused/Idle の `Ctrl+X` が shutdown に割り当てられており、Paused turn のキャンセル導線として機能していない。
|
||||
|
||||
## Requirements
|
||||
|
||||
- TUI Console で Pod が `Paused` のとき、`Ctrl+X` は shutdown ではなく paused/interrupted turn の cancel を要求する。
|
||||
- `Running` 中の `Ctrl+X -> Method::Cancel` は維持する。
|
||||
- `Idle` 中の `Ctrl+X` の挙動は、意図的に変更する理由がなければ現状の shutdown を維持する。
|
||||
- Paused 状態で cancel した後、Pod は resume 可能な paused turn を残さず、Idle 相当として次の入力を受けられる。
|
||||
- queued input がある場合は、既存 Running cancel と同様に誤送信されないよう clear される。
|
||||
- UI の paused hint / actionbar / tests など、ユーザーが操作を理解できる範囲を必要に応じて更新する。
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `Ctrl+C` で Running turn を Pause した後、Console 上で `Ctrl+X` を押すと、TUI 終了や Pod shutdown ではなく turn cancel が実行される。
|
||||
- Paused cancel 後、`Enter` で前の turn を resume しようとしても resume されない。
|
||||
- Paused cancel 後、新規入力は通常の新規 turn として扱われる。
|
||||
- Running 中の `Ctrl+X` cancel と Idle 中の `Ctrl+X` 挙動に意図しない regressions がない。
|
||||
- Focused tests が Paused 状態の `Ctrl+X` key handling と Pod/controller 側の cancel semantics をカバーする。
|
||||
|
||||
## Binding decisions / invariants
|
||||
|
||||
- `Ctrl+C` の Pause semantics は変更しない。
|
||||
- `Ctrl+C` の Idle/Paused 2-tap TUI quit guard は、この Ticket では置き換えない。
|
||||
- この Ticket は in-flight input injection / history append policy を扱わない。
|
||||
- provider stream を直接 mutate しない。
|
||||
- cancel は hidden context/history mutation ではなく、既存の typed `Method::Cancel` semantics またはそれに準じる明示的 lifecycle 操作で表現する。
|
||||
|
||||
## Implementation latitude
|
||||
|
||||
- `Paused` 中の `Ctrl+X` を `Method::Cancel` に変えるだけで足りるか、controller/worker 側に Paused cancel handling を追加するかは実装調査で判断してよい。
|
||||
- UI hint の文言や配置は実装者に任せてよい。
|
||||
- 必要なら既存 test を修正・分割して、「Running cancel」と「Paused cancel」を明確に分ける。
|
||||
|
||||
## Readiness
|
||||
|
||||
- readiness: implementation_ready
|
||||
- risk_flags: [tui-keybinding, pod-lifecycle]
|
||||
|
||||
## Escalation conditions
|
||||
|
||||
- `Method::Cancel` を Paused 状態に拡張すると session/history cleanup や orphan tool-result closure の設計判断が必要になる場合は、実装者は Orchestrator/maintainer に戻す。
|
||||
- `Ctrl+X` の Idle 挙動変更が必要になる場合は、別途合意を取る。
|
||||
|
||||
## Validation
|
||||
|
||||
- Focused tests:
|
||||
- `cargo test -p tui pause` または該当 TUI key handling tests
|
||||
- `cargo test -p pod cancel` または controller paused cancel の focused tests
|
||||
- 通常確認:
|
||||
- `cargo fmt --check`
|
||||
- 必要に応じて `cargo check -q`
|
||||
- terminal UX 変更なので、可能なら実機 TUI/manual check も推奨。
|
||||
|
||||
## Related work
|
||||
|
||||
- Related, not duplicate: `.yoi/tickets/00001KSVP63K8`
|
||||
- Files:
|
||||
- `crates/tui/src/console/mod.rs`
|
||||
- `crates/tui/src/ui.rs`
|
||||
- `crates/protocol/src/lib.rs`
|
||||
- `crates/pod/src/controller.rs`
|
||||
@@ -0,0 +1,28 @@
|
||||
Ticket 00001KVSMJJNV は完了。
|
||||
|
||||
実装内容:
|
||||
- TUI Console の `Paused` 状態で `Ctrl+X` を TUI/Pod shutdown ではなく `Method::Cancel` として扱うようにした。
|
||||
- `Idle` の `Ctrl+X` shutdown behavior と、`Running` の cancel behavior は維持した。
|
||||
- paused cancel 後に resume 可能な interrupted state が残らず、次の入力が fresh run になるよう controller / Pod lifecycle を更新した。
|
||||
- paused cancel を normal `RunCompleted { Finished }` として永続化せず、typed session log entry `LogEntry::PausedTurnAbandoned { ts }` として記録するようにした。
|
||||
- replay / restore で `PausedTurnAbandoned` が `last_run_interrupted` を clear するようにした。
|
||||
- focused tests を追加・更新し、TUI key handling、controller behavior、session log JSON/replay semantics、fake normal-finished run が残らないことを確認した。
|
||||
|
||||
主要 commits:
|
||||
- `90b1a1fc tui: cancel paused turns with ctrl-x`
|
||||
- `8c8fb014 fix: log paused cancel lifecycle explicitly`
|
||||
- `76c80054 merge: 00001KVSMJJNV paused ctrl-x cancel`
|
||||
|
||||
Review:
|
||||
- 初回 review は lifecycle log semantics の不一致で request_changes。
|
||||
- `PausedTurnAbandoned` による typed lifecycle representation を追加後、Reviewer が approve。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p session-store paused_turn_abandoned -- --nocapture`
|
||||
- `cargo test -p pod paused_cancel_abandons_resume_and_next_input_is_fresh_run -- --nocapture`
|
||||
- `cargo test -p tui ctrl_x -- --nocapture`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check HEAD~1..HEAD`
|
||||
|
||||
Merge note:
|
||||
- orchestration branch で実装・Ticket 記録・close resolution をまとめ、merge target へ fast-forward 予定。
|
||||
@@ -0,0 +1,318 @@
|
||||
<!-- event: create author: ticket-intake at: 2026-06-23T07:02:07Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-23T08:41:00Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-23T12:42:28Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: blocked_by_dependency_or_missing_authority
|
||||
|
||||
Reason:
|
||||
- Ticket 自体は `implementation_ready` と判断できる。目的、binding decisions / invariants、acceptance criteria、validation、escalation conditions は揃っており、`tui-keybinding` / `pod-lifecycle` risk は reviewer focus として扱える。
|
||||
- ただし routing 時点の merge target `/home/hare/Projects/yoi` に、この Ticket の対象ではない `crates/tui/src/dashboard/mod.rs` と `crates/tui/src/dashboard/tests.rs` の未コミット変更がある。workflow の dirty-state gate に従い、この状態では implementation worktree 作成 / Coder Pod 起動 / merge へ進めない。
|
||||
- 既存 worktree entry `.worktree/00001KVSMJJNV-paused-ctrlx-cancel` は `git worktree list` 上で prunable と表示され、gitdir が存在しないため、再利用には cleanup/recreate 判断が必要。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread / artifacts: TicketShow で body、queued event、artifacts なしを確認。
|
||||
- Ticket relations: TicketRelationQuery で blocker relation なし。
|
||||
- Orchestration plan: TicketOrchestrationPlanQuery で accepted-plan / conflict / waiting record なし。
|
||||
- Queue state: queued Ticket はこの 1 件のみ。ready / inprogress は 0 件。
|
||||
- Workspace/worktree/Pod state: `/home/hare/Projects/yoi` は `develop...origin/develop [ahead 48]` かつ dashboard files に dirty change あり。`.worktree/orchestration` は clean。visible Pods は peer `yoi` idle と self `yoi-orchestrator` running、spawned child なし。
|
||||
|
||||
Next action:
|
||||
- merge target の未コミット dashboard 変更を所有者が commit / revert / 明示的に退避許可した後、この Ticket を再 routing する。
|
||||
- その時点で blocker がなければ `queued -> inprogress` を記録してから、worktree を clean に recreate し、Coder/Reviewer loop に渡す。
|
||||
|
||||
Escalate if:
|
||||
- dashboard 変更がこの Ticket と同時に保持すべき作業なら、別 Ticket/branch として扱うか、今回の implementation worktree/merge 計画に含めるかを人間が決める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-23T13:21:02Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing correction:
|
||||
|
||||
直前の `blocked_by_dependency_or_missing_authority` 判断は取り下げる。merge target `/home/hare/Projects/yoi` の dashboard files dirty は最終 merge 時の確認事項だが、この Ticket の implementation acceptance / implementation worktree 作成を止める gate として扱うのは過剰だった。
|
||||
|
||||
Corrected routing decision: implementation_ready
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: 目的、requirements、acceptance criteria、binding decisions / invariants、implementation latitude、escalation conditions、validation が揃っている。
|
||||
- TicketRelationQuery: blocker relation なし。
|
||||
- TicketOrchestrationPlanQuery: accepted-plan / conflict / blocker / waiting-capacity record なし。
|
||||
- Queue/capacity: queued Ticket はこの 1 件。visible spawned child はなし。
|
||||
- Worktree state: orchestration worktree は Ticket 記録変更のみ。既存 `.worktree/00001KVSMJJNV-paused-ctrlx-cancel` は prunable なので cleanup/recreate 対象。
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録する。
|
||||
- stale/prunable implementation worktree entry を掃除して、`.worktree/00001KVSMJJNV-paused-ctrlx-cancel` を作り直す。
|
||||
- Coder Pod に IntentPacket を渡して実装を開始する。
|
||||
|
||||
Merge note:
|
||||
- merge target 側の unrelated dashboard dirty は final merge 前に再確認し、必要なら人間へ確認する。implementation worktree 内の作業開始 blocker にはしない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T13:21:07Z from: queued to: inprogress reason: orchestrator_acceptance field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: Ticket evidence、relation blockers、orchestration plan、worktree/capacity 状態を再確認し、implementation_ready と判断した。implementation side effect 前に queued -> inprogress を記録する。
|
||||
|
||||
Acceptance basis:
|
||||
- blocker relation なし。
|
||||
- orchestration plan blocker/conflict なし。
|
||||
- queued Ticket はこの 1 件で child capacity あり。
|
||||
- risk flags は `tui-keybinding` / `pod-lifecycle` として IntentPacket の reviewer focus に反映する。
|
||||
|
||||
Next:
|
||||
- implementation worktree を clean に作成し、Coder Pod に routing する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: plan author: yoi-orchestrator at: 2026-06-23T13:21:47Z -->
|
||||
|
||||
## Plan
|
||||
|
||||
IntentPacket for implementation
|
||||
|
||||
Intent:
|
||||
- TUI Console で Pod が `Paused` のとき、`Ctrl+X` を TUI shutdown ではなく paused/interrupted turn の cancel として扱えるようにする。
|
||||
- Paused cancel 後は resume 可能な paused turn を残さず、次の新規入力を通常の新規 turn として受けられる状態にする。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- `Ctrl+C` の Running -> Pause semantics は変更しない。
|
||||
- `Ctrl+C` の Idle/Paused 2-tap TUI quit guard はこの Ticket では置き換えない。
|
||||
- `Running` 中の `Ctrl+X -> Method::Cancel` は維持する。
|
||||
- `Idle` 中の `Ctrl+X` は、必要な明示理由がなければ現状の shutdown を維持する。
|
||||
- in-flight input injection / history append policy は扱わない。
|
||||
- provider stream を直接 mutate しない。
|
||||
- cancel は hidden context/history mutation ではなく、既存の typed `Method::Cancel` semantics またはそれに準じる明示的 lifecycle 操作で表現する。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- `Ctrl+C` で Running turn を Pause した後、Console 上で `Ctrl+X` を押すと TUI exit / Pod shutdown ではなく turn cancel が実行される。
|
||||
- Paused cancel 後、`Enter` で前の turn が resume されない。
|
||||
- Paused cancel 後、新規入力は通常の新規 turn として扱われる。
|
||||
- Running cancel と Idle `Ctrl+X` に意図しない regression がない。
|
||||
- focused tests が Paused 状態の `Ctrl+X` key handling と Pod/controller 側の cancel semantics をカバーする。
|
||||
|
||||
Implementation latitude:
|
||||
- `Paused` 中の `Ctrl+X` を `Method::Cancel` に変えるだけで足りるか、controller/worker 側に Paused cancel handling を追加するかは実装調査で判断してよい。
|
||||
- UI hint の文言や配置は実装者に任せてよい。
|
||||
- 既存 test の修正・分割は許容する。
|
||||
|
||||
Escalate if:
|
||||
- `Method::Cancel` を Paused 状態に拡張すると session/history cleanup や orphan tool-result closure の新しい設計判断が必要になる。
|
||||
- `Ctrl+X` の Idle 挙動変更が必要になる。
|
||||
- provider stream / history mutation / lifecycle authority の境界を変える必要が出る。
|
||||
|
||||
Validation:
|
||||
- focused: `cargo test -p tui pause` または該当 TUI key handling tests。
|
||||
- focused: `cargo test -p pod cancel` または controller paused cancel tests。
|
||||
- `cargo fmt --check`。
|
||||
- 必要に応じて `cargo check -q`。
|
||||
|
||||
Current code map:
|
||||
- 主対象: `crates/tui/src/console/mod.rs`。
|
||||
- 関連: `crates/tui/src/ui.rs`, `crates/protocol/src/lib.rs`, `crates/pod/src/controller.rs`。
|
||||
- 既存事実: `Ctrl+X` は Running のみ `Method::Cancel`、Paused/Idle は shutdown 側。controller の非-running Cancel は `NotRunning` 経路がある可能性。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- Paused と Idle の key handling を混同して shutdown behavior を壊していないか。
|
||||
- Running cancel の既存 behavior / queued input clear に regression がないか。
|
||||
- Paused cancel 後に resume 可能な interrupted state が残らないか。
|
||||
- Cancel semantics が hidden history/context mutation になっていないか。
|
||||
- tests が実際に app status を Paused に更新した状態をカバーしているか。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T13:37:51Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report
|
||||
|
||||
Worktree / branch:
|
||||
- `/home/hare/Projects/yoi/.worktree/00001KVSMJJNV-paused-ctrlx-cancel`
|
||||
- `work/00001KVSMJJNV-paused-ctrlx-cancel`
|
||||
|
||||
Commit:
|
||||
- `90b1a1fc tui: cancel paused turns with ctrl-x`
|
||||
|
||||
Implemented changes:
|
||||
- `crates/tui/src/console/mod.rs`: `Ctrl+X` key handling を Paused 状態でも cancel path に乗せ、Idle の shutdown behavior と分離。
|
||||
- `crates/tui/src/ui.rs`: Paused UI hint を cancel 操作に合わせて更新。
|
||||
- `crates/pod/src/controller.rs` / `crates/pod/src/pod.rs`: Paused 状態の `Method::Cancel` を `NotRunning` ではなく paused turn cancel として処理し、resume 可能な interrupted state を破棄して次入力を fresh run として扱う経路を追加。
|
||||
- `crates/pod/tests/controller_test.rs`: Paused cancel 後に resume されず、次入力が fresh run になることを確認する focused test を追加。
|
||||
|
||||
Validation run by Orchestrator:
|
||||
- `cargo test -p tui ctrl_x -- --nocapture`
|
||||
- `cargo test -p pod paused_cancel_abandons_resume_and_next_input_is_fresh_run -- --nocapture`
|
||||
- `git diff --check`
|
||||
- `cargo fmt --check`
|
||||
|
||||
Next:
|
||||
- Reviewer Pod に recorded IntentPacket と commit diff を基準に review を依頼する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: reviewer-00001KVSMJJNV-ctrlx-cancel at: 2026-06-23T13:42:48Z status: request_changes -->
|
||||
|
||||
## Review: request changes
|
||||
|
||||
Review result: request_changes
|
||||
|
||||
Findings:
|
||||
- `crates/pod/src/pod.rs:1871-1884` は paused cancel cleanup を `LogEntry::RunCompleted { result: WorkerResult::Finished, interrupted: false }` として記録している。しかしここでは `run()` / `resume()` が完了したわけではなく、paused turn を明示的に abandon している。`crates/session-store/src/segment_log.rs:31` および `:100-106` の session log semantics では、`RunCompleted` は `run()` / `resume()` call の終了を表し、`Finished` は通常の Worker completion を意味する。現在の immediate replay は `interrupted` を使うため focused behavior は通るが、durable session/audit stream が cancel 後に normal `Finished` run を記録してしまう。
|
||||
- Ticket の invariant は cancel を explicit typed lifecycle semantics で表現することなので、typed paused-cancel / abandoned-turn lifecycle record を追加するか、log schema / consumers / tests を更新して durable history が normal `Finished` run を主張しないようにする必要がある。
|
||||
|
||||
Validation performed:
|
||||
- `cargo test -p tui ctrl_x -- --nocapture` passed
|
||||
- `cargo test -p pod paused_cancel_abandons_resume_and_next_input_is_fresh_run -- --nocapture` passed
|
||||
- `git diff --check 5954021c..90b1a1fc` passed
|
||||
- `cargo fmt --check` passed
|
||||
- `git status --short` clean
|
||||
|
||||
Rationale:
|
||||
- TUI key handling separation は正しい。`Paused` の `Ctrl+X` は `Method::Cancel`、`Idle` は `Shutdown` のまま、`Ctrl+C` quit/pause behavior も変更されていない。
|
||||
- controller test は Pod を実際に `Paused` にし、cancel 後の `Resume` rejection と次入力の fresh `Run` を確認している。
|
||||
- blocker は persisted lifecycle representation。functional state reset は実装されているが、session log が abandoned paused turn を normal finished run として記録している点が durable semantics と不一致。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T13:49:36Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report update after review request
|
||||
|
||||
Reviewer-requested change addressed in implementation worktree:
|
||||
- `/home/hare/Projects/yoi/.worktree/00001KVSMJJNV-paused-ctrlx-cancel`
|
||||
- branch `work/00001KVSMJJNV-paused-ctrlx-cancel`
|
||||
|
||||
New commit:
|
||||
- `8c8fb014 fix: log paused cancel lifecycle explicitly`
|
||||
|
||||
Change summary:
|
||||
- `crates/session-store/src/segment_log.rs`: typed `LogEntry::PausedTurnAbandoned { ts }` を追加し、replay / `collect_state` で `last_run_interrupted` を clear するようにした。JSON round-trip と replay semantics の tests を追加。
|
||||
- `crates/pod/src/pod.rs`: paused cancel cleanup で fake `RunCompleted { result: Finished }` を記録せず、`PausedTurnAbandoned` を記録するように変更。
|
||||
- `crates/pod/src/segment_log_sink.rs`: lifecycle コメントを更新。
|
||||
- `crates/pod/tests/controller_test.rs`: paused cancel が `PausedTurnAbandoned` を記録し、normal finished run としては記録されないことを確認する assertion を追加。
|
||||
|
||||
Validation run by Orchestrator:
|
||||
- `cargo test -p session-store paused_turn_abandoned -- --nocapture`
|
||||
- `cargo test -p pod paused_cancel_abandons_resume_and_next_input_is_fresh_run -- --nocapture`
|
||||
- `cargo test -p tui ctrl_x -- --nocapture`
|
||||
- `git diff --check 5954021c..HEAD`
|
||||
|
||||
Next:
|
||||
- Reviewer に再 review を依頼する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: reviewer-00001KVSMJJNV-ctrlx-cancel at: 2026-06-23T13:53:16Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
Findings:
|
||||
- なし。
|
||||
|
||||
Validation performed by Reviewer:
|
||||
- `cargo test -p session-store paused_turn_abandoned -- --nocapture` — passed
|
||||
- `cargo test -p pod paused_cancel_abandons_resume_and_next_input_is_fresh_run -- --nocapture` — passed
|
||||
- `cargo test -p tui ctrl_x -- --nocapture` — passed
|
||||
- `git diff --check 5954021c..HEAD` — passed
|
||||
- `cargo fmt --check` — passed
|
||||
- `git status --short` — clean
|
||||
|
||||
Rationale:
|
||||
- prior blocker は解消済み。`Pod::cancel_paused_turn()` は fake `RunCompleted { Finished, interrupted: false }` ではなく `LogEntry::PausedTurnAbandoned` を記録する。
|
||||
- typed lifecycle entry は session log schema / replay に含まれ、`last_run_interrupted` を clear するため restore 後も resume 不可になる。
|
||||
- tests は JSON kind `paused_turn_abandoned`、replay semantics、explicit lifecycle log、fake normal-finished run が残らないことを確認している。
|
||||
- TUI acceptance criteria も満たしている。Paused `Ctrl+X` は `Method::Cancel`、Idle `Ctrl+X` は shutdown のまま、Running cancel は queued input clear を含む既存 behavior を維持している。
|
||||
- controller test は Paused 到達、cancel 後 Idle、resume rejection、cancel/resume で追加 LLM request が発生しないこと、次入力が fresh run になることを確認している。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T13:56:05Z from: inprogress to: done reason: implementation_review_validation_passed field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation, review, and post-merge validation completed in orchestration worktree.
|
||||
|
||||
Evidence:
|
||||
- Implementation commits merged into orchestration: `90b1a1fc`, `8c8fb014`, merge commit `76c80054`.
|
||||
- Reviewer approved after requested lifecycle-log fix.
|
||||
- Validation on merged orchestration branch passed:
|
||||
- `cargo test -p session-store paused_turn_abandoned -- --nocapture`
|
||||
- `cargo test -p pod paused_cancel_abandons_resume_and_next_input_is_fresh_run -- --nocapture`
|
||||
- `cargo test -p tui ctrl_x -- --nocapture`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check HEAD~1..HEAD`
|
||||
|
||||
Next:
|
||||
- Close Ticket with resolution, then fast-forward merge target if safe.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: hare at: 2026-06-23T13:56:16Z from: done to: closed reason: closed field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を closed にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: close author: hare at: 2026-06-23T13:56:16Z status: closed -->
|
||||
|
||||
## 完了
|
||||
|
||||
Ticket 00001KVSMJJNV は完了。
|
||||
|
||||
実装内容:
|
||||
- TUI Console の `Paused` 状態で `Ctrl+X` を TUI/Pod shutdown ではなく `Method::Cancel` として扱うようにした。
|
||||
- `Idle` の `Ctrl+X` shutdown behavior と、`Running` の cancel behavior は維持した。
|
||||
- paused cancel 後に resume 可能な interrupted state が残らず、次の入力が fresh run になるよう controller / Pod lifecycle を更新した。
|
||||
- paused cancel を normal `RunCompleted { Finished }` として永続化せず、typed session log entry `LogEntry::PausedTurnAbandoned { ts }` として記録するようにした。
|
||||
- replay / restore で `PausedTurnAbandoned` が `last_run_interrupted` を clear するようにした。
|
||||
- focused tests を追加・更新し、TUI key handling、controller behavior、session log JSON/replay semantics、fake normal-finished run が残らないことを確認した。
|
||||
|
||||
主要 commits:
|
||||
- `90b1a1fc tui: cancel paused turns with ctrl-x`
|
||||
- `8c8fb014 fix: log paused cancel lifecycle explicitly`
|
||||
- `76c80054 merge: 00001KVSMJJNV paused ctrl-x cancel`
|
||||
|
||||
Review:
|
||||
- 初回 review は lifecycle log semantics の不一致で request_changes。
|
||||
- `PausedTurnAbandoned` による typed lifecycle representation を追加後、Reviewer が approve。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p session-store paused_turn_abandoned -- --nocapture`
|
||||
- `cargo test -p pod paused_cancel_abandons_resume_and_next_input_is_fresh_run -- --nocapture`
|
||||
- `cargo test -p tui ctrl_x -- --nocapture`
|
||||
- `cargo fmt --check`
|
||||
- `git diff --check HEAD~1..HEAD`
|
||||
|
||||
Merge note:
|
||||
- orchestration branch で実装・Ticket 記録・close resolution をまとめ、merge target へ fast-forward 予定。
|
||||
|
||||
---
|
||||
@@ -0,0 +1,37 @@
|
||||
# 実装報告: 00001KVTNAY20
|
||||
|
||||
## 変更概要
|
||||
|
||||
- `client::spawn` に `PodProcessLaunchConfig` と `PodProcessLaunchOptions` を導入し、低レベルの Pod プロセス起動設定から Ticket role marker を分離した。
|
||||
- Ticket role 起動は `TicketRoleLaunchPlan::spawn_options()` 経由で hidden CLI marker を渡す形にし、`TicketRoleLaunchResult` に Run 受理証跡 (`TicketRoleLaunchAcceptanceEvidence`) を追加した。
|
||||
- Workspace server の `LocalRuntimeBridge` を `WorkspaceWorkerRuntime` trait の実装として整理し、hosts/workers 一覧、worker lookup、spawn/stop typed request/result、将来の proxy/stream 接続点を型として追加した。
|
||||
- Workspace 側の spawn request shape は policy intent ベースにし、browser/API caller から raw `workspace_root` / `cwd` / executable path / raw profile selector を受け取らない形にした。
|
||||
- Dashboard/TUI 側の直接 spawn 呼び出しを新しい low-level config/options 分離に追従した。
|
||||
|
||||
## 変更ファイル
|
||||
|
||||
- `crates/client/src/lib.rs`
|
||||
- `crates/client/src/spawn.rs`
|
||||
- `crates/client/src/ticket_role.rs`
|
||||
- `crates/tui/src/dashboard/mod.rs`
|
||||
- `crates/tui/src/spawn.rs`
|
||||
- `crates/workspace-server/src/hosts.rs`
|
||||
- `crates/workspace-server/src/server.rs`
|
||||
|
||||
## 検証結果
|
||||
|
||||
- `cargo test -p yoi-workspace-server`: 成功
|
||||
- `cargo check -p yoi`: 成功
|
||||
- `cd web/workspace && deno task check && deno task build`: 成功
|
||||
- `cargo test -p client`: 成功(追加確認)
|
||||
- `git diff --check`: 成功
|
||||
|
||||
## コミット
|
||||
|
||||
- 実装コミット: `217a4828d73ab553b5406cc7e22e43b1ec7be48e`
|
||||
|
||||
## 残リスク / 非ゴールとして残したもの
|
||||
|
||||
- `WorkspaceWorkerRuntime::spawn_worker` / `stop_worker` は typed boundary と request/result を用意した段階で、実際の Worker operation UI 完成、stream proxy、remote Host protocol、認可/権限、registry locking までは実装していない。
|
||||
- low-level launcher は trusted in-process resolver からの追加 CLI args を受け取れるが、Ticket role などのドメイン概念は `PodProcessLaunchConfig` からは除外している。
|
||||
- TS 型生成やフロントエンド API surface の追加は本 Ticket の非ゴールとして変更していない。
|
||||
@@ -0,0 +1,2 @@
|
||||
{"id":"orch-plan-20260623-192711-1","ticket_id":"00001KVTNAY20","kind":"accepted_plan","accepted_plan":{"summary":"Ticket 00001KVTNAY20 は implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` と branch `work/00001KVTNAY20-worker-runtime-spawn` で、Workspace Worker runtime spawn abstraction を実装し、routing record の IntentPacket を基準に coder/reviewer sibling loop へ進める。root/original workspace では git/read/write/validate/merge/cleanup を行わない。","branch":"work/00001KVTNAY20-worker-runtime-spawn","worktree":"/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn","role_plan":"Orchestrator: acceptance/routing, worktree creation, final integration/validation/cleanup. Coder: implementation in dedicated child worktree with narrow write scope. Reviewer: read-only review by default against recorded IntentPacket, validation evidence, and diff. Orchestrator handles merge into orchestration branch after reviewer approval."},"author":"yoi-orchestrator","at":"2026-06-23T19:27:11Z"}
|
||||
{"id":"orch-plan-20260623-193340-2","ticket_id":"00001KVTNAY20","kind":"waiting_capacity_note","note":"Coder sibling execution is temporarily blocked by runtime/provider startup failures, not by Ticket requirements. `builtin:coder` started but both initial run and retry failed with provider API error `Unsupported content type`; alternate `inherit` / `builtin:default` / `builtin:companion` recovery attempts did not produce a socket within 10s. Worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` remains clean at orchestration commit `b8388655`; no implementation diff exists yet. Human/tooling follow-up is needed before continuing multi-agent implementation, unless Orchestrator is explicitly authorized to implement directly.","author":"yoi-orchestrator","at":"2026-06-23T19:33:40Z"}
|
||||
@@ -0,0 +1,158 @@
|
||||
---
|
||||
title: 'Abstract Workspace Worker runtime spawn operations'
|
||||
state: 'done'
|
||||
created_at: '2026-06-23T16:34:39Z'
|
||||
updated_at: '2026-06-24T10:35:01Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-23T19:25:09Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Workspace web / Workspace backend から Worker を起動・停止・操作する UI/API を作るには、現在 read-only live view として実装されている runtime bridge を、Worker 操作も扱える backend abstraction に拡張する必要がある。
|
||||
|
||||
現状:
|
||||
|
||||
- `crates/workspace-server/src/hosts.rs` の `LocalRuntimeBridge` は local runtime metadata を読んで `HostSummary` / `WorkerSummary` を返す read-only bridge である。
|
||||
- `/api/hosts`、`/api/workers`、`/api/hosts/{host_id}/workers` はこの bridge を直接使っている。
|
||||
- Worker 起動の最終境界は `yoi pod [POD_OPTIONS]` process launch である。
|
||||
- 既存の `client::spawn::SpawnConfig` は `yoi pod` 起動 options の typed 表現に近いが、`ticket_role` のような Ticket/Orchestration domain の情報も混ざっている。
|
||||
- Workspace backend には Worker spawn / stop / protocol proxy の抽象境界がまだない。
|
||||
- Worker 起動を web backend から実装する際、workspace root / cwd / pod name / profile / role-session claim の経路が TUI とズレると、Panel 表示や workspace 所属判定が壊れる。
|
||||
|
||||
この Ticket では、Workspace backend から Worker spawn 操作を実装する前段として、**Pod process 起動境界**と**Ticket / Orchestration intent 境界**を分離して整理する。低レベル起動は Ticket system を知らず、Ticket/Orchestration 情報は上位 resolver / launch policy が低レベル config へ落とす。
|
||||
|
||||
## 要件
|
||||
|
||||
### Layering / responsibility split
|
||||
|
||||
起動系は少なくとも以下の層に分ける。
|
||||
|
||||
1. **Pod process launch layer**
|
||||
- `yoi pod [POD_OPTIONS]` を起動する唯一の低レベル境界。
|
||||
- Ticket / Orchestration / Role / TicketId を直接知らない。
|
||||
- `workspace_root`、`pod_name`、`profile`、`manifest`、`project`、`store`、`cwd`、`initial_input`、`workflow`、`require_pod_state` のような process 起動 options だけを扱う。
|
||||
2. **Worker runtime layer**
|
||||
- Workspace backend / API から見える Worker 操作境界。
|
||||
- hosts/workers live view、worker lookup、spawn/stop/protocol proxy の entrypoint を持つ。
|
||||
- API intent を低レベル Pod process launch config へ解決する。
|
||||
3. **Ticket / Orchestration resolver layer**
|
||||
- Ticket ID、Ticket role、Orchestrator/Coder/Reviewer といった workflow domain を扱う。
|
||||
- Role/Profile/Workflow/Ticket context を解決し、低レベル Pod process launch config と必要な launch policy / prompt input を作る。
|
||||
- Ticket/Orchestration 情報を低レベル launcher に直接漏らさない。
|
||||
|
||||
### Pod process launch abstraction
|
||||
|
||||
- `SpawnConfig` をそのまま Workspace backend API の入力として扱わない。
|
||||
- 低レベルの起動 config は Ticket/Orchestration domain を持たない形に整理する。
|
||||
- 既存 `SpawnConfig` を改名/分割するか、別の `PodProcessLaunchConfig` / `PodLaunchOptions` を導入する。
|
||||
- `ticket_role` は低レベル process config から分離する。
|
||||
- 必要なら `PodLaunchPolicy` / `ProfileLaunchPolicy` のような別引数/別 layer に移す。
|
||||
- `--ticket-role` は現状 hidden CLI marker として存在してよいが、汎用 `yoi pod` 起動 config の概念には含めない。
|
||||
- 低レベル launcher は `Command::new("yoi")` 相当の process 起動と acceptance evidence 取得に責務を限定する。
|
||||
- TUI/Panel、SpawnPod tool、Workspace backend はこの低レベル launcher を共有できるようにする。
|
||||
|
||||
### Worker runtime abstraction
|
||||
|
||||
- `LocalRuntimeBridge` 相当の read-only live view を、Worker 操作用の抽象境界へ整理する。
|
||||
- trait 名は実装時に決めてよいが、概念としては `WorkerRuntime` / `WorkspaceWorkerRuntime` / `HostRuntime` のような境界を作る。
|
||||
- 最低限、以下の責務を同じ abstraction から扱えるようにする。
|
||||
- hosts list
|
||||
- workers list
|
||||
- worker detail / lookup
|
||||
- worker spawn request
|
||||
- worker stop request
|
||||
- 将来の protocol method proxy / event stream の接続点
|
||||
- v0 では local implementation のみでよい。
|
||||
- 例: `LocalPodRuntime` / `LocalWorkspaceRuntime`。
|
||||
- 将来 Host protocol / remote worker backend を差し替えられるよう、Workspace API handler が concrete local implementation に密結合しすぎない形にする。
|
||||
|
||||
### Spawn operation abstraction
|
||||
|
||||
- Backend API から Worker を起動するための typed request / result を設計する。
|
||||
- Browser から `workspace_root` / `cwd` / executable path / raw profile selector を自由入力させない。
|
||||
- Frontend/API request は intent を中心にする。
|
||||
- 例: generic worker profile launch、orchestrator start、ticket coder/reviewer start。
|
||||
- ticket_id が必要な operation は path または typed field から受ける。
|
||||
- Backend / resolver が以下を解決する。
|
||||
- canonical workspace root
|
||||
- process cwd
|
||||
- pod name
|
||||
- profile / manifest / project
|
||||
- initial input / workflow
|
||||
- optional launch policy
|
||||
- role-session claim
|
||||
- Orchestrator の dedicated worktree 起動では、runtime workspace identity と cwd を混同しない。
|
||||
- `workspace_root` は original/main workspace
|
||||
- `cwd` は orchestration worktree
|
||||
- Coder / Reviewer / Orchestrator の Ticket-specific 起動経路は、低レベル Pod process launch config を生成する上位 resolver として扱う。
|
||||
- Workspace backend が独自に `Command::new("yoi")` を組み立てて挙動を分岐させない。
|
||||
|
||||
### Ticket / Orchestration information boundary
|
||||
|
||||
- Ticket ID、Ticket role、Orchestration role は低レベル `PodProcessLaunchConfig` に入れない。
|
||||
- Ticket/Orchestration resolver は以下を出力する。
|
||||
- low-level Pod process launch config
|
||||
- optional profile/launch policy
|
||||
- role-session claim metadata
|
||||
- model-visible initial input / workflow selection
|
||||
- Role は Profile と同一視しない。
|
||||
- Role は workflow 上の責務。
|
||||
- Profile は Pod recipe。
|
||||
- Role/Profile/Ticket の対応は上位 resolver の責務であり、低レベル launcher の責務ではない。
|
||||
- Role を使わない generic Worker 起動では Ticket/Orchestration 情報を一切要求しない。
|
||||
|
||||
### API surface planning
|
||||
|
||||
- 実装する API はこの Ticket で確定しなくてもよいが、初期案として以下を検討する。
|
||||
- generic: `POST /api/workers/spawn`
|
||||
- operation: `POST /api/workers/{worker_id}/stop`
|
||||
- orchestration: `POST /api/orchestrator/start`
|
||||
- ticket-specific: `POST /api/tickets/{ticket_id}/workers`
|
||||
- 起動 operation は HTTP command として扱う。
|
||||
- 状態観測 / stream / transcript は後続 Ticket で SSE/WebSocket を検討する。
|
||||
- spawn success は process start だけでなく、socket/connect/snapshot 等の acceptance evidence を持つこと。
|
||||
|
||||
### Role-session / Panel integration
|
||||
|
||||
- Backend spawn でも Panel が Worker を見つけられるようにする。
|
||||
- 起動成功後に必要な local role-session claim を作る、または既存 helper を共有する。
|
||||
- Runtime registry、Pod metadata、role-session registry のどれを authority / hint として扱うかを明確にする。
|
||||
- stale/missing/already-running の扱いを typed error として返す。
|
||||
|
||||
### Safety / authority boundary
|
||||
|
||||
- Browser は local Unix socket path や runtime registry path を直接知らない。
|
||||
- Backend が worker identity を解決し、対象 Worker が current Workspace から見えることを確認する。
|
||||
- user permission model はこの Ticket の scope 外だが、将来挟める場所を backend abstraction に残す。
|
||||
- Raw Pod protocol を browser から受ける場合でも、backend が最低限の method allow/block を挟める構造にする。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Worker operation UI の完成。
|
||||
- WebSocket/SSE event stream の完成。
|
||||
- Full permission / user auth model の設計。
|
||||
- Remote Host protocol implementation。
|
||||
- Pod protocol TypeScript 型生成の実装。
|
||||
- Workspace identity `.yoi/workspace.toml` 実装。
|
||||
- StopPod / registry locking の追加修正。
|
||||
- Ticket/Orchestration domain を廃止すること。
|
||||
- `--ticket-role` hidden CLI marker の即時削除。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
この Ticket は planning から開始する。ready に進める前に以下を満たす。
|
||||
|
||||
- Workspace backend runtime abstraction の責務境界が明文化されている。
|
||||
- `yoi pod [POD_OPTIONS]` process launch 境界と Ticket/Orchestration resolver 境界が分離されている。
|
||||
- 低レベル Pod process launch config が Ticket ID / Ticket role / Orchestration role を直接持たない方針が明記されている。
|
||||
- 既存 `SpawnConfig` の `ticket_role` をどう分離するかが決まっている。
|
||||
- 現在の `LocalRuntimeBridge` をどう trait / service に置き換えるかが決まっている。
|
||||
- Worker spawn request / result の typed shape が設計されている。
|
||||
- Orchestrator / Coder / Reviewer の起動時に `workspace_root` と `cwd` をどう決めるかが明記されている。
|
||||
- TUI/Panel、SpawnPod tool、Workspace backend が低レベル Pod process launcher を共有する方針が明記されている。
|
||||
- Ticket/Orchestration resolver が低レベル launch config・launch policy・role-session claim を生成する方針が明記されている。
|
||||
- Backend API endpoint の初期案が整理されている。
|
||||
- role-session claim / Pod metadata / runtime registry との連携方針が明記されている。
|
||||
- 実装まで含める場合は `cargo test -p yoi-workspace-server`、`cargo check -p yoi`、`cd web/workspace && deno task check && deno task build`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,291 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-23T16:34:39Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-23T18:26:48Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-23T18:26:48Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-23T19:25:09Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-23T19:26:52Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- Ticket body は Workspace backend の Worker runtime / Pod process launch / Ticket-Orchestration resolver の境界分離、typed spawn request/result、role-session 連携、安全境界、non-goals、validation を具体的に列挙している。
|
||||
- `TicketRelationQuery` では blocking relation は 0 件、`TicketOrchestrationPlanQuery` では既存の ordering / blocker / conflict / accepted-plan 記録は 0 件だった。
|
||||
- orchestration worktree は `## orchestration` で dirty changes なし、既存 implementation worktree は別 Ticket `00001KVSMJJNV-paused-ctrlx-cancel` と orchestration worktree のみで、この Ticket 用 worktree/branch はまだ無い。
|
||||
- `crates/client/src/spawn.rs`、`crates/client/src/ticket_role.rs`、`crates/workspace-server/src/hosts.rs`、`crates/workspace-server/src/server.rs` を bounded に確認し、Ticket に書かれた現状認識と実装対象の code map が一致している。残る不確実性は local tactic / bounded investigation に収まる。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`、`thread.md`。thread は create、planning->ready、ready->queued のみで、未解決 blocker は記録されていない。
|
||||
- related Ticket / orchestration plan records: relation 0 件、orchestration plan 0 件。
|
||||
- code paths: `crates/client/src/spawn.rs`、`crates/client/src/ticket_role.rs`、`crates/workspace-server/src/hosts.rs`、`crates/workspace-server/src/server.rs`。
|
||||
- workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` の `git status --short --branch` は clean な `## orchestration`。visible Pods は `yoi` peer と current `yoi-orchestrator` のみ。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Workspace backend から Worker spawn/stop/proxy を実装できる前段として、低レベル Pod process launch 境界と Worker runtime 境界、Ticket/Orchestration resolver 境界を分離し、既存 read-only `LocalRuntimeBridge` を操作境界へ拡張できる形に整理する。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- 低レベル Pod process launch layer は `yoi pod [POD_OPTIONS]` 起動だけを扱い、Ticket ID / Ticket role / Orchestration role を直接知らない。
|
||||
- `SpawnConfig` をそのまま Workspace backend API 入力にしない。`ticket_role` は低レベル process config から分離する。
|
||||
- Browser/API から `workspace_root` / `cwd` / executable path / raw profile selector を自由入力させない。backend/resolver が canonical workspace root、cwd、pod name、profile、initial input、workflow、launch policy、role-session claim を解決する。
|
||||
- Orchestrator dedicated worktree 起動では runtime `workspace_root` と process `cwd` を混同しない。`workspace_root` は original/main workspace、`cwd` は orchestration worktree。
|
||||
- Workspace backend が独自に `Command::new("yoi")` を組み立てて分岐する設計にしない。共有可能な低レベル launcher / config / acceptance evidence 境界を使う。
|
||||
- この Ticket では Worker operation UI、SSE/WebSocket stream、full auth/permission、remote Host protocol、TypeScript protocol generation、Workspace identity `.yoi/workspace.toml`、StopPod/registry locking の追加修正は non-goal。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Workspace backend runtime abstraction の責務境界を code/docs/tests で追える形にする。
|
||||
- Pod process launch config と Ticket/Orchestration resolver 境界を分離し、低レベル config が Ticket/role/orchestration domain を持たないことを型・モジュール境界で示す。
|
||||
- `LocalRuntimeBridge` 相当を Worker runtime trait/service として整理し、hosts/workers list、worker lookup、spawn/stop request、将来 proxy/stream 接続点を表現できるようにする。
|
||||
- Worker spawn request/result の typed shape と acceptance evidence の扱いを導入する。
|
||||
- role-session claim / Pod metadata / runtime registry の連携方針を実装境界または明文化された設計として残す。
|
||||
- validation として少なくとも `cargo test -p yoi-workspace-server`、`cargo check -p yoi`、`cd web/workspace && deno task check && deno task build`、`git diff --check` を実施する。`nix build .#yoi --no-link` は変更量・依存/packaging 影響に応じて Orchestrator が最終判断する。
|
||||
|
||||
Implementation latitude:
|
||||
- trait / struct 名は Ticket の例示に縛られず、既存 module organization に沿ってよい。
|
||||
- `SpawnConfig` を rename/split するか、新規 `PodProcessLaunchConfig` / `PodLaunchOptions` を導入するかは coder が code map を見て選んでよい。
|
||||
- API endpoint の完全実装ではなく、backend abstraction と typed request/result の初期 shape / handler 接続点を優先してよい。
|
||||
- tests は既存 workspace-server/client test style に合わせて最小限でよい。
|
||||
|
||||
Escalate if:
|
||||
- Browser から raw local path / raw executable / raw profile selector を受ける必要が出る。
|
||||
- Ticket/Orchestration 情報を低レベル launcher に持たせないと実装できないと判断した場合。
|
||||
- workspace_root / cwd / runtime identity / role-session authority の境界を変える必要が出る。
|
||||
- public API endpoint shape をこの Ticket の初期案から大きく固定する必要が出る。
|
||||
- existing Panel/role-session semantics を破壊する変更が必要になる。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p yoi-workspace-server`
|
||||
- `cargo check -p yoi`
|
||||
- `cd web/workspace && deno task check && deno task build`
|
||||
- `git diff --check`
|
||||
- 必要に応じて `nix build .#yoi --no-link`
|
||||
|
||||
Current code map:
|
||||
- Primary: `crates/workspace-server/src/hosts.rs`, `crates/workspace-server/src/server.rs`, `crates/client/src/spawn.rs`, `crates/client/src/ticket_role.rs`。
|
||||
- Secondary if needed: workspace API/client integration, role-session helpers, Pod runtime command utilities, docs/resources prompts only when implementation requires。
|
||||
- Avoid: unrelated UI completion, broad permission model, remote Host protocol, root/original workspace operations。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- Ticket/role/orchestration fields leaking into the low-level launcher.
|
||||
- Workspace runtime abstraction becoming a UI-specific concrete local bridge instead of a backend boundary.
|
||||
- Browser/API accepting authority-bearing raw paths or executable/profile selectors.
|
||||
- `workspace_root` and `cwd` confusion for dedicated Orchestrator/Coder/Reviewer launches.
|
||||
- acceptance evidence treated as mere process start.
|
||||
- role-session claim / metadata / runtime registry authority and hint semantics left ambiguous.
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから、worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` を作成し、multi-agent-workflow で sibling coder/reviewer loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-23T19:27:22Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、blocking relation は 0 件、accepted plan は `orch-plan-20260623-192711-1` のみだった。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- orchestration worktree は clean な `## orchestration` で、この Ticket 用 implementation worktree/branch はまだ作成していない。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T19:30:10Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` と branch `work/00001KVTNAY20-worker-runtime-spawn` を作成した。
|
||||
- child worktree では sparse-checkout を設定し、tracked `.yoi` project records は見える一方で `.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVTNAY20-worker-runtime` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
- 初回 spawn は workspace root read scope が不足して失敗したため、implementation side effect は残さず scope を修正して再試行した。現在 reachable child Pod として起動済み。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T19:31:58Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration recovery:
|
||||
|
||||
- `yoi-coder-00001KVTNAY20-worker-runtime` は provider API error `Unsupported content type` で初回実行・再送とも assistant output を生成できなかった。
|
||||
- child worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` は実装差分なしで、last commit は routing acceptance commit `5a8bcebd ticket: accept worker runtime spawn task` のままだった。
|
||||
- 失敗 Pod は停止して scope を回収した。
|
||||
- 実装 side effect の回復として、同じ child worktree/branch を使い、別 profile で Coder role を再起動する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-23T19:33:48Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration blocked:
|
||||
|
||||
- Coder sibling execution is blocked by runtime/provider failures, not by Ticket requirements or repository state.
|
||||
- `builtin:coder` Pod `yoi-coder-00001KVTNAY20-worker-runtime` started, but both initial run and retry failed before assistant output with provider API error: `Unsupported content type`.
|
||||
- That Pod was stopped and scope reclaimed. child worktree status remained clean with no implementation diff.
|
||||
- Recovery attempts using `inherit` (`yoi-coder-00001KVTNAY20-worker-runtime-2`), `builtin:default` (`...-3`), and `builtin:companion` (`...-4`) did not produce sockets within 10s.
|
||||
- Worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` and branch `work/00001KVTNAY20-worker-runtime-spawn` are prepared and clean at orchestration commit `b8388655`.
|
||||
- `orch-plan-20260623-193340-2` に waiting-capacity note を残した。
|
||||
|
||||
Next action:
|
||||
- Coder Pod/profile/provider startup issue の解消後に同じ worktree/branch で multi-agent workflow を再開する。
|
||||
- あるいは人間が明示的に Orchestrator direct implementation を許可する場合のみ、Orchestrator がこの child worktree で実装へ進む。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: hare at: 2026-06-24T10:26:04Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
# 実装報告: 00001KVTNAY20
|
||||
|
||||
## 変更概要
|
||||
|
||||
- `client::spawn` に `PodProcessLaunchConfig` と `PodProcessLaunchOptions` を導入し、低レベルの Pod プロセス起動設定から Ticket role marker を分離した。
|
||||
- Ticket role 起動は `TicketRoleLaunchPlan::spawn_options()` 経由で hidden CLI marker を渡す形にし、`TicketRoleLaunchResult` に Run 受理証跡 (`TicketRoleLaunchAcceptanceEvidence`) を追加した。
|
||||
- Workspace server の `LocalRuntimeBridge` を `WorkspaceWorkerRuntime` trait の実装として整理し、hosts/workers 一覧、worker lookup、spawn/stop typed request/result、将来の proxy/stream 接続点を型として追加した。
|
||||
- Workspace 側の spawn request shape は policy intent ベースにし、browser/API caller から raw `workspace_root` / `cwd` / executable path / raw profile selector を受け取らない形にした。
|
||||
- Dashboard/TUI 側の直接 spawn 呼び出しを新しい low-level config/options 分離に追従した。
|
||||
|
||||
## 変更ファイル
|
||||
|
||||
- `crates/client/src/lib.rs`
|
||||
- `crates/client/src/spawn.rs`
|
||||
- `crates/client/src/ticket_role.rs`
|
||||
- `crates/tui/src/dashboard/mod.rs`
|
||||
- `crates/tui/src/spawn.rs`
|
||||
- `crates/workspace-server/src/hosts.rs`
|
||||
- `crates/workspace-server/src/server.rs`
|
||||
|
||||
## 検証結果
|
||||
|
||||
- `cargo test -p yoi-workspace-server`: 成功
|
||||
- `cargo check -p yoi`: 成功
|
||||
- `cd web/workspace && deno task check && deno task build`: 成功
|
||||
- `cargo test -p client`: 成功(追加確認)
|
||||
- `git diff --check`: 成功
|
||||
|
||||
## コミット
|
||||
|
||||
- 実装コミット: `217a4828d73ab553b5406cc7e22e43b1ec7be48e`
|
||||
|
||||
## 残リスク / 非ゴールとして残したもの
|
||||
|
||||
- `WorkspaceWorkerRuntime::spawn_worker` / `stop_worker` は typed boundary と request/result を用意した段階で、実際の Worker operation UI 完成、stream proxy、remote Host protocol、認可/権限、registry locking までは実装していない。
|
||||
- low-level launcher は trusted in-process resolver からの追加 CLI args を受け取れるが、Ticket role などのドメイン概念は `PodProcessLaunchConfig` からは除外している。
|
||||
- TS 型生成やフロントエンド API surface の追加は本 Ticket の非ゴールとして変更していない。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVTNAY20-worker-runtime at: 2026-06-24T10:33:54Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
Read-only で Ticket `00001KVTNAY20`、implementation report、`a729d686..HEAD` の差分を確認した。ファイル変更・Ticket review 記録・merge/cleanup は reviewer では行っていない。
|
||||
|
||||
確認した主な点:
|
||||
- 低レベル Pod launcher は `crates/client/src/spawn.rs` の `PodProcessLaunchConfig` / options に分離され、Ticket/role/orchestration 固有の型や field は入っていない。`--workspace` と process `cwd` も別 field のまま扱われている。
|
||||
- Ticket role 起動は `crates/client/src/ticket_role.rs` 側に寄せられ、role/profile/workflow/prompt/初回 `Run` の組み立ては launcher ではなく role 層で処理されている。
|
||||
- 起動成功は単なる process start ではなく、既存 socket readiness に加えて Ticket role launch では `Method::Run` 送信後の `UserMessage` / `InvokeStart(UserSend)` / `TurnStart` を待つ形になっている。
|
||||
- Workspace server 側は `WorkspaceWorkerRuntime` trait と `WorkerSpawnRequest` / `WorkerStopRequest` / `WorkerProtocolProxyRequest` を導入し、現在の local 実装は Pod metadata read boundary + unsupported lifecycle operation として明示されている。Browser/API request shape に `workspace_root` / `cwd` / executable path / raw profile selector は受けていない。
|
||||
- Dedicated Orchestrator launch では runtime `workspace_root` と process `cwd` を混同しないテストが追加されており、original workspace と orchestration checkout が分離されている。
|
||||
- 非ゴールである実 scheduler、E2E、merge/cleanup automation 等の scope creep は入っていない。
|
||||
|
||||
Validation evidence:
|
||||
- reviewer は read-only 制約のため build/test は再実行していない。
|
||||
- 実装報告の検証結果として `cargo test -p yoi-workspace-server`、`cargo check -p yoi`、`cd web/workspace && deno task check && deno task build`、`cargo test -p client`、`git diff --check` の成功を確認した。
|
||||
- reviewer 側では read-only な `git diff --check a729d686..HEAD` を実行し、問題なし。
|
||||
|
||||
Non-blocking notes:
|
||||
- `WorkerSpawnRequest` はまだ実 endpoint 未接続かつ local runtime では `Unsupported` なのでこの Ticket では問題ない。今後実装時は `requested_worker_name` を backend 側で厳格に validate し、Browser 由来の値を Pod authority として扱わないことを明示すると安全。
|
||||
- `launch_ticket_role_pod` の acceptance 待ちは fresh spawn 前提では妥当。将来既存 Pod restore/競合を扱う場合は、connect-time `Snapshot`/`Alert` の drain と「送信した Run に対応する evidence」の対応付けをより強くするとよい。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T10:34:55Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder retry `yoi-coder-00001KVTNAY20-worker-runtime-retry1` が完走し、implementation branch `work/00001KVTNAY20-worker-runtime-spawn` に実装を commit した。
|
||||
- Reviewer `yoi-reviewer-00001KVTNAY20-worker-runtime` は read-only review で `approve`。低レベル launcher と Ticket/role/orchestration resolver の分離、Workspace runtime abstraction、raw authority input 非受理、`workspace_root`/`cwd` 分離、acceptance evidence、scope creep なしを確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVTNAY20-worker-runtime-spawn` を merge 済み。
|
||||
- merge commit: `97555bb5 merge: 00001KVTNAY20 worker runtime spawn`
|
||||
- implementation commit: `217a4828 feat: abstract worker runtime spawn boundary`
|
||||
- implementation report commit: `d62ab6e1 docs: record worker runtime implementation report`
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo test -p yoi-workspace-server`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `cd web/workspace && deno task check`: success
|
||||
- `cd web/workspace && deno task build`: success
|
||||
- `git diff --check`: success
|
||||
|
||||
Notes:
|
||||
- Reviewer non-blocking note: future actual spawn endpoint should validate any requested worker name server-side and avoid treating Browser-provided values as Pod authority.
|
||||
- Reviewer non-blocking note: future restore/competition handling may need stronger association between a sent `Run` and acceptance evidence after connect-time `Snapshot`/`Alert` drain.
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T10:35:01Z from: inprogress to: done reason: merged_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `97555bb5 merge: 00001KVTNAY20 worker runtime spawn`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration` succeeded:
|
||||
- `cargo test -p yoi-workspace-server`
|
||||
- `cargo check -p yoi`
|
||||
- `cd web/workspace && deno task check`
|
||||
- `cd web/workspace && deno task build`
|
||||
- `git diff --check`
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
title: 'Planning Ticket API and UI without queue operations'
|
||||
state: 'planning'
|
||||
created_at: '2026-06-23T19:41:51Z'
|
||||
updated_at: '2026-06-23T19:41:51Z'
|
||||
assignee: null
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Ticket 管理 UI を作るにあたり、最初から DB migration や Queue 操作まで含めると authority 境界が大きくなりすぎる。現行の Ticket authority は `.yoi/tickets/<ticket-id>/` の flat file backend であり、Workspace server 側にも Ticket 用 SQLite schema の器はあるが、現時点では authority ではない。
|
||||
|
||||
この Ticket では migration を行わず、まず Workspace backend に Ticket 操作用 API を整備し、その API を操作する最小 UI を実装する。対象は Planning Ticket の作成・確認に限定し、`ready -> queued` の Queue 操作や Orchestrator 起動には踏み込まない。
|
||||
|
||||
## 目的
|
||||
|
||||
- Workspace web から Ticket を確認し、Planning 状態の Ticket を作成できるようにする。
|
||||
- UI は backend API を通じて Ticket を操作し、frontend が `.yoi/tickets` の内部ファイル構造や authority path に依存しないようにする。
|
||||
- 将来 DB authority / migration に進む余地を残しつつ、この Ticket では現行 file backend を正として扱う。
|
||||
|
||||
## 要件
|
||||
|
||||
### Backend API
|
||||
|
||||
- Workspace server に Ticket 管理用 API を追加または整理する。
|
||||
- v0 では現行 `LocalTicketBackend` / project record reader を authority として使い、DB migration はしない。
|
||||
- API は少なくとも以下を扱う。
|
||||
- Ticket 一覧取得
|
||||
- Ticket 詳細取得
|
||||
- Planning 状態の Ticket 作成
|
||||
- 作成 API は title と本文/背景/受け入れ条件などの必要最小限の入力を受け、canonical Ticket ID を返す。
|
||||
- frontend から raw `.yoi/tickets` path や内部 artifact path を直接指定させない。
|
||||
- Ticket ID は canonical ID のみを扱い、title slug や legacy alias を API contract にしない。
|
||||
- API の error は typed response として扱う。
|
||||
- invalid input
|
||||
- duplicate / conflict
|
||||
- backend unavailable
|
||||
- workspace not found / outside current workspace
|
||||
|
||||
### UI
|
||||
|
||||
- Workspace web に Ticket 管理画面または Ticket 作成導線を追加する。
|
||||
- v0 UI は Planning Ticket の作成までに限定する。
|
||||
- 作成フォームは最低限以下を扱う。
|
||||
- title
|
||||
- 背景 / 要件の本文
|
||||
- 受け入れ条件
|
||||
- 作成後は作成された canonical Ticket ID と状態を表示し、詳細画面または一覧へ反映する。
|
||||
- UI は API response を authority とし、frontend 側で Ticket file layout を再実装しない。
|
||||
|
||||
### Scope boundary
|
||||
|
||||
- Queue 操作は実装しない。
|
||||
- `ready -> queued`
|
||||
- Panel / Workspace UI からの Queue button
|
||||
- Orchestrator / Coder / Reviewer 起動
|
||||
- role-session claim 作成
|
||||
- Ticket DB migration は実装しない。
|
||||
- 既存 `.yoi/tickets` authority を変更しない。
|
||||
- 既存 Ticket CLI / Pod tool の挙動を壊さない。
|
||||
|
||||
### Safety / authority
|
||||
|
||||
- Browser は local path / runtime path / socket path を直接 authority として渡さない。
|
||||
- Workspace backend が current workspace の Ticket backend root を解決する。
|
||||
- Ticket 作成は current workspace の `.yoi/tickets` に限定する。
|
||||
- 将来 permission model を挟めるよう、API handler と backend operation の境界を分ける。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Ticket storage の DB migration。
|
||||
- SQLite `tickets` schema を authority に昇格すること。
|
||||
- Queue / ready / inprogress / close などの lifecycle mutation UI。
|
||||
- Orchestrator 起動、Worker spawn、role-session claim 連携。
|
||||
- Ticket relation / artifact / orchestration-plan 編集 UI。
|
||||
- SSE/WebSocket による live Ticket update。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- Workspace server に Ticket list/detail/create planning 用 API がある。
|
||||
- Planning Ticket 作成 API が canonical Ticket ID を返す。
|
||||
- 作成された Ticket は既存 `yoi ticket list/show` から確認できる。
|
||||
- Workspace web から Planning Ticket を作成できる。
|
||||
- UI から Queue 操作はできない。
|
||||
- DB migration や SQLite Ticket authority 化を行っていない。
|
||||
- `cargo test -p yoi-workspace-server` が通る。
|
||||
- `cargo check -p yoi` が通る。
|
||||
- `cd web/workspace && deno task check && deno task build` が通る。
|
||||
- `git diff --check` が通る。
|
||||
- `nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,7 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-23T19:41:51Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
@@ -0,0 +1,3 @@
|
||||
{"id":"orch-plan-20260624-092429-1","ticket_id":"00001KVWECEQG","kind":"do_not_parallelize","related_ticket":"00001KVTNAY20","note":"`00001KVWECEQG` と inprogress `00001KVTNAY20` はどちらも `LocalRuntimeBridge` / Workspace Worker runtime abstraction / runtime identity・cwd 境界を扱い、primary code surface が `crates/workspace-server/src/hosts.rs` と API handler 層で重なる。`00001KVTNAY20` は Coder runtime/provider blocker で実装未開始のまま child worktree を保持しているため、並列実装すると registry abstraction と spawn abstraction の境界を二重に固定する conflict risk が高い。先に `00001KVTNAY20` の blocker 解消または明示的な ordering/design decision が必要。","author":"yoi-orchestrator","at":"2026-06-24T09:24:29Z"}
|
||||
{"id":"orch-plan-20260624-092435-2","ticket_id":"00001KVWECEQG","kind":"waiting_capacity_note","note":"Queued routing was authorized, and the Ticket appears implementation-ready after bounded evidence checks, but current Coder sibling capacity is unavailable: prior inprogress Ticket `00001KVTNAY20` already attempted multi-agent startup and hit provider/startup failures (`Unsupported content type`, alternate profiles no socket). Because this Ticket overlaps the same Worker runtime abstraction surface and no Coder/Reviewer loop can currently run safely, leave `00001KVWECEQG` queued rather than accepting `queued -> inprogress`. Resume when Coder runtime is healthy or when a human explicitly authorizes Orchestrator direct implementation/order.","author":"yoi-orchestrator","at":"2026-06-24T09:24:35Z"}
|
||||
{"id":"orch-plan-20260624-103655-3","ticket_id":"00001KVWECEQG","kind":"accepted_plan","accepted_plan":{"summary":"`00001KVTNAY20` は done/merged/validated になったため、以前の do_not_parallelize/waiting-capacity blocker は解消済みとして扱う。`00001KVWECEQG` は dedicated worktree `/home/hare/Projects/yoi/.worktree/00001KVWECEQG-worker-runtime-registry` と branch `work/00001KVWECEQG-worker-runtime-registry` で Worker runtime registry / capability / overview abstraction を実装する。root/original workspace では git/read/write/validate/merge/cleanup を行わない。","branch":"work/00001KVWECEQG-worker-runtime-registry","worktree":"/home/hare/Projects/yoi/.worktree/00001KVWECEQG-worker-runtime-registry","role_plan":"Orchestrator: routing acceptance, worktree creation, final integration/validation/cleanup. Coder: implementation in dedicated child worktree with narrow write scope, using current `00001KVTNAY20` result as base. Reviewer: read-only review against recorded IntentPacket, diff, and validation evidence."},"author":"yoi-orchestrator","at":"2026-06-24T10:36:55Z"}
|
||||
@@ -0,0 +1,162 @@
|
||||
---
|
||||
title: 'Abstract Worker runtime registry and overview reporting'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T09:11:38Z'
|
||||
updated_at: '2026-06-24T11:15:13Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T09:22:55Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Workspace backend には現状 `LocalRuntimeBridge` があり、local Pod metadata から `HostSummary` / `WorkerSummary` を返す read-only live view として動いている。しかしこれは concrete local 実装に近く、将来の Backend internal runtime、local Pod runtime、remote / multi-machine runtime を同じ control plane から扱う抽象境界にはまだなっていない。
|
||||
|
||||
今後の Ticket / Worker 管理 UI では、Backend が Worker を直接 `yoi pod` や local metadata path として扱うのではなく、複数の Worker runtime を束ねる control plane になる必要がある。Companion / Intake / routing-only Orchestrator のような filesystem を必須としない Worker は Backend internal runtime で動かせるべきであり、Coder / Reviewer / build-heavy Worker は local / remote の filesystem-capable runtime に配置できるべきである。
|
||||
|
||||
また、Worker session を Backend が raw log として全量・恒久的に収集する設計にはしない。raw session / provider trace / detailed event stream は execution runtime 側の prune 可能な debug/source log とし、Backend は Worker run overview、usage aggregate、lifecycle event、Ticket / role / runtime link、artifact reference、failure summary のような後から使える durable projection を持つ。
|
||||
|
||||
この Ticket では、既存 `LocalRuntimeBridge` をレベル上げして、Workspace backend の Worker runtime registry / runtime abstraction として整理する。
|
||||
|
||||
## 目的
|
||||
|
||||
- Workspace backend が複数の Worker runtime を扱える抽象境界を持つ。
|
||||
- 既存 local Pod metadata read-only bridge を `LocalPodRuntime` 相当の runtime 実装として位置付ける。
|
||||
- Backend が runtime registry を持ち、API handler が concrete local bridge に直接依存しないようにする。
|
||||
- raw session を Backend authority にせず、overview / metrics / durable outcome を中心に扱う方針を型と API 境界に反映する。
|
||||
- 後続の spawn / stop / protocol proxy / remote runtime / internal runtime 実装に進める基盤を作る。
|
||||
|
||||
## 要件
|
||||
|
||||
### Worker runtime abstraction
|
||||
|
||||
- `LocalRuntimeBridge` をそのまま API handler から直接使う構造をやめ、Worker runtime trait / service 境界を導入する。
|
||||
- 概念名は実装時に決めてよいが、`WorkerRuntime` / `WorkspaceWorkerRuntime` / `RuntimeRegistry` / `WorkerRuntimeRegistry` のような責務が明確な名前にする。
|
||||
- v0 では少なくとも以下の read operations を抽象化する。
|
||||
- runtime / host list
|
||||
- runtime / host detail
|
||||
- worker list
|
||||
- worker detail / lookup
|
||||
- 後続 operation の接続点を型として残す。
|
||||
- spawn worker
|
||||
- stop worker
|
||||
- send input / interrupt / compact などの worker command routing
|
||||
- bounded transcript / debug session read
|
||||
- event stream / run overview stream
|
||||
- v0 で未実装の operation は unsupported として typed error を返せるようにする。
|
||||
|
||||
### Runtime registry
|
||||
|
||||
- Workspace backend は単一の concrete `LocalRuntimeBridge` ではなく、runtime registry 経由で Worker / Host を取得する。
|
||||
- registry は複数 runtime を保持できる構造にする。
|
||||
- backend internal runtime
|
||||
- local Pod runtime
|
||||
- future remote runtime
|
||||
- v0 では local Pod runtime のみ登録してよい。
|
||||
- runtime_id / host_id / worker_id は API contract 上 opaque id として扱う。
|
||||
- `pod_name` は local Pod runtime の implementation detail / display hint とし、外部操作の主キーにはしない。
|
||||
- API handler は runtime_id / worker_id を registry に解決させ、raw local path / socket path / metadata path を browser に出さない。
|
||||
|
||||
### Runtime capability model
|
||||
|
||||
- Runtime / Host detail は capability summary を返す。
|
||||
- 少なくとも以下のような区別ができること。
|
||||
- can_list_workers
|
||||
- can_get_worker
|
||||
- can_spawn_worker
|
||||
- can_stop_worker
|
||||
- can_accept_input
|
||||
- can_stream_events
|
||||
- can_read_bounded_transcript / debug session
|
||||
- has_workspace_fs
|
||||
- has_shell
|
||||
- has_git
|
||||
- supports_worktrees
|
||||
- supports_backend_internal_tools / ticket tools
|
||||
- Companion / Intake / routing-only Orchestrator は filesystem なし runtime でも動かせる、Coder / Reviewer は filesystem-capable runtime が必要、という placement 判断を後続で表現できる shape にする。
|
||||
|
||||
### Worker identity / visibility
|
||||
|
||||
- Worker identity は runtime scoped に扱う。
|
||||
- runtime_id
|
||||
- worker_id
|
||||
- optional active run id
|
||||
- optional active session id / segment id は implementation detail または debug field
|
||||
- Workspace UI の通常表示では current workspace から見える Worker だけを返す。
|
||||
- local Pod runtime では `PodMetadata.workspace_root` を current workspace root と比較して visibility を決める。
|
||||
- `cwd` と runtime workspace identity を混同しない。
|
||||
- dedicated Orchestrator worktree があっても、runtime workspace identity は original/main workspace root である。
|
||||
- workspace root が無い / 不一致 / metadata invalid な Worker は diagnostics または debug scope として扱い、通常 UI の authority を歪めない。
|
||||
|
||||
### Session / overview boundary
|
||||
|
||||
- Backend は raw session log を恒久 authority として持たない。
|
||||
- raw session / provider trace / verbose event stream は execution runtime 側に残し、runtime retention / prune 対象とする。
|
||||
- Backend が durable に持つものは以下を中心にする。
|
||||
- Worker run overview
|
||||
- lifecycle event
|
||||
- usage aggregate
|
||||
- Ticket / role / runtime / worker link
|
||||
- durable outcome summary
|
||||
- failure summary
|
||||
- artifact / report reference
|
||||
- Runtime interface は必要に応じて bounded transcript / debug session tail を読める接続点を持つが、これは debug / live UI 用であり Backend DB の durable authority ではない。
|
||||
- usage dashboard は raw session ingest ではなく、runtime からの usage event / aggregate を元に構築できる形にする。
|
||||
|
||||
### Backend internal runtime planning
|
||||
|
||||
- Backend internal runtime はこの Ticket で完全実装しなくてよいが、registry / capability / identity model がそれを表現できること。
|
||||
- Backend internal runtime は filesystem tool を前提にしない Worker 用とする。
|
||||
- Companion
|
||||
- Intake
|
||||
- Ticket planning / routing assistant
|
||||
- Dashboard assistant
|
||||
- Backend internal Worker は Ticket / Workspace API を tool として使う形を想定し、raw local filesystem authority を要求しない。
|
||||
|
||||
### Local Pod runtime migration
|
||||
|
||||
- 既存 `LocalRuntimeBridge` の read-only local metadata 実装を `LocalPodRuntime` 相当へ移す、または薄い adapter として registry に登録する。
|
||||
- 既存 API の挙動を壊さない。
|
||||
- `GET /api/hosts`
|
||||
- `GET /api/workers`
|
||||
- `GET /api/hosts/{host_id}/workers`
|
||||
- 追加可能であれば worker detail endpoint を追加する。
|
||||
- `GET /api/workers/{worker_id}`
|
||||
- `GET /api/hosts/{host_id}/workers/{worker_id}`
|
||||
- local Pod metadata の raw content / snapshot content / socket path は API response に出さない。
|
||||
|
||||
### API / error boundary
|
||||
|
||||
- API response は runtime registry 経由の typed response にする。
|
||||
- unknown runtime / host / worker は typed error として返す。
|
||||
- runtime unavailable、operation unsupported、worker not visible、invalid query は区別できるようにする。
|
||||
- Browser は local Unix socket path、runtime registry file path、Pod metadata path、raw session path を authority として渡さない。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Worker spawn / stop の本実装。
|
||||
- Remote runtime protocol の本実装。
|
||||
- Backend internal runtime で実際に LLM Worker を起動すること。
|
||||
- raw session 全量の Backend DB ingest。
|
||||
- Session log schema migration。
|
||||
- Ticket storage migration。
|
||||
- Worker operation UI の完成。
|
||||
- SSE/WebSocket event stream の完成。
|
||||
- Permission / auth model の完成。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
この Ticket は planning から開始する。ready に進める前に以下を満たす。
|
||||
|
||||
- Worker runtime / runtime registry / local Pod runtime の責務境界が明文化されている。
|
||||
- 既存 `LocalRuntimeBridge` をどう level-up / rename / adapter 化するかが決まっている。
|
||||
- Backend が複数 runtime を保持できる registry 構造の方針が決まっている。
|
||||
- runtime_id / host_id / worker_id の identity 方針が決まっている。
|
||||
- local Pod `pod_name` を external operation key にしない方針が明記されている。
|
||||
- Runtime capability model の最小 field が整理されている。
|
||||
- current workspace visibility と workspace_root / cwd の扱いが明記されている。
|
||||
- raw session を Backend durable authority にしない方針が明記されている。
|
||||
- Backend に残す Worker run overview / usage aggregate / lifecycle projection の方針が明記されている。
|
||||
- bounded transcript / debug session read は runtime-local optional operation とする方針が明記されている。
|
||||
- 既存 `/api/hosts` / `/api/workers` を registry 経由へ移す方針が明記されている。
|
||||
- 実装まで含める場合は `cargo test -p yoi-workspace-server`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,377 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T09:11:38Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T09:21:22Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T09:21:22Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T09:22:55Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T09:24:52Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: blocked_by_dependency_or_missing_authority
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- Ticket body は Worker runtime registry / overview reporting / runtime capability / identity / visibility / raw-session boundary / local Pod runtime migration を具体的に列挙しており、実装意図と受け入れ条件は implementation-ready に近い。
|
||||
- `TicketRelationQuery` では blocking relation は 0 件、初回 `TicketOrchestrationPlanQuery` では既存 plan record は 0 件だった。
|
||||
- ただし現在 `00001KVTNAY20` (`Abstract Workspace Worker runtime spawn operations`) が `inprogress` で、同じ `LocalRuntimeBridge` / Workspace Worker runtime abstraction / runtime identity・cwd 境界と `crates/workspace-server/src/hosts.rs` 周辺を扱っている。
|
||||
- `00001KVTNAY20` は multi-agent startup が provider/runtime error で停止しており、implementation worktree は clean だが Coder sibling capacity が実質利用できない状態である。
|
||||
- この Ticket を今 `queued -> inprogress` にすると、同じ runtime abstraction の registry 側と spawn 側を別 branch で同時に固定して conflict risk が高い。さらに Coder/Reviewer loop を起動できないため、acceptance 後に進められない。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `00001KVWECEQG` の item/thread。thread は create、planning->ready、ready->queued のみで未解決 planning question は記録されていない。
|
||||
- Relations / orchestration plan: `00001KVWECEQG` は relation 0 件、既存 plan 0 件。routing 中に `orch-plan-20260624-092429-1` (`do_not_parallelize` with `00001KVTNAY20`) と `orch-plan-20260624-092435-2` (waiting capacity note) を記録した。
|
||||
- Related Ticket: `00001KVTNAY20` は `inprogress`、accepted plan と waiting-capacity note があり、Coder Pod startup/provider failure により実装未開始。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。既存 implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVTNAY20-worker-runtime-spawn` は clean at `a729d686`。
|
||||
- Visible Pods: `yoi`, current `yoi-orchestrator`, and stopped/restorable failed `yoi-coder-00001KVTNAY20-worker-runtime` metadata only; active usable Coder/Reviewer sibling は無い。
|
||||
|
||||
Decision:
|
||||
- `00001KVWECEQG` は planning へ戻さない。Ticket の missing decision / missing information は現時点で具体化していない。
|
||||
- ただし `queued -> inprogress` acceptance は行わず、queued のまま待機させる。
|
||||
- Blocker は Ticket 要件ではなく、(1) `00001KVTNAY20` との runtime abstraction/code-surface conflict、(2) Coder sibling runtime/provider capacity failure。
|
||||
|
||||
Next action:
|
||||
- 先に `00001KVTNAY20` の Coder runtime/provider blocker を解消して multi-agent workflow を再開する、または人間が Orchestrator direct implementation / ordering を明示的に許可する。
|
||||
- その後、この Ticket を再 routing し、必要なら `00001KVTNAY20` の実装結果に合わせて registry abstraction の IntentPacket を作る。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T10:37:25Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- ユーザーから「進めて」と明示 follow-up があり、以前 `queued` のまま待機させた blocker を再確認した。
|
||||
- Ticket body は Worker runtime registry / overview reporting / runtime capability / identity / visibility / raw-session boundary / local Pod runtime migration を具体的に列挙しており、observable な acceptance criteria と reviewer focus がある。
|
||||
- `TicketRelationQuery` は blocking relation 0 件。
|
||||
- 以前の `do_not_parallelize` / waiting-capacity note は `00001KVTNAY20` が `done` になり、merge/validation 済みになったことで解消済みとして扱える。
|
||||
- 現在の `crates/workspace-server/src/hosts.rs` には `00001KVTNAY20` の結果として `WorkspaceWorkerRuntime`、typed spawn/stop/proxy request/result、local Pod metadata overview が入り、今回の registry/capability/overview abstraction をその上に重ねられる。残る不確実性は local tactic / bounded investigation に収まる。
|
||||
- orchestration worktree は clean で、同一 Ticket 用 worktree/branch はまだ無い。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `00001KVWECEQG` の item/thread。前回 routing decision 以降の missing planning question はなし。
|
||||
- Relations / orchestration plan: relation 0 件。既存 plan は前回の `do_not_parallelize` / waiting-capacity と、今回記録した accepted plan `orch-plan-20260624-103655-3`。
|
||||
- Related Ticket: `00001KVTNAY20` は `done`。review approve、orchestration merge、validation success、child cleanup 済み。
|
||||
- Code map: `crates/workspace-server/src/hosts.rs`, `crates/workspace-server/src/server.rs` を current orchestration branch で確認。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Workspace backend の Worker runtime surface を、single local bridge から registry / host / capability / overview reporting の境界へ抽象化し、Dashboard/API が runtime 一覧・worker 一覧・capability/diagnostic を安全に表示できる基盤を作る。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- registry/overview は local Pod metadata と role-session/runtime metadata の安全な summary を扱う。raw session contents や unchecked private/runtime paths を API response に出さない。
|
||||
- Browser/API 由来の値を runtime authority として扱わない。worker/host id は backend が解決・検証した bounded identifier として扱う。
|
||||
- runtime identity / workspace_root / process cwd / role-session claim は混同しない。
|
||||
- `00001KVTNAY20` で入った low-level launch boundary と Ticket/role/orchestration resolver separation を崩さない。
|
||||
- remote Host protocol、full scheduler、operation UI、stream/proxy 実装、permission/auth の完成、raw session inspection は non-goal。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Worker runtime registry/service abstraction が、複数 runtime/host summary と capability/diagnostic reporting を表現できる。
|
||||
- `LocalRuntimeBridge` 由来の local runtime が registry の一実装/entry として扱われ、API handler が concrete bridge に直接密結合しすぎない。
|
||||
- overview response は bounded/safe fields のみで、local Pod metadata failure や unavailable capability を diagnostic として返せる。
|
||||
- existing `/api/hosts` / `/api/workers` semantics を維持または明確に migration し、UI が使う shape を壊す場合は対応も含める。
|
||||
- validation として少なくとも `cargo test -p yoi-workspace-server`, `cargo check -p yoi`, `cd web/workspace && deno task check && deno task build`, `git diff --check` を実施する。
|
||||
|
||||
Implementation latitude:
|
||||
- registry trait/struct 名、module split、capability enum/string shape、diagnostic aggregation の詳細は coder が既存 code style に合わせて決めてよい。
|
||||
- API の大規模追加ではなく、current endpoints の内部境界整理と typed overview/capability shape の初期導入を優先してよい。
|
||||
- UI 変更は必要最小限でよい。既存 web build/typecheck を通すための追随は行ってよい。
|
||||
|
||||
Escalate if:
|
||||
- Browser/API から raw path/session/executable/profile 等を受けないと実装できない。
|
||||
- runtime registry を scheduler/lease/remote Host protocol として固定する必要が出る。
|
||||
- `00001KVTNAY20` の launch boundary を戻す/破る必要が出る。
|
||||
- raw session content や private metadata を overview に出す必要がある。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p yoi-workspace-server`
|
||||
- `cargo check -p yoi`
|
||||
- `cd web/workspace && deno task check && deno task build`
|
||||
- `git diff --check`
|
||||
- 影響範囲に応じて追加 Rust tests。
|
||||
|
||||
Current code map:
|
||||
- Primary: `crates/workspace-server/src/hosts.rs`, `crates/workspace-server/src/server.rs`。
|
||||
- Secondary: Workspace web API consumers under `web/workspace`, role-session/local metadata helpers if needed, `crates/client/src/spawn.rs` / `crates/client/src/ticket_role.rs` only to preserve boundaries.
|
||||
- Avoid: root/original workspace operations, unrelated Panel UI completion, remote Host protocol, scheduler/queue implementation, raw session reading.
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- registry abstraction becoming a scheduler or authority layer by accident.
|
||||
- leaking raw session/private paths/unchecked metadata into overview responses.
|
||||
- host/worker ids derived from user-controlled strings without bounding/validation.
|
||||
- breaking the launch boundary from `00001KVTNAY20`.
|
||||
- conflating runtime workspace root, process cwd, role-session claim, and local metadata hints.
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから、worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVWECEQG-worker-runtime-registry` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T10:37:43Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、blocking relation は 0 件。
|
||||
- 以前の blocker だった `00001KVTNAY20` は `done` になり、orchestration branch に merge/validated 済み。
|
||||
- `TicketOrchestrationPlanQuery` では過去の do_not_parallelize / waiting-capacity note と、今回の accepted plan `orch-plan-20260624-103655-3` を確認した。過去 blocker は解消済みとして扱う。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVWECEQG-worker-runtime-registry` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T10:38:50Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVWECEQG-worker-runtime-registry` と branch `work/00001KVWECEQG-worker-runtime-registry` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVWECEQG-worker-registry` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVWECEQG-worker-registry at: 2026-06-24T10:57:04Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report:
|
||||
|
||||
実装概要:
|
||||
- `crates/workspace-server/src/hosts.rs`
|
||||
- `WorkerRuntimeRegistry` を追加。
|
||||
- `WorkspaceWorkerRuntime` trait を runtime entry の抽象境界として再整理。
|
||||
- 既存 local Pod metadata 読み取りを `LocalPodRuntime` adapter として registry に登録。
|
||||
- `RuntimeSummary`, `RuntimeCapabilitySummary`, `WorkerCapabilitySummary`, `WorkerWorkspaceSummary`, typed `RuntimeDiagnostic` を追加。
|
||||
- API caller 由来の `host_id` / `worker_id` を backend 側で bounded identifier として検証。
|
||||
- raw session contents / socket path / metadata file path / raw workspace path を summary に出さないよう整理。
|
||||
- metadata の `workspace_root` は runtime workspace identity との照合にだけ使い、API には `current_workspace` summary として出す。
|
||||
- 他 workspace / workspace_root missing の Pod metadata は通常 worker overview から除外し、typed diagnostic のみ返す。
|
||||
- 先行 Ticket `00001KVTNAY20` の low-level launch 境界用 typed request/intent/result shape は維持。
|
||||
- `crates/workspace-server/src/server.rs`
|
||||
- server state を `Arc<WorkerRuntimeRegistry>` に変更。
|
||||
- `/api/hosts`, `/api/workers`, `/api/hosts/{host_id}/workers` を registry 経由に変更。
|
||||
- `/api/runtimes` を追加し、runtime overview を返せるようにした。
|
||||
- invalid runtime identifier / unknown worker / unsupported capability の API error mapping を追加。
|
||||
- server tests を registry source / runtime overview / safe summary 仕様に更新。
|
||||
- `crates/workspace-server/src/lib.rs`
|
||||
- registry/worker/capability 用 error variant を追加。
|
||||
- `crates/workspace-server/src/repositories.rs`
|
||||
- shared typed diagnostic severity に合わせて更新。
|
||||
- `web/workspace/src/lib/workspace-sidebar/types.ts`
|
||||
- runtime / capability / worker workspace summary 型を更新。
|
||||
- raw `workspace_root` / local `pod_name` 前提を削除。
|
||||
- `web/workspace/src/lib/workspace-pages/WorkspacePage.svelte`
|
||||
- Host/Worker overview 表示を safe summary fields に合わせて更新。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p yoi-workspace-server`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `cd web/workspace && deno task check`: success
|
||||
- `cd web/workspace && deno task build`: success
|
||||
- `git diff --check`: success
|
||||
|
||||
Commit:
|
||||
- `9bd15507 feat: add worker runtime registry overview`
|
||||
|
||||
Residual risks / notes:
|
||||
- remote Host protocol / scheduler / stream proxy / worker control operation は non-goal のまま、typed capability/diagnostic で unsupported/pending を返す境界に留めた。
|
||||
- API response から raw workspace/session/private path は出さない方針に寄せたため、UI は workspace path ではなく `current_workspace` scope/identity summary を表示する。
|
||||
- `nix build .#yoi --no-link` は Cargo/Deno validation が通過済みだが、最終統合 confidence を上げる場合は Orchestrator 側判断で実行可能。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVWECEQG-worker-registry at: 2026-06-24T11:01:43Z status: request_changes -->
|
||||
|
||||
## Review: request changes
|
||||
|
||||
Review result: request_changes
|
||||
|
||||
確認範囲:
|
||||
- child worktree `/home/hare/Projects/yoi/.worktree/00001KVWECEQG-worker-runtime-registry` のみで read-only inspection。
|
||||
- Ticket `item.md` / `thread.md` / orchestration plan、`371fd7c6..HEAD` の差分、主に `crates/workspace-server/src/hosts.rs` / `server.rs` / web 型・表示を確認。
|
||||
- read-only のため、テスト・ビルド・`git diff --check` は実行していない。
|
||||
|
||||
良い点:
|
||||
- `WorkspaceWorkerRuntime` trait、`WorkerRuntimeRegistry`、`LocalPodRuntime` が導入され、`WorkspaceApi` は `Arc<WorkerRuntimeRegistry>` を保持し、`/api/hosts` / `/api/workers` / `/api/hosts/{host_id}/workers` / 新規 `/api/runtimes` が registry 経由になっている。
|
||||
- `HostSummary` / `WorkerSummary` は raw `workspace_root` / metadata path / socket path / raw session を直接返さない形に整理されており、UI 側も新しい safe summary shape に追随している。
|
||||
- spawn/stop/proxy/stream は unsupported/reserved の型・diagnostic に留めており、scheduler / remote host protocol / raw session ingest には踏み込んでいない。
|
||||
|
||||
Blockers:
|
||||
1. worker detail/lookup の id 解決が opaque id 境界を満たしていない。
|
||||
- `worker_id_for_pod()` は `pod_name` を sanitize/lowercase/truncate して `local-pod-*` を作る一方、`LocalPodRuntime::worker()` は `local-pod-` を strip した値をそのまま `pod_root/<pod_name>/metadata.json` のディレクトリ名として使っている。
|
||||
- 実 Pod 名に大文字、`.` などの置換対象文字、truncate 対象が含まれると、`list_workers()` が返した `worker_id` から同じ Worker を lookup できない。
|
||||
- Yoi の実 Pod 名には Ticket ID 由来の大文字を含むものがあり得るため現実的に壊れる。これは Ticket の「worker detail / lookup」「`pod_name` を external operation key にしない」「worker_id は backend が解決する opaque id」という要件に反する。
|
||||
2. id の bounded/unique 性が full id に対して保証されていない。
|
||||
- `sanitize_identifier()` は fragment を最大 120 にするが、`local-pod-` / `local-` prefix 付与後の id は `validate_backend_identifier()` の `MAX_IDENTIFIER_LEN = 120` を超え得る。
|
||||
- sanitize による衝突(例: `foo.bar` と `foo-bar`)も避けられていない。将来 detail endpoint や operation routing を足した時に、一覧で返した id が lookup/validation で拒否される・別 Worker に衝突するリスクがある。
|
||||
|
||||
Required fixes:
|
||||
- `worker_id` は返却後に確実に backend で再解決できる opaque/stable id にする。raw pod name を authority として外へ出さず、scan した metadata/dir entry から `generated_worker_id -> actual pod dir` を backend 内で照合する、または衝突しない hash/digest を含める。
|
||||
- `MAX_IDENTIFIER_LEN` は prefix を含む full id に対して満たすようにし、生成側と検証側の不一致をなくす。
|
||||
- 大文字 Ticket ID を含む Pod 名、`.` など sanitize される Pod 名、長い Pod 名、衝突ケースについて、`list_workers()` が返した `worker_id` を `registry.worker()` / `LocalPodRuntime::worker()` で引けるテストを追加する。
|
||||
|
||||
Non-blocking note:
|
||||
- Ticket acceptance には `nix build .#yoi --no-link` も含まれている一方、coder 報告にはない。必要なら修正後に Orchestrator 判断で実施・明示すること。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVWECEQG-worker-registry at: 2026-06-24T11:09:03Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Follow-up implementation report after review request_changes:
|
||||
|
||||
対応内容:
|
||||
- `worker_id` を raw Pod dir 名から逆算する実装を廃止した。
|
||||
- `LocalPodRuntime::worker()` は Pod registry を backend 側で scan し、生成済み opaque `worker_id` と実 Pod dir を照合して解決する。
|
||||
- API caller が渡す `worker_id` は raw path / raw Pod name authority ではなく、backend-resolved identifier として扱う。
|
||||
- `worker_id` / `host_id` の生成を bounded + collision-resistant に変更した。
|
||||
- prefix を含む full id が `MAX_IDENTIFIER_LEN = 120` 以下になるよう制御。
|
||||
- `sha2` digest の短縮 hex を suffix として含め、`foo.bar` / `foo-bar` や長大名 truncation による collision を避ける。
|
||||
- 生成 id は既存 validation を通る形式に限定。
|
||||
- focused tests を追加・更新した。
|
||||
- uppercase Ticket-ID-like Pod name。
|
||||
- `.` / `@` / `#` 等の sanitized char。
|
||||
- `foo.bar` vs `foo-bar` collision case。
|
||||
- long/truncated names。
|
||||
- `list_workers()` が返す id を `registry.worker()` / `LocalPodRuntime::worker()` に渡して解決できること。
|
||||
- id が bounded / validation-compatible / duplicate-free であること。
|
||||
|
||||
変更ファイル:
|
||||
- `Cargo.lock`
|
||||
- `crates/workspace-server/Cargo.toml`
|
||||
- `crates/workspace-server/src/hosts.rs`
|
||||
- `crates/workspace-server/src/server.rs`
|
||||
|
||||
Validation:
|
||||
- `cargo test -p yoi-workspace-server`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `cd web/workspace && deno task check`: success
|
||||
- `cd web/workspace && deno task build`: success
|
||||
- `git diff --check`: success
|
||||
|
||||
Commit:
|
||||
- `38d25582 fix: make worker runtime ids resolvable`
|
||||
|
||||
Residual risks / notes:
|
||||
- `sha2.workspace = true` を `yoi-workspace-server` に追加したため、`Cargo.lock` の workspace-server dependency entry が更新された。
|
||||
- raw session/private path leak、scheduler/remote protocol scope creep、`00001KVTNAY20` の low-level launch boundary は維持している。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVWECEQG-worker-registry at: 2026-06-24T11:10:55Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
確認内容:
|
||||
- child worktree のみで `9bd15507..HEAD` fix diff と必要箇所の現行実装を read-only 確認。
|
||||
- ビルド/テストは read-only 指示のため再実行せず、coder 報告を参照。
|
||||
|
||||
判断:
|
||||
- 以前の blocker 2件は解消されている。
|
||||
|
||||
根拠:
|
||||
- `LocalPodRuntime::worker()` は `local-pod-` strip で raw Pod dir 名へ戻す実装をやめ、`pod_names()` で registry を scan し、各 actual Pod dir name から生成した `worker_id_for_pod()` と照合して backend 内部で解決する形になっている。これにより、大文字・記号・sanitize 対象文字を含む Pod 名でも list→lookup が成立する。
|
||||
- `worker_id_for_pod()` / `host_id_for_workspace()` は `bounded_backend_identifier()` 経由になり、prefix を含む full id が `MAX_IDENTIFIER_LEN` 内に収まるよう body を切り詰め、SHA-256 digest suffix を付けて sanitize/truncation collision を避ける設計になっている。
|
||||
- 追加テストで Ticket-like uppercase Pod 名、`.`/`-` collision、`#`/`@`、長い Pod 名、duplicate-free、validation-compatible、registry/runtime lookup roundtrip がカバーされている。
|
||||
- raw metadata path / socket path / workspace root / raw session を overview API に出さない方針、registry 経由の read-only API、spawn/stop/proxy 非実装の unsupported 境界は維持されている。
|
||||
|
||||
Non-blocking notes:
|
||||
- `worker_id` は sanitize 済み body を含むため完全な無意味 IDではないが、操作キーとしては backend 解決の opaque id になっており、今回の Ticket 意図には十分合っている。
|
||||
- reported validation は通過とのことだが、reviewer では再実行していない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T11:15:04Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVWECEQG-worker-registry` が implementation branch `work/00001KVWECEQG-worker-runtime-registry` に実装を commit した。
|
||||
- Reviewer `yoi-reviewer-00001KVWECEQG-worker-registry` は初回 review で `worker_id` opaque lookup / bounded unique id の blocker を指摘し、Coder が `38d25582 fix: make worker runtime ids resolvable` で修正した。
|
||||
- Follow-up review は `approve`。`LocalPodRuntime::worker()` の backend 内部 scan/照合、bounded digest 付き id 生成、list→lookup roundtrip tests、raw path/session 非公開、unsupported capability boundary が確認された。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVWECEQG-worker-runtime-registry` を merge 済み。
|
||||
- merge commit: `1251c0ca merge: 00001KVWECEQG worker runtime registry`
|
||||
- implementation commit: `9bd15507 feat: add worker runtime registry overview`
|
||||
- fix commit: `38d25582 fix: make worker runtime ids resolvable`
|
||||
- `sha2.workspace = true` 追加により `Cargo.lock` が変わったため、Nix package cargoHash を更新した。
|
||||
- package hash commit: `b975812c nix: update yoi cargo hash`
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo test -p yoi-workspace-server`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `cd web/workspace && deno task check`: success
|
||||
- `cd web/workspace && deno task build`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success after updating `package.nix` cargoHash to `sha256-rR8mrMDg1CCXb3Y5MnhUqSd0vAsI5OStFQCRIrvx8fg=`
|
||||
|
||||
Notes:
|
||||
- Initial `nix build .#yoi --no-link` failed only because cargoHash was stale after the new dependency; this was fixed and revalidated.
|
||||
- Reviewer non-blocking note: generated `worker_id` still includes a sanitized body fragment, but as an operation key it is now backend-resolved opaque id and acceptable for this Ticket.
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T11:15:13Z from: inprogress to: done reason: merged_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `1251c0ca merge: 00001KVWECEQG worker runtime registry`
|
||||
- package hash commit: `b975812c nix: update yoi cargo hash`
|
||||
- reviewer result: approve after requested changes were fixed
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration` succeeded:
|
||||
- `cargo test -p yoi-workspace-server`
|
||||
- `cargo check -p yoi`
|
||||
- `cd web/workspace && deno task check`
|
||||
- `cd web/workspace && deno task build`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"orch-plan-20260624-120242-1","ticket_id":"00001KVWPVHFJ","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVWPVHFJ` は implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVWPVHFJ-storage-cleanup-cli` と branch `work/00001KVWPVHFJ-storage-cleanup-cli` で、safe Pod/session storage cleanup CLI を実装する。destructive operations は dry-run/force/live refusal/path-safety を厳守する。","branch":"work/00001KVWPVHFJ-storage-cleanup-cli","worktree":"/home/hare/Projects/yoi/.worktree/00001KVWPVHFJ-storage-cleanup-cli","role_plan":"Orchestrator: routing acceptance, worktree creation, final integration/validation/cleanup. Coder: CLI/storage implementation in dedicated child worktree. Reviewer: read-only review focusing on path safety, live Pod refusal, dry-run/force semantics, and session history preservation."},"author":"yoi-orchestrator","at":"2026-06-24T12:02:42Z"}
|
||||
@@ -0,0 +1,150 @@
|
||||
---
|
||||
title: 'Pod/session storage cleanup CLI を追加する'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T11:39:41Z'
|
||||
updated_at: '2026-06-24T12:36:12Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['pod-lifecycle', 'persistence', 'destructive-operation', 'cli-ux', 'session-history', 'authority-boundary']
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T12:01:42Z'
|
||||
---
|
||||
|
||||
## User claims / request snapshot
|
||||
|
||||
- Pod 名を指定して Pod を消去する CLI コマンドを実装する。
|
||||
- Pod から参照されていないセッションを削除するコマンドを用意する。
|
||||
- 古い Pod / セッションを削除するコマンドを用意する。
|
||||
- コマンド名は以下で合意済み:
|
||||
- `yoi pod delete <NAME> [--force] [--dry-run]`
|
||||
- `yoi pod prune [--older-than <DURATION>] [--force] [--dry-run]`
|
||||
- `yoi session prune --unreferenced [--older-than <DURATION>] [--force] [--dry-run]`
|
||||
|
||||
## Confirmed facts / sources
|
||||
|
||||
- 関連 closed Ticket `00001KTJ7MACG` は fresh-start 専用 UX を実装しない方針で closed 済み。ただし resolution で、Pod 名を明示的に空ける archive/delete と storage cleanup/prune commands は必要になれば別 Ticket として扱う、と記録されている。
|
||||
- `crates/pod-store/src/lib.rs` では Pod metadata authority は `{data_dir}/pods/{pod_name}/metadata.json` であり、`PodMetadataStore::delete_by_name` / `FsPodStore::delete_by_name` が既に存在する。
|
||||
- `crates/session-store/src/fs_store.rs` / `crates/session-store/src/lib.rs` では session log は `{sessions_root}/{session_id}/{segment_id}.jsonl` と trace jsonl で、`FsStore` は `list_sessions`, `list_segments`, `lookup_session_of` を持つ。確認範囲では削除用 public API は見当たらない。
|
||||
- `crates/yoi/src/main.rs` では `yoi pod ...` は現在 `pod::entrypoint::run_cli_from("yoi pod", args)` に委譲されており、Pod runtime spawn/restore 用 entrypoint として使われている。
|
||||
- `crates/yoi/src/session_cli.rs` では `yoi session ...` は現在 `analyze <SESSION_JSONL_PATH> --json` のみ。
|
||||
- `crates/pod/src/entrypoint.rs` では `--pod <NAME>` は name-keyed Pod state があれば restore、なければ fresh create する。sessions dir は `--store` または `manifest::paths::sessions_dir()`、Pod store は `manifest::paths::data_dir()/pods` から解決している。
|
||||
- duplicate / related search では、直接同じ目的の open Ticket は見つからなかった。関連 closed Ticket は `00001KTJ7MACG`, `00001KSTRGFX0`, `00001KSXXRRC8`。
|
||||
|
||||
## Unverified hypotheses
|
||||
|
||||
- live Pod protection は runtime socket / Pod registry / discovery layer と組み合わせて判定できる可能性が高いが、実装時に正確な helper/API を確認する必要がある。
|
||||
- orphan session 判定は「active Pod metadata から参照されない SessionId」を基本にできそうだが、fork/segment lineage、trace file、古い closed metadata、manual session restore use case をどこまで保存対象にするかは実装時に注意する必要がある。
|
||||
- `yoi pod delete` を runtime entrypoint に足すより、product CLI 側で `yoi pod delete` を捕捉するほうが安全かもしれないが、既存 `yoi pod` の意味と衝突しない設計確認が必要。
|
||||
|
||||
## Undecided points / open questions
|
||||
|
||||
- Blocking open question は現時点ではない。
|
||||
- 実装中に CLI boundary が既存 `yoi pod` runtime entrypoint と衝突する場合は、Orchestrator / maintainer に escalate する。
|
||||
- orphan session 判定で session lineage semantics や manual restore use case への影響が大きい場合は、削除範囲を安全側に狭めるか follow-up に分ける。
|
||||
|
||||
## Background
|
||||
|
||||
以前の fresh-start Ticket では、restore bypass 専用 path を作らず、Pod 名の衝突解消や古い履歴蓄積は Pod/session storage cleanup commands として扱う方針になった。現在も Pod metadata と session logs は durable authority が分かれており、手で `~/.yoi/pods` や `~/.yoi/sessions` を消すのは危険で discoverable ではない。公式 CLI と safety rails が必要。
|
||||
|
||||
## Requirements
|
||||
|
||||
- Pod 名を指定して、name-keyed Pod metadata を削除できる CLI を追加する。
|
||||
- コマンド名は `yoi pod delete <NAME> [--force] [--dry-run]` とする。
|
||||
- 削除後、同じ Pod 名の通常起動は既存の `missing -> spawn fresh` path に乗る。
|
||||
- session logs/history は `pod delete` では削除しない。
|
||||
- live/reachable Pod の metadata 削除は拒否する。
|
||||
- 実装が live 判定できない場合は安全側に倒し、削除せず診断する。
|
||||
- live Pod を止める操作や stop semantics の変更はこの Ticket の主目的にしない。
|
||||
- orphan session cleanup CLI を追加する。
|
||||
- コマンド名は `yoi session prune --unreferenced [--older-than <DURATION>] [--force] [--dry-run]` とする。
|
||||
- Pod metadata の active pointer から参照されていない session/segment を候補として列挙できる。
|
||||
- 実削除は `--force` が必要。
|
||||
- 初期実装は dry-run / report を重視し、削除対象と根拠を表示する。
|
||||
- old Pod / old session cleanup CLI を追加する。
|
||||
- Pod 側は `yoi pod prune [--older-than <DURATION>] [--force] [--dry-run]` とする。
|
||||
- 「古い」の判定は暗黙 default を持たせず、`--older-than <DURATION>` のような明示 threshold を要求する。
|
||||
- threshold 未指定で「古い」と判断して削除しない。
|
||||
- destructive operation は共通で:
|
||||
- default は dry-run または削除拒否にする。
|
||||
- 実削除には `--force` を要求する。
|
||||
- 削除対象、保持対象、拒否理由を bounded に表示する。
|
||||
- product CLI help/docs を更新し、manual data-dir surgery ではなく公式 command を案内する。
|
||||
- `yoi pod` が既存 runtime entrypoint として使われている境界を壊さない。
|
||||
- management subcommands を product CLI 側で捕捉するか、runtime entrypoint 側に安全に追加するかは実装判断でよいが、既存 spawn/restore options と互換的に動くこと。
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- `yoi pod delete <NAME>` 相当の公式 CLI で stopped/restorable Pod metadata を削除できる。
|
||||
- 削除後、同名 Pod 起動は existing metadata restore ではなく fresh create path になる。
|
||||
- live/reachable Pod に対する delete/prune は拒否され、理由が表示される。
|
||||
- `pod delete` は session logs を削除しない。
|
||||
- Pod metadata から参照されていない session を dry-run で列挙でき、`--force` 指定時だけ削除できる。
|
||||
- 古い Pod / session cleanup は `--older-than` 等の明示条件なしでは削除しない。
|
||||
- prune/delete の出力は、削除予定/削除済み/保持/拒否をユーザーが確認できる。
|
||||
- focused tests が以下を cover する:
|
||||
- stopped/restorable Pod delete success。
|
||||
- live Pod delete refusal。
|
||||
- Pod delete 後の same-name missing/fresh behavior。
|
||||
- referenced session is preserved。
|
||||
- unreferenced session prune dry-run and force behavior。
|
||||
- old Pod/session prune requires explicit threshold。
|
||||
- CLI parsing/help。
|
||||
|
||||
## Binding decisions / invariants
|
||||
|
||||
- No silent restore bypass. Fresh same-name start は、ユーザーが明示的に metadata を削除した結果としてのみ発生する。
|
||||
- Pod metadata delete の副作用として session history を自動削除しない。
|
||||
- live/reachable Pod metadata を削除しない。
|
||||
- 暗黙の “old” threshold を持たせない。old Pod/session cleanup では age criteria をユーザーが明示する。
|
||||
- destructive deletion には明示的な `--force` を要求し、dry-run/report behavior を提供する。
|
||||
- Pod metadata authority は `pod-store`、session log authority は `session-store` のままにする。
|
||||
- legacy top-level resume flags や bare Pod-name inference を再導入しない。
|
||||
- この Ticket では Panel/TUI を broad Pod manager にしない。CLI 実装で十分とし、Panel integration は必要なら follow-up に分ける。
|
||||
|
||||
## Implementation latitude
|
||||
|
||||
- 合意済み command spelling は維持する。ただし clap/parser 上の曖昧さを避けるための minor option shape 調整は、既存 UX を壊さない範囲で許容する。
|
||||
- product CLI 側で management subcommands を捕捉するか、runtime entrypoint 側へ安全に追加するかは実装判断でよい。
|
||||
- 必要なら product CLI から使う shared cleanup module を作ってよい。
|
||||
- 必要なら `session-store` に削除 API を追加してよい。その場合は path safety と trace/log cleanup の tests を追加する。
|
||||
- Orphan session detection は初期実装では active `PodMetadata.active.session_id` references を authority としてよい。より高度な lineage-aware retention は、referenced sessions を削除しない限り follow-up に分けてよい。
|
||||
- Output は初期実装では human-readable でよい。JSON output は周辺 CLI と自然に揃えられる場合を除き follow-up でよい。
|
||||
|
||||
## Readiness
|
||||
|
||||
- readiness: implementation_ready
|
||||
- risk_flags: [pod-lifecycle, persistence, destructive-operation, cli-ux, session-history, authority-boundary]
|
||||
|
||||
## Escalation conditions
|
||||
|
||||
以下の場合は実装を進める前に Orchestrator / maintainer に escalate する。
|
||||
|
||||
- live Pod detection を安全に拒否できるほど reliable にできない。
|
||||
- orphan detection が session lineage semantics の変更を必要とする。
|
||||
- Pod delete の副作用として sessions を削除する必要が出る。
|
||||
- storage migration や compatibility fallback が必要になる。
|
||||
- command design が `yoi pod` runtime entrypoint usage と衝突する。
|
||||
- cleanup が Panel role-session/Ticket claims、worktrees、branches、Ticket state を mutate しようとする。
|
||||
|
||||
## Validation
|
||||
|
||||
- `cargo fmt --check`
|
||||
- focused `cargo test` for `yoi`, `pod-store`, `session-store`, and affected Pod/discovery code
|
||||
- `cargo check -p yoi -p pod -p pod-store -p session-store`
|
||||
- `target/debug/yoi ticket doctor` または `yoi ticket doctor`
|
||||
- `git diff --check`
|
||||
|
||||
Reviewer は path safety、live/refusal behavior、dry-run/force semantics、session history を accidental に削除しないことを重点確認する。
|
||||
|
||||
## Related work
|
||||
|
||||
- Related closed Ticket: `00001KTJ7MACG` — Add Pod archive and fresh-start path.
|
||||
- Related closed Ticket: `00001KSTRGFX0` — Split Pod metadata into a dedicated pod-store crate.
|
||||
- Related closed Ticket: `00001KSXXRRC8` — Pod tools: unify pod listing and rename restore operation.
|
||||
- Files inspected:
|
||||
- `crates/yoi/src/main.rs`
|
||||
- `crates/yoi/src/session_cli.rs`
|
||||
- `crates/pod/src/entrypoint.rs`
|
||||
- `crates/pod-store/src/lib.rs`
|
||||
- `crates/session-store/src/fs_store.rs`
|
||||
- `crates/session-store/src/lib.rs`
|
||||
@@ -0,0 +1,216 @@
|
||||
<!-- event: create author: ticket-intake at: 2026-06-24T11:39:41Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T12:01:42Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T12:03:42Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- Ticket body は `yoi pod delete`, `yoi pod prune`, `yoi session prune --unreferenced` の command spelling、dry-run/force semantics、live Pod refusal、session history preservation、explicit age threshold、validation を具体的に列挙している。
|
||||
- `TicketRelationQuery` は blocking relation 0 件、`TicketOrchestrationPlanQuery` は既存 plan 0 件だった。
|
||||
- risk flags は pod-lifecycle / persistence / destructive-operation / cli-ux / session-history / authority-boundary だが、destructive operations の safety rails と escalation conditions が明記されている。risk は reviewer focus として扱えばよく、planning return 理由にはならない。
|
||||
- 同時 queued Ticket `00001KVWPW3KX` は TUI Console rendering で code surface が別。conflict risk は低く、別 worktree/branch で並列開始可能。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。thread は create と ready->queued のみで未解決 blocker は記録されていない。
|
||||
- Relations / orchestration plan: relation 0 件、routing 前 plan 0 件。accepted plan `orch-plan-20260624-120242-1` を記録済み。
|
||||
- Code map: Grep で `crates/yoi/src/main.rs`, `crates/yoi/src/session_cli.rs`, `crates/pod-store/src/lib.rs`, `crates/session-store`, `crates/pod/src/entrypoint.rs`, `crates/pod/src/discovery.rs` 周辺を確認。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。active inprogress Ticket は 0 件。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Pod/session storage を手動削除せずに安全に整理できる公式 CLI を追加し、Pod metadata delete / Pod prune / unreferenced session prune を dry-run-first、force-required、live-safe に実装する。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- No silent restore bypass。same-name fresh start は、ユーザーが明示的に stopped/restorable Pod metadata を削除した結果としてのみ発生する。
|
||||
- `pod delete` は session logs/history を削除しない。
|
||||
- live/reachable Pod metadata は削除しない。live 判定が不確実なら安全側に拒否する。
|
||||
- old cleanup に暗黙 threshold を持たせない。`--older-than` など明示 criteria が必要。
|
||||
- destructive deletion は `--force` 必須。`--dry-run` / default report を重視する。
|
||||
- Pod metadata authority は `pod-store`、session log authority は `session-store` のまま。
|
||||
- legacy top-level resume flags / bare Pod-name inference は再導入しない。
|
||||
- Panel/TUI の broad Pod manager 化は non-goal。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- `yoi pod delete <NAME> [--force] [--dry-run]` で stopped/restorable Pod metadata を削除できる。
|
||||
- live/reachable Pod delete/prune は拒否され理由を出す。
|
||||
- `yoi pod prune --older-than <DURATION> [--force] [--dry-run]` は explicit threshold なしに old 判定削除しない。
|
||||
- `yoi session prune --unreferenced [--older-than <DURATION>] [--force] [--dry-run]` は Pod metadata active pointer から参照されない session/segment を report/prune できる。
|
||||
- delete/prune output は deleted/would delete/kept/refused reason を bounded に示す。
|
||||
- focused tests が stopped Pod delete, live refusal, session preservation, unreferenced prune dry-run/force, threshold requirement, CLI parsing/help を cover する。
|
||||
|
||||
Implementation latitude:
|
||||
- product CLI 側で management subcommands を捕捉するか、runtime entrypoint 側に安全に追加するかは coder が code map を見て判断してよい。
|
||||
- 必要なら shared cleanup module や `session-store` delete API を追加してよい。path safety tests を伴うこと。
|
||||
- Orphan detection は初期実装では active `PodMetadata.active.session_id` references を authority としてよい。lineage-aware retention は referenced sessions を削除しない限り follow-up に分けてよい。
|
||||
- Output は human-readable でよい。JSON は自然なら追加してよいが必須ではない。
|
||||
|
||||
Escalate if:
|
||||
- live Pod detection を安全に拒否できるほど reliable にできない。
|
||||
- orphan detection が session lineage semantics の変更を必要とする。
|
||||
- Pod delete の副作用として sessions を削除する必要が出る。
|
||||
- storage migration / compatibility fallback が必要になる。
|
||||
- command design が existing `yoi pod` runtime entrypoint usage と衝突する。
|
||||
- cleanup が Panel role-session/Ticket claims, worktrees, branches, Ticket state を mutate しようとする。
|
||||
|
||||
Validation:
|
||||
- `cargo fmt --check`
|
||||
- focused `cargo test` for `yoi`, `pod-store`, `session-store`, affected Pod/discovery code
|
||||
- `cargo check -p yoi -p pod -p pod-store -p session-store`
|
||||
- `target/debug/yoi ticket doctor` または `yoi ticket doctor`
|
||||
- `git diff --check`
|
||||
|
||||
Current code map:
|
||||
- Primary: `crates/yoi/src/main.rs`, `crates/yoi/src/session_cli.rs`, `crates/pod-store/src/lib.rs`, `crates/session-store/src/fs_store.rs`, `crates/session-store/src/lib.rs`, `crates/pod/src/entrypoint.rs`, `crates/pod/src/discovery.rs`。
|
||||
- Avoid: Panel/TUI manager UI, scheduler/stop semantics changes, Ticket/worktree/branch cleanup operations。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- accidental deletion of session history from `pod delete`。
|
||||
- live/reachable Pod metadata deletion。
|
||||
- unsafe path deletion or broad directory removal。
|
||||
- force/dry-run semantics bypass。
|
||||
- ambiguous age parsing/default threshold。
|
||||
- breaking `yoi pod` runtime entrypoint spawn/restore behavior。
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で dedicated worktree を作成し、Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T12:04:07Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、blocking relation は 0 件、accepted plan `orch-plan-20260624-120242-1` を確認した。
|
||||
- 同時 queued Ticket `00001KVWPW3KX` は disjoint code surface のため別 worktree/branch で並列開始可能と判断した。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVWPVHFJ-storage-cleanup-cli` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T12:05:13Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVWPVHFJ-storage-cleanup-cli` と branch `work/00001KVWPVHFJ-storage-cleanup-cli` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVWPVHFJ-cleanup-cli` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVWPVHFJ-cleanup-cli at: 2026-06-24T12:30:40Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
確認内容:
|
||||
- child worktree `/home/hare/Projects/yoi/.worktree/00001KVWPVHFJ-storage-cleanup-cli` のみを read-only 確認。
|
||||
- Ticket 要件・acceptance criteria・IntentPacket / implementation report、`5c9331e8..HEAD` の差分、主な実装箇所 `crates/yoi/src/main.rs`, `crates/yoi/src/pod_cleanup_cli.rs`, `crates/yoi/src/session_cli.rs`, `crates/pod-store/src/lib.rs`, `crates/session-store/src/fs_store.rs` を確認。
|
||||
- read-only 指示のため validation は再実行していない。
|
||||
|
||||
承認根拠:
|
||||
- `yoi pod delete <NAME> [--force] [--dry-run]`, `yoi pod prune --older-than <DURATION> ...`, `yoi session prune --unreferenced ...` の command spelling と product CLI routing が追加されている。
|
||||
- `pod delete` は `FsPodStore::delete_by_name` 経由で Pod metadata のみを削除し、session logs/history を削除しない。出力にも preserve が明示される。
|
||||
- live/reachable Pod は Unix socket connect 成功時に拒否され、権限エラー等の uncertain liveness も fail-safe で拒否される。`--force` でも live/uncertain は override しない。
|
||||
- destructive deletion は `--force && !--dry-run` の場合のみ実行され、通常時/dry-run は report-only になる。
|
||||
- `pod prune` は `--older-than` 必須で、暗黙の old threshold を持たない。
|
||||
- `session prune --unreferenced` は Pod metadata の active `session_id` を保護集合にしており、referenced session を削除対象から外す。削除は `SessionId` ベースの session-store API 経由で、path traversal 的な広範削除には見えない。
|
||||
- Panel/TUI/scheduler や legacy resume/bare Pod-name inference の scope creep は見当たらない。
|
||||
- Coder reported validation は Ticket 指定範囲を概ね満たしており、広い Pod lib test の失敗は既存 prompt assertion と説明され、対象 discovery test は再実行成功と記録されている。
|
||||
|
||||
Non-blocking note:
|
||||
- dry-run/失敗 path でも既存 store constructor が root directory を初期作成し得る設計に見える。削除は発生しないため今回の blocker とは見なさないが、将来「dry-run は完全 no-write」と定義するなら follow-up で明確化するとよい。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T12:36:01Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVWPVHFJ-cleanup-cli` が implementation branch `work/00001KVWPVHFJ-storage-cleanup-cli` に実装を commit した。
|
||||
- implementation commit: `80d6861a feat: add pod and session cleanup CLI`
|
||||
- child ticket report commit: `439f967c chore: record cleanup cli implementation report`
|
||||
- Reviewer `yoi-reviewer-00001KVWPVHFJ-cleanup-cli` は read-only review で `approve`。Pod metadata only delete、session preservation、live/uncertain refusal、force/dry-run semantics、explicit threshold、session active reference protection、path authority、scope creep なしを確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVWPVHFJ-storage-cleanup-cli` を merge 済み。
|
||||
- merge commit: `4fb75ec3 merge: 00001KVWPVHFJ storage cleanup cli`
|
||||
- merge 時に Ticket item/thread の append conflict が発生したため、orchestration 側の Ticket record を保持して merge し、この integration outcome に実装・review・validation evidence を集約して記録した。
|
||||
- cleanup CLI 実装で Cargo dependencies / `Cargo.lock` が変わったため、Nix package cargoHash を更新した。
|
||||
- package hash commit: `28d53aad nix: update yoi cleanup cargo hash`
|
||||
|
||||
Implemented behavior:
|
||||
- `yoi pod delete <NAME> [--force] [--dry-run]`: stopped/restorable Pod metadata のみ削除。sessions/history は削除しない。live/uncertain liveness は拒否。
|
||||
- `yoi pod prune --older-than <DURATION> [--force] [--dry-run]`: explicit threshold required。Pod metadata のみ prune。
|
||||
- `yoi session prune --unreferenced [--older-than <DURATION>] [--force] [--dry-run]`: Pod metadata active session references を保護し、unreferenced session のみ対象。
|
||||
- `session-store` に session deletion / mtime support を追加。
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo fmt --check`: success
|
||||
- `cargo test -p yoi`: success
|
||||
- `cargo test -p session-store --lib`: success
|
||||
- `cargo test -p pod-store --lib`: success
|
||||
- `cargo test -p pod discovery:: --lib`: success
|
||||
- `cargo check -p yoi -p pod -p pod-store -p session-store`: success
|
||||
- `cargo run -p yoi -- ticket doctor`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success after updating `package.nix` cargoHash to `sha256-8mo2/IZMq3tfnv8fKRxJOdfb+T3NOheUmqT8TiR+Wag=`
|
||||
|
||||
Notes:
|
||||
- 初回 `nix build .#yoi --no-link` は cargoHash stale のため失敗し、hash 更新後に成功した。
|
||||
- Reviewer non-blocking note: dry-run/失敗 path でも既存 store constructor が root directory を初期作成し得る設計に見える。削除は起きないため blocker ではないが、将来「dry-run は完全 no-write」と定義するなら follow-up で明確化可能。
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T12:36:12Z from: inprogress to: done reason: merged_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `4fb75ec3 merge: 00001KVWPVHFJ storage cleanup cli`
|
||||
- package hash commit: `28d53aad nix: update yoi cleanup cargo hash`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration` succeeded:
|
||||
- `cargo fmt --check`
|
||||
- `cargo test -p yoi`
|
||||
- `cargo test -p session-store --lib`
|
||||
- `cargo test -p pod-store --lib`
|
||||
- `cargo test -p pod discovery:: --lib`
|
||||
- `cargo check -p yoi -p pod -p pod-store -p session-store`
|
||||
- `cargo run -p yoi -- ticket doctor`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"orch-plan-20260624-120242-1","ticket_id":"00001KVWPW3KX","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVWPW3KX` は implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVWPW3KX-thinking-group` と branch `work/00001KVWPW3KX-thinking-group` で、TUI Console の render-time Thinking block aggregation を実装する。protocol/history/persistence は変更せず、TUI rendering tests と focused validation を行う。","branch":"work/00001KVWPW3KX-thinking-group","worktree":"/home/hare/Projects/yoi/.worktree/00001KVWPW3KX-thinking-group","role_plan":"Orchestrator: routing acceptance, worktree creation, final integration/validation/cleanup. Coder: TUI implementation in dedicated child worktree. Reviewer: read-only review focusing on render-only aggregation, selection behavior, no protocol/history changes."},"author":"yoi-orchestrator","at":"2026-06-24T12:02:42Z"}
|
||||
@@ -0,0 +1,124 @@
|
||||
---
|
||||
title: 'TUI Console: 連続した Thinking block を一つの表示グループにまとめる'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T11:39:59Z'
|
||||
updated_at: '2026-06-24T12:20:08Z'
|
||||
assignee: null
|
||||
readiness: 'implementation_ready'
|
||||
risk_flags: ['tui-rendering', 'reasoning-display', 'block-aggregation', 'text-selection']
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T12:01:41Z'
|
||||
---
|
||||
|
||||
## User claims / request snapshot
|
||||
|
||||
- ユーザーは、TUI Console で連続した `Thinking` を `Read` tool 表示のように一つにまとめて表示したいと依頼した。
|
||||
- 対象 workspace は `yoi`。
|
||||
- Panel handoff の orchestrator Pod は `yoi-orchestrator`。
|
||||
|
||||
## Confirmed facts / sources
|
||||
|
||||
- 既存 Ticket 確認では、同じ目的の active duplicate は見当たらなかった。
|
||||
- 関連 closed Ticket:
|
||||
- `00001KT5D44Z0` — reasoning / thinking persistence を block lifecycle に統一済み。
|
||||
- `00001KVMT2J25` — in-flight snapshot が unfinished thinking block を含め、TUI が snapshot から unfinished thinking を seed して live delta 継続できるようにした。
|
||||
- `00001KVHX0WBE` — Dashboard / Console / TUI の呼称と module boundary を整理済み。今回の対象は Console / single-Pod chat surface。
|
||||
- `00001KTKCK8W8` — chat view の Markdown rendering 改善。今回と同じく表示層の変更であり、history / context 変更は避ける方針が近い。
|
||||
- `00001KSVP63K8` は planning の in-flight composer injection で、今回の Thinking 表示集約とは別件。
|
||||
- `crates/tui/src/block.rs` では `Block::Thinking(ThinkingBlock)` が独立した history block として存在し、`ThinkingState::{Streaming, Finished, Incomplete}` を持つ。
|
||||
- `crates/tui/src/app.rs` では `Event::ThinkingStart` ごとに新しい `Block::Thinking` を push し、`ThinkingDelta` は最後の streaming thinking に追記し、`ThinkingDone` で finished にする。
|
||||
- `crates/tui/src/ui.rs` の `compute_history` は block 列を走査し、`Block::ToolCall` だけ `crate::tool::render_tool(...)` に委譲して複数 block 消費を許している。
|
||||
- `crates/tui/src/tool.rs` の `Read` renderer は、連続する `Read` tool call block を `render_read_aggregate` でまとめ、1つの header と path list として表示している。
|
||||
- `crates/tui/src/ui.rs` の `render_thinking` は現在、各 `ThinkingBlock` を個別に header / body preview / detail として描画している。連続 Thinking をまとめる専用 path は見当たらない。
|
||||
|
||||
## Unverified hypotheses
|
||||
|
||||
- 実装は `Read` と同様に `compute_history` 側で連続する `Block::Thinking` をまとめる renderer を導入する形が自然そう。
|
||||
- 「連続」は、同じ turn 内で他の block を挟まない `Block::Thinking` の連なりとして扱うのが妥当そう。
|
||||
- Normal mode では 1 header + 最新または先頭 preview、Detail mode では各 Thinking body を連結または小見出し付きで読める形にすればよさそう。
|
||||
|
||||
## Undecided points / open questions
|
||||
|
||||
- blocking な未決定点はない。
|
||||
- 表示文言の細部(例: `Thoughts — 3 blocks` / `Thinking... (3 blocks)` / elapsed 表示の集約方法)は実装者判断でよい。
|
||||
- ただし、連続していない Thinking や turn を跨ぐ Thinking までまとめるべきではない、という invariant は維持する。
|
||||
|
||||
## Background
|
||||
|
||||
Provider / model によっては 1 turn 内で Thinking / reasoning block が複数連続して発生する。現状の Console 表示では、それぞれが個別の Thinking 表示になり、会話ログが冗長に見える可能性がある。`Read` tool は連続する `Read` call を 1つの表示グループにまとめる既存 UX があるため、Thinking でも同様の表示集約を行う。
|
||||
|
||||
## Requirements
|
||||
|
||||
- TUI Console の history rendering で、連続する `Block::Thinking` を一つの logical display group として表示する。
|
||||
- 対象は Console / single-Pod chat view の表示層に限定する。
|
||||
- `Read` tool の連続 aggregation と同じく、rendering 時に複数 block を消費して一つの表示にまとめられること。
|
||||
- 連続していない Thinking、別 turn の Thinking、間に `AssistantText` / `ToolCall` / `User` / `System` などを挟む Thinking はまとめない。
|
||||
- `Streaming` / `Finished` / `Incomplete` が混在しても、状態が誤解されない header / body 表示にする。
|
||||
- Normal / Detail / Overview mode の既存意味を保つ。
|
||||
- Pod history、session log、worker history、prompt context、protocol event model、reasoning persistence は変更しない。
|
||||
- In-flight snapshot から復元された unfinished Thinking と live delta continuation の表示が退行しない。
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- 1 turn 内で `Thinking` block が複数連続する場合、Console history 上では 1つの Thinking group として表示される。
|
||||
- 連続 Thinking group は、少なくとも group header と読み取り可能な preview / detail body を持つ。
|
||||
- Normal mode で冗長な `Thought` / `Thinking...` header が連続表示されない。
|
||||
- Detail mode では、集約された各 Thinking の本文が欠落せず読める。
|
||||
- Overview mode でも 1 group として扱われ、行数が不必要に増えない。
|
||||
- 間に non-Thinking block がある場合や turn を跨ぐ場合は、別 group として表示される。
|
||||
- Text selection / copy の既存方針が壊れない。Thinking は現在 text-like selectable block ではないため、集約後も不用意に selectable transcript text にしない。
|
||||
- Read tool aggregation、ToolCall rendering、AssistantText rendering に退行がない。
|
||||
- Focused TUI rendering test が追加または更新される。
|
||||
|
||||
## Binding decisions / invariants
|
||||
|
||||
- これは TUI Console の表示改善であり、reasoning / thinking の protocol、persistence、provider event semantics の変更ではない。
|
||||
- Thinking content を history / context に別形式で保存し直さない。
|
||||
- 未完了 Thinking を finalized assistant history と混同しない。
|
||||
- `Read` aggregation と同じく render-time aggregation として扱い、source block sequence 自体は保持する。
|
||||
- Turn boundary を跨いで group 化しない。
|
||||
- Non-Thinking block を跨いで group 化しない。
|
||||
- Dashboard / Panel の Ticket rows や web UI は対象外。
|
||||
|
||||
## Implementation latitude
|
||||
|
||||
- `compute_history` に `Block::Thinking` の consecutive aggregation path を追加し、`tool::render_tool` と同様に consumed count を返す helper を作ってよい。
|
||||
- `render_thinking` を単体 renderer として残しつつ、複数 block 用の `render_thinking_aggregate` を追加してよい。
|
||||
- Header 文言、elapsed 表示、複数 state 混在時の summary は実装者判断でよい。ただし streaming / incomplete を隠さない。
|
||||
- Detail mode で各 block の境界を薄い separator / index / blank line で示すか、単純連結するかは実装者判断でよい。
|
||||
- Existing tests に加えて、synthetic `App { blocks: [...] }` から `compute_history` output を見る focused unit test を追加するのが自然。
|
||||
|
||||
## Readiness
|
||||
|
||||
- readiness: implementation_ready
|
||||
- risk_flags: [tui-rendering, reasoning-display, block-aggregation, text-selection]
|
||||
|
||||
## Escalation conditions
|
||||
|
||||
- protocol / pod / persistence 層の変更が必要だと分かった場合。
|
||||
- Thinking を selectable / copyable transcript text として扱う UX 変更が必要になる場合。
|
||||
- Provider-specific reasoning metadata の扱いに踏み込む必要が出た場合。
|
||||
- Console 以外の Dashboard / web / protocol UI surface まで範囲が広がる場合。
|
||||
- 表示集約のために broad TUI rendering rewrite が必要になる場合。
|
||||
|
||||
## Validation
|
||||
|
||||
- `cargo test -p tui` または focused `cargo test -p tui thinking` / rendering tests。
|
||||
- `cargo fmt --check`。
|
||||
- `git diff --check`。
|
||||
- 必要に応じて `cargo check -p tui`。
|
||||
- 変更範囲が TUI / package integration に広がる場合のみ `nix build .#yoi` を検討。
|
||||
|
||||
## Related work
|
||||
|
||||
- Tickets:
|
||||
- `00001KT5D44Z0` — Unify reasoning persistence with block lifecycle
|
||||
- `00001KVMT2J25` — Pod protocol: in-flight LLM response reconnect snapshot should include unfinished blocks
|
||||
- `00001KVHX0WBE` — Dashboard / Console 呼称導入と TUI モジュール境界整理
|
||||
- `00001KTKCK8W8` — TUI chat view should render Markdown tables
|
||||
- related but not duplicate: `00001KSVP63K8`
|
||||
- Files:
|
||||
- `crates/tui/src/block.rs`
|
||||
- `crates/tui/src/app.rs`
|
||||
- `crates/tui/src/ui.rs`
|
||||
- `crates/tui/src/tool.rs`
|
||||
@@ -0,0 +1,211 @@
|
||||
<!-- event: create author: LocalTicketBackend at: 2026-06-24T11:39:59Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: ticket-intake at: 2026-06-24T11:56:52Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
ユーザーが draft 内容を確認し、Ticket `00001KVWPW3KX` を ready にするよう明示した。Ticket 本文には implementation_ready、blocking open questions なし、対象範囲・invariants・validation が記録済みで、Orchestrator が implementation routing を判断できる。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: ticket-intake at: 2026-06-24T11:56:52Z from: planning to: ready reason: user_confirmed_ready field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
ユーザー確認済みのため planning から ready へ移行する。blocking open questions はなく、Orchestrator は通常の routing 判断に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T12:01:41Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T12:03:09Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- Ticket body は TUI Console の連続 Thinking block を render-time で一つの表示 group にまとめる目的、non-goals、binding invariants、validation を具体的に列挙している。
|
||||
- `TicketRelationQuery` は blocking relation 0 件、`TicketOrchestrationPlanQuery` は既存 plan 0 件だった。
|
||||
- risk flags は TUI rendering / reasoning-display / block-aggregation / text-selection だが、protocol / pod / persistence 変更をしない、source block sequence を保持する、turn boundary / non-Thinking block を跨がない、selection behavior を壊さない、という invariant が明示されている。risk は reviewer focus として扱えばよく、planning return 理由にはならない。
|
||||
- 同時 queued Ticket `00001KVWPVHFJ` は Pod/session storage cleanup CLI で code surface が別。conflict risk は低く、別 worktree/branch で並列開始可能。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。thread は create、planning->ready、ready->queued のみで未解決 blocker は記録されていない。
|
||||
- Relations / orchestration plan: relation 0 件、routing 前 plan 0 件。accepted plan `orch-plan-20260624-120242-1` を記録済み。
|
||||
- Code map: Grep で `ThinkingStart` / `ThinkingDelta` / `ThinkingStop` / `thinking` 周辺を確認し、primary files `crates/tui/src/block.rs`, `crates/tui/src/app.rs`, `crates/tui/src/ui.rs`, `crates/tui/src/tool.rs` が妥当。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。active inprogress Ticket は 0 件。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- TUI Console の transcript rendering で、assistant turn 内に連続する `Thinking` blocks を一つの表示 group として描画し、reasoning が細切れに見える UX を改善する。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- これは render-time aggregation。history / protocol / persistence / block sequence は変更しない。
|
||||
- turn boundary を跨いで group 化しない。
|
||||
- non-Thinking block を跨いで group 化しない。
|
||||
- streaming / incomplete thinking を隠さない。
|
||||
- Thinking を selectable/copyable transcript text に変える UX 変更はしない。
|
||||
- Dashboard / Panel / web UI は対象外。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- 連続 Thinking blocks が Console 表示で一つのまとまりとして見える。
|
||||
- 既存の `Read` aggregation / tool rendering と同様に、rendering helper が consumed count 等で `compute_history` の走査を壊さない。
|
||||
- 単独 Thinking block の表示は regress しない。
|
||||
- Detail mode / collapsed mode / streaming state が破綻しない。
|
||||
- focused unit tests で consecutive Thinking, non-Thinking separator, turn boundary, incomplete/streaming case を確認する。
|
||||
|
||||
Implementation latitude:
|
||||
- `render_thinking` を単体 renderer として残し、必要なら aggregate renderer/helper を追加してよい。
|
||||
- Header 文言、elapsed 表示、detail mode の separator/index/blank line は既存 UX に沿って実装判断してよい。
|
||||
- `compute_history` の構造に合わせ、最小変更で実装してよい。
|
||||
|
||||
Escalate if:
|
||||
- protocol / pod / persistence 層の変更が必要になる。
|
||||
- Thinking を text selection/copy target にする必要が出る。
|
||||
- Provider-specific reasoning metadata の意味づけ変更が必要になる。
|
||||
- Console 以外の UI surface に範囲が広がる。
|
||||
- broad TUI rendering rewrite が必要になる。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p tui` または focused `cargo test -p tui thinking` / rendering tests。
|
||||
- `cargo fmt --check`。
|
||||
- `git diff --check`。
|
||||
- 必要に応じて `cargo check -p tui`。
|
||||
|
||||
Current code map:
|
||||
- Primary: `crates/tui/src/block.rs`, `crates/tui/src/app.rs`, `crates/tui/src/ui.rs`, `crates/tui/src/tool.rs`。
|
||||
- Avoid: protocol/history/persistence, Dashboard/Panel/web UI, broad TUI rewrite。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- source blocks/history を変更してしまうこと。
|
||||
- non-Thinking block や turn boundary を跨いだ誤 grouping。
|
||||
- streaming/incomplete thinking state の欠落。
|
||||
- text selection/copy semantics の accidental change。
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で dedicated worktree を作成し、Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T12:04:07Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、blocking relation は 0 件、accepted plan `orch-plan-20260624-120242-1` を確認した。
|
||||
- 同時 queued Ticket `00001KVWPVHFJ` は disjoint code surface のため別 worktree/branch で並列開始可能と判断した。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVWPW3KX-thinking-group` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T12:05:13Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVWPW3KX-thinking-group` と branch `work/00001KVWPW3KX-thinking-group` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVWPW3KX-thinking-group` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVWPW3KX-thinking-group at: 2026-06-24T12:18:51Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
確認内容:
|
||||
- child worktree の `.yoi/tickets/00001KVWPW3KX/item.md` / `thread.md` / implementation report / `5c9331e8..HEAD` diff を read-only 確認。
|
||||
- 変更範囲は `crates/tui/src/ui.rs` の Console history rendering と、既存 dashboard test fixture の必須 field 追加に限定されている。
|
||||
- `compute_history` で `Block::Thinking` のみを render-time に連続消費し、source block sequence / history / protocol / persistence は変更していない。
|
||||
- 単独 Thinking は既存 `render_thinking` に委譲され、複数 Thinking のみ `render_thinking_group` で集約される。
|
||||
- `TurnHeader` や `AssistantText` など non-Thinking を跨ぐ grouping は起きない構造で、focused tests も追加されている。
|
||||
- streaming / incomplete は group header と preview/detail に反映され、未完了 Thinking を finalized text と混同する変更はない。
|
||||
- group 行は `selectable=false` で追加されており、Thinking を copyable transcript text にする変更はない。
|
||||
- Read tool aggregation / single ToolCall rendering の回帰確認テストも追加されている。
|
||||
|
||||
Validation:
|
||||
- reviewer: `git diff --check 5c9331e8..HEAD`: PASS
|
||||
- cargo 系は read-only/no-write 指示に合わせて再実行せず、implementation report の結果を確認した。
|
||||
|
||||
Non-blocking note:
|
||||
- 実端末での目視確認は未実施だが、`compute_history` の行生成・selectable 属性を中心にテストされており、Ticket acceptance には十分。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T12:20:02Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVWPW3KX-thinking-group` が implementation branch `work/00001KVWPW3KX-thinking-group` に実装を commit した。
|
||||
- implementation commit: `0b2ce6ca tui: group consecutive thinking blocks`
|
||||
- child ticket report commit: `7ee2b78b ticket: report thinking grouping implementation`
|
||||
- Reviewer `yoi-reviewer-00001KVWPW3KX-thinking-group` は read-only review で `approve`。render-time aggregation のみで history/protocol/persistence を変更していないこと、turn/non-Thinking boundary、streaming/incomplete visibility、selectable=false、tool rendering regression tests を確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVWPW3KX-thinking-group` を merge 済み。
|
||||
- merge commit: `b52b7c96 merge: 00001KVWPW3KX thinking grouping`
|
||||
- merge 時に Ticket item/thread の append conflict が発生したため、orchestration 側の Ticket record を保持して merge し、この integration outcome に実装・review・validation evidence を集約して記録した。
|
||||
|
||||
Implemented behavior:
|
||||
- `crates/tui/src/ui.rs` で `compute_history` の render-time 処理に連続 `Block::Thinking` aggregation を追加。
|
||||
- 単一 Thinking は既存 `render_thinking` に委譲。
|
||||
- 複数 Thinking group は Normal/Overview で一つの header、Detail で各 Thinking body を読める形にした。
|
||||
- streaming / incomplete state は header / preview / detail に残し、group rows は selectable=false を維持。
|
||||
- `crates/tui/src/dashboard/tests.rs` は current `TicketRoleLaunchResult.acceptance_evidence` 必須 field に追随。
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo test -p tui`: success
|
||||
- `cargo fmt --check`: success
|
||||
- `cargo check -p tui`: success
|
||||
- `git diff --check`: success
|
||||
|
||||
Notes:
|
||||
- 実端末での目視確認は未実施。focused tests と full `cargo test -p tui` で `compute_history` rows/selectable/tool regression を確認済み。
|
||||
- dependency/package change は無いため `nix build .#yoi` は実施していない。
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T12:20:08Z from: inprogress to: done reason: merged_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `b52b7c96 merge: 00001KVWPW3KX thinking grouping`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration` succeeded:
|
||||
- `cargo test -p tui`
|
||||
- `cargo fmt --check`
|
||||
- `cargo check -p tui`
|
||||
- `git diff --check`
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"orch-plan-20260624-190611-1","ticket_id":"00001KVWSQM22","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVWSQM22` は implementation_ready as a design/planning artifact。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVWSQM22-backend-orch-runtime` と branch `work/00001KVWSQM22-backend-orch-runtime` で、Backend internal Orchestrator runtime / Kanban durable orchestration event / WorkerRuntime registry identity and spawn-intent boundary を明文化する。Backend internal Orchestrator の full implementation や direct filesystem authority は non-goal。","branch":"work/00001KVWSQM22-backend-orch-runtime","worktree":"/home/hare/Projects/yoi/.worktree/00001KVWSQM22-backend-orch-runtime","role_plan":"Orchestrator: routing acceptance, worktree creation, final integration/validation/cleanup. Coder: design/planning implementation in dedicated child worktree, producing maintained design documentation and any minimal code/test updates needed to align existing Workspace runtime/Panel queue boundaries. Reviewer: read-only review against recorded IntentPacket, focusing on authority boundaries, durable event semantics, runtime identity, and non-goals."},"author":"yoi-orchestrator","at":"2026-06-24T19:06:11Z"}
|
||||
@@ -0,0 +1,153 @@
|
||||
---
|
||||
title: 'Backend internal Orchestrator runtime for Kanban operations'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T12:29:58Z'
|
||||
updated_at: '2026-06-24T19:15:42Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T19:04:55Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Workspace / Kanban UI から Ticket を `ready -> queued` する操作は、単なる表示変更ではなく「Orchestrator が routing / start-if-unblocked を開始してよい」という human gate として扱いたい。一方で、現状の Orchestrator は local Pod として起動・接続・通知される形に寄っており、Kanban 操作を transient Pod notification に直接結びつけると、Pod lifetime / socket / session / workspace cwd / local filesystem authority に依存しやすい。
|
||||
|
||||
今後の Workspace backend は Worker runtime registry を持つ control plane になり、Backend internal runtime、local Pod runtime、remote / multi-machine runtime を束ねる方向に進めたい。Kanban 操作を Orchestration に接続するなら、routing / decision / spawn intent を担当する Orchestrator は、filesystem-capable Pod ではなく Backend internal runtime 上の Worker として扱う方が自然である。
|
||||
|
||||
ただし、Backend internal Orchestrator は実装者ではなく control-plane の判断者 / ルーターであり、Bash / raw filesystem / raw socket path / raw session 全量読みのような authority を持つべきではない。実装・review・build・worktree 操作は、local / remote の filesystem-capable runtime 上の Coder / Reviewer / helper Worker に委譲する。
|
||||
|
||||
この Ticket では、Kanban operation と Orchestration を durable event / Backend internal Worker / WorkerRuntime registry 経由で接続する設計を planning する。
|
||||
|
||||
## 目的
|
||||
|
||||
- Kanban の Ticket state operation を Orchestration の durable trigger として扱う設計を固める。
|
||||
- Orchestrator を Backend internal runtime 上の Worker として表現する設計を固める。
|
||||
- Backend internal Orchestrator が使う tool / operation surface を、Pod 用 filesystem tools ではなく domain-specific backend tools として整理する。
|
||||
- routing decision、spawn intent、overview / audit projection を raw session に依存せず残せるようにする。
|
||||
- Coder / Reviewer / worktree / shell 操作は filesystem-capable runtime に委譲する境界を明確にする。
|
||||
|
||||
## 要件
|
||||
|
||||
### Kanban operation / orchestration event
|
||||
|
||||
- Workspace / Kanban UI の Ticket operation は backend API を通じて実行する。
|
||||
- `ready -> queued` は「Orchestrator routing を開始してよい」という human gate として扱う。
|
||||
- Kanban operation は transient Pod notify ではなく、durable orchestration event を生成する。
|
||||
- 例: `ticket_queued`, `ticket_state_changed`, `ticket_returned_to_planning`, `ticket_done`。
|
||||
- orchestration event は actor / source / ticket_id / before state / after state / timestamp / request id を持つ。
|
||||
- event は再処理・重複・backend restart に耐える形にする。
|
||||
- UI click から直接 local Pod socket や raw runtime path へ通知しない。
|
||||
|
||||
### Backend internal Orchestrator Worker
|
||||
|
||||
- Backend internal runtime 上に Orchestrator Worker を置ける設計にする。
|
||||
- Backend internal Orchestrator は filesystem / shell / git authority を前提にしない。
|
||||
- Backend internal Orchestrator は Kanban / Ticket / runtime registry event を読み、routing decision を行う。
|
||||
- Orchestrator の durable output は raw session ではなく以下を中心にする。
|
||||
- routing decision
|
||||
- orchestration plan / blocker / waiting reason
|
||||
- spawn intent
|
||||
- worker run overview
|
||||
- usage aggregate / lifecycle projection
|
||||
- failure summary / escalation request
|
||||
- Backend internal Orchestrator が停止・再起動しても、未処理 event / in-progress decision の扱いが壊れないようにする。
|
||||
|
||||
### Tool / operation surface redesign
|
||||
|
||||
Backend internal Orchestrator に渡す tool / operation surface は、Pod 用の汎用 filesystem tools ではなく、Backend domain operation として設計する。
|
||||
|
||||
最低限検討する tool / operation:
|
||||
|
||||
- Ticket list / show / comment / state transition。
|
||||
- Ticket relation / orchestration plan read/write。
|
||||
- Kanban event read / ack / defer / fail。
|
||||
- Runtime registry list / capability query / worker lookup。
|
||||
- Worker spawn intent create / dispatch。
|
||||
- Worker run overview read / append。
|
||||
- Usage aggregate read。
|
||||
- Audit / decision record append。
|
||||
|
||||
原則として渡さないもの:
|
||||
|
||||
- `Bash`。
|
||||
- raw `Read` / `Write` / `Edit` over workspace filesystem。
|
||||
- raw Unix socket path 操作。
|
||||
- raw session 全量 ingest / unrestricted read。
|
||||
- local Pod metadata path / session path を直接 authority とする操作。
|
||||
|
||||
### WorkerRuntime registry connection
|
||||
|
||||
- Backend internal Orchestrator は、実装作業を直接行わず、WorkerRuntime registry に typed spawn intent を渡す。
|
||||
- runtime selection は capability を見る。
|
||||
- routing-only / intake / dashboard assistant は Backend internal runtime でもよい。
|
||||
- coder / reviewer / worktree / git / shell / build が必要な作業は filesystem-capable local / remote runtime を必要とする。
|
||||
- spawn intent は raw process launch config ではなく role / ticket_id / required capabilities / workspace identity / cwd semantics / profile/workflow selection intent を表す。
|
||||
- local Pod runtime はその intent を低レベル Pod process launch config へ解決する adapter として扱う。
|
||||
|
||||
### Worker identity / API / DB shape
|
||||
|
||||
- UI 表示では human-readable な `worker-name@runtime-name` 形式を使う。
|
||||
- 例: `super-duper-pod@runtimeA`。
|
||||
- これは表示用 label / `display_ref` であり、操作対象の authority にはしない。
|
||||
- API の canonical identity は `runtime_id` + `worker_id` とする。
|
||||
- `runtime_id` / `worker_id` は opaque id として扱う。
|
||||
- `pod_name` は local Pod runtime の implementation detail / display hint とする。
|
||||
- Browser から `display_ref`、`pod_name`、runtime display name を authority として渡さない。
|
||||
- Worker list/detail response は少なくとも以下を返せる形にする。
|
||||
- `runtime_id`
|
||||
- `worker_id`
|
||||
- `display_name`
|
||||
- `runtime_display_name`
|
||||
- `display_ref`
|
||||
- `implementation.kind`
|
||||
- local Pod runtime の場合のみ diagnostic/display 用 `implementation.pod_name`
|
||||
- API path は runtime scoped identity を表現する。
|
||||
- 例: `GET /api/runtimes/{runtime_id}/workers/{worker_id}`。
|
||||
- 横断 list は `GET /api/workers` とし、各 item に `runtime_id` / `worker_id` / `display_ref` を含める。
|
||||
- DB では `UNIQUE(runtime_id, worker_id)` を必須にする。
|
||||
- DB の primary key は composite PK でもよいが、run overview / lifecycle event / usage aggregate からの参照を考えると、surrogate `id` + `UNIQUE(runtime_id, worker_id)` を優先候補とする。
|
||||
- Worker run / lifecycle / usage / overview record は surrogate worker record id を参照できる形にしつつ、external API では runtime scoped identity を正とする。
|
||||
|
||||
### Session / overview boundary
|
||||
|
||||
- Backend は raw session log を durable authority として全量保持しない。
|
||||
- Backend internal Orchestrator の decision / overview / audit を durable projection とする。
|
||||
- raw session / verbose event stream / provider trace は runtime-local debug/source log とし、必要時に bounded read できる程度に留める。
|
||||
- Kanban / Orchestration UI は raw transcript ではなく overview / decision / worker state / usage aggregate を表示する。
|
||||
|
||||
### Safety / authority
|
||||
|
||||
- Kanban UI click から Backend internal Orchestrator が直接 shell/git/filesystem を実行する設計にしない。
|
||||
- implementation side effect 前には、既存 Ticket lifecycle authority に従って `queued -> inprogress` acceptance と decision record を残す。
|
||||
- dependency / conflict / dirty workspace / missing requirement / runtime unavailable の場合は、spawn せず decision / blocker / waiting reason を記録する。
|
||||
- Backend internal Orchestrator の tool set は permission/auth model を後から挟める境界にする。
|
||||
- Browser は local path / socket / runtime registry path / raw session path を authority として渡さない。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Backend internal Orchestrator の full implementation。
|
||||
- Kanban UI の完成。
|
||||
- Coder / Reviewer spawn の本実装。
|
||||
- Remote runtime protocol の本実装。
|
||||
- raw session 全量の Backend DB ingest。
|
||||
- Ticket storage の DB migration。
|
||||
- Permission / auth model の完成。
|
||||
- Worktree / git 操作を Backend process に直接持たせること。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
この Ticket は planning から開始する。ready に進める前に以下を満たす。
|
||||
|
||||
- Kanban operation から durable orchestration event を生成する方針が明文化されている。
|
||||
- `ready -> queued` を Orchestrator routing human gate として扱う方針が明記されている。
|
||||
- Backend internal Orchestrator Worker の責務と non-responsibility が明確になっている。
|
||||
- Backend internal Orchestrator に渡す domain-specific tool / operation surface が整理されている。
|
||||
- Bash / raw filesystem / raw socket / raw session 全量 ingest を internal Orchestrator authority にしない方針が明記されている。
|
||||
- WorkerRuntime registry と spawn intent の接続方針が明記されている。
|
||||
- UI 表示は `worker-name@runtime-name` 形式を使い、API authority にはしない方針が明記されている。
|
||||
- API canonical identity は `runtime_id` + `worker_id` とし、runtime scoped opaque id として扱う方針が明記されている。
|
||||
- DB は surrogate worker record id + `UNIQUE(runtime_id, worker_id)` を優先候補とし、run overview / lifecycle / usage 参照に使える方針が明記されている。
|
||||
- filesystem-capable work は local / remote runtime 上の Coder / Reviewer / helper Worker に委譲する方針が明記されている。
|
||||
- raw session ではなく overview / decision / lifecycle / usage aggregate を Backend durable projection とする方針が明記されている。
|
||||
- failure / blocker / retry / event ack semantics の初期方針が整理されている。
|
||||
- 実装まで含める場合は `cargo test -p yoi-workspace-server`、`cargo check -p yoi`、`git diff --check`、必要に応じて `nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,257 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T12:29:58Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T13:20:54Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T13:20:54Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T19:04:55Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T19:06:45Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- Ticket body は Backend internal Orchestrator runtime / Kanban operation / durable orchestration event / WorkerRuntime registry identity / spawn intent / session overview boundary / safety authority を具体的に列挙している。
|
||||
- `TicketRelationQuery` は blocking relation 0 件、routing 前 `TicketOrchestrationPlanQuery` は既存 plan 0 件だった。
|
||||
- Ticket の受け入れ条件は「planning artifact を明文化する」性質であり、Backend internal Orchestrator の full implementation は non-goal と明記されている。したがって Coder に実装詳細を固定させるのではなく、maintained design/planning document と必要最小限の boundary alignment を作る task として bounded に進められる。
|
||||
- risk flags 相当の domain は orchestration authority / runtime identity / durable event / raw session boundary だが、Bash/raw filesystem/raw socket/raw session ingest を authority にしない、`queued -> inprogress` acceptance を守る、Browser が raw local path を渡さない、という invariant が明示されている。risk は reviewer focus と escalation condition に反映すればよく、planning return 理由にはならない。
|
||||
- 現在 inprogress Ticket は 0 件、orchestration worktree は clean。既存 worktree は unrelated paused Ctrl-X cancel worktree のみで、この Ticket の branch/worktree はまだ無い。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。thread は create、planning->ready、ready->queued のみで未解決 blocker は記録されていない。
|
||||
- Relations / orchestration plan: relation 0 件、routing 前 plan 0 件。accepted plan `orch-plan-20260624-190611-1` を記録済み。
|
||||
- Workspace/code context: recent Worker runtime registry / spawn boundary work in `crates/workspace-server/src/hosts.rs`, `crates/workspace-server/src/server.rs`; Dashboard/Kanban queue surface in `crates/tui/src/dashboard/mod.rs`; docs/design structure under `docs/design/`。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。visible Pods は current Orchestrator と stopped/restorable historical role Pods only, active child work is none。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Kanban UI operation を Backend internal Orchestrator Worker へ安全に接続するための design/planning artifact を作る。Kanban operation は durable orchestration event として記録され、internal Orchestrator は domain-specific tools で event を処理し、実 filesystem-capable work は local/remote runtime 上の Coder/Reviewer/helper Worker へ委譲する境界を明確にする。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- Kanban click / API request から Backend process が直接 shell/git/filesystem を実行しない。
|
||||
- implementation side effect 前には既存 Ticket lifecycle authority、特に `queued -> inprogress` acceptance と decision record を保持する。
|
||||
- `ready -> queued` は Orchestrator routing human gate として扱い、unattended scheduler にしない。
|
||||
- Browser は raw local path / socket path / runtime registry path / raw session path / executable path を authority として渡さない。
|
||||
- UI display は `worker-name@runtime-name` 形式を使ってよいが、API authority にはしない。
|
||||
- canonical API identity は `runtime_id` + `worker_id` の runtime-scoped opaque id とする。
|
||||
- DB design は surrogate worker record id + `UNIQUE(runtime_id, worker_id)` を優先候補とし、run overview / lifecycle event / usage aggregate 参照に使える形にする。
|
||||
- Backend durable projection は raw transcript 全量ではなく overview / decision / lifecycle / usage aggregate を中心にする。raw session/provider trace は runtime-local source/debug log として bounded read に留める。
|
||||
- Backend internal Orchestrator の full implementation、Kanban UI completion、remote protocol、raw session full DB ingest、Ticket DB migration、permission/auth completion は non-goal。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Kanban operation から durable orchestration event を生成する方針が明文化される。
|
||||
- Backend internal Orchestrator Worker の責務 / non-responsibility、domain-specific tool/operation surface、failure/blocker/retry/event ack semantics が整理される。
|
||||
- WorkerRuntime registry と spawn intent の接続方針が明記される。
|
||||
- runtime/worker identity, display label, DB identity, event and overview projection boundaries が明確化される。
|
||||
- filesystem-capable work は runtime 上の Coder/Reviewer/helper Worker に委譲する方針が明記される。
|
||||
- existing docs/code organization に沿って maintained design artifact が置かれる。
|
||||
|
||||
Implementation latitude:
|
||||
- Primary output は docs/design などの maintained design document でよい。必要に応じて README/index や small comments/tests を追加してよい。
|
||||
- 既存 Workspace runtime registry / spawn boundary の code names に合わせて wording を調整してよい。
|
||||
- Full backend implementation や new DB schema migration はしない。
|
||||
|
||||
Escalate if:
|
||||
- Backend process が direct shell/git/filesystem authority を持つ設計にしないと要件を満たせない。
|
||||
- raw session full ingest / raw socket path / raw workspace path を API authority にする必要が出る。
|
||||
- `ready -> queued` の human gate を scheduler/lease に置き換える必要が出る。
|
||||
- API canonical identity を display label や raw Pod name に寄せる必要が出る。
|
||||
- Ticket DB migration / permission-auth model completion / remote runtime protocol をこの Ticket で固定する必要が出る。
|
||||
|
||||
Validation:
|
||||
- `git diff --check`
|
||||
- docs-only なら `cargo fmt --check` は不要だが、Rust/comments/tests を触るなら `cargo fmt --check` と relevant `cargo check` / `cargo test` を実施する。
|
||||
- If `crates/workspace-server` is touched: `cargo test -p yoi-workspace-server` and `cargo check -p yoi`。
|
||||
|
||||
Current code/docs map:
|
||||
- Primary docs: `docs/design/` and docs index/README if appropriate。
|
||||
- Context code: `crates/workspace-server/src/hosts.rs`, `crates/workspace-server/src/server.rs`, `crates/tui/src/dashboard/mod.rs`。
|
||||
- Avoid: root/original workspace operations, broad scheduler implementation, Kanban UI completion, remote Host protocol, raw session DB ingest, Ticket storage migration。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- accidental scheduler/lease semantics。
|
||||
- Backend internal Orchestrator gaining raw shell/filesystem/socket authority。
|
||||
- display labels becoming API authority。
|
||||
- runtime workspace root / process cwd / worker id / DB surrogate id confusion。
|
||||
- raw session/provider trace becoming Backend durable projection instead of bounded debug source。
|
||||
- design doc that repeats Ticket text without resolving event/ack/failure/spawn-intent boundaries.
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVWSQM22-backend-orch-runtime` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T19:07:09Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、blocking relation は 0 件、accepted plan `orch-plan-20260624-190611-1` を確認した。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- `00001KVWSQM22` は planning/design artifact として implementation-ready であり、Backend internal Orchestrator の full implementation は non-goal として明示した。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVWSQM22-backend-orch-runtime` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T19:08:11Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVWSQM22-backend-orch-runtime` と branch `work/00001KVWSQM22-backend-orch-runtime` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVWSQM22-backend-orch-runtime` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
- この Ticket は full implementation ではなく design/planning artifact として進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVWSQM22-backend-orch-runtime at: 2026-06-24T19:12:33Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report:
|
||||
|
||||
- 対象: Ticket `00001KVWSQM22`
|
||||
- 作業ブランチ: `work/00001KVWSQM22-backend-orch-runtime`
|
||||
- 作業場所: `/home/hare/Projects/yoi/.worktree/00001KVWSQM22-backend-orch-runtime`
|
||||
- コミット: `f901b9bee37a03faf380894926241107362da360`
|
||||
- コミットメッセージ: `docs: design backend internal orchestrator runtime`
|
||||
|
||||
変更ファイル:
|
||||
|
||||
- `docs/design/workspace-kanban-orchestrator-runtime.md`
|
||||
- Kanban/API 操作から Backend internal Orchestrator Worker へ接続するための設計文書を追加。
|
||||
- durable orchestration event の形、`ack` / `defer` / `fail`、idempotency/restart/retry 方針を整理。
|
||||
- Backend internal Orchestrator が routing/control-plane Worker であり、Bash/filesystem/git/raw socket/session authority を持たないことを明記。
|
||||
- Coder/Reviewer/helper など filesystem-capable work は typed spawn intent と `WorkerRuntimeRegistry` 経由で委譲する設計として整理。
|
||||
- runtime/worker identity、API 形状、DB projection 方針、`display_ref` / `pod_name` が authority ではないことを明記。
|
||||
- raw session は通常 projection ではなく bounded debug-only とする境界を整理。
|
||||
- dependency/conflict/dirty workspace/missing requirement/runtime unavailable などの waiting/blocker reason を整理。
|
||||
|
||||
- `docs/README.md`
|
||||
- 新しい設計文書を docs index に追加。
|
||||
|
||||
- `docs/design/overview.md`
|
||||
- `workspace-server` を local Workspace control-plane seam として位置づけ、raw path/socket/Pod/session を browser/API authority にしない方針を追記。
|
||||
|
||||
検証:
|
||||
|
||||
- `git diff --check`: success
|
||||
- docs-only 変更のため `cargo fmt` / `cargo test` / `cargo check` は実行していません。
|
||||
|
||||
残リスク / エスカレーション:
|
||||
|
||||
- 本 Ticket の意図どおり、設計・計画 artifact の作成までで停止しています。
|
||||
- Backend internal Orchestrator 本体、Kanban UI 完成、spawn 実装、remote runtime protocol、raw session DB ingest、Ticket storage DB migration、permission/auth completion は未実装のまま non-goal として明記しました。
|
||||
- merge / close は行っていません。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVWSQM22-backend-orch-runtime at: 2026-06-24T19:15:09Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
確認範囲:
|
||||
- child worktree `/home/hare/Projects/yoi/.worktree/00001KVWSQM22-backend-orch-runtime` のみ。
|
||||
- Ticket `item.md` / `thread.md` / `artifacts/orchestration-plan.jsonl`、commit `f901b9b...` の docs diff、追加 design doc を read-only で確認。
|
||||
- `git diff --check 8931227..f901b9b -- docs/...`: success。
|
||||
|
||||
承認根拠:
|
||||
- 追加された `docs/design/workspace-kanban-orchestrator-runtime.md` は Ticket の単純コピーではなく、維持対象の設計 artifact として Core rule / durable events / ack-defer-fail / internal Orchestrator tool surface / spawn intent / API identity / DB projection / failure semantics / future implementation order まで具体化している。
|
||||
- Kanban/API 操作から durable orchestration event、Backend internal Orchestrator Worker、`WorkerRuntimeRegistry`、typed spawn intent、filesystem-capable Coder/Reviewer/helper Worker への委譲までの鎖が明記されている。
|
||||
- `ready -> queued` は human gate であり unattended scheduler / lease ではない、と明記されている。
|
||||
- Backend internal Orchestrator は routing/control-plane Worker で、`Bash`、raw filesystem、git/worktree/build、raw socket/session path、raw session full ingest を持たない境界が明確。
|
||||
- API authority は `runtime_id` + `worker_id` の opaque runtime-scoped identity に限定し、`worker-name@runtime-name` / `display_ref` / `pod_name` / path / socket / session を authority にしない方針が明記されている。
|
||||
- DB/projection は surrogate `workers.id` + `UNIQUE(runtime_id, worker_id)`、run overview / lifecycle / usage aggregate 参照方針まで記述されている。
|
||||
- failure/blocker/retry/ack/defer/fail semantics は future implementation Ticket の入力として十分な初期方針になっている。
|
||||
- Non-goals も維持されており、full backend implementation、Kanban UI completion、remote protocol、raw session DB ingest、Ticket DB migration、permission/auth completion に踏み込んでいない。
|
||||
|
||||
Non-blocking notes:
|
||||
- child worktree 側の Ticket thread には Orchestrator 側で記録した implementation_report が見えなかったが、Orchestrator 側 Ticket record には report を記録済みであり、レビューは commit/diff と Coder report に基づいて行った。
|
||||
- 新規 design doc は diff 上 EOF newline が無いように見えたが、`git diff --check` は通っており blocker ではない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T19:15:35Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVWSQM22-backend-orch-runtime` が implementation branch `work/00001KVWSQM22-backend-orch-runtime` に design artifact を commit した。
|
||||
- design commit: `f901b9be docs: design backend internal orchestrator runtime`
|
||||
- Reviewer `yoi-reviewer-00001KVWSQM22-backend-orch-runtime` は read-only review で `approve`。durable orchestration event、ack/defer/fail、Backend internal Orchestrator tool surface、spawn intent、runtime/worker identity、DB projection、failure semantics、non-goals が future implementation Ticket の入力として十分に具体化されていることを確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVWSQM22-backend-orch-runtime` を merge 済み。
|
||||
- merge commit: `4e713fce merge: 00001KVWSQM22 backend orchestrator design`
|
||||
|
||||
Changed files:
|
||||
- `docs/design/workspace-kanban-orchestrator-runtime.md`
|
||||
- `docs/README.md`
|
||||
- `docs/design/overview.md`
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `git diff --check HEAD~1..HEAD`: success
|
||||
- `git diff --check f367d732..HEAD -- docs .yoi/tickets/00001KVWSQM22`: success
|
||||
|
||||
Notes:
|
||||
- docs/design-only change のため Cargo validation は実施していない。
|
||||
- Reviewer non-blocking note: child worktree 側の Ticket thread には Orchestrator 側 report が見えなかったが、Orchestrator 側 Ticket record には report/review/outcome を記録済み。
|
||||
- Backend internal Orchestrator 本体、Kanban UI completion、Coder/Reviewer spawn 実装、remote runtime protocol、raw session DB ingest、Ticket DB migration、permission/auth completion は non-goal のまま。
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T19:15:42Z from: inprogress to: done reason: merged_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Design/planning artifact is merged into the orchestration branch and validated.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `4e713fce merge: 00001KVWSQM22 backend orchestrator design`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration` succeeded:
|
||||
- `git diff --check HEAD~1..HEAD`
|
||||
- `git diff --check f367d732..HEAD -- docs .yoi/tickets/00001KVWSQM22`
|
||||
|
||||
Closure is not performed here; this state records implementation/design completion after merge/validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,142 @@
|
||||
---
|
||||
title: 'Redesign Plugin WASM runtime API and execution model'
|
||||
state: 'closed'
|
||||
created_at: '2026-06-24T19:31:28Z'
|
||||
updated_at: '2026-06-24T19:55:18Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T19:39:36Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Yoi の Plugin API はまだ public release されていないにもかかわらず、実装上 `LegacyToolAdapter` / legacy raw `wasm` runtime と新しい `wasm-component` runtime が併存している。外部互換性を守る必要がない段階で legacy layer を残すと、Plugin runtime の責務境界、権限設計、service / ingress 実行モデル、host API の将来設計が曖昧になる。
|
||||
|
||||
現状の Plugin 実行モデルは、Pod process 内の Feature として Plugin を有効化し、Tool call / explicit ingress dispatch のタイミングで Wasm component の exported function を同期的に呼ぶ形である。Tool Plugin には使えるが、Discord Gateway / Slack Socket Mode のような長寿命 WebSocket integration、host-managed background service、非同期 ingress delivery、heartbeat / reconnect / backpressure を必要とする用途には足りない。
|
||||
|
||||
また、`host_api.websocket` は `open` / `send-text` / `recv(timeout)` / `close` の pull 型 API であり、Plugin service が WebSocket frame arrival を非同期 event として受け取る実行モデルになっていない。Service / Ingress の型と下地はあるが、実運用可能な event-driven Plugin runtime としては未完成である。
|
||||
|
||||
この Ticket では、未公開機能としての整理を前提に legacy runtime を削除し、要件を満たす WASM Plugin runtime API / execution model を設計し直す。
|
||||
|
||||
## 目的
|
||||
|
||||
- 未公開の legacy Plugin runtime / adapter を active design から削除する。
|
||||
- Plugin runtime を `wasm-component` / Component Model 中心に一本化する。
|
||||
- Tool Plugin、Service Plugin、Ingress Plugin の責務と実行モデルを明確化する。
|
||||
- 長寿命 integration に必要な host-managed event runtime を設計する。
|
||||
- WebSocket を `recv(timeout)` pull primitive ではなく、host-owned connection / event delivery / outbound command model として扱えるようにする。
|
||||
- Plugin が hidden context injection や ambient authority を持たず、明示 grant / explicit history / domain operation の原則を保つ。
|
||||
|
||||
## 要件
|
||||
|
||||
### Legacy runtime cleanup
|
||||
|
||||
- public release 前であるため、`LegacyToolAdapter` / raw `wasm` runtime / `yoi-plugin-wasm-1` 互換 layer は active runtime から削除する方針にする。
|
||||
- 新規 Plugin API は `wasm-component` runtime のみを正とする。
|
||||
- manifest schema から legacy runtime を残す必要があるかを確認し、不要なら reject する。
|
||||
- compatibility alias / fallback を作らない。
|
||||
- tests / templates / docs から legacy wording を取り除く。
|
||||
- migration は不要。既存 private fixture が必要なら fixture を更新する。
|
||||
|
||||
### Runtime model
|
||||
|
||||
- Plugin は Pod process 内の untrusted extension であり、ambient process / filesystem / network authority を持たない。
|
||||
- Component call は bounded execution とし、fuel / memory / input / output limits を維持する。
|
||||
- Tool Plugin は request-response 型の bounded operation として扱う。
|
||||
- Service Plugin は host-managed lifecycle を持つ。
|
||||
- start
|
||||
- status
|
||||
- stop
|
||||
- failure / restart / disable semantics
|
||||
- Ingress Plugin は host-managed event queue から配送される event を処理する。
|
||||
- 同一 Plugin instance の concurrency policy を明確にする。
|
||||
- v0 は per-plugin serial dispatch でよい。
|
||||
- queue / backpressure / timeout / failure handling を定義する。
|
||||
- `start()` が無限 loop / long polling / recv loop を実行するモデルにしない。
|
||||
|
||||
### Service / Ingress event runtime
|
||||
|
||||
- Plugin service 用の event queue を導入する方針にする。
|
||||
- Host が event source を管理し、Plugin の `handle-ingress` 相当へ配送する。
|
||||
- event delivery は bounded / observable / retry-safe にする。
|
||||
- event は source / ingress name / payload / created_at / delivery attempt / correlation id を持つ。
|
||||
- Plugin output は raw side effect ではなく command / result として返す。
|
||||
- websocket send
|
||||
- request dispatch
|
||||
- domain event append
|
||||
- diagnostic / status update
|
||||
- output command の許可は manifest declaration + enablement grant で制御する。
|
||||
|
||||
### WebSocket runtime
|
||||
|
||||
- 現行 `host_api.websocket.open/send/recv/close` pull API を、長寿命 integration の正 API として扱わない。
|
||||
- Discord Gateway などを実装できる host-owned WebSocket driver を設計する。
|
||||
- Host が connection lifecycle を管理する。
|
||||
- connect
|
||||
- reader task
|
||||
- incoming frame queue
|
||||
- close / error detection
|
||||
- reconnect / resume hook
|
||||
- heartbeat support
|
||||
- backpressure
|
||||
- Incoming WS frame は Plugin service の ingress event として配送する。
|
||||
- Plugin は必要な返信を output command として返し、Host が WebSocket send を実行する。
|
||||
- binary / text / close / ping / pong の扱いを明確化する。
|
||||
- guest-supplied handshake headers / auth injection は grant / secret ref / host policy 経由で扱う。
|
||||
|
||||
### Host API and authority
|
||||
|
||||
- Host API は explicit capability として扱う。
|
||||
- request
|
||||
- websocket service driver
|
||||
- scoped fs
|
||||
- future domain operations
|
||||
- Plugin package declaration と enablement grant の両方が必要であることを維持する。
|
||||
- Workspace filesystem scope / Pod tool authority を Plugin が自動継承しない。
|
||||
- raw session / raw socket path / local runtime path を Plugin authority にしない。
|
||||
- Plugin が prompt/context に隠し injection する API は作らない。
|
||||
- MCP bridge は Plugin API と混同しない。
|
||||
|
||||
### Manifest / PDK / WIT
|
||||
|
||||
- `plugin.toml` の runtime / surface / service / ingress / host_api declaration を再整理する。
|
||||
- `world tool` と `world instance` の責務を見直す。
|
||||
- Service / Ingress 用の WIT / PDK API を、event-driven runtime に合う形へ更新する。
|
||||
- WebSocket は low-level recv loop ではなく subscription / event / command model を表現できる API にする。
|
||||
- PDK が長寿命 loop を推奨しない形にする。
|
||||
- templates は新 API のみを生成する。
|
||||
|
||||
### Observability / status
|
||||
|
||||
- Plugin instance / service の status を backend / Pod から確認できるようにする。
|
||||
- WebSocket connection status、last event、last error、queue depth、restart count、dropped event count などの diagnostic shape を設計する。
|
||||
- Plugin service failure は fail closed とし、LLM-visible tool surface に曖昧な成功として出さない。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Discord Plugin の実装。
|
||||
- Public plugin registry / install / update / signature policy の完成。
|
||||
- Remote plugin execution runtime。
|
||||
- MCP を Plugin runtime に統合すること。
|
||||
- Plugin に unrestricted filesystem / shell / network authority を与えること。
|
||||
- Legacy runtime 互換性の維持。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- `LegacyToolAdapter` / raw `wasm` runtime / `yoi-plugin-wasm-1` 互換 layer が active runtime から削除されている。
|
||||
- `plugin.toml` / manifest validation は legacy runtime を新規 Plugin runtime として受け付けない。
|
||||
- Plugin runtime は `wasm-component` / Component Model を正とする実装に一本化されている。
|
||||
- Tool Plugin は bounded request-response operation として動作し、既存 Tool registration / execution tests が新 runtime model で通る。
|
||||
- Service Plugin は host-managed lifecycle として `start` / `status` / `stop` / failure state を扱える。
|
||||
- `start()` が long-running loop / polling loop / WebSocket recv loop を担わない実行モデルになっている。
|
||||
- Ingress event は host-managed queue / dispatcher から Plugin instance に配送できる。
|
||||
- Ingress dispatch には bounded queue、serial dispatch、backpressure、timeout、failure handling の実装または型境界がある。
|
||||
- WebSocket は host-owned connection driver として扱われ、incoming frame を ingress event に変換できる。
|
||||
- Plugin は WebSocket 返信・request dispatch・diagnostic update などの side effect を output command として返し、Host が grant 検査後に実行する。
|
||||
- 現行 `open` / `send-text` / `recv(timeout)` / `close` pull API は、長寿命 integration の正 API から外れている、または互換目的で残す場合も public/recommended API として露出していない。
|
||||
- Manifest / WIT / PDK / templates が新しい Component Model runtime、Service lifecycle、Ingress event、WebSocket command model に合わせて更新されている。
|
||||
- Plugin package declaration と enablement grant の両方が必要な authority 境界が維持されている。
|
||||
- Plugin は workspace filesystem scope、Pod tool authority、raw session、raw socket path、local runtime path を自動継承しない。
|
||||
- Plugin instance / service / WebSocket connection の status と diagnostics を Pod/backend から確認できる。
|
||||
- 関連 docs と tests から legacy runtime 前提の記述・fixture が削除または更新されている。
|
||||
- `cargo test -p pod`、`cargo test -p yoi-plugin-pdk`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,10 @@
|
||||
Decomposed into the Plugin objective and concrete implementation Tickets:
|
||||
|
||||
- 00001KVXK0WD3 Remove legacy raw WASM Plugin runtime
|
||||
- 00001KVXK0WDH Reject legacy Plugin runtime in manifest and CLI diagnostics
|
||||
- 00001KVXK0WDQ Define Plugin Service lifecycle and ingress queue runtime
|
||||
- 00001KVXK0WDX Add Plugin service output command model
|
||||
- 00001KVXK0WE4 Add host-owned WebSocket driver for Plugin services
|
||||
- 00001KVXK0WEA Update Plugin WIT PDK templates for service event runtime
|
||||
|
||||
The broad redesign record is no longer an implementation work item.
|
||||
@@ -0,0 +1,135 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T19:31:28Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T19:39:33Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T19:39:33Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T19:39:36Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T19:40:42Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: return_to_planning
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- Ticket body は Plugin WASM runtime の全面 redesign を要求しているが、acceptance criteria が legacy runtime removal、Component Model only 化、Tool/Service/Ingress runtime、host-managed WebSocket driver、event queue/backpressure/retry、output command/grant checks、Manifest/WIT/PDK/templates 更新、status diagnostics、docs/tests/Nix validation まで含んでおり、単一の実装 Ticket としては broad multi-surface effort になっている。
|
||||
- bounded context check で既存 `docs/design/plugin-component-model.md` と `docs/development/plugin-development.md` を確認したところ、現行 docs/code direction は raw core-Wasm runtime を explicit compatibility/transitional support として残し、`PluginInstanceRegistry` で legacy raw-wasm / `yoi:plugin/tool@1.0.0` component packages を adapter する方針を記録している。これは本 Ticket の「compatibility alias / fallback を作らない」「legacy runtime を active runtime から削除」と衝突する可能性がある。
|
||||
- `TicketRelationQuery` は blocking relation 0 件、`TicketOrchestrationPlanQuery` は既存 plan 0 件だったが、関連 docs/code の recorded direction と Ticket 要件の間に未解決の design decision が残っている。
|
||||
- これは risk flag だけの問題ではなく、実装前に release/pre-release compatibility 方針、WIT/manifest/service event API、WebSocket driver execution model、legacy removal scope、分割順序を固定しないと coder が project-wide API を決めてしまう種類の不足である。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `00001KVXHVCR5` の `item.md`, `thread.md`。thread は create、planning->ready、ready->queued のみで、詳細な design decision / split plan / implementation order は記録されていない。
|
||||
- Relations / orchestration plan: relation 0 件、plan 0 件。
|
||||
- Docs/code context:
|
||||
- `docs/design/plugin-component-model.md`: Component Model migration、legacy raw `wasm` explicit/transitional support、`PluginInstanceRegistry` adapter 方針、host API grant boundary。
|
||||
- `docs/development/plugin-development.md`: `wasm-component` preferred runtime だが raw core-Wasm runtime が compatibility/transitional support として説明されている。
|
||||
- Grep context: `LegacyToolAdapter`, `wasm-component`, `host_api.websocket`, Service/Ingress/PluginInstance 周辺が複数 file に分散。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean、inprogress Ticket は 0 件、implementation worktree/branch for this Ticket は未作成。
|
||||
|
||||
Missing decision / information:
|
||||
- この Ticket を「一括実装 Ticket」として進めるのか、Objective + concrete Tickets に分割するのか。
|
||||
- Legacy raw `wasm` / `yoi-plugin-wasm-1` を即削除するか、現行 docs の transitional/adapter 方針を明示的に撤回するか。
|
||||
- v0 で実装する exact surface: Tool runtime cleanup のみ、Service/Ingress event queue boundary、WebSocket driver、WIT/PDK/templates、diagnostics/status のどこまでを同一 Ticket の done condition に含めるか。
|
||||
- `plugin.toml` / WIT / PDK の concrete schema/API shape と、現行 `host_api.websocket` pull API を reject/remove/deprecate/internal-only のどれにするか。
|
||||
- Wasmtime/component/service runtime の binary size / Nix / sandbox policy / execution limits に関する validation scope。
|
||||
|
||||
Why implementation latitude is insufficient:
|
||||
- Coder の local tactic selection で legacy compatibility policy や public/pre-release Plugin API direction を固定すると、manifest/WIT/PDK/templates/docs/tests すべての public-facing shape を一度に決めてしまう。
|
||||
- Service/Ingress event runtime と WebSocket driver は execution model と host authority boundary の設計そのものであり、単なる file-local implementation detail ではない。
|
||||
- 既存 docs に recorded direction があり、Ticket がそれを上書きするかどうかを実装者判断にすると project design authority を越える。
|
||||
|
||||
Next planning question/action:
|
||||
- この Ticket を Objective/roadmap context として扱い、以下のような concrete Tickets に分割するかを決める。
|
||||
1. Legacy raw `wasm` runtime removal / manifest rejection / docs fixture cleanup。
|
||||
2. Service/Ingress event queue and PluginInstance lifecycle boundary。
|
||||
3. Host-owned WebSocket driver design/implementation。
|
||||
4. WIT/PDK/templates update for event/command model。
|
||||
5. Plugin status/diagnostics overview。
|
||||
- あるいは、まず design/planning artifact Ticket に変更し、exact v0 schema/API/non-goals を決めてから実装 Ticket を切る。
|
||||
|
||||
Next action:
|
||||
- `queued -> planning` に戻し、Intake/planning で split plan または explicit v0 scope decision を作る。
|
||||
- Coder/Reviewer Pod は起動しない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T19:40:53Z from: queued to: planning reason: missing_plugin_runtime_design_scope_and_split_decision field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Queued Ticket is returned to planning before any implementation side effect.
|
||||
|
||||
Concrete missing decisions/information:
|
||||
- Whether this broad Plugin runtime redesign is a single implementation Ticket or should become Objective context plus concrete implementation Tickets.
|
||||
- Whether current recorded transitional/adapter support for raw `wasm` / `yoi-plugin-wasm-1` is explicitly revoked before public release.
|
||||
- Exact v0 scope for legacy removal, Service/Ingress event queue, WebSocket driver, WIT/PDK/templates, and diagnostics/status.
|
||||
- Concrete manifest/WIT/PDK/API shape and how current `host_api.websocket` pull API is handled.
|
||||
- Validation and packaging scope for component/service runtime changes.
|
||||
|
||||
Checked context:
|
||||
- Ticket body/thread; relation 0 件; orchestration plan 0 件。
|
||||
- `docs/design/plugin-component-model.md` and `docs/development/plugin-development.md`, which currently describe raw core-Wasm as explicit compatibility/transitional support and mention adapter behavior.
|
||||
- Workspace state is clean and no implementation worktree/branch was created.
|
||||
|
||||
Why implementation latitude is insufficient:
|
||||
- These choices fix project-wide Plugin API, manifest, WIT, PDK, runtime authority, and service execution semantics. They conflict with or supersede existing recorded design direction and are not safe as coder-local tactic choices.
|
||||
|
||||
Next planning action:
|
||||
- Decide split plan / Objective context or convert this to an explicit design/planning artifact Ticket with a bounded v0 API decision before implementation routing.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: hare at: 2026-06-24T19:55:18Z from: planning to: closed reason: closed field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を closed にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: close author: hare at: 2026-06-24T19:55:18Z status: closed -->
|
||||
|
||||
## 完了
|
||||
|
||||
Decomposed into the Plugin objective and concrete implementation Tickets:
|
||||
|
||||
- 00001KVXK0WD3 Remove legacy raw WASM Plugin runtime
|
||||
- 00001KVXK0WDH Reject legacy Plugin runtime in manifest and CLI diagnostics
|
||||
- 00001KVXK0WDQ Define Plugin Service lifecycle and ingress queue runtime
|
||||
- 00001KVXK0WDX Add Plugin service output command model
|
||||
- 00001KVXK0WE4 Add host-owned WebSocket driver for Plugin services
|
||||
- 00001KVXK0WEA Update Plugin WIT PDK templates for service event runtime
|
||||
|
||||
The broad redesign record is no longer an implementation work item.
|
||||
|
||||
|
||||
---
|
||||
@@ -0,0 +1 @@
|
||||
{"id":"orch-plan-20260624-201247-1","ticket_id":"00001KVXK0WD3","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVXK0WD3` は dependency chain の先頭で implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WD3-remove-legacy-wasm-runtime` と branch `work/00001KVXK0WD3-remove-legacy-wasm-runtime` で、Pod runtime 内の `LegacyToolAdapter` / raw-WASM active execution path を削除し、Component Model path を唯一の active execution path にする。Manifest/CLI diagnostics rejection は後続 `00001KVXK0WDH` の範囲に残す。","branch":"work/00001KVXK0WD3-remove-legacy-wasm-runtime","worktree":"/home/hare/Projects/yoi/.worktree/00001KVXK0WD3-remove-legacy-wasm-runtime","role_plan":"Orchestrator: accept/routing, worktree creation, final integration/validation/cleanup. Coder: remove active legacy raw-WASM runtime path in dedicated child worktree. Reviewer: read-only review focusing on preserving component Tool execution, grants, discovery/enablement/ToolRegistry, and not implementing manifest/CLI rejection slice."},"author":"yoi-orchestrator","at":"2026-06-24T20:12:47Z"}
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: 'Remove legacy raw WASM Plugin runtime'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-24T20:51:02Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:11:56Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Plugin platform roadmap は、public release 前に raw core-Wasm runtime を compatibility bridge として残す方針を撤回し、`wasm-component` / Component Model を正の Plugin runtime として一本化する。未公開機能に legacy layer を残すと、Manifest / WIT / PDK / runtime authority / Service execution model の境界が曖昧になる。
|
||||
|
||||
この Ticket は最初の実装 slice として、Pod runtime 内の legacy raw `wasm` execution path と `LegacyToolAdapter` を削除する。Manifest validation / CLI diagnostics の外向き rejection は別 Ticket で扱う。
|
||||
|
||||
## 要件
|
||||
|
||||
- `PluginInstanceRuntime::LegacyToolAdapter` 相当の active execution path を削除する。
|
||||
- raw core-Wasm tool execution を Plugin instance runtime の active path から外す。
|
||||
- `wasm-component` runtime を Plugin execution の唯一の active runtime path とする。
|
||||
- legacy path 削除に伴い、不要になった adapter-only tests / fixtures / helper を削除または component runtime 用に更新する。
|
||||
- Plugin Tool execution は Component Model path で維持する。
|
||||
- Host API grant boundary、package discovery、enablement、digest pinning、ToolRegistry 登録の既存挙動を壊さない。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Manifest / CLI diagnostics で legacy runtime を拒否する外向き UX の完成。
|
||||
- Service / Ingress event queue の実装。
|
||||
- WebSocket driver の実装。
|
||||
- WIT / PDK / templates の service event model 更新。
|
||||
- Public registry / install / update policy。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- `LegacyToolAdapter` または同等の legacy raw-Wasm adapter が active runtime から削除されている。
|
||||
- raw `wasm` runtime を通じた Plugin Tool execution path が使われていない。
|
||||
- Component Model Plugin Tool execution の既存 tests が通る。
|
||||
- Legacy runtime 削除に伴う dead code / dead tests / obsolete fixtures が整理されている。
|
||||
- Plugin discovery / enablement / Tool registration / grant validation の既存 tests が通る。
|
||||
- `cargo test -p pod`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,273 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T19:51:56Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T19:55:29Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T19:55:29Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T20:11:56Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T20:13:18Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- Ticket body は legacy raw `wasm` runtime redesign のうち最初の concrete slice として、Pod runtime 内の `PluginInstanceRuntime::LegacyToolAdapter` 相当 active execution path を削除し、`wasm-component` / Component Model path を唯一の active runtime path にする範囲に限定している。
|
||||
- Manifest / CLI diagnostics rejection、Service / Ingress event queue、WebSocket driver、WIT / PDK / templates は明示的に non-goal / 後続 Ticket に分割されている。
|
||||
- `TicketRelationQuery` は 1 件で、この Ticket は後続 Ticket から参照される dependency chain の先頭であり、blocking outgoing dependency はない。
|
||||
- `TicketOrchestrationPlanQuery` は routing 前 plan 0 件。accepted plan `orch-plan-20260624-201247-1` を記録済み。
|
||||
- bounded context check で `crates/pod/src/feature/plugin.rs` の `LegacyToolAdapter` / raw `wasm` active path、`crates/manifest/src/plugin.rs` と `crates/yoi/src/plugin_cli.rs` の legacy manifest/diagnostic fixtures、docs の transitional runtime 記述を確認した。Ticket は manifest rejection を後続 Ticket に分けているため、残る不確実性は local implementation / test update に収まる。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。thread は create、planning->ready、ready->queued のみで未解決 blocker は記録されていない。
|
||||
- Relations / orchestration plan: relation 1 件(後続 Ticket がこの Ticket に依存する view)、routing 前 plan 0 件。
|
||||
- Code/docs context: `crates/pod/src/feature/plugin.rs` の `LegacyToolAdapter` / raw WASM handling、`crates/manifest/src/plugin.rs` / `crates/yoi/src/plugin_cli.rs` の legacy runtime constants/tests、Plugin docs の current transition notes。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。inprogress Ticket は 0 件。
|
||||
- Queue context: 他の queued Plugin follow-up Tickets は dependency chain 上でこの Ticket の完了後に進める。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Pod Plugin runtime の active execution path から legacy raw core-WASM Tool adapter を削除し、Plugin Tool execution を Component Model runtime path に一本化する。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- この Ticket では active runtime execution path を整理する。Manifest / CLI の外向き rejection UX は後続 `00001KVXK0WDH` の範囲として残す。
|
||||
- Component Model Plugin Tool execution、Host API grant boundary、package discovery、enablement、digest pinning、ToolRegistry registration は維持する。
|
||||
- raw core-WASM path を compatibility fallback として active execution に残さない。
|
||||
- Service / Ingress event runtime、WebSocket driver、WIT/PDK/templates service event update は実装しない。
|
||||
- broad Plugin redesign や public registry/install/update policy に範囲を広げない。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- `PluginInstanceRuntime::LegacyToolAdapter` または同等の legacy raw-WASM adapter が active runtime から削除される。
|
||||
- raw `wasm` runtime を通じた Plugin Tool execution path が使われない。
|
||||
- Component Model Plugin Tool execution tests が通る。
|
||||
- Legacy runtime 削除に伴う dead code / dead tests / obsolete fixtures が整理される。
|
||||
- Discovery / enablement / Tool registration / grant validation の既存挙動が壊れない。
|
||||
|
||||
Implementation latitude:
|
||||
- `PluginInstanceRuntime` enum の shape を単一 component path に畳むか、名前を残して variant を整理するかは既存 code style に合わせてよい。
|
||||
- Manifest layer の legacy constants/tests は、active runtime removal に必要な最小限だけ調整してよい。ただし user-facing rejection/diagnostic completion は後続 Ticket に残す。
|
||||
- Docs の compatibility/transitional wording は、active runtime removal と矛盾する部分を最小限更新してよい。
|
||||
|
||||
Escalate if:
|
||||
- Component Model path だけでは既存 Tool execution / grant validation / ToolRegistry registration を維持できない。
|
||||
- Manifest/CLI outward rejection を同時実装しないと build/test が成立しない。
|
||||
- Wasmtime/component runtime limits or sandbox boundaries を再設計する必要がある。
|
||||
- Service/Ingress/WebSocket/WIT/PDK の設計変更が必要になる。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p pod`
|
||||
- `cargo check -p yoi`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
- 必要に応じて focused Plugin tests / `cargo test -p manifest` / `cargo test -p yoi plugin_cli`。
|
||||
|
||||
Current code/docs map:
|
||||
- Primary: `crates/pod/src/feature/plugin.rs`。
|
||||
- Secondary: `crates/manifest/src/plugin.rs`, `crates/yoi/src/plugin_cli.rs`, Plugin docs/templates only as needed for active runtime removal consistency。
|
||||
- Avoid: full service runtime, WebSocket driver, WIT/PDK event model, remote plugin registry, root/original workspace operations。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- legacy raw-WASM execution path accidentally remains as fallback。
|
||||
- Component Model Tool execution regression。
|
||||
- host API grant / digest pinning / enablement / ToolRegistry registration regression。
|
||||
- scope creep into manifest rejection or Service/Ingress runtime beyond this slice。
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WD3-remove-legacy-wasm-runtime` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T20:14:08Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、blocking outgoing relation は 0 件、accepted plan `orch-plan-20260624-201247-1` を確認した。
|
||||
- 後続 queued Tickets (`00001KVXK0WDH`, `00001KVXK0WDQ`, `00001KVXK0WDX`, `00001KVXK0WE4`, `00001KVXK0WEA`) は dependency chain 上この Ticket またはその後続 prerequisites に blocked として orchestration plan に記録済み。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WD3-remove-legacy-wasm-runtime` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T20:14:56Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- queue review で dependency chain を確認し、`00001KVXK0WD3` のみを先頭 prerequisite として受理した。
|
||||
- 後続 queued Tickets (`00001KVXK0WDH`, `00001KVXK0WDQ`, `00001KVXK0WDX`, `00001KVXK0WE4`, `00001KVXK0WEA`) は relation/orchestration plan 上の dependency blocker として待機理由を記録した。
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WD3-remove-legacy-wasm-runtime` と branch `work/00001KVXK0WD3-remove-legacy-wasm-runtime` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVXK0WD3-legacy-wasm-removal` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVXK0WD3-legacy-wasm-removal at: 2026-06-24T20:43:50Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report:
|
||||
|
||||
実装概要:
|
||||
- `PluginInstanceRuntime::LegacyToolAdapter` 相当の raw core-WASM fallback 実行経路を削除した。
|
||||
- `wasm-component` の Tool world は `ComponentToolAdapter` として明示的に扱い、ToolRegistry 経由の実行は `run_plugin_component_tool` のみを使うよう変更した。
|
||||
- raw `wasm` runtime metadata は static inspection / instance startup の両方で非対応として扱い、実行 fallback しないようにした。
|
||||
- Component Model Plugin Tool / Component Instance 実行経路、host API grant boundary、ToolRegistry 登録経路は維持した。
|
||||
- raw WASM 実行用の `wasmi` 依存・テスト・古い helper を削除した。
|
||||
- `package.nix` の `cargoHash` を更新した。
|
||||
- Component Model design doc の現状記述を active runtime に合わせて更新した。
|
||||
|
||||
変更ファイル:
|
||||
- `crates/pod/src/feature/plugin.rs`
|
||||
- `crates/pod/Cargo.toml`
|
||||
- `Cargo.lock`
|
||||
- `package.nix`
|
||||
- `docs/design/plugin-component-model.md`
|
||||
|
||||
Validation:
|
||||
- `cargo test -p pod feature::plugin --lib`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed in unrelated prompt snapshot tests:
|
||||
- `workflow::tests::workflow_usage_guidance_contract_snapshot_matches_prompt_resource`
|
||||
- `tests::companion_prompt_matches_resource_snapshot`
|
||||
|
||||
Commit:
|
||||
- `741d71327aec213e564d47a4b4c37141c727803c refactor: remove legacy wasm plugin runtime`
|
||||
|
||||
Residual risks / notes:
|
||||
- Full `cargo test -p pod` failure appears unrelated to this Plugin runtime change and was not fixed here.
|
||||
- Follow-up Ticket `00001KVXK0WDH` remains responsible for manifest / CLI legacy runtime rejection UX. This implementation only removes active runtime fallback and minimal static inspection consistency.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVXK0WD3-legacy-wasm-removal at: 2026-06-24T20:48:55Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
確認範囲:
|
||||
- child worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WD3-remove-legacy-wasm-runtime` のみで read-only inspection。
|
||||
- Ticket / IntentPacket / `1b5a39db..HEAD` の diff を確認。
|
||||
- reviewer では cargo/nix は再実行していない。`git diff --check 1b5a39db..HEAD` は問題なし。
|
||||
|
||||
承認根拠:
|
||||
- Ticket / IntentPacket の核心である「Pod Plugin runtime の active execution path から legacy raw core-WASM Tool adapter を削除し、Component Model path に一本化」が満たされている。
|
||||
- `crates/pod/src/feature/plugin.rs` から `LegacyToolAdapter` / `PluginWasmTool` / `run_plugin_wasm_tool` / `wasmi` host adapter 系が削除され、`crates/pod/Cargo.toml` からも `wasmi` dependency が削除されている。
|
||||
- raw `wasm` runtime は static inspection で `eligible: false` かつ active execution path ではない diagnostic になり、`PluginInstanceRuntime::new` でも `PLUGIN_RUNTIME_WASM_KIND` が fail-closed するため、fallback 実行は残っていない。
|
||||
- Component Model Tool path は `ComponentToolAdapter -> run_plugin_component_tool -> read_resolved_plugin_runtime_component -> wasmtime::component` に整理され、ToolRegistry 登録も既存の `ToolContribution` / `plugin_instance_tool_definition` 経由を維持している。
|
||||
- Host API grant / digest binding / tool permission validation は `authorize_plugin_tool`、`authorize_plugin_host_api`、`validate_component_imports` 側で維持され、component import permission/grant check tests も残っている。
|
||||
- Manifest / CLI rejection UX には踏み込んでおらず、raw `wasm` constants / manifest parsing が残っているのは後続 Ticket `00001KVXK0WDH` の範囲として許容できる。
|
||||
- Service / Ingress / WebSocket / WIT / PDK runtime への不要な scope creep は見当たらない。
|
||||
|
||||
Non-blocking notes:
|
||||
- 報告された `cargo test -p pod` 全体失敗は prompt snapshot 2 件で、今回 diff の変更対象外に見えるため blocker とは判断しない。ただし完了処理時には既知 unrelated failure として扱う根拠を残すか、別対応後に再実行するのが安全。
|
||||
- `docs/development/plugin-development.md` には raw core-Wasm compatibility がまだ有効に読める文言が残っている。今回 Ticket の主目的は active runtime removal で、外向き rejection/docs 全面更新は後続範囲なので blocker ではないが、後続 Ticket で整理した方がよい。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T20:50:37Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVXK0WD3-legacy-wasm-removal` が implementation branch `work/00001KVXK0WD3-remove-legacy-wasm-runtime` に実装を commit した。
|
||||
- implementation commit: `741d7132 refactor: remove legacy wasm plugin runtime`
|
||||
- Reviewer `yoi-reviewer-00001KVXK0WD3-legacy-wasm-removal` は read-only review で `approve`。legacy raw-WASM fallback execution path が削除され、Component Model Tool path、host API grant、digest binding、ToolRegistry registration が維持され、manifest/CLI rejection や Service/Ingress/WebSocket/WIT/PDK へ scope creep していないことを確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVXK0WD3-remove-legacy-wasm-runtime` を merge 済み。
|
||||
- merge commit: `29953111 merge: 00001KVXK0WD3 legacy wasm removal`
|
||||
|
||||
Implemented behavior:
|
||||
- `crates/pod/src/feature/plugin.rs` から `LegacyToolAdapter` / raw core-WASM Tool execution helper / `wasmi` host adapter 系を削除。
|
||||
- raw `wasm` runtime は static inspection と instance startup で fail-closed / non-executable diagnostic になり、active fallback execution path は残していない。
|
||||
- Component Model Tool runtime path は `ComponentToolAdapter` / `run_plugin_component_tool` / `wasmtime::component` に整理。
|
||||
- `crates/pod/Cargo.toml` から `wasmi` dependency を削除し、`Cargo.lock` と `package.nix` cargoHash を更新。
|
||||
- `docs/design/plugin-component-model.md` の transitional runtime wording を active runtime removal に合わせて最小更新。
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo test -p pod feature::plugin --lib`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed in two prompt guidance snapshot assertions that are outside this Plugin diff:
|
||||
- `prompt::catalog::tests::pod_orchestration_guidance_section_renders_resource_body`
|
||||
- `prompt::system::tests::pod_orchestration_guidance_is_included_for_pod_management_tools`
|
||||
- Plugin focused tests within the same full run passed, including `core_wasm_is_not_silently_reinterpreted_as_component`, component execution, component grant/import, lifecycle, memory/table/output cap tests.
|
||||
|
||||
Notes:
|
||||
- Full `cargo test -p pod` failure is recorded as an existing/unrelated prompt-resource assertion issue and not treated as this Ticket blocker because changed files do not touch prompt resources or those test modules, focused Plugin tests pass, reviewer approved, and `nix build .#yoi --no-link` succeeds.
|
||||
- Follow-up `00001KVXK0WDH` remains responsible for external manifest/CLI rejection diagnostics and broader docs cleanup such as `docs/development/plugin-development.md` compatibility wording.
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
- Dependency-unblocked queued Ticket `00001KVXK0WDH` can be re-routed next.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T20:50:45Z from: inprogress to: done reason: merged_validated_with_unrelated_full_suite_caveat field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated with one unrelated existing full-suite caveat.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `29953111 merge: 00001KVXK0WD3 legacy wasm removal`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration`:
|
||||
- `cargo test -p pod feature::plugin --lib`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed only in prompt guidance snapshot assertions outside this Plugin diff; focused Plugin tests in the same run passed.
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/review/focused validation.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T20:51:02Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Correction:
|
||||
|
||||
- 直前の integration outcome / state-change body に記載した merge commit `29953111` は誤記。
|
||||
- 正しい merge commit は `bedbb670 merge: 00001KVXK0WD3 legacy wasm removal`。
|
||||
- 実装 commit `741d7132`、review approve、validation results、Ticket done 判断には変更なし。
|
||||
|
||||
---
|
||||
@@ -0,0 +1,2 @@
|
||||
{"id":"orch-plan-20260624-201335-1","ticket_id":"00001KVXK0WDH","kind":"blocked_by","related_ticket":"00001KVXK0WD3","note":"Queue review: `00001KVXK0WDH` は manifest/CLI rejection slice だが、active legacy runtime path removal `00001KVXK0WD3` に depends_on している。`00001KVXK0WD3` を先に受理し、この Ticket は dependency completion 後に再 routing する。","author":"yoi-orchestrator","at":"2026-06-24T20:13:35Z"}
|
||||
{"id":"orch-plan-20260624-205226-2","ticket_id":"00001KVXK0WDH","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVXK0WDH` は prerequisite `00001KVXK0WD3` が done になったため implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WDH-plugin-manifest-reject-legacy` と branch `work/00001KVXK0WDH-plugin-manifest-reject-legacy` で、legacy raw `wasm` / `yoi-plugin-wasm-1` manifest/CLI diagnostics を拒否・整理する。Service/Ingress/WebSocket/WIT/PDK runtime work は後続 Tickets に残す。","branch":"work/00001KVXK0WDH-plugin-manifest-reject-legacy","worktree":"/home/hare/Projects/yoi/.worktree/00001KVXK0WDH-plugin-manifest-reject-legacy","role_plan":"Orchestrator: accept/routing, worktree creation, final integration/validation/cleanup. Coder: manifest/CLI/docs diagnostics implementation in dedicated child worktree. Reviewer: read-only review focusing on clear legacy rejection, component package non-regression, no runtime-scope creep."},"author":"yoi-orchestrator","at":"2026-06-24T20:52:26Z"}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"relations": [
|
||||
{
|
||||
"ticket_id": "00001KVXK0WDH",
|
||||
"kind": "depends_on",
|
||||
"target": "00001KVXK0WD3",
|
||||
"note": "Manifest/CLI rejection should follow removal of the active legacy runtime path.",
|
||||
"author": "yoi ticket",
|
||||
"at": "2026-06-24T19:55:30Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
---
|
||||
title: 'Reject legacy Plugin runtime in manifest and CLI diagnostics'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-24T21:20:45Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:11:58Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Plugin runtime は public release 前に `wasm-component` へ一本化する。runtime implementation から legacy raw `wasm` path を削除しても、Manifest parser / validator / `yoi plugin check/list/show` が legacy runtime を曖昧に受け付けると、ユーザー向け API と実装方針がズレる。
|
||||
|
||||
この Ticket では、legacy runtime を外向き schema / diagnostics でも明示的に拒否し、docs / fixtures から transitional wording を消す。
|
||||
|
||||
## 要件
|
||||
|
||||
- `plugin.toml` の runtime validation で legacy raw `wasm` / `yoi-plugin-wasm-1` を新規 Plugin runtime として受け付けない。
|
||||
- `runtime.kind = "wasm-component"` を正の runtime kind として扱う。
|
||||
- `yoi plugin check` は legacy runtime を invalid / unsupported として分かりやすく報告する。
|
||||
- `yoi plugin list/show` は legacy package を有効 Plugin として曖昧に表示しない。
|
||||
- docs/design / docs/development / templates / examples から「raw core-Wasm compatibility bridge を残す」前提の記述を削除または撤回済み方針に更新する。
|
||||
- Manifest schema / static inspection / error message tests を更新する。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Runtime internal の legacy adapter 削除そのもの。
|
||||
- Service / Ingress event runtime の実装。
|
||||
- WebSocket driver の実装。
|
||||
- PDK API の全面更新。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- Legacy raw `wasm` runtime manifest が validation で拒否される。
|
||||
- `yoi-plugin-wasm-1` ABI は current public/recommended Plugin API として表示されない。
|
||||
- `yoi plugin check/list/show` が legacy runtime package を安全かつ明確に diagnostic する。
|
||||
- Component Model package の check/list/show は regress しない。
|
||||
- Plugin objective / design / development docs が Component Model only 方針と整合している。
|
||||
- Legacy runtime 前提の fixtures が削除または rejected fixture として更新されている。
|
||||
- `cargo test -p manifest`、`cargo test -p yoi`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,306 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T19:51:56Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T19:55:29Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T19:55:29Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T20:11:58Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T20:52:56Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- この Ticket は legacy Plugin runtime redesign chain の 2 番目の concrete slice で、manifest validation / CLI diagnostics / docs cleanup に範囲が限定されている。
|
||||
- outgoing `depends_on` は `00001KVXK0WD3` だが、`00001KVXK0WD3` は done / merged / reviewed / validated 済み。`TicketShow` derived blockers は空で、implementation acceptance blocker は残っていない。
|
||||
- incoming dependent `00001KVXK0WDQ` はこの Ticket 完了後に進めるべき後続であり、この Ticket の acceptance blocker ではない。
|
||||
- `TicketOrchestrationPlanQuery` には以前の `blocked_by 00001KVXK0WD3` があるが、prerequisite 完了により解消済みとして扱い、accepted plan `orch-plan-20260624-205226-2` を記録した。
|
||||
- bounded context check で current orchestration branch の `crates/manifest/src/plugin.rs`, `crates/yoi/src/plugin_cli.rs`, `docs/development/plugin-development.md`, `docs/design/plugin-component-model.md`, `docs/design/plugin-packages.md` 周辺に raw `wasm` / `yoi-plugin-wasm-1` / transitional wording が残っていることを確認した。Ticket の scope はこれらの outward schema/diagnostic/docs 整理として十分に具体的。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。未解決 planning question は記録されていない。
|
||||
- Relations / orchestration plan: outgoing depends_on `00001KVXK0WD3` は done。incoming dependent `00001KVXK0WDQ` は後続。
|
||||
- Related Ticket: `00001KVXK0WD3` は done。active legacy runtime fallback removal completed with corrected merge commit `bedbb670`。
|
||||
- Code/docs context: `crates/manifest/src/plugin.rs`, `crates/yoi/src/plugin_cli.rs`, `docs/development/plugin-development.md`, `docs/design/plugin-component-model.md`, `docs/design/plugin-packages.md`。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。inprogress Ticket は 0 件。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Legacy raw `wasm` / `yoi-plugin-wasm-1` Plugin runtime を external manifest/schema/CLI/docs surface でも rejected/retired として扱い、Component Model `wasm-component` を正の public/recommended runtime に一本化する。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- `00001KVXK0WD3` の active runtime removal を前提にする。raw-WASM execution fallback を戻さない。
|
||||
- `runtime.kind = "wasm-component"` が positive accepted runtime kind。
|
||||
- legacy raw `wasm` / `yoi-plugin-wasm-1` は new/current Plugin package として validation/inspection/check/list/show 上曖昧に active 表示しない。
|
||||
- Component Model package の `check/list/show`、package discovery、digest, grants, Tool schema diagnostics は regress させない。
|
||||
- Service / Ingress runtime、WebSocket driver、WIT/PDK/templates service event update は実装しない。
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Legacy raw `wasm` runtime manifest が validation/check で明確に rejected/unsupported になる。
|
||||
- `yoi plugin check` は legacy package を invalid/unsupported として bounded diagnostic し、exit behavior が current check semantics と整合する。
|
||||
- `yoi plugin list/show` は legacy package を有効/active Plugin として曖昧に表示しない。
|
||||
- Component Model packages の check/list/show は通る。
|
||||
- docs/design / docs/development / templates/examples から raw core-Wasm compatibility bridge 前提を削除または撤回済み方針に更新する。
|
||||
- Manifest schema / static inspection / error message tests を更新する。
|
||||
|
||||
Implementation latitude:
|
||||
- `PLUGIN_RUNTIME_WASM_KIND` / `PLUGIN_RUNTIME_WASM_ABI` constants を削除するか、legacy rejection diagnostic 用に internal-only に残すかは code style と tests に合わせてよい。
|
||||
- Legacy fixture は削除または rejected fixture に変換してよい。
|
||||
- CLI human/json diagnostic wording は bounded and clear であれば具体文言は coder が選んでよい。
|
||||
|
||||
Escalate if:
|
||||
- Manifest parser cannot reject legacy runtime without breaking component packages。
|
||||
- Plugin list/show architecture cannot represent rejected package diagnostics without broader API redesign。
|
||||
- Implementing rejection requires Service/Ingress/WebSocket/WIT/PDK changes。
|
||||
- Existing closed Ticket constraints force raw core-Wasm compatibility to remain externally supported。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p manifest`
|
||||
- `cargo test -p yoi`
|
||||
- `cargo check -p yoi`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
- Add/run focused plugin CLI/check/list/show tests as appropriate。
|
||||
|
||||
Current code/docs map:
|
||||
- Primary: `crates/manifest/src/plugin.rs`, `crates/yoi/src/plugin_cli.rs`。
|
||||
- Secondary: `docs/development/plugin-development.md`, `docs/design/plugin-component-model.md`, `docs/design/plugin-packages.md`, plugin templates/examples only as needed。
|
||||
- Avoid: `crates/pod` active runtime implementation unless minimal diagnostic alignment is needed; Service/Ingress/WebSocket/WIT/PDK event model。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- legacy package still appears active/eligible in CLI inspection。
|
||||
- component package check/list/show regression。
|
||||
- raw-WASM execution fallback being reintroduced。
|
||||
- diagnostic wording that implies compatibility support remains。
|
||||
- scope creep into later service runtime Tickets。
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WDH-plugin-manifest-reject-legacy` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T20:53:45Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、derived blockers は空。
|
||||
- outgoing dependency `00001KVXK0WD3` は done / merged / reviewed / validated 済み。
|
||||
- accepted plan `orch-plan-20260624-205226-2` を確認した。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WDH-plugin-manifest-reject-legacy` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T20:54:43Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- prerequisite `00001KVXK0WD3` が done になったため、`00001KVXK0WDH` を再 routing して受理した。
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WDH-plugin-manifest-reject-legacy` と branch `work/00001KVXK0WDH-plugin-manifest-reject-legacy` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVXK0WDH-plugin-manifest-reject` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVXK0WDH-plugin-manifest-reject at: 2026-06-24T21:11:58Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report:
|
||||
|
||||
対象 Ticket:
|
||||
- `00001KVXK0WDH` — Reject legacy Plugin runtime in manifest and CLI diagnostics
|
||||
|
||||
作業ブランチ / Worktree:
|
||||
- Worktree: `/home/hare/Projects/yoi/.worktree/00001KVXK0WDH-plugin-manifest-reject-legacy`
|
||||
- Branch: `work/00001KVXK0WDH-plugin-manifest-reject-legacy`
|
||||
|
||||
変更内容:
|
||||
- `crates/manifest/src/plugin.rs`
|
||||
- legacy raw `wasm` / `yoi-plugin-wasm-1` runtime を manifest validation で reject。
|
||||
- `wasm-component` を現行 public runtime としてドキュメントコメントを更新。
|
||||
- raw-WASM runtime module 読み込み helper を削除。
|
||||
- legacy manifest rejection のテストを追加。
|
||||
- `crates/yoi/src/plugin_cli.rs`
|
||||
- CLI テスト fixture を `wasm-component` package へ移行。
|
||||
- `yoi plugin check` が legacy raw-WASM package を `rejected` として返すテストを追加。
|
||||
- `list/show` inspection 上で legacy package が active/eligible 表示されないことをテスト。
|
||||
- `crates/pod/src/feature/plugin.rs`
|
||||
- public manifest constant 依存を外し、legacy runtime 名は内部診断用 const に限定。
|
||||
- 既存の runtime fallback rejection 経路を維持。
|
||||
- `docs/development/plugin-development.md`
|
||||
- raw-WASM runtime を「互換/推奨」ではなく retired/rejected として記述更新。
|
||||
- `wasm-component` を supported/public runtime として明示。
|
||||
- `docs/design/plugin-component-model.md`
|
||||
- Component Model runtime を現行 supported runtime として更新。
|
||||
- raw-WASM は bounded diagnostic 用の rejected metadata として整理。
|
||||
- `docs/design/plugin-packages.md`
|
||||
- package runtime 記述を `wasm-component` 中心に更新。
|
||||
- legacy raw-WASM package は active/eligible ではなく rejected として表示されることを明記。
|
||||
|
||||
Validation:
|
||||
- `cargo fmt --check`: success
|
||||
- `cargo test -p manifest`: success
|
||||
- `cargo test -p yoi`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `cargo test -p pod legacy_raw_wasm_runtime_is_rejected_without_fallback_execution`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- dirty tree warning は未コミット検証時点の通常 warning。ビルド自体は成功。
|
||||
|
||||
Commit:
|
||||
- `6086099fe4807b5b12c8d13333f5544a4174e3d9 feat: reject legacy plugin runtime manifests`
|
||||
|
||||
Residual risks / notes:
|
||||
- 既知の残リスクなし。
|
||||
- raw-WASM execution fallback は再導入していない。
|
||||
- legacy runtime 名は manifest/pod 内部の rejected diagnostic fixture/判定用としてのみ残している。
|
||||
- Service/Ingress runtime、WebSocket driver、WIT/PDK/templates の service event 更新、broader runtime redesign は実施していない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVXK0WDH-plugin-manifest-reject at: 2026-06-24T21:18:53Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
確認範囲:
|
||||
- child worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WDH-plugin-manifest-reject-legacy`
|
||||
- branch `work/00001KVXK0WDH-plugin-manifest-reject-legacy`
|
||||
- HEAD `6086099fe4807b5b12c8d13333f5544a4174e3d9`
|
||||
- 実履歴上の親 `ef1d8d9a` → HEAD の差分をレビューした。指定 base `187e6426` はこの worktree では object missing だったが、HEAD の直前 commit は `ticket: accept plugin manifest rejection task` で、レビュー対象差分として妥当と判断した。
|
||||
|
||||
承認根拠:
|
||||
- Ticket / IntentPacket の要件と照合済み。
|
||||
- `crates/manifest/src/plugin.rs`:
|
||||
- legacy `wasm` / `yoi-plugin-wasm-1` は public const ではなく internal rejection 用 const になっている。
|
||||
- `validate_manifest` で `kind = "wasm"` を `legacy raw wasm ... retired; use wasm-component` として `Api/Manifest` diagnostic 付きで拒否している。
|
||||
- `wasm-component` は正の runtime kind として `component` / `world` validation を維持している。
|
||||
- legacy rejection test が追加され、discovery package には入らず diagnostic になることを確認している。
|
||||
- `crates/yoi/src/plugin_cli.rs`:
|
||||
- `plugin check` は manifest/discovery rejection を `status: "rejected"` として bounded diagnostic に載せ、既存 check semantics 通り rejected で Err を返す。
|
||||
- list/show snapshot は discovery/resolution diagnostics から rejected item を構成し、legacy package を active/eligible として扱わない。
|
||||
- component fixture は `wasm-component` / `plugin.component.wasm` に更新され、legacy fixture は rejected fixture に変換されている。
|
||||
- `crates/pod/src/feature/plugin.rs`:
|
||||
- manifest crate の legacy runtime public const 依存は削除済み。
|
||||
- legacy name は internal diagnostic/rejection matching のみ。
|
||||
- `PluginInstanceRuntime::new` は legacy `wasm` を即エラーにし、raw-WASM fallback 実行は戻っていない。
|
||||
- docs:
|
||||
- `docs/development/plugin-development.md`
|
||||
- `docs/design/plugin-component-model.md`
|
||||
- `docs/design/plugin-packages.md`
|
||||
で raw core-Wasm compatibility 前提は撤回され、`wasm-component` が supported/public runtime と明記されている。
|
||||
- `rg 'plugin\.wasm|kind = "wasm"|abi = "yoi-plugin-wasm-1"'` で残存箇所を確認。残りは rejection docs/tests/diagnostics と component build artifact 名の文脈のみで、active public compatibility 表現は見当たらない。
|
||||
- 差分対象は manifest / CLI / pod diagnostic alignment / docs の 6 files に限定され、Service/Ingress/WebSocket/WIT/PDK runtime redesign への scope creep は確認していない。
|
||||
|
||||
Validation:
|
||||
- reviewer は read-only 制約のため `cargo test` / `cargo check` / `nix build` は再実行していない。
|
||||
- reviewer 側で `git diff --check HEAD^..HEAD`: success。
|
||||
- Coder reported validation (`cargo fmt --check`, `cargo test -p manifest`, `cargo test -p yoi`, `cargo check -p yoi`, focused pod test, `nix build .#yoi --no-link`) は実装内容と整合しており、追加で疑う材料はない。
|
||||
|
||||
Non-blocking note:
|
||||
- 親から指定された review base hash `187e6426` は誤記/存在しない hash だった。実レビューは child branch の実 parent `ef1d8d9a` を base として行われた。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T21:20:36Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVXK0WDH-plugin-manifest-reject` が implementation branch `work/00001KVXK0WDH-plugin-manifest-reject-legacy` に実装を commit した。
|
||||
- implementation commit: `6086099f feat: reject legacy plugin runtime manifests`
|
||||
- Reviewer `yoi-reviewer-00001KVXK0WDH-plugin-manifest-reject` は read-only review で `approve`。legacy `wasm` / `yoi-plugin-wasm-1` manifest rejection、CLI check/list/show diagnostic behavior、component package non-regression、pod diagnostic alignment、docs update、scope creep なしを確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVXK0WDH-plugin-manifest-reject-legacy` を merge 済み。
|
||||
- merge commit: `449745ee merge: 00001KVXK0WDH plugin manifest rejection`
|
||||
|
||||
Implemented behavior:
|
||||
- `crates/manifest/src/plugin.rs`:
|
||||
- legacy raw `wasm` / `yoi-plugin-wasm-1` runtime を manifest validation で rejected diagnostic にする。
|
||||
- `wasm-component` を supported public runtime として維持。
|
||||
- `crates/yoi/src/plugin_cli.rs`:
|
||||
- `yoi plugin check` は legacy package を `status: "rejected"` として bounded diagnostic に載せ、既存 check semantics 通り失敗扱いにする。
|
||||
- list/show fixture は legacy package を active/eligible として表示しない。
|
||||
- `crates/pod/src/feature/plugin.rs`:
|
||||
- legacy runtime public constant dependency を外し、legacy runtime name は internal diagnostic/rejection matching のみに限定。
|
||||
- raw-WASM fallback execution は再導入していない。
|
||||
- docs:
|
||||
- `docs/development/plugin-development.md`, `docs/design/plugin-component-model.md`, `docs/design/plugin-packages.md` で raw core-Wasm compatibility 前提を撤回し、`wasm-component` を supported/public runtime と明記。
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo fmt --check`: success
|
||||
- `cargo test -p manifest`: success
|
||||
- `cargo test -p yoi`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `cargo test -p pod legacy_raw_wasm_runtime_is_rejected_without_fallback_execution --lib`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
|
||||
Notes:
|
||||
- Reviewer non-blocking note: Orchestrator から渡した review base `187e6426` は誤記で、child branch の実 parent `ef1d8d9a` を base として review された。review scope は適切だった。
|
||||
- Follow-up `00001KVXK0WDQ` は this Ticket completion により dependency-unblocked and can be re-routed next.
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T21:20:45Z from: inprogress to: done reason: merged_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `449745ee merge: 00001KVXK0WDH plugin manifest rejection`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration` succeeded:
|
||||
- `cargo fmt --check`
|
||||
- `cargo test -p manifest`
|
||||
- `cargo test -p yoi`
|
||||
- `cargo check -p yoi`
|
||||
- `cargo test -p pod legacy_raw_wasm_runtime_is_rejected_without_fallback_execution --lib`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,2 @@
|
||||
{"id":"orch-plan-20260624-201335-1","ticket_id":"00001KVXK0WDQ","kind":"blocked_by","related_ticket":"00001KVXK0WDH","note":"Queue review: `00001KVXK0WDQ` は Service lifecycle / ingress queue runtime slice だが、Component Model-only runtime authority / manifest rejection slice `00001KVXK0WDH` に depends_on している。prerequisite completion 後に再 routing する。","author":"yoi-orchestrator","at":"2026-06-24T20:13:35Z"}
|
||||
{"id":"orch-plan-20260624-212209-2","ticket_id":"00001KVXK0WDQ","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVXK0WDQ` は prerequisites `00001KVXK0WD3` と `00001KVXK0WDH` が done になったため implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WDQ-plugin-service-lifecycle` と branch `work/00001KVXK0WDQ-plugin-service-lifecycle` で、Plugin Service lifecycle と ingress queue runtime を実装する。Output command model / WebSocket driver / WIT-PDK templates は後続 Tickets に残す。","branch":"work/00001KVXK0WDQ-plugin-service-lifecycle","worktree":"/home/hare/Projects/yoi/.worktree/00001KVXK0WDQ-plugin-service-lifecycle","role_plan":"Orchestrator: accept/routing, worktree creation, final integration/validation/cleanup. Coder: implement service lifecycle and ingress queue runtime in dedicated child worktree. Reviewer: read-only review focusing on bounded in-process event queue, no WebSocket driver/output command scope creep, grant/capability boundaries, and component Tool regression."},"author":"yoi-orchestrator","at":"2026-06-24T21:22:09Z"}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"relations": [
|
||||
{
|
||||
"ticket_id": "00001KVXK0WDQ",
|
||||
"kind": "depends_on",
|
||||
"target": "00001KVXK0WDH",
|
||||
"note": "Service runtime should build on Component Model-only plugin runtime authority.",
|
||||
"author": "yoi ticket",
|
||||
"at": "2026-06-24T19:55:30Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
title: 'Define Plugin Service lifecycle and ingress queue runtime'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-24T21:51:13Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:12:00Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Current Plugin instance support exposes `start` / `handle-ingress` / `status` / `stop`, but the execution model is still effectively synchronous function invocation. Service Plugins need a host-managed lifecycle and event queue so `start()` can return promptly, while external events are later delivered to `handle-ingress` without requiring a Plugin-owned polling loop.
|
||||
|
||||
This Ticket implements the first service runtime slice: lifecycle state, ingress queue, serial dispatch, backpressure, timeout, and failure semantics. WebSocket-specific event sources and output commands are handled by later Tickets.
|
||||
|
||||
## 要件
|
||||
|
||||
- Service Plugin lifecycle を host-managed state として扱う。
|
||||
- ready / starting / running / stopping / stopped / failed 相当。
|
||||
- `start()` は initialization only とし、long-running loop / polling loop / recv loop を担わない。
|
||||
- Service Plugin ごとに bounded ingress queue を持つ。
|
||||
- Ingress event は source / ingress name / payload / created_at / attempt / correlation id を持つ。
|
||||
- v0 dispatch は per-plugin serial dispatch とする。
|
||||
- dispatch timeout、Plugin failure、queue full、invalid event、stop 中 event の扱いを typed にする。
|
||||
- queue / lifecycle / failure state は status diagnostics として取得できる。
|
||||
- Existing Tool Plugin execution は service queue に巻き込まず、request-response operation として維持する。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- WebSocket connection driver の実装。
|
||||
- Plugin output command model の本実装。
|
||||
- Discord / Slack など特定 integration。
|
||||
- Concurrent per-plugin event execution。
|
||||
- Durable cross-process event queue。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- Service Plugin instance が host-managed lifecycle state を持つ。
|
||||
- `start()` が返った後でも ingress event を queue 経由で配送できる。
|
||||
- Queue は bounded で、full / timeout / failed service が typed error / diagnostic として扱われる。
|
||||
- 同一 Plugin instance への ingress dispatch は serial に処理される。
|
||||
- `status()` または host diagnostics から lifecycle state / queue depth / last error / dispatch counters を確認できる。
|
||||
- Service lifecycle / ingress queue の unit tests が追加されている。
|
||||
- Tool Plugin execution tests が regress しない。
|
||||
- `cargo test -p pod`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,303 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T19:51:56Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T19:55:29Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T19:55:29Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T20:12:00Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-24T21:22:37Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- Dashboard Queue により人間が Orchestrator routing を許可した queued Ticket として確認した。
|
||||
- `00001KVXK0WDQ` は Service lifecycle / ingress queue runtime の concrete slice で、WebSocket driver、output command model、WIT/PDK/templates update を non-goal として後続に分離している。
|
||||
- outgoing `depends_on` は `00001KVXK0WDH` だが、`00001KVXK0WDH` は done / merged / reviewed / validated 済み。`TicketShow` derived blockers は空で、implementation acceptance blocker は残っていない。
|
||||
- incoming dependents (`00001KVXK0WDX`, `00001KVXK0WE4`) はこの Ticket 完了後に進めるべき後続であり、この Ticket の acceptance blocker ではない。
|
||||
- bounded context check で `crates/pod/src/feature/plugin.rs` の current `PluginInstanceRegistry`, `PluginInstanceHandle`, `PluginIngressEvent`, `PluginIngressDispatchReport`, `ComponentInstanceRuntime` lifecycle methods を確認した。Ticket は in-process service lifecycle / bounded ingress queue / serial dispatch / diagnostics に収まっており、残る不確実性は local implementation に閉じる。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。未解決 planning question は記録されていない。
|
||||
- Relations / orchestration plan: outgoing depends_on `00001KVXK0WDH` は done。routing 前 plan は historical blocked_by `00001KVXK0WDH` のみで、prerequisite 完了により解消済み。accepted plan `orch-plan-20260624-212209-2` を記録済み。
|
||||
- Related Tickets: `00001KVXK0WD3` / `00001KVXK0WDH` は done。
|
||||
- Code context: `crates/pod/src/feature/plugin.rs` の service/ingress registration, instance registry, start/status/stop/handle-ingress, component runtime tests。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。inprogress Ticket は 0 件。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Plugin Service を host-managed lifecycle と bounded ingress queue を持つ in-process runtime として扱い、`start()` を initialization-only にし、後続 ingress events を queue 経由で serial dispatch できるようにする。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- Existing Tool Plugin execution は request-response operation として維持し、service queue に巻き込まない。
|
||||
- v0 dispatch は per-plugin serial dispatch。concurrent per-plugin event execution は non-goal。
|
||||
- Queue は bounded。full / timeout / failed service / stop 中 event / invalid event は typed error / diagnostic として扱う。
|
||||
- `start()` は long-running loop / polling loop / recv loop を担わない。
|
||||
- Durable cross-process event queue は non-goal。まず host-managed in-process queue/lifecycle として実装する。
|
||||
- WebSocket driver と output command model は後続 Tickets (`00001KVXK0WE4`, `00001KVXK0WDX`) に残す。
|
||||
- Component Model-only runtime authority and manifest rejection from prerequisites must not regress.
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Service Plugin instance が ready/starting/running/stopping/stopped/failed 相当の lifecycle state を持つ。
|
||||
- `start()` return 後も ingress event を queue 経由で配送できる。
|
||||
- Ingress event has source / ingress name / payload / created_at / attempt / correlation id.
|
||||
- Queue depth / lifecycle state / last error / dispatch counters are visible in status diagnostics.
|
||||
- Unit tests cover lifecycle start/stop/failure, bounded queue full, serial dispatch, timeout/failure diagnostics, stop-time event rejection, Tool execution regression.
|
||||
- `cargo test -p pod`, `cargo check -p yoi`, `git diff --check`, `nix build .#yoi --no-link` are validation targets.
|
||||
|
||||
Implementation latitude:
|
||||
- Choose exact structs/enums/names and whether queue processing is sync-step driven or background worker, as long as start returns promptly and dispatch remains host-managed/serial.
|
||||
- Existing `PluginInstanceRegistry` may be extended or refactored if authority boundaries remain clear.
|
||||
- Tests may use existing `test-ingress` runtime or focused component fixtures.
|
||||
|
||||
Escalate if:
|
||||
- Implementation requires durable cross-process queue or scheduler semantics.
|
||||
- WebSocket driver or output command model must be implemented to make lifecycle tests pass.
|
||||
- Component Tool execution has to be routed through service queue.
|
||||
- Host API grant/runtime authority or Component Model manifest behavior needs redesign.
|
||||
|
||||
Validation:
|
||||
- `cargo test -p pod`
|
||||
- `cargo check -p yoi`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
- Focused tests for service lifecycle/queue may be run during development.
|
||||
|
||||
Current code map:
|
||||
- Primary: `crates/pod/src/feature/plugin.rs`。
|
||||
- Secondary only if needed: manifest service/ingress declarations and docs comments.
|
||||
- Avoid: WebSocket driver, output command model, WIT/PDK/templates event update, remote runtime protocol, durable cross-process queue.
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- accidentally making Service runtime a scheduler/durable queue.
|
||||
- Tool execution regression or Tool path accidentally using Service queue.
|
||||
- unbounded queue or hidden background loop.
|
||||
- missing stop/failure/timeout diagnostics.
|
||||
- scope creep into WebSocket/output commands/WIT-PDK.
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WDQ-plugin-service-lifecycle` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T21:23:16Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、derived blockers は空。
|
||||
- outgoing dependency `00001KVXK0WDH` は done / merged / reviewed / validated 済み。
|
||||
- accepted plan `orch-plan-20260624-212209-2` を確認した。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WDQ-plugin-service-lifecycle` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T21:24:10Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- prerequisite `00001KVXK0WDH` が done になったため、`00001KVXK0WDQ` を再 routing して受理した。
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WDQ-plugin-service-lifecycle` と branch `work/00001KVXK0WDQ-plugin-service-lifecycle` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVXK0WDQ-service-lifecycle` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVXK0WDQ-service-lifecycle at: 2026-06-24T21:43:56Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report:
|
||||
|
||||
対象 Ticket:
|
||||
- `00001KVXK0WDQ` — Define Plugin Service lifecycle and ingress queue runtime
|
||||
|
||||
変更ファイル:
|
||||
- `crates/pod/src/feature/plugin.rs`
|
||||
|
||||
主な実装:
|
||||
- Plugin Service の host-managed lifecycle を追加。
|
||||
- `Ready / Starting / Running / Stopping / Stopped / Failed`
|
||||
- in-process bounded ingress queue を追加。
|
||||
- v0 は per-plugin serial dispatch。
|
||||
- Tool Plugin 実行は従来通り request-response のまま維持。
|
||||
- `PluginIngressEvent` に以下を追加。
|
||||
- `source`
|
||||
- `ingress_name`
|
||||
- `payload`
|
||||
- `created_at`
|
||||
- `attempt`
|
||||
- `correlation_id`
|
||||
- typed ingress dispatch error / diagnostic を追加。
|
||||
- invalid event
|
||||
- queue full
|
||||
- service unavailable / failed / stopped
|
||||
- dispatch timeout
|
||||
- dispatch failure
|
||||
- status diagnostics に以下を追加。
|
||||
- lifecycle state
|
||||
- queue depth / capacity
|
||||
- last error
|
||||
- dispatch counters
|
||||
- Unit tests を追加・更新。
|
||||
- lifecycle start/stop/failure
|
||||
- bounded queue full
|
||||
- serial dispatch
|
||||
- timeout diagnostic
|
||||
- dispatch failure diagnostic
|
||||
- stopped service rejection
|
||||
- invalid event rejection
|
||||
- Tool execution regression
|
||||
|
||||
Commit:
|
||||
- `4e138b7e365d940bf31397aa64cf14a58b6bc51a feat: add plugin service ingress queue`
|
||||
|
||||
Validation:
|
||||
- `cargo test -p pod feature::plugin::tests`: success (`73 passed`)
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `git diff --check HEAD~1 HEAD`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed in existing prompt guidance assertions outside this Ticket:
|
||||
- `prompt::catalog::tests::pod_orchestration_guidance_section_renders_resource_body`
|
||||
- `prompt::system::tests::pod_orchestration_guidance_is_included_for_pod_management_tools`
|
||||
- failure: `assertion failed: rendered.contains("worktree status, diff, and test results")`
|
||||
|
||||
Residual risks / notes:
|
||||
- Full `cargo test -p pod` remains blocked by unrelated prompt/resource snapshot assertions; Plugin-focused tests pass.
|
||||
- v0 dispatch timeout is implemented as elapsed check after synchronous dispatch completion and typed diagnostic. Force-cancelling executing Wasm in a separate worker is broader runtime redesign and remains non-goal.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVXK0WDQ-service-lifecycle at: 2026-06-24T21:49:35Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
確認範囲:
|
||||
- child worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WDQ-plugin-service-lifecycle`
|
||||
- branch `work/00001KVXK0WDQ-plugin-service-lifecycle`
|
||||
- HEAD `4e138b7e365d940bf31397aa64cf14a58b6bc51a`
|
||||
- base `f26c7e0d`
|
||||
- diff `f26c7e0d..HEAD`
|
||||
- Ticket `00001KVXK0WDQ` の `item.md` / `thread.md` / orchestration plan
|
||||
|
||||
判断:
|
||||
- Ticket intent / IntentPacket に対して実装は妥当。
|
||||
- 変更は `crates/pod/src/feature/plugin.rs` のみで、WebSocket driver / output command model / WIT/PDK/templates / durable queue への scope creep は見当たらない。
|
||||
- Component Model-only runtime と legacy raw wasm rejection は維持されている。
|
||||
|
||||
主な確認根拠:
|
||||
- `PluginInstanceLifecycleState` が `Ready / Starting / Running / Stopping / Stopped / Failed` に拡張され、start/stop/status/dispatch failure で lifecycle と diagnostics が更新される。
|
||||
- `PluginIngressEvent` に `source / ingress_name / payload / created_at / attempt / correlation_id` が揃っている。
|
||||
- `VecDeque` + capacity による in-process bounded queue、`QueueFull` / `InvalidEvent` / `ServiceFailed` / `ServiceStopped` / `DispatchTimeout` / `DispatchFailed` の typed error/diagnostic が追加されている。
|
||||
- dispatch は `Mutex` 下の per-plugin serial dispatch で、concurrent per-plugin execution にはしていない。
|
||||
- Tool execution path は `PluginInstanceTool::execute -> handle_tool` の request-response のままで、Service queue に流していない。
|
||||
- status に `queue_depth / queue_capacity / last_error / dispatch_counters / diagnostics` が出る。
|
||||
- unit tests は lifecycle、queue full、serial dispatch、timeout/failure、stopped rejection、invalid event、Tool regression をカバーしている。
|
||||
|
||||
検証:
|
||||
- reviewer: `git diff --check f26c7e0d..HEAD`: success
|
||||
- cargo/nix は read-only 指示のため再実行せず、coder 報告を確認対象として扱った。
|
||||
|
||||
Non-blocking notes:
|
||||
- queue processing は sync-step driven で、現 public delivery は enqueue 直後に同じ lock 内で dispatch するため、通常経路では queue depth はほぼ 0 になる。Ticket の implementation latitude 内だが、後続の WebSocket driver 側で backpressure/queue depth をどう見せるかは改めて注意が必要。
|
||||
- `cargo test -p pod` は coder 報告では既存の prompt guidance assertion 由来の失敗あり。Plugin-focused tests / `cargo check -p yoi` / nix build は成功報告で、本 Ticket の blocker とは判断しない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-24T21:51:01Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVXK0WDQ-service-lifecycle` が implementation branch `work/00001KVXK0WDQ-plugin-service-lifecycle` に実装を commit した。
|
||||
- implementation commit: `4e138b7e feat: add plugin service ingress queue`
|
||||
- Reviewer `yoi-reviewer-00001KVXK0WDQ-service-lifecycle` は read-only review で `approve`。host-managed in-process lifecycle/queue、bounded queue、serial dispatch、typed diagnostics、Tool path non-regression、scope creep なしを確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVXK0WDQ-plugin-service-lifecycle` を merge 済み。
|
||||
- merge commit: `000afbbe merge: 00001KVXK0WDQ plugin service lifecycle`
|
||||
|
||||
Implemented behavior:
|
||||
- `crates/pod/src/feature/plugin.rs` に Plugin Service lifecycle state を追加。
|
||||
- `Ready / Starting / Running / Stopping / Stopped / Failed`
|
||||
- in-process bounded ingress queue と per-plugin serial dispatch を追加。
|
||||
- `PluginIngressEvent` に `source`, `ingress_name`, `payload`, `created_at`, `attempt`, `correlation_id` を追加。
|
||||
- `QueueFull`, `InvalidEvent`, `ServiceFailed`, `ServiceStopped`, `DispatchTimeout`, `DispatchFailed` など typed error/diagnostic を追加。
|
||||
- status diagnostics に queue depth/capacity, last_error, dispatch_counters, lifecycle diagnostics を追加。
|
||||
- Tool Plugin execution は従来の request-response path のまま維持。
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo test -p pod feature::plugin::tests`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed only in known prompt guidance snapshot assertions outside this Plugin diff:
|
||||
- `prompt::catalog::tests::pod_orchestration_guidance_section_renders_resource_body`
|
||||
- `prompt::system::tests::pod_orchestration_guidance_is_included_for_pod_management_tools`
|
||||
- Plugin-focused tests in the same run passed, including service lifecycle/queue/timeout/Tool regression coverage.
|
||||
|
||||
Notes:
|
||||
- Reviewer non-blocking note: current queue processing is sync-step driven, and public delivery enqueues then dispatches immediately under the lock, so normal queue depth is usually 0. This remains within Ticket latitude, but follow-up WebSocket driver/backpressure work should revisit how queue depth is exposed.
|
||||
- Follow-up `00001KVXK0WDX` is dependency-unblocked and can be re-routed next.
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-24T21:51:13Z from: inprogress to: done reason: merged_validated_with_unrelated_full_suite_caveat field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated with one unrelated known full-suite caveat.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `000afbbe merge: 00001KVXK0WDQ plugin service lifecycle`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration`:
|
||||
- `cargo test -p pod feature::plugin::tests`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed only in prompt guidance snapshot assertions outside this Plugin diff; Plugin-focused tests passed.
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/review/focused validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,2 @@
|
||||
{"id":"orch-plan-20260624-201335-1","ticket_id":"00001KVXK0WDX","kind":"blocked_by","related_ticket":"00001KVXK0WDQ","note":"Queue review: `00001KVXK0WDX` は service output command model slice だが、output commands are returned by service ingress dispatch のため `00001KVXK0WDQ` に depends_on している。prerequisite completion 後に再 routing する。","author":"yoi-orchestrator","at":"2026-06-24T20:13:35Z"}
|
||||
{"id":"orch-plan-20260625-054531-2","ticket_id":"00001KVXK0WDX","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVXK0WDX` は prerequisite `00001KVXK0WDQ` が done になったため implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WDX-plugin-output-commands` と branch `work/00001KVXK0WDX-plugin-output-commands` で、Plugin Service ingress handler の output command envelope / validation / grant-check / diagnostics を追加する。WebSocket transport、HTTP request dispatch 完成、WIT/PDK/templates update は後続 Tickets に残す。","branch":"work/00001KVXK0WDX-plugin-output-commands","worktree":"/home/hare/Projects/yoi/.worktree/00001KVXK0WDX-plugin-output-commands","role_plan":"Orchestrator: accept/routing, worktree creation, final integration/validation/cleanup. Coder: implement service output command envelope and grant-check diagnostics in dedicated child worktree. Reviewer: read-only review focusing on command/result separation from ToolOutput, fail-closed grants, no WebSocket/HTTP transport scope creep, and service lifecycle non-regression."},"author":"yoi-orchestrator","at":"2026-06-25T05:45:31Z"}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"relations": [
|
||||
{
|
||||
"ticket_id": "00001KVXK0WDX",
|
||||
"kind": "depends_on",
|
||||
"target": "00001KVXK0WDQ",
|
||||
"note": "Output commands are returned by service ingress dispatch.",
|
||||
"author": "yoi ticket",
|
||||
"at": "2026-06-24T19:55:30Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
title: 'Add Plugin service output command model'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-25T06:20:26Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:12:02Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Service / Ingress Plugin が外部 event を処理した後、WebSocket send、HTTP request、diagnostic update などの side effect を直接 ambient authority で実行すると、grant boundary と observability が曖昧になる。Plugin は event handler の戻り値として output commands を返し、Host が manifest declaration / enablement grant / runtime policy を検査して実行する形にしたい。
|
||||
|
||||
この Ticket では WebSocket driver 実装前に、Service Plugin の output command envelope と grant check 境界を追加する。
|
||||
|
||||
## 要件
|
||||
|
||||
- `handle-ingress` / service event handler の戻り値に output command list を表現できる型を追加する。
|
||||
- v0 command kind を最小集合で定義する。
|
||||
- diagnostic/status update。
|
||||
- host request dispatch placeholder。
|
||||
- websocket send placeholder。
|
||||
- Command は correlation id / source event id / command id / kind / payload / requested_at を持つ。
|
||||
- Host が command ごとに manifest declaration と enablement grant を検査する。
|
||||
- Unsupported / ungranted / malformed command は fail closed で diagnostic に残す。
|
||||
- Command execution result は service status / run overview / diagnostics から追える形にする。
|
||||
- Tool Plugin の ordinary ToolOutput path と混同しない。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- WebSocket send の実 transport 実装。
|
||||
- HTTP request dispatch command の完全実装。
|
||||
- Domain operation command の完成。
|
||||
- LLM history への hidden context injection。
|
||||
- Unrestricted shell / filesystem command。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- Service Plugin ingress handler が output command envelope を返せる。
|
||||
- Host が output command を parse / validate / grant-check する。
|
||||
- Ungranted command は実行されず、typed diagnostic になる。
|
||||
- Diagnostic/status update command のような safe v0 command が実行または記録される。
|
||||
- WebSocket send / request dispatch は placeholder command として grant-check 可能で、実 transport が無くても安全に unsupported として扱える。
|
||||
- Tool Plugin output と Service Plugin output command が型・docs・testsで区別されている。
|
||||
- `cargo test -p pod`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,299 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T19:51:56Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T19:55:29Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T19:55:29Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T20:12:02Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-25T05:46:02Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- ユーザーから「続けて」と明示 follow-up があり、queued dependency chain の次 Ticket として再確認した。
|
||||
- `00001KVXK0WDX` は Service output command model の concrete slice で、WebSocket transport、HTTP request dispatch completion、Domain operation command completion、WIT/PDK/templates update は non-goal として後続に分離されている。
|
||||
- outgoing `depends_on` は `00001KVXK0WDQ` だが、`00001KVXK0WDQ` は done / merged / reviewed / validated 済み。`TicketShow` derived blockers は空で、implementation acceptance blocker は残っていない。
|
||||
- incoming dependent `00001KVXK0WE4` は WebSocket driver slice で、この Ticket 完了後に進めるべき後続であり、この Ticket の acceptance blocker ではない。
|
||||
- bounded context check で current Plugin service lifecycle / ingress queue implementation が `crates/pod/src/feature/plugin.rs` に入り、event dispatch/status diagnostics の拡張点が存在することを確認した。Ticket の残る不確実性は command envelope / validation / grant-check / diagnostics の local implementation に閉じる。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。未解決 planning question は記録されていない。
|
||||
- Relations / orchestration plan: outgoing depends_on `00001KVXK0WDQ` は done。routing 前 plan は historical blocked_by `00001KVXK0WDQ` のみで、prerequisite 完了により解消済み。accepted plan `orch-plan-20260625-054531-2` を記録済み。
|
||||
- Related Tickets: `00001KVXK0WD3`, `00001KVXK0WDH`, `00001KVXK0WDQ` は done。
|
||||
- Code context: `crates/pod/src/feature/plugin.rs` の Plugin Service lifecycle / bounded ingress queue / `PluginIngressEvent` / status diagnostics / component runtime。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。inprogress Ticket は 0 件。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Service Plugin ingress handler の戻り値として output command envelope を表現し、Host が command ごとに manifest declaration / enablement grant / runtime policy を fail-closed に検査し、結果を service diagnostics/status から追えるようにする。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- Service output command は Tool Plugin の ordinary `ToolOutput` path と型・処理経路・docs/tests で区別する。
|
||||
- v0 command kind は最小集合に留める: diagnostic/status update, host request dispatch placeholder, websocket send placeholder。
|
||||
- WebSocket send の実 transport 実装、HTTP request dispatch completion、Domain operation command completion は non-goal。
|
||||
- Unsupported / ungranted / malformed command は実行せず typed diagnostic にする。
|
||||
- Unrestricted shell / filesystem command や hidden LLM context injection は絶対に導入しない。
|
||||
- Existing Plugin Service lifecycle / bounded ingress queue and Component Model-only runtime from prerequisites must not regress.
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- `handle-ingress` / service event handler result can carry output command list.
|
||||
- Command has correlation id / source event id / command id / kind / payload / requested_at.
|
||||
- Host parses, validates, and grant-checks each command.
|
||||
- Ungranted command is not executed and appears as typed diagnostic.
|
||||
- Safe diagnostic/status update command is executed or recorded.
|
||||
- WebSocket send / request dispatch placeholders are grant-checkable and safely unsupported without transport.
|
||||
- Command execution result is visible from service status / diagnostics or run overview-equivalent state.
|
||||
- Tests distinguish Tool Plugin output from Service output commands.
|
||||
|
||||
Implementation latitude:
|
||||
- Exact Rust names/enums and JSON/envelope shape may follow existing plugin code style.
|
||||
- Manifest declaration/grant mapping can be minimal v0 as long as it is explicit and fail-closed.
|
||||
- Existing tests/fixtures may be extended in `crates/pod/src/feature/plugin.rs`; docs/comments may be updated if needed.
|
||||
|
||||
Escalate if:
|
||||
- Implementing output commands requires actual WebSocket/HTTP transport.
|
||||
- Current manifest/grant model cannot represent placeholder command grants without broader schema redesign.
|
||||
- Command results must be persisted in a durable cross-process run overview to satisfy tests.
|
||||
- Tool Plugin output must be routed through Service command processing.
|
||||
|
||||
Validation:
|
||||
- `cargo test -p pod`
|
||||
- `cargo check -p yoi`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
- Focused plugin service command tests during development are expected.
|
||||
|
||||
Current code map:
|
||||
- Primary: `crates/pod/src/feature/plugin.rs`。
|
||||
- Secondary only if necessary: manifest grant declarations/tests/docs comments。
|
||||
- Avoid: WebSocket transport driver, HTTP request dispatch completion, WIT/PDK/templates service event update, durable cross-process queue, remote runtime protocol。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- output commands becoming ambient authority.
|
||||
- ToolOutput and Service output commands being conflated.
|
||||
- ungranted/malformed commands partially executing.
|
||||
- placeholders accidentally performing network I/O。
|
||||
- scope creep into WebSocket driver or PDK/WIT updates.
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WDX-plugin-output-commands` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-25T05:46:44Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、derived blockers は空。
|
||||
- outgoing dependency `00001KVXK0WDQ` は done / merged / reviewed / validated 済み。
|
||||
- accepted plan `orch-plan-20260625-054531-2` を確認した。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WDX-plugin-output-commands` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-25T05:47:43Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- prerequisite `00001KVXK0WDQ` が done になったため、`00001KVXK0WDX` を再 routing して受理した。
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WDX-plugin-output-commands` と branch `work/00001KVXK0WDX-plugin-output-commands` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVXK0WDX-output-commands` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVXK0WDX-output-commands at: 2026-06-25T06:12:58Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report:
|
||||
|
||||
対象 Ticket:
|
||||
- `00001KVXK0WDX` — Add Plugin service output command model
|
||||
|
||||
変更ファイル:
|
||||
- `crates/pod/src/feature/plugin.rs`
|
||||
|
||||
主な実装:
|
||||
- Service/Ingress handler の戻り値から `output_commands` を読む Service output command model を追加。
|
||||
- command envelope に以下を追加。
|
||||
- `correlation_id`
|
||||
- `source_event_id`
|
||||
- `command_id`
|
||||
- `kind`
|
||||
- `payload`
|
||||
- `requested_at`
|
||||
- v0 command kind を追加。
|
||||
- `diagnostic_status_update`
|
||||
- `host_request_dispatch`
|
||||
- `websocket_send`
|
||||
- Host 側で envelope parse / field validation / `requested_at` RFC3339 validation / `source_event_id` と ingress event correlation id の照合 / payload size bound / kind-specific payload validation / request・websocket grant check を行うようにした。
|
||||
- malformed / ungranted / unsupported command は typed diagnostic として記録し、実行しない。
|
||||
- `diagnostic_status_update` は安全に `component_status` / diagnostics に記録する。
|
||||
- `host_request_dispatch` / `websocket_send` は grant-check 可能だが、v0 では transport 実行せず `Unsupported` として記録する。
|
||||
- Service output command results を `PluginIngressDispatchReport` と `PluginInstanceStatus` から見えるように追加。
|
||||
- ordinary Tool Plugin `ToolOutput` path と Service output command path が混ざらないよう、型・コメント・テストを分離。
|
||||
- focused tests を追加。
|
||||
- diagnostic/status command の記録
|
||||
- ungranted request command の reject と status side effect 非実行
|
||||
- request/websocket placeholder の grant-check + unsupported 記録
|
||||
- malformed envelope の reject
|
||||
|
||||
Commit:
|
||||
- `755d460f0d4e2dccb3f75d9ad980b1e701464a4e feat: add plugin service output commands`
|
||||
|
||||
Validation:
|
||||
- `cargo fmt --check`: success
|
||||
- `cargo test -p pod service_output_command -- --nocapture`: success (`4 passed`)
|
||||
- `cargo test -p pod feature::plugin::tests`: success (`77 passed`)
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed in known prompt guidance snapshot assertions outside this Ticket (`prompt::catalog::tests::pod_orchestration_guidance_section_renders_resource_body`, `prompt::system::tests::pod_orchestration_guidance_is_included_for_pod_management_tools`), with Plugin tests passing.
|
||||
|
||||
Residual risks / notes:
|
||||
- WebSocket send transport と host request dispatch の実実行は Ticket non-goal に従い未実装で、grant-check 後に `Unsupported` diagnostic として記録する。
|
||||
- Service output command schema は Rust 側 JSON envelope として追加した。WIT/PDK/templates 更新は non-goal として触っていない。
|
||||
- Full `cargo test -p pod` の 2 failures は今回の Plugin diff 外の既知 prompt snapshot failure と一致している。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVXK0WDX-output-commands at: 2026-06-25T06:18:37Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
確認結果:
|
||||
- Ticket `00001KVXK0WDX` の IntentPacket / 受け入れ条件に対して、実装 commit `755d460f feat: add plugin service output commands` は妥当。
|
||||
|
||||
承認根拠:
|
||||
- 差分は `crates/pod/src/feature/plugin.rs` のみで、scope creep は見当たらない。
|
||||
- Service/Ingress handler output の `output_commands` を読む専用経路が追加され、ordinary Tool Plugin `ToolOutput` path とは型・処理・report/status field が分離されている。
|
||||
- envelope は `correlation_id` / `source_event_id` / `command_id` / `kind` / `payload` / `requested_at` を持ち、unknown fields reject、id / RFC3339 / `source_event_id == ingress correlation_id` / payload size / kind-specific payload を検証している。
|
||||
- `host_request_dispatch` と `websocket_send` は既存の manifest declaration + enabled grant / allowlist 検査に乗っており、実行段階では `Unsupported` result を返すだけで HTTP/WebSocket transport 実装に踏み込んでいない。
|
||||
- malformed / ungranted command は `ServiceOutputCommandRejected` diagnostic になり、mixed batch でも安全側に倒して部分的な status update を実行しないテストがある。
|
||||
- `diagnostic_status_update` は bounded payload/message 経由で `component_status` / diagnostics / `output_command_results` に記録され、外部 side effect や hidden LLM context injection はない。
|
||||
- Service command results は `PluginIngressDispatchReport` と `PluginInstanceStatus.output_command_results` から追跡可能。
|
||||
- 追加テストは recorded diagnostic、ungranted rejection、placeholder unsupported、malformed envelope を押さえている。
|
||||
|
||||
検証:
|
||||
- Ticket `item.md` / `thread.md` / orchestration plan / relations を確認。
|
||||
- child worktree で `git status` / `git log` / `git diff --stat` / diff 内容を read-only 確認。
|
||||
- read-only 指示のため cargo/nix 等は再実行していない。
|
||||
|
||||
Non-blocking note:
|
||||
- Coder 報告では `cargo test -p pod` が既知の prompt guidance snapshot assertion でのみ失敗、Plugin tests / `cargo check -p yoi` / `git diff --check` / `nix build .#yoi --no-link` は成功。最終統合時に既知 failure 扱いだけ確認すること。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-25T06:20:17Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVXK0WDX-output-commands` が implementation branch `work/00001KVXK0WDX-plugin-output-commands` に実装を commit した。
|
||||
- implementation commit: `755d460f feat: add plugin service output commands`
|
||||
- Reviewer `yoi-reviewer-00001KVXK0WDX-output-commands` は read-only review で `approve`。Service output command path と ToolOutput path の分離、fail-closed validation/grant checks、placeholder command の non-transport behavior、diagnostic/status recording、scope creep なしを確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVXK0WDX-plugin-output-commands` を merge 済み。
|
||||
- merge commit: `d2aa92a7 merge: 00001KVXK0WDX plugin output commands`
|
||||
|
||||
Implemented behavior:
|
||||
- `crates/pod/src/feature/plugin.rs` に Service output command envelope handling を追加。
|
||||
- `output_commands` は `correlation_id`, `source_event_id`, `command_id`, `kind`, `payload`, `requested_at` を持つ。
|
||||
- v0 command kinds:
|
||||
- `diagnostic_status_update`
|
||||
- `host_request_dispatch`
|
||||
- `websocket_send`
|
||||
- Host-side validation:
|
||||
- envelope parse / unknown field rejection
|
||||
- id and RFC3339 validation
|
||||
- `source_event_id` と ingress event correlation id の照合
|
||||
- payload size bound
|
||||
- kind-specific payload validation
|
||||
- manifest declaration + enablement grant / allowlist checks
|
||||
- malformed / ungranted / unsupported commands は typed diagnostic になり、実行しない。
|
||||
- `diagnostic_status_update` は bounded payload/message で component status / diagnostics / output command results に記録。
|
||||
- `host_request_dispatch` / `websocket_send` は grant-check 後に `Unsupported` として記録し、HTTP/WebSocket transport には踏み込まない。
|
||||
- `PluginIngressDispatchReport` と `PluginInstanceStatus.output_command_results` から command result を追跡可能。
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo fmt --check`: success
|
||||
- `cargo test -p pod service_output_command -- --nocapture`: success
|
||||
- `cargo test -p pod feature::plugin::tests`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed only in known prompt guidance snapshot assertions outside this Plugin diff:
|
||||
- `prompt::catalog::tests::pod_orchestration_guidance_section_renders_resource_body`
|
||||
- `prompt::system::tests::pod_orchestration_guidance_is_included_for_pod_management_tools`
|
||||
- Plugin-focused tests in the same run passed.
|
||||
|
||||
Notes:
|
||||
- Full `cargo test -p pod` failure is recorded as the same known unrelated prompt-resource assertion issue seen in previous Plugin Tickets, not a blocker for this Ticket.
|
||||
- Follow-up `00001KVXK0WE4` is dependency-unblocked and can be re-routed next.
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-25T06:20:26Z from: inprogress to: done reason: merged_validated_with_unrelated_full_suite_caveat field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated with one unrelated known full-suite caveat.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `d2aa92a7 merge: 00001KVXK0WDX plugin output commands`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration`:
|
||||
- `cargo fmt --check`: success
|
||||
- `cargo test -p pod service_output_command -- --nocapture`: success
|
||||
- `cargo test -p pod feature::plugin::tests`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed only in prompt guidance snapshot assertions outside this Plugin diff; Plugin-focused tests passed.
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/review/focused validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,3 @@
|
||||
{"id":"orch-plan-20260624-201335-1","ticket_id":"00001KVXK0WE4","kind":"blocked_by","related_ticket":"00001KVXK0WDQ","note":"Queue review: `00001KVXK0WE4` は WebSocket driver slice だが、service ingress queue `00001KVXK0WDQ` と output command model `00001KVXK0WDX` に depends_on している。両 prerequisite completion 後に再 routing する。","author":"yoi-orchestrator","at":"2026-06-24T20:13:35Z"}
|
||||
{"id":"orch-plan-20260624-201341-2","ticket_id":"00001KVXK0WE4","kind":"blocked_by","related_ticket":"00001KVXK0WDX","note":"Queue review: `00001KVXK0WE4` は output command dispatch/grant model `00001KVXK0WDX` にも depends_on している。`00001KVXK0WDQ` と `00001KVXK0WDX` の両方が完了するまで acceptance しない。","author":"yoi-orchestrator","at":"2026-06-24T20:13:41Z"}
|
||||
{"id":"orch-plan-20260625-062148-3","ticket_id":"00001KVXK0WE4","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVXK0WE4` は prerequisites `00001KVXK0WDQ` と `00001KVXK0WDX` が done になったため implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WE4-plugin-websocket-driver` と branch `work/00001KVXK0WE4-plugin-websocket-driver` で、Plugin Service 用 host-owned WebSocket driver を追加し、incoming text frames を ingress queue に入れ、output command の websocket send を grant-check 後に送信する。Discord protocol/full reconnect/secret-store/browser WebSocket/WIT-PDK template update は non-goals。","branch":"work/00001KVXK0WE4-plugin-websocket-driver","worktree":"/home/hare/Projects/yoi/.worktree/00001KVXK0WE4-plugin-websocket-driver","role_plan":"Orchestrator: accept/routing, worktree creation, final integration/validation/cleanup. Coder: implement host-owned WebSocket driver slice in dedicated child worktree. Reviewer: read-only review focusing on host-owned connection authority, ingress queue integration, output command send execution, grant checks, and no protocol-specific/reconnect/scope creep."},"author":"yoi-orchestrator","at":"2026-06-25T06:21:48Z"}
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"version": 1,
|
||||
"relations": [
|
||||
{
|
||||
"ticket_id": "00001KVXK0WE4",
|
||||
"kind": "depends_on",
|
||||
"target": "00001KVXK0WDQ",
|
||||
"note": "WebSocket frames are delivered through the service ingress queue.",
|
||||
"author": "yoi ticket",
|
||||
"at": "2026-06-24T19:55:30Z"
|
||||
},
|
||||
{
|
||||
"ticket_id": "00001KVXK0WE4",
|
||||
"kind": "depends_on",
|
||||
"target": "00001KVXK0WDX",
|
||||
"note": "WebSocket sends are executed through output commands.",
|
||||
"author": "yoi ticket",
|
||||
"at": "2026-06-24T19:55:30Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
title: 'Add host-owned WebSocket driver for Plugin services'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-25T07:06:30Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:12:03Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Current `host_api.websocket` is a pull primitive: Plugin code must explicitly call `recv(timeout)` while an exported function is running. That is insufficient for Discord Gateway / Slack Socket Mode style long-lived integrations. Service Plugins need Host-owned WebSocket connections whose incoming frames are queued as ingress events and whose outgoing sends are requested through output commands.
|
||||
|
||||
This Ticket adds the WebSocket-specific event source and command executor on top of the Service ingress queue and output command model.
|
||||
|
||||
## 要件
|
||||
|
||||
- Host-owned WebSocket connection driver を追加する。
|
||||
- Plugin manifest / grant で WebSocket subscription / target authority を表現できる。
|
||||
- Host が connect / reader task / close / error detection を管理する。
|
||||
- Incoming text frame を Plugin ingress event に変換し、service ingress queue に enqueue する。
|
||||
- Close / error / reconnect-needed も ingress event または status diagnostic として扱う。
|
||||
- Plugin からの WebSocket send は output command として受け取り、grant check 後に Host が送信する。
|
||||
- v0 で扱う frame kind を明確にする。
|
||||
- text frame required。
|
||||
- binary / ping / pong / close の扱いを diagnostic / unsupported / control handling として定義する。
|
||||
- Connection status、last frame time、last error、queue drops、send failures を diagnostics に出す。
|
||||
- Existing `recv(timeout)` pull API は long-lived integration の recommended path にしない。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Discord protocol implementation。
|
||||
- Full reconnect / resume policy の完成。
|
||||
- Secret store / auth injection の全面設計。
|
||||
- Binary frame application payload support。
|
||||
- Browser-facing WebSocket API。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- Host-owned WebSocket driver が Service Plugin に紐づく connection を管理できる。
|
||||
- Incoming text frame が Plugin ingress queue に event として入る。
|
||||
- Plugin output command から WebSocket text send が実行される。
|
||||
- Ungranted send / unauthorized target は fail closed で diagnostic になる。
|
||||
- Connection close / error が service status diagnostics に反映される。
|
||||
- Existing pull `recv(timeout)` API が docs/templates の recommended service integration path から外れている。
|
||||
- WebSocket driver / ingress / send command の tests が追加されている。
|
||||
- `cargo test -p pod`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,288 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T19:51:56Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T19:55:30Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T19:55:30Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T20:12:03Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-25T06:22:18Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- ユーザーから「続けて」と明示 follow-up があり、queued dependency chain の次 Ticket として再確認した。
|
||||
- `00001KVXK0WE4` は host-owned WebSocket driver の concrete slice で、Discord protocol、full reconnect/resume policy、secret store/auth injection、browser-facing WebSocket API、WIT/PDK templates update は non-goal として分離されている。
|
||||
- outgoing `depends_on` は `00001KVXK0WDQ` と `00001KVXK0WDX` だが、両方とも done / merged / reviewed / validated 済み。`TicketShow` derived blockers は空で、implementation acceptance blocker は残っていない。
|
||||
- incoming dependent `00001KVXK0WEA` は WIT/PDK/templates update で、この Ticket 完了後に進めるべき後続であり、この Ticket の acceptance blocker ではない。
|
||||
- bounded context check で current `crates/pod/src/feature/plugin.rs` に existing pull `host_api.websocket` helpers、WebSocket grants/allowlist、Plugin Service lifecycle / ingress queue、Service output command model が存在することを確認した。Ticket の残る不確実性は host-owned connection driver / frame-to-ingress / output command send integration の local implementation に閉じる。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。未解決 planning question は記録されていない。
|
||||
- Relations / orchestration plan: outgoing depends_on `00001KVXK0WDQ` と `00001KVXK0WDX` は done。routing 前 plan は historical blocked_by records 2 件で、prerequisites 完了により解消済み。accepted plan `orch-plan-20260625-062148-3` を記録済み。
|
||||
- Related Tickets: `00001KVXK0WDQ` and `00001KVXK0WDX` are done.
|
||||
- Code context: `crates/pod/src/feature/plugin.rs` の WebSocket allowlist/grants, existing pull API helpers, Plugin Service ingress queue, output command model。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。inprogress Ticket は 0 件。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Service Plugin に紐づく host-owned WebSocket connection driver を追加し、incoming text frames を Plugin ingress queue に event として enqueue し、Service output command の `websocket_send` を grant-check 後に Host が送信できるようにする。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- Connection ownership is Host-side. Plugin code does not run a long-lived recv loop as recommended service path.
|
||||
- Existing pull `host_api.websocket.recv(timeout)` API may remain for compatibility/internal bounded use, but docs/recommended service integration path must move away from it.
|
||||
- WebSocket target authority is manifest declaration + enabled grant / allowlist. Unauthorized target/send fails closed.
|
||||
- v0 handles text frames. Binary application payload is unsupported/diagnostic. ping/pong/close handling should be bounded/control/diagnostic, not app payload.
|
||||
- Incoming frames are converted to service ingress events using existing bounded queue and lifecycle diagnostics.
|
||||
- Outgoing sends use Service output command path from `00001KVXK0WDX`; do not bypass its validation/grant boundary.
|
||||
- Full reconnect/resume policy, Discord/Slack protocol logic, secret injection design, browser-facing WebSocket API, WIT/PDK/templates update are non-goals.
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- Host-owned WebSocket driver can manage a connection associated with a Service Plugin.
|
||||
- Incoming text frames enqueue Plugin ingress events.
|
||||
- Close/error/reconnect-needed states become ingress events or status diagnostics.
|
||||
- Plugin output command can trigger WebSocket text send after grant checks.
|
||||
- Ungranted send / unauthorized target is fail-closed diagnostic.
|
||||
- Connection status, last frame time, last error, queue drops, send failures are visible in diagnostics/status.
|
||||
- Tests cover driver lifecycle, incoming frame to ingress, send command execution/rejection, close/error diagnostics, and frame kind handling.
|
||||
|
||||
Implementation latitude:
|
||||
- Exact struct names and whether tests use mock WebSocket client/connection or local bounded fake are coder choices.
|
||||
- v0 may model reconnect-needed as diagnostic instead of automatic reconnect.
|
||||
- Keep integration in `crates/pod/src/feature/plugin.rs` unless a small helper module split is clearly cleaner.
|
||||
|
||||
Escalate if:
|
||||
- Real network tests or external services are required.
|
||||
- Secret store/auth injection becomes necessary.
|
||||
- Durable cross-process queue or scheduler semantics are required.
|
||||
- Implementing this requires WIT/PDK/template changes rather than Rust-side host runtime only.
|
||||
- Browser-facing WebSocket API or protocol-specific Discord/Slack behavior is needed.
|
||||
|
||||
Validation:
|
||||
- `cargo test -p pod`
|
||||
- `cargo check -p yoi`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
- Focused WebSocket driver / service ingress tests during development.
|
||||
|
||||
Current code map:
|
||||
- Primary: `crates/pod/src/feature/plugin.rs`。
|
||||
- Secondary only if necessary: docs/development recommended path wording。
|
||||
- Avoid: WIT/PDK/templates update (reserved for `00001KVXK0WEA`), protocol-specific integrations, full reconnect policy, secret store, browser WebSocket API。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- hidden ambient network authority or bypassing manifest/grant allowlist。
|
||||
- pull `recv(timeout)` remaining as recommended long-lived service path。
|
||||
- output command send bypassing Service command validation。
|
||||
- unbounded reader task/queue or dropped diagnostics。
|
||||
- tests that require real external network。
|
||||
- scope creep into PDK/templates or protocol-specific behavior。
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WE4-plugin-websocket-driver` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-25T06:23:16Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、derived blockers は空。
|
||||
- outgoing dependencies `00001KVXK0WDQ` と `00001KVXK0WDX` は done / merged / reviewed / validated 済み。
|
||||
- accepted plan `orch-plan-20260625-062148-3` を確認した。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WE4-plugin-websocket-driver` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-25T06:24:16Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- prerequisite `00001KVXK0WDX` が done になったため、`00001KVXK0WE4` を再 routing して受理した。
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WE4-plugin-websocket-driver` と branch `work/00001KVXK0WE4-plugin-websocket-driver` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVXK0WE4-websocket-driver` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVXK0WE4-websocket-driver at: 2026-06-25T06:56:37Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report:
|
||||
|
||||
- Ticket: `00001KVXK0WE4`
|
||||
- Branch/worktree: `work/00001KVXK0WE4-plugin-websocket-driver` / `/home/hare/Projects/yoi/.worktree/00001KVXK0WE4-plugin-websocket-driver`
|
||||
- Commit: `f2c51ffe399fc4eaa0ab4e4052867d55e534b229`
|
||||
- Commit message: `feat: add plugin websocket service driver`
|
||||
|
||||
変更ファイル:
|
||||
- `crates/pod/src/feature/plugin.rs`
|
||||
- Service Plugin 用の host-owned WebSocket driver を追加。
|
||||
- `ingress.sources` の `websocket:wss://...` / `ws(s)://...` を Service WebSocket 接続として扱う実装を追加。
|
||||
- incoming text frame を既存の bounded Service ingress queue へ `websocket_text` event として enqueue。
|
||||
- close/error を `websocket_close` / `websocket_error` ingress event と status diagnostic に反映。
|
||||
- `websocket_send` Service output command を host-owned connection 経由の text send に接続。
|
||||
- manifest declaration + enabled grant / allowlist を通らない open/send は fail-closed。
|
||||
- status に connection state、last frame time、last error、received/sent count、queue drops、send failures を追加。
|
||||
- driver lifecycle / incoming / send success / send rejection / send failure / close-error diagnostics / binary-like frame error の focused tests を追加。
|
||||
- `docs/development/plugin-development.md`
|
||||
- Service Plugin の推奨 WebSocket integration を、guest long-lived recv loop ではなく host-owned Service WebSocket driver + `websocket_send` output command に更新。
|
||||
|
||||
検証結果:
|
||||
- `cargo test -p pod --lib websocket_`: success (`14 passed`)
|
||||
- `cargo test -p pod --lib service_output_command`: success (`4 passed`)
|
||||
- `cargo check -p pod`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- Nix dirty warning は worktree の ignored `target/` によるもので、tracked changes はなし。
|
||||
- `cargo test -p pod`: failed only in known prompt guidance snapshot tests outside this Ticket (`438 passed; 2 failed`)
|
||||
- `prompt::catalog::tests::pod_orchestration_guidance_section_renders_resource_body`
|
||||
- `prompt::system::tests::pod_orchestration_guidance_is_included_for_pod_management_tools`
|
||||
|
||||
Residual risks / notes:
|
||||
- v0 は自動 reconnect/resume policy を実装せず、close/error は diagnostic/event 化に留めている。
|
||||
- Service WebSocket source の manifest 表現は既存 `ingress.sources` の文字列規約として追加。WIT/PDK/templates 更新は Ticket `00001KVXK0WEA` 側に残している。
|
||||
- 実ネットワーク test は non-goal のため、mock WebSocket client/connection による bounded focused tests で検証している。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVXK0WE4-websocket-driver at: 2026-06-25T07:03:47Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
読み取り専用で Ticket / IntentPacket / `62e467c0..HEAD` diff を確認した。Ticket review 記録・merge・close・検証コマンド実行は reviewer では行っていない。
|
||||
|
||||
確認した証拠:
|
||||
- 変更範囲は `crates/pod/src/feature/plugin.rs` と `docs/development/plugin-development.md` のみで、WIT / PDK / templates へのスコープ拡大はない。
|
||||
- Host-owned Service WebSocket driver:
|
||||
- Service/Ingress 有効時に `ingress.sources` から `websocket:` / `ws(s)://` source を subscription 化している。
|
||||
- instance start 後に host 側で connection start し、reader thread を生成している。
|
||||
- authority / fail-closed:
|
||||
- open は `host_api.websocket` permission と manifest/grant allowlist を通した既存 validation を再利用している。
|
||||
- `websocket_send` は Service output command envelope の validation/grant check 経由でのみ実行され、URL scheme/credentials/static target/manifest+grant allowlist を検査している。
|
||||
- ingress queue / diagnostics:
|
||||
- text frame は `websocket_text` event として既存 `deliver_ingress` path に渡され、失敗時は queue drop と diagnostic を記録する。
|
||||
- close/error は `websocket_close` / `websocket_error` event と status diagnostic に反映される。
|
||||
- status には connection state, last frame, last error, received/sent counts, queue drops, send failures が出る。
|
||||
- output command send:
|
||||
- `PluginServiceOutputCommandKind::WebSocketSend` が追加され、実行時は host-owned connection の `send_text` に接続され、send failure diagnostic も記録する。
|
||||
- docs:
|
||||
- `recv(timeout)` は bounded/internal/tool-style use として残しつつ、Service Plugin では host-owned Service WebSocket driver + `websocket_send` を推奨する文面に更新されている。
|
||||
- tests:
|
||||
- mock/fake client による incoming text/close、send success/failure、unauthorized target、receive error/binary相当 diagnostic のテストが追加されている。
|
||||
|
||||
検証状況:
|
||||
- reviewer は cargo/nix 等を実行していない(read-only / no writes 指示のため)。
|
||||
- diff・対象コード・Ticket acceptance を静的確認し、coder 報告の `cargo check` / focused tests / nix build 結果を前提証跡として扱った。
|
||||
|
||||
Non-blocking notes:
|
||||
- `docs/development/plugin-development.md` の “Current status” 付近にはまだ Service/Ingress/WebSocket を future work と読む余地が残っているが、本 Ticket の受け入れ条件である「pull recv を recommended service path にしない」は満たしている。後続の docs/PDK/templates Ticket で整理するとよい。
|
||||
- close/error event の enqueue 失敗は text frame のような queue-drop counter には載せていないが、status diagnostic は記録されるため今回の acceptance 上は blocker ではない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-25T07:06:19Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVXK0WE4-websocket-driver` が implementation branch `work/00001KVXK0WE4-plugin-websocket-driver` に実装を commit した。
|
||||
- implementation commit: `f2c51ffe feat: add plugin websocket service driver`
|
||||
- Reviewer `yoi-reviewer-00001KVXK0WE4-websocket-driver` は read-only review で `approve`。host-owned connection authority、manifest/grant allowlist、ingress queue integration、`websocket_send` command validation、status diagnostics、scope creep なしを確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVXK0WE4-plugin-websocket-driver` を merge 済み。
|
||||
- merge commit: `b9e786e1 merge: 00001KVXK0WE4 plugin websocket driver`
|
||||
|
||||
Implemented behavior:
|
||||
- `crates/pod/src/feature/plugin.rs` に Service Plugin 用 host-owned WebSocket driver を追加。
|
||||
- `ingress.sources` の `websocket:wss://...` / `ws(s)://...` source を Service WebSocket connection として扱う。
|
||||
- incoming text frame を existing bounded Service ingress queue へ `websocket_text` event として enqueue。
|
||||
- close/error は `websocket_close` / `websocket_error` event と status diagnostic に反映。
|
||||
- `websocket_send` Service output command は host-owned connection 経由の text send に接続。
|
||||
- manifest declaration + enabled grant / allowlist を通らない open/send は fail-closed。
|
||||
- status に connection state, last frame time, last error, received/sent counts, queue drops, send failures を追加。
|
||||
- `docs/development/plugin-development.md` の Service Plugin 推奨 WebSocket integration を host-owned driver + `websocket_send` output command に更新。
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo test -p pod --lib websocket_`: success
|
||||
- `cargo test -p pod --lib service_output_command`: success
|
||||
- `cargo check -p pod`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed only in known prompt guidance snapshot assertions outside this Plugin diff:
|
||||
- `prompt::catalog::tests::pod_orchestration_guidance_section_renders_resource_body`
|
||||
- `prompt::system::tests::pod_orchestration_guidance_is_included_for_pod_management_tools`
|
||||
- Plugin/WebSocket focused tests in the same run passed.
|
||||
|
||||
Notes:
|
||||
- Reviewer non-blocking note: `docs/development/plugin-development.md` の “Current status” 付近にはまだ Service/Ingress/WebSocket を future work と読む余地が残る。後続 `00001KVXK0WEA` の docs/PDK/templates update で整理するのがよい。
|
||||
- Reviewer non-blocking note: close/error event enqueue failure は text frame と同じ queue-drop counter には載らないが、status diagnostic は記録されるため blocker ではない。
|
||||
- Follow-up `00001KVXK0WEA` is dependency-unblocked and can be re-routed next.
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-25T07:06:30Z from: inprogress to: done reason: merged_validated_with_unrelated_full_suite_caveat field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated with one unrelated known full-suite caveat.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `b9e786e1 merge: 00001KVXK0WE4 plugin websocket driver`
|
||||
- reviewer result: approve
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration`:
|
||||
- `cargo test -p pod --lib websocket_`: success
|
||||
- `cargo test -p pod --lib service_output_command`: success
|
||||
- `cargo check -p pod`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- `cargo test -p pod`: failed only in prompt guidance snapshot assertions outside this Plugin diff; Plugin/WebSocket-focused tests passed.
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/review/focused validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,2 @@
|
||||
{"id":"orch-plan-20260624-201335-1","ticket_id":"00001KVXK0WEA","kind":"blocked_by","related_ticket":"00001KVXK0WE4","note":"Queue review: `00001KVXK0WEA` は WIT/PDK/templates finishing slice で、implemented WebSocket event/command model `00001KVXK0WE4` に depends_on している。prerequisite completion 後に再 routing する。","author":"yoi-orchestrator","at":"2026-06-24T20:13:35Z"}
|
||||
{"id":"orch-plan-20260625-070739-2","ticket_id":"00001KVXK0WEA","kind":"accepted_plan","accepted_plan":{"summary":"Ticket `00001KVXK0WEA` は prerequisite `00001KVXK0WE4` が done になったため implementation_ready。専用 worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WEA-plugin-pdk-service-events` と branch `work/00001KVXK0WEA-plugin-pdk-service-events` で、Plugin WIT / Rust PDK / embedded templates / docs を Component Model-only Service ingress event + output command + host-owned WebSocket model に合わせて更新する。Runtime実装の再設計や protocol-specific integration は non-goal。","branch":"work/00001KVXK0WEA-plugin-pdk-service-events","worktree":"/home/hare/Projects/yoi/.worktree/00001KVXK0WEA-plugin-pdk-service-events","role_plan":"Orchestrator: accept/routing, worktree creation, final integration/validation/cleanup. Coder: update WIT/PDK/templates/docs/authoring CLI fixtures in dedicated child worktree. Reviewer: read-only review focusing on PDK/template consistency with implemented runtime, no legacy raw-wasm compatibility, and no runtime reimplementation."},"author":"yoi-orchestrator","at":"2026-06-25T07:07:39Z"}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"version": 1,
|
||||
"relations": [
|
||||
{
|
||||
"ticket_id": "00001KVXK0WEA",
|
||||
"kind": "depends_on",
|
||||
"target": "00001KVXK0WE4",
|
||||
"note": "Authoring templates should reflect the implemented WebSocket event/command model.",
|
||||
"author": "yoi ticket",
|
||||
"at": "2026-06-24T19:55:30Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
---
|
||||
title: 'Update Plugin WIT PDK templates for service event runtime'
|
||||
state: 'done'
|
||||
created_at: '2026-06-24T19:51:56Z'
|
||||
updated_at: '2026-06-25T07:57:15Z'
|
||||
assignee: null
|
||||
queued_by: 'workspace-panel'
|
||||
queued_at: '2026-06-24T20:12:05Z'
|
||||
---
|
||||
|
||||
## 背景
|
||||
|
||||
Runtime implementation が Component Model only、host-managed Service lifecycle、Ingress queue、output command、host-owned WebSocket driver へ移るなら、WIT / PDK / templates / docs もその実行モデルを正として表現する必要がある。PDK が long-running `start()` loop や explicit `recv(timeout)` polling を推奨すると、runtime 方針と authoring UX がズレる。
|
||||
|
||||
この Ticket は implementation runtime が揃った後、外部 authoring API を新 model に合わせて更新する仕上げ slice とする。
|
||||
|
||||
## 要件
|
||||
|
||||
- WIT world / interfaces を新しい Service lifecycle / Ingress event / output command model に合わせて更新する。
|
||||
- PDK API は `start()` で long-running loop を書かせない形にする。
|
||||
- PDK は ingress event handler から output command を返す authoring model を提供する。
|
||||
- WebSocket integration template は Host-owned subscription / ingress event / send command pattern を示す。
|
||||
- Tool template は bounded request-response Tool Plugin として維持する。
|
||||
- `plugin.toml` template は `wasm-component` runtime のみを生成する。
|
||||
- `yoi plugin new` / `check` / `pack` が新 templates / schema と整合する。
|
||||
- Docs は legacy raw `wasm` runtime、polling WebSocket loop、ambient authority を推奨しない。
|
||||
|
||||
## Non-goals
|
||||
|
||||
- Runtime internal queue / WebSocket driver の本実装。
|
||||
- Discord-specific PDK abstraction。
|
||||
- Public plugin registry。
|
||||
- MCP bridge integration。
|
||||
|
||||
## 受け入れ条件
|
||||
|
||||
- WIT files が Component Model only runtime と Service event/command model を表現している。
|
||||
- `yoi-plugin-pdk` が Tool Plugin と Service/Ingress Plugin の新 API を提供する。
|
||||
- Templates は legacy raw `wasm` runtime を生成しない。
|
||||
- Service/WebSocket template は polling `recv(timeout)` loop ではなく ingress event / output command pattern を使う。
|
||||
- `yoi plugin new rust-component-tool` と service-oriented template が check/pack できる。
|
||||
- Development docs が新 authoring model と authority boundary を説明している。
|
||||
- `cargo test -p yoi-plugin-pdk`、`cargo test -p yoi`、`cargo check -p yoi`、`git diff --check`、`nix build .#yoi --no-link` が通る。
|
||||
@@ -0,0 +1,363 @@
|
||||
<!-- event: create author: "yoi ticket" at: 2026-06-24T19:51:56Z -->
|
||||
|
||||
## 作成
|
||||
|
||||
LocalTicketBackend によって作成されました。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: intake_summary author: hare at: 2026-06-24T19:55:30Z -->
|
||||
|
||||
## Intake summary
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: "yoi ticket" at: 2026-06-24T19:55:30Z from: planning to: ready reason: cli_state field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Marked ready by `yoi ticket state`.
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: workspace-panel at: 2026-06-24T20:12:05Z from: ready to: queued reason: queued field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Ticket を `workspace-panel` が queued にしました。
|
||||
|
||||
|
||||
---
|
||||
|
||||
<!-- event: decision author: yoi-orchestrator at: 2026-06-25T07:08:09Z -->
|
||||
|
||||
## Decision
|
||||
|
||||
Routing decision: implementation_ready
|
||||
|
||||
Reason:
|
||||
- ユーザーから「続けて」と明示 follow-up があり、queued dependency chain の最終 Ticket として再確認した。
|
||||
- `00001KVXK0WEA` は WIT / PDK / templates / docs を、既に実装済みの Component Model-only runtime、Service lifecycle / ingress queue、Service output commands、host-owned WebSocket driver に合わせる finishing slice である。
|
||||
- outgoing `depends_on` は `00001KVXK0WE4` だが、`00001KVXK0WE4` は done / merged / reviewed / validated 済み。`TicketShow` derived blockers は空で、implementation acceptance blocker は残っていない。
|
||||
- bounded context check で `resources/plugin/wit/*`, `crates/plugin-pdk`, `resources/plugin/templates/rust-component-tool`, `crates/yoi/src/plugin_cli.rs`, `docs/development/plugin-development.md` 周辺に authoring-facing surfaces があることを確認した。Ticket は runtime 実装ではなく authoring surface alignment に限定されており、残る不確実性は local implementation / fixture update に閉じる。
|
||||
|
||||
Evidence checked:
|
||||
- Ticket body / thread: `item.md`, `thread.md`。未解決 planning question は記録されていない。
|
||||
- Relations / orchestration plan: outgoing depends_on `00001KVXK0WE4` は done。routing 前 plan は historical blocked_by `00001KVXK0WE4` のみで、prerequisite 完了により解消済み。accepted plan `orch-plan-20260625-070739-2` を記録済み。
|
||||
- Related Tickets: `00001KVXK0WD3`, `00001KVXK0WDH`, `00001KVXK0WDQ`, `00001KVXK0WDX`, `00001KVXK0WE4` are done.
|
||||
- Code/docs context: `resources/plugin/wit/*.wit`, `crates/plugin-pdk`, `resources/plugin/templates/rust-component-tool`, `crates/yoi/src/plugin_cli.rs`, `docs/development/plugin-development.md`。
|
||||
- Workspace state: `/home/hare/Projects/yoi/.worktree/orchestration` は clean。inprogress Ticket は 0 件。
|
||||
|
||||
IntentPacket:
|
||||
|
||||
Intent:
|
||||
- Plugin authoring surface (WIT, Rust PDK, embedded templates, docs, `yoi plugin new/check/pack` fixtures) を、Component Model-only runtime と Service ingress event / output command / host-owned WebSocket model に合わせて更新する。
|
||||
|
||||
Binding decisions / invariants:
|
||||
- `plugin.toml` template は `wasm-component` runtime のみを生成する。
|
||||
- Service/WebSocket authoring pattern は polling `recv(timeout)` loop ではなく、ingress event handler + output command (`websocket_send`) を正とする。
|
||||
- Tool Plugin authoring support must continue to work.
|
||||
- Runtime implementation from previous Tickets is not redesigned here; this Ticket updates WIT/PDK/templates/docs/tests to match it.
|
||||
- No raw core-Wasm compatibility template or legacy runtime alias is introduced.
|
||||
- No protocol-specific Discord/Slack integration, secret store/auth injection, or full reconnect policy is implemented.
|
||||
|
||||
Requirements / acceptance criteria:
|
||||
- WIT expresses Service ingress event payloads and output command model enough for authoring/tests.
|
||||
- `yoi-plugin-pdk` exposes ergonomic Tool and Service/Ingress helpers aligned with runtime JSON envelopes.
|
||||
- Embedded templates include current Tool template and a service-oriented template or equivalent examples using ingress event / output command pattern.
|
||||
- `yoi plugin new` / `check` / `pack` are consistent with new templates/schema.
|
||||
- Docs no longer recommend long-running `recv(timeout)` loop for Service WebSocket integration.
|
||||
- Tests cover PDK helpers, template generation/check/pack, and docs/manifest fixture consistency.
|
||||
|
||||
Implementation latitude:
|
||||
- Exact WIT/interface names and Rust PDK helper APIs may follow existing PDK style, as long as runtime envelopes and docs are consistent.
|
||||
- If a full new `plugin new` template name is too large, coder may add minimal service template/example plus CLI support needed to satisfy acceptance, but must keep scope bounded.
|
||||
- Template wasm build/check may use existing test helpers and temporary target dirs.
|
||||
|
||||
Escalate if:
|
||||
- WIT/PDK update requires changing runtime JSON envelope semantics from previous Tickets.
|
||||
- `yoi plugin new/check/pack` requires broad CLI redesign.
|
||||
- Real WebSocket network/protocol integration or secret handling is needed.
|
||||
- Legacy raw-WASM compatibility has to be restored for templates/tests.
|
||||
|
||||
Validation:
|
||||
- `cargo test -p yoi-plugin-pdk`
|
||||
- `cargo test -p yoi plugin` or focused plugin CLI/template tests
|
||||
- `cargo check -p yoi`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
- Template cargo-check if applicable, with cleanup of generated template artifacts.
|
||||
|
||||
Current code/docs map:
|
||||
- Primary: `resources/plugin/wit/*.wit`, `crates/plugin-pdk`, `resources/plugin/templates/rust-component-tool`, possible new template under `resources/plugin/templates/`, `crates/yoi/src/plugin_cli.rs`, `docs/development/plugin-development.md`。
|
||||
- Secondary: manifest tests/fixtures only as needed.
|
||||
- Avoid: Pod runtime reimplementation, WebSocket driver changes unless minor doc/test alignment, protocol-specific integrations, secret store/auth injection, raw-WASM compatibility。
|
||||
|
||||
Critical risks / reviewer focus:
|
||||
- PDK/template API drift from runtime JSON envelopes。
|
||||
- Tool template regression while adding Service support。
|
||||
- reintroducing `recv(timeout)` as recommended Service pattern。
|
||||
- template generation/check/pack writing outside destination or leaving build artifacts。
|
||||
- accidental legacy raw-WASM runtime compatibility in examples。
|
||||
|
||||
Next action:
|
||||
- `queued -> inprogress` を記録してから worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WEA-plugin-pdk-service-events` を作成し、multi-agent-workflow で Coder/Reviewer sibling loop に進める。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-25T07:08:46Z from: queued to: inprogress reason: orchestrator_acceptance_unblocked field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Orchestrator acceptance: queued -> inprogress
|
||||
|
||||
- 直前確認で `TicketShow` は state `queued`、derived blockers は空。
|
||||
- outgoing dependency `00001KVXK0WE4` は done / merged / reviewed / validated 済み。
|
||||
- accepted plan `orch-plan-20260625-070739-2` を確認した。
|
||||
- routing decision と IntentPacket は Ticket thread に記録済み。
|
||||
- これ以降に worktree-workflow で `/home/hare/Projects/yoi/.worktree/00001KVXK0WEA-plugin-pdk-service-events` を作成し、multi-agent-workflow に接続する。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-25T07:09:39Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation orchestration update:
|
||||
|
||||
- prerequisite `00001KVXK0WE4` が done になったため、`00001KVXK0WEA` を再 routing して受理した。
|
||||
- worktree-workflow に従い、implementation worktree `/home/hare/Projects/yoi/.worktree/00001KVXK0WEA-plugin-pdk-service-events` と branch `work/00001KVXK0WEA-plugin-pdk-service-events` を作成した。
|
||||
- child worktree では tracked `.yoi` project records を見える状態にし、`.yoi/memory`、local/runtime/log/lock/secret-like `.yoi` paths を sparse-checkout で除外する方針にした。
|
||||
- Coder Pod `yoi-coder-00001KVXK0WEA-pdk-service-events` を sibling として起動した。write scope は child worktree に限定し、runtime workspace root `/home/hare/Projects/yoi` は startup 要件を満たすため non-recursive read のみにした。
|
||||
- Coder には root/original workspace と orchestration worktree で read/write/validation/git operation を行わないよう明示した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVXK0WEA-pdk-service-events at: 2026-06-25T07:38:44Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Implementation report:
|
||||
|
||||
対象 Ticket:
|
||||
- `00001KVXK0WEA` — Update Plugin WIT PDK templates for service event runtime
|
||||
|
||||
実装概要:
|
||||
- Plugin authoring surface を Component Model-only / Service ingress event / output command model に合わせて更新した。
|
||||
|
||||
変更ファイル:
|
||||
- `resources/plugin/wit/yoi-plugin-instance-v1.wit`
|
||||
- Service ingress event JSON と `output_commands` / `websocket_send` の authoring 向け説明を追加。
|
||||
- `resources/plugin/wit/yoi-plugin-tool-v1.wit`
|
||||
- current runtime 前提の説明に整理。
|
||||
- `crates/plugin-pdk/src/lib.rs`
|
||||
- `PluginIngressEvent` に `ingress_name`, `created_at`, `attempt`, `correlation_id` を追加。
|
||||
- `ServiceOutput`, `ServiceOutputCommand`, `ServiceOutputCommandKind` を追加。
|
||||
- `PluginIngressEvent::websocket_text()`, `websocket_send()`, `ServiceOutput::websocket_send()` を追加。
|
||||
- `Plugin::handle_ingress` の戻り値を `ServiceOutput` に変更。
|
||||
- `crates/plugin-pdk/tests/template.rs`
|
||||
- PDK helper / WIT / template consistency tests を追加・更新。
|
||||
- `resources/plugin/templates/rust-component-instance/*`
|
||||
- Service-oriented template に更新。
|
||||
- guest-side `recv(timeout)` loop ではなく、`handle_ingress` で ingress event を受け、`ServiceOutput::websocket_send` で output command を返す構成に変更。
|
||||
- `plugin.toml` は `runtime.kind = "wasm-component"` のみ。
|
||||
- Tool handler も残し、Tool Plugin authoring support を維持。
|
||||
- `crates/yoi/src/plugin_cli.rs`, `crates/yoi/src/main.rs`
|
||||
- `yoi plugin new rust-component-service <path>` を追加。
|
||||
- service template の `new` / `check` / `pack` consistency を unit test で確認。
|
||||
- CLI usage を更新。
|
||||
- `docs/development/plugin-development.md`
|
||||
- Service/Ingress は host-owned ingress event + output command model として記述。
|
||||
- Service WebSocket integration で long-running guest `recv(timeout)` loop を推奨しない内容に更新。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p yoi-plugin-pdk`: success
|
||||
- `cargo test -p yoi plugin`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success (`nix-exit:0`)
|
||||
- Template cargo-check: success
|
||||
- `cargo test -p yoi-plugin-pdk` 内で `rust-component-tool` / `rust-component-instance` の `cargo check --target wasm32-unknown-unknown --offline --target-dir <temp>` を実行し、temporary target dir を使用。
|
||||
|
||||
Commit:
|
||||
- `7a4fd975268b655dca2f0861b8f2bd767c1e914f feat: update plugin service authoring templates`
|
||||
|
||||
Residual risks / notes:
|
||||
- Runtime envelope の再設計は行っていない。
|
||||
- protocol-specific integration / secret injection / reconnect policy / runtime reimplementation は範囲外として未実装。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVXK0WEA-pdk-service-events at: 2026-06-25T07:44:48Z status: request_changes -->
|
||||
|
||||
## Review: request changes
|
||||
|
||||
Review result: request_changes
|
||||
|
||||
実装は概ね Ticket の方向に沿っているが、Service WebSocket template の manifest が runtime の authority boundary と不整合で、生成テンプレートの中心例が実行時に `websocket_send` できない状態に見える。
|
||||
|
||||
Blocker:
|
||||
- Service template が `websocket_send` に必要な manifest 権限/target を宣言していない。
|
||||
- `resources/plugin/templates/rust-component-instance/src/lib.rs` は `ServiceOutput::websocket_send(...)` を返す Service/WebSocket 例になっている。
|
||||
- `resources/plugin/templates/rust-component-instance/plugin.toml` は `surface/tool/service/ingress` と `tool/service/ingress` permission はあるが、`{ kind = "host_api", api = "websocket" }` がない。
|
||||
- 同 `plugin.toml` には matching `[[websocket]]` target declaration もない。
|
||||
- runtime 側の `websocket_send` 処理は manifest permissions の `host_api.websocket`、grants permissions の `host_api.websocket`、manifest の `[[websocket]]` target declaration、enablement 側の usable websocket grant を要求する。
|
||||
- そのため生成された service template は `yoi plugin check/pack` は通っても、実行時に `requested host_api.websocket permission is missing` / `manifest host_api.websocket target declaration is missing` 系で拒否されるはず。
|
||||
|
||||
Required fixes:
|
||||
- `resources/plugin/templates/rust-component-instance/plugin.toml` に少なくとも以下を追加する。
|
||||
- `permissions` の `{ kind = "host_api", api = "websocket" }`
|
||||
- `[[websocket]]` target declaration(例: `scheme = "wss"`, `host = "example.com"`, `path_prefixes = ["/socket"]`)
|
||||
- template/CLI tests に、service template が `host_api.websocket` permission と matching `[[websocket]]` declaration を含むことの assertion を追加する。
|
||||
- 必要なら README/docs で、enablement grants も同じ WebSocket target を明示的に許可する必要があることを補足する。
|
||||
|
||||
Good points:
|
||||
- WIT は `handle-ingress`、ingress event envelope、`output_commands` / `websocket_send` 例を記述している。
|
||||
- PDK は `PluginIngressEvent`、`ServiceOutput`、`ServiceOutputCommand`、`websocket_text()` / `websocket_send()` helper を追加し、runtime envelope 形状に概ね合っている。
|
||||
- Service template は `recv(timeout)` polling loop を推奨しておらず、`handle_ingress` + `ServiceOutput::websocket_send` の形になっている。
|
||||
- template `runtime.kind` は `wasm-component` で、raw `wasm` template 復活は見当たらない。
|
||||
- `yoi plugin new rust-component-service` は既存の path-safety 方針上に追加されており、広い CLI redesign や runtime reimplementation は見当たらない。
|
||||
|
||||
Validation:
|
||||
- reviewer は read-only 指示のため cargo/nix/git diff validation は再実行していない。
|
||||
- Ticket item/thread、IntentPacket、`cd200630..HEAD` の変更、WIT / PDK / template / CLI / docs / runtime envelope 関連箇所を静的確認した。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-coder-00001KVXK0WEA-pdk-service-events at: 2026-06-25T07:53:08Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Follow-up implementation report after review request_changes:
|
||||
|
||||
対応内容:
|
||||
- Reviewer blocker に対応し、Service template の `websocket_send` output command に必要な runtime authority を追加した。
|
||||
|
||||
変更点:
|
||||
- `resources/plugin/templates/rust-component-instance/plugin.toml`
|
||||
- `permissions` に `{ kind = "host_api", api = "websocket" }` を追加。
|
||||
- matching target として `[[websocket]]` を追加。
|
||||
- `scheme = "wss"`
|
||||
- `host = "example.com"`
|
||||
- `path_prefixes = ["/socket"]`
|
||||
- `crates/plugin-pdk/tests/template.rs`
|
||||
- service template manifest に `host_api.websocket` permission が含まれることを検証。
|
||||
- `[[websocket]]` target が `wss://example.com/socket` に対応していることを検証。
|
||||
- `crates/yoi/src/plugin_cli.rs`
|
||||
- `yoi plugin new rust-component-service ...` で生成される manifest に `host_api.websocket` permission / `[[websocket]]` declaration が含まれることを CLI test に追加。
|
||||
- `resources/plugin/templates/rust-component-instance/README.md`
|
||||
- manifest 側の `host_api.websocket` / `[[websocket]]` declaration と、enablement grants 側でも同じ WebSocket target を明示許可する必要があることを追記。
|
||||
- `docs/development/plugin-development.md`
|
||||
- Service ingress / output command の minimal manifest example に `host_api.websocket` permission と `[[websocket]]` target を追加。
|
||||
- `websocket_send` output command には manifest declaration だけでなく runtime enablement grants も必要であることを明記。
|
||||
|
||||
Validation:
|
||||
- `cargo test -p yoi-plugin-pdk`: success
|
||||
- `cargo test -p yoi plugin`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success (`nix-exit:0`)
|
||||
|
||||
Commit:
|
||||
- `6c8998878dc1d59ad70da3280efd503a9a060ebb fix: declare plugin service websocket authority`
|
||||
|
||||
Residual risks / notes:
|
||||
- なし。runtime envelope の再設計、raw wasm compatibility、protocol-specific integration、secret/reconnect policy、runtime reimplementation は行っていない。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: review author: yoi-reviewer-00001KVXK0WEA-pdk-service-events at: 2026-06-25T07:55:26Z status: approve -->
|
||||
|
||||
## Review: approve
|
||||
|
||||
Review result: approve
|
||||
|
||||
前回 blocker は解消されている。
|
||||
|
||||
確認した証拠:
|
||||
- `resources/plugin/templates/rust-component-instance/plugin.toml`
|
||||
- `permissions` に `{ kind = "host_api", api = "websocket" }` が追加済み。
|
||||
- `[[websocket]]` target が追加済みで、`wss://example.com/socket` と一致する `scheme = "wss"`, `host = "example.com"`, `path_prefixes = ["/socket"]` を宣言している。
|
||||
- `runtime.kind = "wasm-component"` のままで、raw `wasm` 互換は導入されていない。
|
||||
- Service template README:
|
||||
- `websocket_send` には manifest の `host_api.websocket` と matching `[[websocket]]` target が必要で、enablement grants も同じ target を許可する必要がある、と明記済み。
|
||||
- Development docs:
|
||||
- Service ingress/output command 節で `websocket_send` に必要な `host_api.websocket` permission / `[[websocket]]` target / enablement grant 境界を説明している。
|
||||
- polling `recv(timeout)` loop ではなく ingress event / output command pattern を推奨する説明を維持している。
|
||||
- Tests:
|
||||
- PDK template test が service template manifest の websocket permission と matching target を assert するよう更新されている。
|
||||
- CLI `plugin new rust-component-service` test も生成 manifest に websocket permission / `[[websocket]]` / host / path_prefix が含まれることを assert している。
|
||||
|
||||
リスク確認:
|
||||
- 前回懸念した「template は `ServiceOutput::websocket_send` を返すのに manifest authority が足りない」不整合は修正済み。
|
||||
- 今回差分は template/docs/tests の authority declaration 補正に閉じており、runtime redesign、protocol-specific integration、secret injection、raw-WASM compatibility の追加は見当たらない。
|
||||
|
||||
検証:
|
||||
- reviewer は read-only 指定のため `cargo` / `nix` / `git diff --check` は再実行していない。
|
||||
- `7a4fd975..HEAD` と fix commit `6c899887` の静的レビューのみ実施。
|
||||
|
||||
---
|
||||
|
||||
<!-- event: implementation_report author: yoi-orchestrator at: 2026-06-25T07:57:03Z -->
|
||||
|
||||
## Implementation report
|
||||
|
||||
Integration outcome:
|
||||
|
||||
- Coder `yoi-coder-00001KVXK0WEA-pdk-service-events` が implementation branch `work/00001KVXK0WEA-plugin-pdk-service-events` に実装と review fix を commit した。
|
||||
- implementation commit: `7a4fd975 feat: update plugin service authoring templates`
|
||||
- fix commit: `6c899887 fix: declare plugin service websocket authority`
|
||||
- Reviewer `yoi-reviewer-00001KVXK0WEA-pdk-service-events` は初回 review で request_changes。Service template が `ServiceOutput::websocket_send` を返す一方で `host_api.websocket` permission と matching `[[websocket]]` target declaration を持たない点を blocker とした。
|
||||
- Coder は service template manifest / tests / docs を修正し、follow-up review は `approve`。template authority declaration、enablement grants guidance、runtime envelope alignment、raw-WASM compatibility 非復活を確認した。
|
||||
- Orchestrator worktree `/home/hare/Projects/yoi/.worktree/orchestration` で branch `work/00001KVXK0WEA-plugin-pdk-service-events` を merge 済み。
|
||||
- merge commit: `8d4fee23 merge: 00001KVXK0WEA plugin pdk service events`
|
||||
|
||||
Implemented behavior:
|
||||
- WIT docs/descriptionsを Service ingress event JSON と `output_commands` / `websocket_send` authoring に合わせて更新。
|
||||
- `crates/plugin-pdk` に `PluginIngressEvent` 拡張、`ServiceOutput` / `ServiceOutputCommand` / `ServiceOutputCommandKind`、`websocket_text` / `websocket_send` helpers を追加。
|
||||
- `Plugin::handle_ingress` returns `ServiceOutput`。
|
||||
- `resources/plugin/templates/rust-component-instance` を service-oriented template に更新し、`handle_ingress` + `ServiceOutput::websocket_send` pattern を示す。
|
||||
- service template `plugin.toml` は `runtime.kind = "wasm-component"`、`host_api.websocket` permission、matching `[[websocket]]` target を含む。
|
||||
- `yoi plugin new rust-component-service <path>` を追加し、new/check/pack consistency tests を更新。
|
||||
- docs は long-running guest `recv(timeout)` loop ではなく host-owned ingress event + output command model を推奨し、enablement grants でも matching websocket target が必要と明記。
|
||||
|
||||
Validation in Orchestrator worktree:
|
||||
- `cargo test -p yoi-plugin-pdk`: success
|
||||
- `cargo test -p yoi plugin`: success
|
||||
- `cargo check -p yoi`: success
|
||||
- `git diff --check`: success
|
||||
- `nix build .#yoi --no-link`: success
|
||||
- Template cargo-check is covered by `cargo test -p yoi-plugin-pdk` using temporary target dirs.
|
||||
|
||||
Notes:
|
||||
- This Ticket completes the queued Plugin runtime redesign chain slices that were split from the original broad redesign request.
|
||||
- No runtime envelope redesign, protocol-specific integration, secret injection, reconnect policy, runtime reimplementation, or raw-WASM compatibility was introduced.
|
||||
|
||||
Next action:
|
||||
- Mark Ticket done after this integration/validation evidence.
|
||||
- Then stop related child Pods and remove only the child implementation worktree/branch.
|
||||
|
||||
---
|
||||
|
||||
<!-- event: state_changed author: yoi-orchestrator at: 2026-06-25T07:57:15Z from: inprogress to: done reason: merged_validated field: state -->
|
||||
|
||||
## State changed
|
||||
|
||||
Implementation is merged into the orchestration branch and validated.
|
||||
|
||||
Evidence:
|
||||
- merge commit: `8d4fee23 merge: 00001KVXK0WEA plugin pdk service events`
|
||||
- reviewer result: approve after requested changes were fixed
|
||||
- validation in `/home/hare/Projects/yoi/.worktree/orchestration` succeeded:
|
||||
- `cargo test -p yoi-plugin-pdk`
|
||||
- `cargo test -p yoi plugin`
|
||||
- `cargo check -p yoi`
|
||||
- `git diff --check`
|
||||
- `nix build .#yoi --no-link`
|
||||
|
||||
Closure is not performed here; this state records implementation completion after merge/validation.
|
||||
|
||||
---
|
||||
@@ -0,0 +1,3 @@
|
||||
workspace_id = "0197a949-4b6b-7f2a-9d9a-1f87e3a4c5b6"
|
||||
created_at = "2026-06-23T00:00:00Z"
|
||||
display_name = "yoi"
|
||||
@@ -31,6 +31,7 @@ Podの状態から純粋に再現可能で、且つ揮発性の無い操作で
|
||||
|
||||
明示的に指示されない限り、読み取り以外の操作は控えること。
|
||||
基本はworktree上の一時的なブランチでコミットを重ね、メインブランチに取り込む運用をしている。
|
||||
Orchestrator の cwd が orchestration 用ブランチ/worktree の場合、通常作業では親ブランチの dirty state を気にしない。
|
||||
コミットメッセージは適当に`<prefix>: *簡潔な1行*`で書いている。
|
||||
|
||||
外部の参考プロジェクトは必要に応じてローカルの外部 checkout からReadすること。
|
||||
|
||||
Generated
+28
-67
@@ -2913,7 +2913,6 @@ dependencies = [
|
||||
"tracing",
|
||||
"tungstenite",
|
||||
"uuid",
|
||||
"wasmi",
|
||||
"wasmtime",
|
||||
"wat",
|
||||
"workflow",
|
||||
@@ -3035,6 +3034,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"ts-rs",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
@@ -4034,12 +4034,6 @@ dependencies = [
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
version = "0.9.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.1"
|
||||
@@ -4052,16 +4046,6 @@ version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "string-interner"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23de088478b31c349c9ba67816fa55d9355232d63c3afea8bf513e31f0f1d2c0"
|
||||
dependencies = [
|
||||
"hashbrown 0.15.5",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "string_cache"
|
||||
version = "0.8.9"
|
||||
@@ -4696,6 +4680,28 @@ dependencies = [
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ts-rs"
|
||||
version = "12.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "756050066659291d47a554a9f558125db17428b073c5ffce1daf5dcb0f7231d8"
|
||||
dependencies = [
|
||||
"thiserror 2.0.18",
|
||||
"ts-rs-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ts-rs-macros"
|
||||
version = "12.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "38d90eea51bc7988ef9e674bf80a85ba6804739e535e9cab48e4bb34a8b652aa"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.117",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ttf-parser"
|
||||
version = "0.25.1"
|
||||
@@ -5073,56 +5079,6 @@ dependencies = [
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmi"
|
||||
version = "0.51.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bb321403ce594274827657a908e13d1d9918aa02257b8bf8391949d9764023ff"
|
||||
dependencies = [
|
||||
"spin",
|
||||
"wasmi_collections",
|
||||
"wasmi_core",
|
||||
"wasmi_ir",
|
||||
"wasmparser 0.228.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmi_collections"
|
||||
version = "0.51.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e9b8e98e45a2a534489f8225e765cbf1cb9a3078072605e58158910cf4749172"
|
||||
dependencies = [
|
||||
"string-interner",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmi_core"
|
||||
version = "0.51.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c25f375c0cdf14810eab07f532f61f14d4966f09c747a55067fdf3196e8512e6"
|
||||
dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmi_ir"
|
||||
version = "0.51.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624e2a68a4293ecb8f564260b68394b29cf3b3edba6bce35532889a2cb33c3d9"
|
||||
dependencies = [
|
||||
"wasmi_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.228.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4abf1132c1fdf747d56bbc1bb52152400c70f336870f968b85e89ea422198ae3"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"indexmap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.244.0"
|
||||
@@ -5987,6 +5943,7 @@ dependencies = [
|
||||
"manifest",
|
||||
"memory",
|
||||
"pod",
|
||||
"pod-store",
|
||||
"project-record",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -6027,6 +5984,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"chrono",
|
||||
"manifest",
|
||||
"pod-store",
|
||||
"project-record",
|
||||
@@ -6034,12 +5992,15 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml",
|
||||
"sha2 0.11.0",
|
||||
"tempfile",
|
||||
"thiserror 2.0.18",
|
||||
"ticket",
|
||||
"tokio",
|
||||
"toml",
|
||||
"tower",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -16,7 +16,10 @@ pub mod ticket_role;
|
||||
pub use runtime_command::PodRuntimeCommand;
|
||||
|
||||
pub use pod_client::PodClient;
|
||||
pub use spawn::{SpawnConfig, SpawnError, SpawnReady, spawn_pod};
|
||||
pub use spawn::{
|
||||
PodProcessLaunchConfig, PodProcessLaunchOptions, SpawnConfig, SpawnError, SpawnReady,
|
||||
spawn_pod, spawn_pod_with_options,
|
||||
};
|
||||
pub use ticket_role::{
|
||||
TicketRef, TicketRoleLaunchContext, TicketRoleLaunchError, TicketRoleLaunchOptions,
|
||||
TicketRoleLaunchPlan, TicketRoleLaunchResult, TicketRolePreRunWarning, launch_ticket_role_pod,
|
||||
|
||||
+51
-18
@@ -23,7 +23,7 @@ const READY_PREFIX: &str = "YOI-READY\t";
|
||||
const READY_TIMEOUT: Duration = Duration::from_secs(20);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SpawnConfig {
|
||||
pub struct PodProcessLaunchConfig {
|
||||
pub runtime_command: PodRuntimeCommand,
|
||||
/// `pod.name` として使う識別子。runtime ディレクトリ
|
||||
/// (`manifest::paths::pod_runtime_dir`) の解決と、ready 行に乗る
|
||||
@@ -32,9 +32,6 @@ pub struct SpawnConfig {
|
||||
/// Optional reusable Profile selector. Pod identity is always supplied
|
||||
/// separately with `--pod`; profile selection must not imply a name.
|
||||
pub profile: Option<String>,
|
||||
/// Process-local Ticket role marker supplied only by Ticket role launches.
|
||||
/// This does not alter prompts, manifests, or Ticket claim records.
|
||||
pub ticket_role: Option<String>,
|
||||
/// Explicit runtime workspace root. The child receives it via
|
||||
/// `--workspace` so startup does not infer workspace identity from the
|
||||
/// parent process cwd.
|
||||
@@ -48,6 +45,28 @@ pub struct SpawnConfig {
|
||||
pub resume_from: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct PodProcessLaunchOptions {
|
||||
/// Extra child CLI arguments supplied by an upper resolver layer. The
|
||||
/// low-level launch config intentionally does not model Ticket IDs,
|
||||
/// Ticket roles, orchestration roles, executable authority, or raw
|
||||
/// browser-provided profile/cwd/workspace inputs.
|
||||
pub extra_args: Vec<String>,
|
||||
}
|
||||
|
||||
impl PodProcessLaunchOptions {
|
||||
pub fn with_hidden_arg(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
|
||||
self.extra_args.extend([name.into(), value.into()]);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.extra_args.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
pub type SpawnConfig = PodProcessLaunchConfig;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct SpawnReady {
|
||||
pub pod_name: String,
|
||||
@@ -112,7 +131,7 @@ impl From<io::Error> for SpawnError {
|
||||
}
|
||||
}
|
||||
|
||||
fn runtime_args(config: &SpawnConfig) -> Vec<String> {
|
||||
fn runtime_args(config: &PodProcessLaunchConfig, options: &PodProcessLaunchOptions) -> Vec<String> {
|
||||
let mut args = vec![
|
||||
"--workspace".to_string(),
|
||||
config.workspace_root.display().to_string(),
|
||||
@@ -130,9 +149,7 @@ fn runtime_args(config: &SpawnConfig) -> Vec<String> {
|
||||
args.extend(["--profile".to_string(), profile.clone()]);
|
||||
}
|
||||
}
|
||||
if let Some(ticket_role) = &config.ticket_role {
|
||||
args.extend(["--ticket-role".to_string(), ticket_role.clone()]);
|
||||
}
|
||||
args.extend(options.extra_args.clone());
|
||||
args
|
||||
}
|
||||
|
||||
@@ -140,7 +157,21 @@ fn runtime_args(config: &SpawnConfig) -> Vec<String> {
|
||||
///
|
||||
/// `progress` は ready 行を見つけるまでに観測した stderr の各行で呼ばれる
|
||||
/// (ready 行自体は除外される)。UI の表示更新や E2E ログ取得に使う。
|
||||
pub async fn spawn_pod<F>(config: SpawnConfig, mut progress: F) -> Result<SpawnReady, SpawnError>
|
||||
pub async fn spawn_pod<F>(
|
||||
config: PodProcessLaunchConfig,
|
||||
progress: F,
|
||||
) -> Result<SpawnReady, SpawnError>
|
||||
where
|
||||
F: FnMut(&str),
|
||||
{
|
||||
spawn_pod_with_options(config, PodProcessLaunchOptions::default(), progress).await
|
||||
}
|
||||
|
||||
pub async fn spawn_pod_with_options<F>(
|
||||
config: PodProcessLaunchConfig,
|
||||
options: PodProcessLaunchOptions,
|
||||
mut progress: F,
|
||||
) -> Result<SpawnReady, SpawnError>
|
||||
where
|
||||
F: FnMut(&str),
|
||||
{
|
||||
@@ -158,7 +189,7 @@ where
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::from(stderr_file))
|
||||
.process_group(0);
|
||||
for arg in runtime_args(&config) {
|
||||
for arg in runtime_args(&config, &options) {
|
||||
command.arg(arg);
|
||||
}
|
||||
let mut child = command
|
||||
@@ -332,12 +363,11 @@ mod tests {
|
||||
use super::*;
|
||||
use std::ffi::OsString;
|
||||
|
||||
fn base_config() -> SpawnConfig {
|
||||
SpawnConfig {
|
||||
fn base_config() -> PodProcessLaunchConfig {
|
||||
PodProcessLaunchConfig {
|
||||
runtime_command: PodRuntimeCommand::new("/bin/yoi", vec![OsString::from("pod")]),
|
||||
pod_name: "explicit-pod".to_string(),
|
||||
profile: Some("project:companion".to_string()),
|
||||
ticket_role: None,
|
||||
workspace_root: PathBuf::from("/work/other-project"),
|
||||
cwd: None,
|
||||
resume_from: None,
|
||||
@@ -347,7 +377,7 @@ mod tests {
|
||||
#[test]
|
||||
fn runtime_args_keep_workspace_pod_and_profile_separate() {
|
||||
assert_eq!(
|
||||
runtime_args(&base_config()),
|
||||
runtime_args(&base_config(), &PodProcessLaunchOptions::default()),
|
||||
vec![
|
||||
"--workspace",
|
||||
"/work/other-project",
|
||||
@@ -364,7 +394,7 @@ mod tests {
|
||||
let mut config = base_config();
|
||||
config.resume_from = Some(Uuid::nil());
|
||||
assert_eq!(
|
||||
runtime_args(&config),
|
||||
runtime_args(&config, &PodProcessLaunchOptions::default()),
|
||||
vec![
|
||||
"--workspace",
|
||||
"/work/other-project",
|
||||
@@ -377,13 +407,16 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn runtime_args_do_not_include_child_cwd() {
|
||||
fn runtime_args_include_upper_resolver_extra_args_without_child_cwd() {
|
||||
let mut config = base_config();
|
||||
config.ticket_role = Some("orchestrator".to_string());
|
||||
config.cwd = Some(PathBuf::from("/work/main/.worktree/orchestration/yoi"));
|
||||
|
||||
assert_eq!(
|
||||
runtime_args(&config),
|
||||
runtime_args(
|
||||
&config,
|
||||
&PodProcessLaunchOptions::default()
|
||||
.with_hidden_arg("--ticket-role", "orchestrator"),
|
||||
),
|
||||
vec![
|
||||
"--workspace",
|
||||
"/work/other-project",
|
||||
|
||||
@@ -14,7 +14,10 @@ use thiserror::Error;
|
||||
pub use ticket::config::TicketRole;
|
||||
use ticket::config::{TicketConfig, TicketConfigError, TicketRoleLaunchConfigError};
|
||||
|
||||
use crate::{PodClient, PodRuntimeCommand, SpawnConfig, SpawnError, SpawnReady, spawn_pod};
|
||||
use crate::{
|
||||
PodClient, PodProcessLaunchConfig, PodProcessLaunchOptions, PodRuntimeCommand, SpawnError,
|
||||
SpawnReady, spawn_pod_with_options,
|
||||
};
|
||||
|
||||
const MAX_FIELD_CHARS: usize = 8_000;
|
||||
const MAX_POD_NAME_CHARS: usize = 80;
|
||||
@@ -170,20 +173,24 @@ impl TicketRoleLaunchPlan {
|
||||
pub fn spawn_config(
|
||||
&self,
|
||||
runtime_command: PodRuntimeCommand,
|
||||
) -> Result<SpawnConfig, TicketRoleLaunchError> {
|
||||
) -> Result<PodProcessLaunchConfig, TicketRoleLaunchError> {
|
||||
if self.profile == "inherit" {
|
||||
return Err(TicketRoleLaunchError::UnsupportedInheritProfile);
|
||||
}
|
||||
Ok(SpawnConfig {
|
||||
Ok(PodProcessLaunchConfig {
|
||||
runtime_command,
|
||||
pod_name: self.pod_name.clone(),
|
||||
profile: Some(self.profile.clone()),
|
||||
ticket_role: Some(self.role.as_str().to_string()),
|
||||
workspace_root: self.workspace_root.clone(),
|
||||
cwd: self.cwd.clone(),
|
||||
resume_from: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn spawn_options(&self) -> PodProcessLaunchOptions {
|
||||
PodProcessLaunchOptions::default()
|
||||
.with_hidden_arg("--ticket-role", self.role.as_str().to_string())
|
||||
}
|
||||
}
|
||||
|
||||
/// Result of executing a Ticket role launch.
|
||||
@@ -191,9 +198,28 @@ impl TicketRoleLaunchPlan {
|
||||
pub struct TicketRoleLaunchResult {
|
||||
pub plan: TicketRoleLaunchPlan,
|
||||
pub ready: SpawnReady,
|
||||
/// Evidence that the spawned worker accepted the initial Run request.
|
||||
/// This is intentionally distinct from process readiness: a socket
|
||||
/// snapshot only proves that the runtime is reachable, not that the
|
||||
/// worker operation was durably queued/started.
|
||||
pub acceptance_evidence: TicketRoleLaunchAcceptanceEvidence,
|
||||
pub pre_run_warnings: Vec<TicketRolePreRunWarning>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TicketRoleLaunchAcceptanceEvidence {
|
||||
pub pod_name: String,
|
||||
pub accepted_run_segments: usize,
|
||||
pub event: TicketRoleLaunchAcceptanceEvent,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum TicketRoleLaunchAcceptanceEvent {
|
||||
UserMessage,
|
||||
UserSendInvokeStart,
|
||||
TurnStart,
|
||||
}
|
||||
|
||||
/// Non-fatal diagnostic produced by bounded pre-run launch actions.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct TicketRolePreRunWarning {
|
||||
@@ -369,7 +395,9 @@ where
|
||||
F: FnMut(&str),
|
||||
{
|
||||
let plan = plan_ticket_role_launch(context)?;
|
||||
let ready = spawn_pod(plan.spawn_config(runtime_command)?, progress).await?;
|
||||
let spawn_config = plan.spawn_config(runtime_command)?;
|
||||
let spawn_options = plan.spawn_options();
|
||||
let ready = spawn_pod_with_options(spawn_config, spawn_options, progress).await?;
|
||||
let mut client = PodClient::connect(&ready.socket_path)
|
||||
.await
|
||||
.map_err(|source| TicketRoleLaunchError::Connect {
|
||||
@@ -377,10 +405,17 @@ where
|
||||
source,
|
||||
})?;
|
||||
let pre_run_warnings = run_pre_run_options_then_send_run(&mut client, &plan, &options).await?;
|
||||
let acceptance_event =
|
||||
wait_for_run_acceptance(&mut client, &plan.run_segments, RUN_ACCEPTANCE_TIMEOUT).await?;
|
||||
let acceptance_evidence = TicketRoleLaunchAcceptanceEvidence {
|
||||
pod_name: ready.pod_name.clone(),
|
||||
accepted_run_segments: plan.run_segments.len(),
|
||||
event: acceptance_event,
|
||||
};
|
||||
Ok(TicketRoleLaunchResult {
|
||||
plan,
|
||||
ready,
|
||||
acceptance_evidence,
|
||||
pre_run_warnings,
|
||||
})
|
||||
}
|
||||
@@ -471,18 +506,20 @@ async fn wait_for_run_acceptance(
|
||||
client: &mut PodClient,
|
||||
expected_segments: &[Segment],
|
||||
timeout: Duration,
|
||||
) -> Result<(), TicketRoleLaunchError> {
|
||||
) -> Result<TicketRoleLaunchAcceptanceEvent, TicketRoleLaunchError> {
|
||||
let wait = async {
|
||||
loop {
|
||||
let Some(event) = client.next_event().await else {
|
||||
return Err(TicketRoleLaunchError::RunAcceptanceClosed);
|
||||
};
|
||||
match event {
|
||||
Event::UserMessage { segments } if segments == expected_segments => return Ok(()),
|
||||
Event::UserMessage { segments } if segments == expected_segments => {
|
||||
return Ok(TicketRoleLaunchAcceptanceEvent::UserMessage);
|
||||
}
|
||||
Event::InvokeStart {
|
||||
kind: InvokeKind::UserSend,
|
||||
}
|
||||
| Event::TurnStart { .. } => return Ok(()),
|
||||
} => return Ok(TicketRoleLaunchAcceptanceEvent::UserSendInvokeStart),
|
||||
Event::TurnStart { .. } => return Ok(TicketRoleLaunchAcceptanceEvent::TurnStart),
|
||||
Event::Error { code, message } => {
|
||||
return Err(TicketRoleLaunchError::RunRejected { code, message });
|
||||
}
|
||||
@@ -547,9 +584,6 @@ fn append_operation_targets(out: &mut String, context: &TicketRoleLaunchContext)
|
||||
if context.role != TicketRole::Orchestrator {
|
||||
return;
|
||||
}
|
||||
if context.original_workspace_root.is_none() && context.target_workspace_root.is_none() {
|
||||
return;
|
||||
}
|
||||
|
||||
out.push_str("\nOrchestrator operation targets:\n");
|
||||
push_bounded_bullet(
|
||||
@@ -557,13 +591,6 @@ fn append_operation_targets(out: &mut String, context: &TicketRoleLaunchContext)
|
||||
"implementation_worktree_root",
|
||||
&context.implementation_worktree_root().display().to_string(),
|
||||
);
|
||||
if context.target_workspace_root.is_some() {
|
||||
push_bounded_bullet(
|
||||
out,
|
||||
"merge_target_workspace_root",
|
||||
&context.target_workspace_root().display().to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn default_pod_name(role: TicketRole, ticket: Option<&TicketRef>) -> String {
|
||||
@@ -706,6 +733,7 @@ mod tests {
|
||||
context_tokens: 0,
|
||||
},
|
||||
status: PodStatus::Idle,
|
||||
in_flight: protocol::InFlightSnapshot::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1035,8 +1063,12 @@ workflow = "ticket-review-workflow"
|
||||
.unwrap();
|
||||
assert_eq!(spawn.pod_name, "reviewer-fixed");
|
||||
assert_eq!(spawn.profile.as_deref(), Some("builtin:default"));
|
||||
assert_eq!(spawn.ticket_role.as_deref(), Some("reviewer"));
|
||||
assert_eq!(spawn.workspace_root, temp.path());
|
||||
assert!(spawn.cwd.is_none());
|
||||
assert_eq!(
|
||||
plan.spawn_options().extra_args,
|
||||
vec!["--ticket-role".to_string(), "reviewer".to_string()]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1152,7 +1184,7 @@ workflow = "ticket-review-workflow"
|
||||
|
||||
assert!(text.contains("Orchestrator operation targets:"));
|
||||
assert!(text.contains("implementation_worktree_root"));
|
||||
assert!(text.contains("merge_target_workspace_root"));
|
||||
assert!(!text.contains("merge_target_workspace_root"));
|
||||
assert!(!text.contains("Workspace routing context:"));
|
||||
assert!(!text.contains("role_workspace_root"));
|
||||
assert!(!text.contains("role_cwd"));
|
||||
|
||||
@@ -63,7 +63,7 @@ impl ResolvedAuth {
|
||||
}
|
||||
}
|
||||
|
||||
fn header_value_for_diagnostics(headers: &HeaderMap, name: &'static HeaderName) -> Option<String> {
|
||||
fn header_value_for_diagnostics(headers: &HeaderMap, name: &str) -> Option<String> {
|
||||
headers
|
||||
.get(name)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
@@ -74,10 +74,25 @@ fn header_value_for_diagnostics(headers: &HeaderMap, name: &'static HeaderName)
|
||||
|
||||
fn response_header_diagnostics(headers: &HeaderMap) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"content_type": header_value_for_diagnostics(headers, &CONTENT_TYPE),
|
||||
"content_encoding": header_value_for_diagnostics(headers, &CONTENT_ENCODING),
|
||||
"transfer_encoding": header_value_for_diagnostics(headers, &TRANSFER_ENCODING),
|
||||
"content_length": header_value_for_diagnostics(headers, &CONTENT_LENGTH),
|
||||
"content_type": header_value_for_diagnostics(headers, CONTENT_TYPE.as_str()),
|
||||
"content_encoding": header_value_for_diagnostics(headers, CONTENT_ENCODING.as_str()),
|
||||
"transfer_encoding": header_value_for_diagnostics(headers, TRANSFER_ENCODING.as_str()),
|
||||
"content_length": header_value_for_diagnostics(headers, CONTENT_LENGTH.as_str()),
|
||||
})
|
||||
}
|
||||
|
||||
fn request_header_diagnostics(headers: &HeaderMap) -> serde_json::Value {
|
||||
serde_json::json!({
|
||||
"content_type": header_value_for_diagnostics(headers, CONTENT_TYPE.as_str()),
|
||||
"content_encoding": header_value_for_diagnostics(headers, CONTENT_ENCODING.as_str()),
|
||||
"accept": header_value_for_diagnostics(headers, ACCEPT.as_str()),
|
||||
"openai_beta": header_value_for_diagnostics(headers, "openai-beta"),
|
||||
"session_id_present": headers.contains_key("session-id"),
|
||||
"thread_id_present": headers.contains_key("thread-id"),
|
||||
"legacy_session_id_present": headers.contains_key("session_id"),
|
||||
"legacy_thread_id_present": headers.contains_key("thread_id"),
|
||||
"x_client_request_id_present": headers.contains_key("x-client-request-id"),
|
||||
"chatgpt_account_id_present": headers.contains_key("chatgpt-account-id"),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -211,6 +226,11 @@ impl<S: Scheme> HttpTransport<S> {
|
||||
let value = HeaderValue::from_str(cache_key).map_err(|e| {
|
||||
ClientError::Config(format!("invalid Codex conversation header: {e}"))
|
||||
})?;
|
||||
// Codex CLI sends hyphenated session/thread headers to the
|
||||
// ChatGPT Codex backend. Keep the legacy underscore header for
|
||||
// existing traces/backends while exposing the current Codex shape.
|
||||
headers.insert(HeaderName::from_static("session-id"), value.clone());
|
||||
headers.insert(HeaderName::from_static("thread-id"), value.clone());
|
||||
headers.insert(HeaderName::from_static("session_id"), value.clone());
|
||||
headers.insert(HeaderName::from_static("x-client-request-id"), value);
|
||||
}
|
||||
@@ -451,6 +471,7 @@ impl<S: Scheme + Clone + 'static> LlmClient for HttpTransport<S> {
|
||||
json!({
|
||||
"elapsed_ms": headers_started.elapsed().as_millis() as u64,
|
||||
"headers_len": headers.len(),
|
||||
"headers": request_header_diagnostics(&headers),
|
||||
}),
|
||||
);
|
||||
headers
|
||||
@@ -486,6 +507,7 @@ impl<S: Scheme + Clone + 'static> LlmClient for HttpTransport<S> {
|
||||
json!({
|
||||
"elapsed_ms": stream_headers_started.elapsed().as_millis() as u64,
|
||||
"headers_len": headers.len(),
|
||||
"headers": request_header_diagnostics(&headers),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -520,15 +542,19 @@ impl<S: Scheme + Clone + 'static> LlmClient for HttpTransport<S> {
|
||||
return Err(error);
|
||||
}
|
||||
};
|
||||
let final_request_headers = request_header_diagnostics(&headers);
|
||||
let body_compression = request_body.encoding().to_string();
|
||||
emit_transport_trace(
|
||||
&request,
|
||||
"transport_body_encode_done",
|
||||
json!({
|
||||
"elapsed_ms": encode_started.elapsed().as_millis() as u64,
|
||||
"encoding": request_body.encoding(),
|
||||
"encoding": body_compression.as_str(),
|
||||
"body_compression": body_compression.as_str(),
|
||||
"raw_json_bytes": request_body.raw_json_bytes(),
|
||||
"wire_bytes": request_body.wire_bytes(),
|
||||
"request_shape": body_shape.clone(),
|
||||
"headers": final_request_headers.clone(),
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -586,6 +612,8 @@ impl<S: Scheme + Clone + 'static> LlmClient for HttpTransport<S> {
|
||||
"context_length_exceeded": context_length_exceeded,
|
||||
"provider_usage_absent": context_length_exceeded,
|
||||
"request_shape": body_shape.clone(),
|
||||
"request_headers": final_request_headers.clone(),
|
||||
"body_compression": body_compression.as_str(),
|
||||
}),
|
||||
);
|
||||
return Err(error);
|
||||
@@ -817,10 +845,26 @@ mod tests {
|
||||
let encoded = transport.encode_request_body(&body, &mut headers).unwrap();
|
||||
|
||||
assert_eq!(headers.get(ACCEPT).unwrap(), "text/event-stream");
|
||||
assert_eq!(headers.get("session-id").unwrap(), "segment-123");
|
||||
assert_eq!(headers.get("thread-id").unwrap(), "segment-123");
|
||||
assert_eq!(headers.get("session_id").unwrap(), "segment-123");
|
||||
assert_eq!(headers.get("x-client-request-id").unwrap(), "segment-123");
|
||||
assert_eq!(headers.get(CONTENT_ENCODING).unwrap(), "zstd");
|
||||
|
||||
let diagnostics = request_header_diagnostics(&headers);
|
||||
assert_eq!(diagnostics["content_type"], "application/json");
|
||||
assert_eq!(diagnostics["content_encoding"], "zstd");
|
||||
assert_eq!(diagnostics["accept"], "text/event-stream");
|
||||
assert!(diagnostics["session_id_present"].as_bool().unwrap());
|
||||
assert!(diagnostics["thread_id_present"].as_bool().unwrap());
|
||||
assert!(diagnostics["legacy_session_id_present"].as_bool().unwrap());
|
||||
assert!(
|
||||
diagnostics["x_client_request_id_present"]
|
||||
.as_bool()
|
||||
.unwrap()
|
||||
);
|
||||
assert!(diagnostics["chatgpt_account_id_present"].as_bool().unwrap());
|
||||
|
||||
let RequestBody::CompressedJson {
|
||||
bytes: compressed,
|
||||
raw_json_bytes,
|
||||
@@ -850,6 +894,8 @@ mod tests {
|
||||
let encoded = transport.encode_request_body(&body, &mut headers).unwrap();
|
||||
|
||||
assert_eq!(headers.get(ACCEPT).unwrap(), "text/event-stream");
|
||||
assert!(headers.get("session-id").is_none());
|
||||
assert!(headers.get("thread-id").is_none());
|
||||
assert!(headers.get("session_id").is_none());
|
||||
assert!(headers.get("x-client-request-id").is_none());
|
||||
assert!(headers.get(CONTENT_ENCODING).is_none());
|
||||
|
||||
+62
-185
@@ -560,13 +560,14 @@ impl PluginPackageManifest {
|
||||
}
|
||||
}
|
||||
|
||||
pub const PLUGIN_RUNTIME_WASM_KIND: &str = "wasm";
|
||||
pub const PLUGIN_RUNTIME_WASM_ABI: &str = "yoi-plugin-wasm-1";
|
||||
/// Manifest runtime kind for WebAssembly Component Model Tool packages.
|
||||
const LEGACY_PLUGIN_RUNTIME_WASM_KIND: &str = "wasm";
|
||||
const LEGACY_PLUGIN_RUNTIME_WASM_ABI: &str = "yoi-plugin-wasm-1";
|
||||
/// Manifest runtime kind for current WebAssembly Component Model packages.
|
||||
///
|
||||
/// Component runtime manifests must set `component` to the packaged component
|
||||
/// artifact path and `world` to [`PLUGIN_COMPONENT_TOOL_WORLD`]. Raw core-Wasm
|
||||
/// packages remain explicit `kind = "wasm"` plus `abi = "yoi-plugin-wasm-1"`.
|
||||
/// artifact path and `world` to [`PLUGIN_COMPONENT_TOOL_WORLD`] or
|
||||
/// [`PLUGIN_COMPONENT_INSTANCE_WORLD`]. Legacy raw core-Wasm manifests are
|
||||
/// intentionally rejected by validation; `wasm-component` is the public runtime.
|
||||
pub const PLUGIN_RUNTIME_COMPONENT_KIND: &str = "wasm-component";
|
||||
pub const PLUGIN_COMPONENT_TOOL_WORLD: &str = "yoi:plugin/tool@1.0.0";
|
||||
pub const PLUGIN_COMPONENT_INSTANCE_WORLD: &str = "yoi:plugin/instance@1.0.0";
|
||||
@@ -1060,158 +1061,6 @@ pub fn resolve_plugin_config_for_startup(
|
||||
snapshot
|
||||
}
|
||||
|
||||
/// Load the recorded WASM runtime module for a resolved plugin package.
|
||||
///
|
||||
/// Restore and execution paths use this helper instead of reading arbitrary
|
||||
/// package paths directly so module selection remains tied to the resolved
|
||||
/// package identity, runtime manifest entry, and deterministic package digest.
|
||||
pub fn read_resolved_plugin_runtime_module(
|
||||
record: &ResolvedPluginRecord,
|
||||
limits: &PluginDiscoveryLimits,
|
||||
) -> Result<Vec<u8>, PluginDiagnostic> {
|
||||
let runtime = record.manifest.runtime.as_ref().ok_or_else(|| {
|
||||
PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Missing,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"resolved plugin package does not declare a WASM runtime",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest)
|
||||
})?;
|
||||
|
||||
if runtime.kind != PLUGIN_RUNTIME_WASM_KIND {
|
||||
return Err(PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Api,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"plugin runtime kind is unsupported",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest));
|
||||
}
|
||||
if runtime.abi.as_deref() != Some(PLUGIN_RUNTIME_WASM_ABI) {
|
||||
return Err(PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Api,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"plugin WASM ABI is unsupported",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest));
|
||||
}
|
||||
|
||||
let entry = runtime.entry.as_deref().ok_or_else(|| {
|
||||
PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Missing,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"plugin WASM runtime entry is required",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest)
|
||||
})?;
|
||||
|
||||
let metadata = fs::metadata(&record.package_path).map_err(|error| {
|
||||
PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Io,
|
||||
PluginDiagnosticPhase::Discovery,
|
||||
format!(
|
||||
"resolved plugin package metadata could not be read: {}",
|
||||
safe_io_error(&error)
|
||||
),
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest)
|
||||
})?;
|
||||
if !metadata.is_file() {
|
||||
return Err(PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Malformed,
|
||||
PluginDiagnosticPhase::Discovery,
|
||||
"resolved plugin package is not a regular file",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest));
|
||||
}
|
||||
if metadata.len() > limits.max_package_size_bytes {
|
||||
return Err(PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Bounds,
|
||||
PluginDiagnosticPhase::Discovery,
|
||||
"resolved plugin package exceeds the configured package size bound",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest));
|
||||
}
|
||||
|
||||
let bytes = fs::read(&record.package_path).map_err(|error| {
|
||||
PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Io,
|
||||
PluginDiagnosticPhase::Discovery,
|
||||
format!(
|
||||
"resolved plugin package content could not be read: {}",
|
||||
safe_io_error(&error)
|
||||
),
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest)
|
||||
})?;
|
||||
let archive = parse_stored_zip(&bytes, &record.package_label, record.source, limits)?;
|
||||
let actual_digest = deterministic_digest(&archive.files);
|
||||
if !digest_matches(&record.digest, &actual_digest) {
|
||||
return Err(PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Digest,
|
||||
PluginDiagnosticPhase::Resolution,
|
||||
"resolved plugin package digest does not match current package content",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(actual_digest));
|
||||
}
|
||||
|
||||
validate_manifest_path(
|
||||
entry,
|
||||
&archive,
|
||||
&record.package_label,
|
||||
record.source,
|
||||
&record.manifest.id,
|
||||
)?;
|
||||
let normalized = normalize_archive_path(entry).ok_or_else(|| {
|
||||
PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Traversal,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"plugin manifest references a path outside the package root",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest)
|
||||
})?;
|
||||
archive.files.get(&normalized).cloned().ok_or_else(|| {
|
||||
PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Missing,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"plugin runtime module entry is missing from the package",
|
||||
)
|
||||
.with_source(record.source)
|
||||
.with_identity(&record.identity)
|
||||
.with_package(&record.package_label)
|
||||
.with_digest(&record.digest)
|
||||
})
|
||||
}
|
||||
|
||||
/// Reads the WebAssembly Component Model artifact selected by a resolved plugin
|
||||
/// package manifest while preserving package digest pinning.
|
||||
pub fn read_resolved_plugin_runtime_component(
|
||||
@@ -2046,39 +1895,22 @@ fn validate_manifest(
|
||||
}
|
||||
if let Some(runtime) = &manifest.runtime {
|
||||
match runtime.kind.as_str() {
|
||||
PLUGIN_RUNTIME_WASM_KIND => {
|
||||
if runtime.abi.as_deref() != Some(PLUGIN_RUNTIME_WASM_ABI) {
|
||||
LEGACY_PLUGIN_RUNTIME_WASM_KIND => {
|
||||
return Err(PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Api,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"plugin WASM ABI is unsupported",
|
||||
format!(
|
||||
"legacy raw wasm plugin runtime `{LEGACY_PLUGIN_RUNTIME_WASM_KIND}` / `{}` is retired; use `{PLUGIN_RUNTIME_COMPONENT_KIND}`",
|
||||
runtime
|
||||
.abi
|
||||
.as_deref()
|
||||
.unwrap_or(LEGACY_PLUGIN_RUNTIME_WASM_ABI)
|
||||
),
|
||||
)
|
||||
.with_source(source)
|
||||
.with_identity(SourceQualifiedPluginId::new(source, manifest.id.clone()))
|
||||
.with_package(label));
|
||||
}
|
||||
let Some(entry) = runtime.entry.as_deref() else {
|
||||
return Err(PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Missing,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"plugin WASM runtime entry is required",
|
||||
)
|
||||
.with_source(source)
|
||||
.with_identity(SourceQualifiedPluginId::new(source, manifest.id.clone()))
|
||||
.with_package(label));
|
||||
};
|
||||
if runtime.component.is_some() || runtime.world.is_some() {
|
||||
return Err(PluginDiagnostic::new(
|
||||
PluginDiagnosticKind::Malformed,
|
||||
PluginDiagnosticPhase::Manifest,
|
||||
"plugin WASM runtime must not declare component metadata",
|
||||
)
|
||||
.with_source(source)
|
||||
.with_identity(SourceQualifiedPluginId::new(source, manifest.id.clone()))
|
||||
.with_package(label));
|
||||
}
|
||||
validate_manifest_path(entry, archive, label, source, &manifest.id)?;
|
||||
}
|
||||
PLUGIN_RUNTIME_COMPONENT_KIND => {
|
||||
if runtime.abi.is_some() || runtime.entry.is_some() {
|
||||
return Err(PluginDiagnostic::new(
|
||||
@@ -2844,6 +2676,51 @@ description = "bad"
|
||||
assert!(err.message.contains("service/ingress"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn legacy_raw_wasm_runtime_manifest_is_rejected() {
|
||||
let temp = TempDir::new().unwrap();
|
||||
let workspace = temp.path().join("workspace");
|
||||
let plugins = workspace.join(".yoi/plugins");
|
||||
fs::create_dir_all(&plugins).unwrap();
|
||||
let manifest = r#"
|
||||
schema_version = 1
|
||||
id = "legacy"
|
||||
name = "Legacy"
|
||||
version = "0.1.0"
|
||||
surfaces = ["tool"]
|
||||
|
||||
[runtime]
|
||||
kind = "wasm"
|
||||
entry = "plugin.wasm"
|
||||
abi = "yoi-plugin-wasm-1"
|
||||
|
||||
[[tools]]
|
||||
name = "Echo"
|
||||
description = "legacy"
|
||||
input_schema = { type = "object" }
|
||||
"#;
|
||||
write_stored_zip(
|
||||
&plugins.join("legacy.yoi-plugin"),
|
||||
&[
|
||||
("plugin.toml", manifest.as_bytes().to_vec(), 0),
|
||||
("plugin.wasm", b"not wasm".to_vec(), 0),
|
||||
],
|
||||
);
|
||||
|
||||
let report = discover_plugins(&PluginDiscoveryOptions::new(&workspace));
|
||||
|
||||
assert!(report.packages.is_empty());
|
||||
let diagnostic = report
|
||||
.diagnostics
|
||||
.iter()
|
||||
.find(|diag| diag.kind == PluginDiagnosticKind::Api)
|
||||
.unwrap();
|
||||
assert_eq!(diagnostic.phase, PluginDiagnosticPhase::Manifest);
|
||||
assert_eq!(diagnostic.identity.as_deref(), Some("project:legacy"));
|
||||
assert!(diagnostic.message.contains("legacy raw wasm"));
|
||||
assert!(diagnostic.message.contains(PLUGIN_RUNTIME_COMPONENT_KIND));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn discovers_valid_user_and_workspace_packages() {
|
||||
let temp = TempDir::new().unwrap();
|
||||
@@ -3521,9 +3398,9 @@ version = "1.0.0"
|
||||
surfaces = ["tool"]
|
||||
|
||||
[runtime]
|
||||
kind = "wasm"
|
||||
entry = "plugin.wasm"
|
||||
abi = "yoi-plugin-wasm-1"
|
||||
kind = "wasm-component"
|
||||
component = "plugin.component.wasm"
|
||||
world = "yoi:plugin/tool@1.0.0"
|
||||
|
||||
[[permissions]]
|
||||
kind = "host_api"
|
||||
|
||||
@@ -468,15 +468,48 @@ mod tests {
|
||||
assert!(error.message().len() <= MAX_ERROR_MESSAGE_BYTES + "…".len());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn service_output_helper_builds_runtime_command_envelope() {
|
||||
let event = PluginIngressEvent {
|
||||
kind: "websocket_text".to_string(),
|
||||
source: "websocket:wss://example.test/socket".to_string(),
|
||||
ingress_name: "example_ws".to_string(),
|
||||
payload: json!({"text":"ping"}),
|
||||
created_at: "2026-06-25T00:00:00Z".to_string(),
|
||||
attempt: 1,
|
||||
correlation_id: "event-1".to_string(),
|
||||
};
|
||||
|
||||
assert_eq!(event.websocket_text(), Some("ping"));
|
||||
let output =
|
||||
ServiceOutput::websocket_send(&event, "reply-1", "wss://example.test/socket", "pong")
|
||||
.unwrap();
|
||||
let value = serde_json::to_value(output).unwrap();
|
||||
|
||||
assert_eq!(value["accepted"], true);
|
||||
assert_eq!(value["output_commands"][0]["source_event_id"], "event-1");
|
||||
assert_eq!(value["output_commands"][0]["command_id"], "reply-1");
|
||||
assert_eq!(value["output_commands"][0]["kind"], "websocket_send");
|
||||
assert_eq!(value["output_commands"][0]["payload"]["text"], "pong");
|
||||
assert_eq!(
|
||||
value["output_commands"][0]["requested_at"],
|
||||
"2026-06-25T00:00:00Z"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wit_constants_match_current_world() {
|
||||
assert!(TOOL_WIT.contains("package yoi:plugin@1.0.0"));
|
||||
assert!(TOOL_WIT.contains("world tool"));
|
||||
assert!(TOOL_WIT.contains("export call"));
|
||||
assert_eq!(TOOL_WORLD, "yoi:plugin/tool@1.0.0");
|
||||
assert!(HOST_WIT.contains("interface https"));
|
||||
assert!(HOST_WIT.contains("interface request"));
|
||||
assert!(HOST_WIT.contains("interface websocket"));
|
||||
assert!(HOST_WIT.contains("interface fs"));
|
||||
assert!(HOST_WIT.contains("%list: func"));
|
||||
assert!(INSTANCE_WIT.contains("world instance"));
|
||||
assert!(INSTANCE_WIT.contains("export handle-ingress"));
|
||||
assert!(INSTANCE_WIT.contains("websocket_send"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,12 +521,48 @@ pub const PLUGIN_INSTANCE_WORLD: &str = "yoi:plugin/instance@1.0.0";
|
||||
pub const INSTANCE_WIT: &str =
|
||||
include_str!("../../../resources/plugin/wit/yoi-plugin-instance-v1.wit");
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct PluginIngressEvent {
|
||||
pub kind: String,
|
||||
pub source: String,
|
||||
#[serde(default)]
|
||||
pub ingress_name: String,
|
||||
#[serde(default)]
|
||||
pub payload: Value,
|
||||
#[serde(default)]
|
||||
pub created_at: String,
|
||||
#[serde(default = "default_attempt")]
|
||||
pub attempt: u32,
|
||||
#[serde(default)]
|
||||
pub correlation_id: String,
|
||||
}
|
||||
|
||||
impl PluginIngressEvent {
|
||||
/// Return the text payload carried by a host-owned WebSocket ingress event.
|
||||
pub fn websocket_text(&self) -> Option<&str> {
|
||||
self.payload.get("text").and_then(Value::as_str)
|
||||
}
|
||||
|
||||
/// Build a `websocket_send` output command that replies through the
|
||||
/// host-owned Service WebSocket driver. The host still validates the target
|
||||
/// URL and matching grants before sending.
|
||||
pub fn websocket_send(
|
||||
&self,
|
||||
command_id: impl Into<String>,
|
||||
url: impl Into<String>,
|
||||
text: impl Into<String>,
|
||||
) -> Result<ServiceOutputCommand> {
|
||||
ServiceOutputCommand::new(
|
||||
self,
|
||||
command_id,
|
||||
ServiceOutputCommandKind::WebSocketSend,
|
||||
serde_json::json!({ "url": url.into(), "text": text.into() }),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn default_attempt() -> u32 {
|
||||
1
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||
@@ -519,12 +588,118 @@ impl PluginStatus {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum ServiceOutputCommandKind {
|
||||
DiagnosticStatusUpdate,
|
||||
HostRequestDispatch,
|
||||
#[serde(rename = "websocket_send")]
|
||||
WebSocketSend,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ServiceOutputCommand {
|
||||
pub correlation_id: String,
|
||||
pub source_event_id: String,
|
||||
pub command_id: String,
|
||||
pub kind: ServiceOutputCommandKind,
|
||||
pub payload: Value,
|
||||
pub requested_at: String,
|
||||
}
|
||||
|
||||
impl ServiceOutputCommand {
|
||||
pub fn new(
|
||||
event: &PluginIngressEvent,
|
||||
command_id: impl Into<String>,
|
||||
kind: ServiceOutputCommandKind,
|
||||
payload: impl Serialize,
|
||||
) -> Result<Self> {
|
||||
let command_id = sanitize_command_id(command_id.into());
|
||||
if command_id.is_empty() {
|
||||
return Err(ToolError::invalid_output(
|
||||
"service output command_id must not be empty",
|
||||
));
|
||||
}
|
||||
let source_event_id = event.correlation_id.clone();
|
||||
if source_event_id.is_empty() {
|
||||
return Err(ToolError::invalid_output(
|
||||
"service output command requires ingress event correlation_id",
|
||||
));
|
||||
}
|
||||
let requested_at = if event.created_at.is_empty() {
|
||||
"1970-01-01T00:00:00Z".to_string()
|
||||
} else {
|
||||
event.created_at.clone()
|
||||
};
|
||||
Ok(Self {
|
||||
correlation_id: sanitize_command_id(format!("{source_event_id}:{command_id}")),
|
||||
source_event_id,
|
||||
command_id,
|
||||
kind,
|
||||
payload: serde_json::to_value(payload).map_err(ToolError::serialization)?,
|
||||
requested_at,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||
pub struct ServiceOutput {
|
||||
#[serde(default)]
|
||||
pub accepted: bool,
|
||||
#[serde(default, skip_serializing_if = "Value::is_null")]
|
||||
pub data: Value,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub output_commands: Vec<ServiceOutputCommand>,
|
||||
}
|
||||
|
||||
impl ServiceOutput {
|
||||
pub fn accepted(data: impl Serialize) -> Result<Self> {
|
||||
Ok(Self {
|
||||
accepted: true,
|
||||
data: serde_json::to_value(data).map_err(ToolError::serialization)?,
|
||||
output_commands: Vec::new(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn empty() -> Self {
|
||||
Self {
|
||||
accepted: true,
|
||||
data: Value::Null,
|
||||
output_commands: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_command(mut self, command: ServiceOutputCommand) -> Self {
|
||||
self.output_commands.push(command);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn websocket_send(
|
||||
event: &PluginIngressEvent,
|
||||
command_id: impl Into<String>,
|
||||
url: impl Into<String>,
|
||||
text: impl Into<String>,
|
||||
) -> Result<Self> {
|
||||
Ok(Self::empty().with_command(event.websocket_send(command_id, url, text)?))
|
||||
}
|
||||
}
|
||||
|
||||
fn sanitize_command_id(value: String) -> String {
|
||||
bounded_text(
|
||||
value
|
||||
.chars()
|
||||
.map(|ch| if ch.is_control() { '-' } else { ch })
|
||||
.collect(),
|
||||
128,
|
||||
)
|
||||
}
|
||||
|
||||
/// Rust-facing instance Plugin contract. Hosts call `start` once, then route
|
||||
/// Tool/Ingress surfaces through the same mutable instance.
|
||||
pub trait Plugin: Sized + 'static {
|
||||
fn start(config: Value) -> Result<Self>;
|
||||
fn handle_tool(&mut self, name: &str, input: Value) -> Result<ToolOutput>;
|
||||
fn handle_ingress(&mut self, name: &str, event: PluginIngressEvent) -> Result<Value>;
|
||||
fn handle_ingress(&mut self, name: &str, event: PluginIngressEvent) -> Result<ServiceOutput>;
|
||||
fn status(&self) -> Result<PluginStatus> {
|
||||
Ok(PluginStatus::ready(Value::Null))
|
||||
}
|
||||
|
||||
@@ -12,6 +12,14 @@ const TEMPLATE_PLUGIN: &str =
|
||||
include_str!("../../../resources/plugin/templates/rust-component-tool/plugin.toml");
|
||||
const TEMPLATE_README: &str =
|
||||
include_str!("../../../resources/plugin/templates/rust-component-tool/README.md");
|
||||
const SERVICE_TEMPLATE_CARGO: &str =
|
||||
include_str!("../../../resources/plugin/templates/rust-component-instance/Cargo.toml");
|
||||
const SERVICE_TEMPLATE_LIB: &str =
|
||||
include_str!("../../../resources/plugin/templates/rust-component-instance/src/lib.rs");
|
||||
const SERVICE_TEMPLATE_PLUGIN: &str =
|
||||
include_str!("../../../resources/plugin/templates/rust-component-instance/plugin.toml");
|
||||
const SERVICE_TEMPLATE_README: &str =
|
||||
include_str!("../../../resources/plugin/templates/rust-component-instance/README.md");
|
||||
const SAMPLE_LIB: &str = include_str!("../../../docs/examples/plugin-component-tool/lib.rs");
|
||||
const PDK_CARGO: &str = include_str!("../Cargo.toml");
|
||||
|
||||
@@ -25,7 +33,7 @@ fn rust_component_tool_template_has_expected_files() {
|
||||
cargo["dependencies"]["yoi-plugin-pdk"]["path"].as_str(),
|
||||
Some("../../../../crates/plugin-pdk")
|
||||
);
|
||||
assert!(TEMPLATE_CARGO.contains("rev = \"<pinned-yoi-revision>\""));
|
||||
assert!(TEMPLATE_CARGO.contains("rev = \"<pinned-yoi-commit-sha>\""));
|
||||
|
||||
let plugin: Value = toml::from_str(TEMPLATE_PLUGIN).expect("template plugin.toml parses");
|
||||
assert_eq!(plugin["schema_version"].as_integer(), Some(1));
|
||||
@@ -45,6 +53,71 @@ fn rust_component_tool_template_has_expected_files() {
|
||||
assert!(TEMPLATE_README.contains("Component Model Tool Plugin"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rust_component_service_template_has_event_output_pattern() {
|
||||
let cargo: Value = toml::from_str(SERVICE_TEMPLATE_CARGO).expect("service Cargo.toml parses");
|
||||
assert_eq!(cargo["package"]["edition"].as_str(), Some("2024"));
|
||||
assert_eq!(cargo["lib"]["crate-type"][0].as_str(), Some("cdylib"));
|
||||
assert_eq!(
|
||||
cargo["dependencies"]["yoi-plugin-pdk"]["path"].as_str(),
|
||||
Some("../../../../crates/plugin-pdk")
|
||||
);
|
||||
assert!(SERVICE_TEMPLATE_CARGO.contains("rev = \"<pinned-yoi-commit-sha>\""));
|
||||
|
||||
let plugin: Value =
|
||||
toml::from_str(SERVICE_TEMPLATE_PLUGIN).expect("service plugin.toml parses");
|
||||
assert_eq!(plugin["schema_version"].as_integer(), Some(1));
|
||||
assert_eq!(plugin["runtime"]["kind"].as_str(), Some("wasm-component"));
|
||||
assert_eq!(
|
||||
plugin["runtime"]["world"].as_str(),
|
||||
Some("yoi:plugin/instance@1.0.0")
|
||||
);
|
||||
assert!(
|
||||
plugin["permissions"]
|
||||
.as_array()
|
||||
.expect("permissions array")
|
||||
.iter()
|
||||
.any(|permission| permission["kind"].as_str() == Some("host_api")
|
||||
&& permission["api"].as_str() == Some("websocket"))
|
||||
);
|
||||
assert_eq!(
|
||||
plugin["services"].as_array().expect("services array").len(),
|
||||
1
|
||||
);
|
||||
let ingress = &plugin["ingresses"].as_array().expect("ingresses array")[0];
|
||||
assert!(
|
||||
ingress["event_kinds"]
|
||||
.as_array()
|
||||
.expect("event kinds")
|
||||
.iter()
|
||||
.any(|kind| kind.as_str() == Some("websocket_text"))
|
||||
);
|
||||
assert!(
|
||||
ingress["sources"]
|
||||
.as_array()
|
||||
.expect("sources")
|
||||
.iter()
|
||||
.any(|source| source.as_str() == Some("websocket:wss://example.com/socket"))
|
||||
);
|
||||
let websocket = &plugin["websocket"].as_array().expect("websocket targets")[0];
|
||||
assert_eq!(websocket["scheme"].as_str(), Some("wss"));
|
||||
assert_eq!(websocket["host"].as_str(), Some("example.com"));
|
||||
assert!(
|
||||
websocket["path_prefixes"]
|
||||
.as_array()
|
||||
.expect("websocket path prefixes")
|
||||
.iter()
|
||||
.any(|prefix| prefix.as_str() == Some("/socket"))
|
||||
);
|
||||
|
||||
assert!(SERVICE_TEMPLATE_LIB.contains("world: \"instance\""));
|
||||
assert!(SERVICE_TEMPLATE_LIB.contains("PluginIngressEvent"));
|
||||
assert!(SERVICE_TEMPLATE_LIB.contains("ServiceOutput::websocket_send"));
|
||||
assert!(!SERVICE_TEMPLATE_LIB.contains("recv(timeout"));
|
||||
assert!(SERVICE_TEMPLATE_README.contains("output command"));
|
||||
assert!(!SERVICE_TEMPLATE_PLUGIN.contains("kind = \"wasm\""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn documented_sample_uses_pdk_component_path() {
|
||||
assert!(SAMPLE_LIB.contains("use yoi_plugin_pdk::wit_bindgen"));
|
||||
@@ -57,8 +130,17 @@ fn documented_sample_uses_pdk_component_path() {
|
||||
|
||||
#[test]
|
||||
fn embedded_template_cargo_checks_for_wasm_target() {
|
||||
cargo_check_template("rust-component-tool");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn embedded_service_template_cargo_checks_for_wasm_target() {
|
||||
cargo_check_template("rust-component-instance");
|
||||
}
|
||||
|
||||
fn cargo_check_template(template: &str) {
|
||||
let crate_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
|
||||
let template_dir = crate_dir.join("../../resources/plugin/templates/rust-component-tool");
|
||||
let template_dir = crate_dir.join(format!("../../resources/plugin/templates/{template}"));
|
||||
let manifest_path = template_dir.join("Cargo.toml");
|
||||
let lock_path = template_dir.join("Cargo.lock");
|
||||
let _ = fs::remove_file(&lock_path);
|
||||
|
||||
@@ -4,12 +4,17 @@ use std::fs::{DirBuilder, File, OpenOptions};
|
||||
use std::io::{self, Read, Seek, SeekFrom, Write};
|
||||
use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use fs4::fs_std::FileExt;
|
||||
use manifest::{ScopeRule, paths};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use session_store::SegmentId;
|
||||
|
||||
const LOCK_WAIT_TIMEOUT: Duration = Duration::from_secs(10);
|
||||
const LOCK_WAIT_POLL_INTERVAL: Duration = Duration::from_millis(25);
|
||||
|
||||
/// On-disk representation of the allocation table.
|
||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||
pub struct LockFile {
|
||||
@@ -119,7 +124,37 @@ impl LockFileGuard {
|
||||
.truncate(false)
|
||||
.mode(0o600)
|
||||
.open(path)?;
|
||||
FileExt::lock_exclusive(&file)?;
|
||||
let started = Instant::now();
|
||||
loop {
|
||||
match FileExt::try_lock_exclusive(&file) {
|
||||
Ok(true) => break,
|
||||
Ok(false) => {
|
||||
if started.elapsed() >= LOCK_WAIT_TIMEOUT {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::TimedOut,
|
||||
format!(
|
||||
"timed out waiting for pod registry lock `{}`",
|
||||
path.display()
|
||||
),
|
||||
));
|
||||
}
|
||||
thread::sleep(LOCK_WAIT_POLL_INTERVAL);
|
||||
}
|
||||
Err(error) if error.kind() == io::ErrorKind::WouldBlock => {
|
||||
if started.elapsed() >= LOCK_WAIT_TIMEOUT {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::TimedOut,
|
||||
format!(
|
||||
"timed out waiting for pod registry lock `{}`",
|
||||
path.display()
|
||||
),
|
||||
));
|
||||
}
|
||||
thread::sleep(LOCK_WAIT_POLL_INTERVAL);
|
||||
}
|
||||
Err(error) => return Err(error),
|
||||
}
|
||||
}
|
||||
let mut this = Self {
|
||||
file,
|
||||
data: LockFile::default(),
|
||||
|
||||
@@ -37,7 +37,6 @@ workflow-crate = { package = "workflow", path = "../workflow" }
|
||||
uuid = { workspace = true, features = ["v7"] }
|
||||
session-metrics = { workspace = true }
|
||||
arc-swap = "1.9.1"
|
||||
wasmi = { version = "0.51.1", default-features = false, features = ["std", "extra-checks"] }
|
||||
wasmtime = { version = "45.0.2", default-features = false, features = ["std", "runtime", "cranelift", "component-model"] }
|
||||
tungstenite = { version = "0.28.0", default-features = false, features = ["handshake", "native-tls", "url"] }
|
||||
tokio-tungstenite = { version = "0.28.0", default-features = false, features = ["native-tls", "connect"] }
|
||||
|
||||
@@ -900,12 +900,36 @@ async fn controller_loop<C, St>(
|
||||
pending = Some(PendingRun::Resume);
|
||||
}
|
||||
|
||||
Method::Cancel => {
|
||||
Method::Cancel => match shared_state.get_status() {
|
||||
PodStatus::Paused => match pod.cancel_paused_turn() {
|
||||
Ok(()) => {
|
||||
set_controller_status(
|
||||
&shared_state,
|
||||
&runtime_dir,
|
||||
&event_tx,
|
||||
PodStatus::Idle,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
Err(error) => {
|
||||
let _ = event_tx.send(Event::Error {
|
||||
code: worker_error_code(&error),
|
||||
message: error.to_string(),
|
||||
});
|
||||
}
|
||||
},
|
||||
PodStatus::Idle => {
|
||||
let _ = event_tx.send(Event::Error {
|
||||
code: ErrorCode::NotRunning,
|
||||
message: "Pod is not running".into(),
|
||||
});
|
||||
}
|
||||
PodStatus::Running => {
|
||||
// Running turns receive Cancel through drive_turn; this is
|
||||
// only reachable across a defensive race window.
|
||||
let _ = cancel_tx.try_send(());
|
||||
}
|
||||
},
|
||||
|
||||
Method::Pause => {
|
||||
// Already paused → idempotent no-op. Otherwise the
|
||||
|
||||
+2344
-1362
File diff suppressed because it is too large
Load Diff
+128
-6
@@ -235,8 +235,24 @@ impl InFlightInner {
|
||||
self.remove_first_text_matching(&text);
|
||||
}
|
||||
}
|
||||
LoggedItem::Reasoning { text, .. } => {
|
||||
self.remove_first_thinking_matching(text);
|
||||
LoggedItem::Reasoning {
|
||||
text,
|
||||
summary,
|
||||
encrypted_content,
|
||||
..
|
||||
} => {
|
||||
let mut removed = false;
|
||||
if !text.is_empty() {
|
||||
removed |= self.remove_first_thinking_matching(text);
|
||||
}
|
||||
for summary_text in summary {
|
||||
if !summary_text.is_empty() {
|
||||
removed |= self.remove_first_thinking_matching(summary_text);
|
||||
}
|
||||
}
|
||||
if !removed && encrypted_content.is_some() {
|
||||
self.remove_first_empty_finished_thinking();
|
||||
}
|
||||
}
|
||||
LoggedItem::ToolCall { call_id, .. } => {
|
||||
self.remove_tool_call(call_id);
|
||||
@@ -255,21 +271,39 @@ impl InFlightInner {
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_first_text_matching(&mut self, committed: &str) {
|
||||
fn remove_first_text_matching(&mut self, committed: &str) -> bool {
|
||||
if let Some(index) = self.blocks.iter().position(|block| match block {
|
||||
TrackedBlock::Text { text, .. } => text == committed,
|
||||
_ => false,
|
||||
}) {
|
||||
self.blocks.remove(index);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_first_thinking_matching(&mut self, committed: &str) {
|
||||
fn remove_first_thinking_matching(&mut self, committed: &str) -> bool {
|
||||
if let Some(index) = self.blocks.iter().position(|block| match block {
|
||||
TrackedBlock::Thinking { text, .. } => text == committed,
|
||||
_ => false,
|
||||
}) {
|
||||
self.blocks.remove(index);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_first_empty_finished_thinking(&mut self) -> bool {
|
||||
if let Some(index) = self.blocks.iter().position(|block| match block {
|
||||
TrackedBlock::Thinking { text, finished, .. } => text.is_empty() && *finished,
|
||||
_ => false,
|
||||
}) {
|
||||
self.blocks.remove(index);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -304,10 +338,16 @@ impl TrackedBlock {
|
||||
})
|
||||
}
|
||||
}
|
||||
TrackedBlock::Thinking { text, finished, .. } => Some(InFlightBlock::Thinking {
|
||||
TrackedBlock::Thinking { text, finished, .. } => {
|
||||
if text.is_empty() && *finished {
|
||||
None
|
||||
} else {
|
||||
Some(InFlightBlock::Thinking {
|
||||
text: text.clone(),
|
||||
finished: *finished,
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
TrackedBlock::ToolCall {
|
||||
id,
|
||||
name,
|
||||
@@ -474,4 +514,86 @@ mod tests {
|
||||
let guard = in_flight.snapshot_guard();
|
||||
assert!(snapshot_from_guard(&guard).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn committed_reasoning_summary_clears_matching_in_flight_thinking_blocks() {
|
||||
let (event_tx, _) = broadcast::channel(16);
|
||||
let in_flight = InFlightEvents::new(event_tx);
|
||||
let first = in_flight.thinking_start();
|
||||
in_flight.thinking_delta(first, "summary A".into());
|
||||
in_flight.thinking_done(first, "".into());
|
||||
let second = in_flight.thinking_start();
|
||||
in_flight.thinking_delta(second, "summary B".into());
|
||||
in_flight.thinking_done(second, "".into());
|
||||
|
||||
in_flight.clear_for_committed_item_then(
|
||||
&LoggedItem::Reasoning {
|
||||
text: String::new(),
|
||||
summary: vec!["summary A".into(), "summary B".into()],
|
||||
encrypted_content: Some("opaque".into()),
|
||||
signature: None,
|
||||
},
|
||||
|| (),
|
||||
);
|
||||
|
||||
let guard = in_flight.snapshot_guard();
|
||||
assert!(snapshot_from_guard(&guard).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn committed_encrypted_only_reasoning_clears_empty_finished_thinking_block() {
|
||||
let (event_tx, _) = broadcast::channel(16);
|
||||
let in_flight = InFlightEvents::new(event_tx);
|
||||
let first = in_flight.thinking_start();
|
||||
in_flight.thinking_done(first, "".into());
|
||||
let second = in_flight.thinking_start();
|
||||
in_flight.thinking_delta(second, "still running".into());
|
||||
|
||||
in_flight.clear_for_committed_item_then(
|
||||
&LoggedItem::Reasoning {
|
||||
text: String::new(),
|
||||
summary: Vec::new(),
|
||||
encrypted_content: Some("opaque".into()),
|
||||
signature: None,
|
||||
},
|
||||
|| (),
|
||||
);
|
||||
|
||||
let guard = in_flight.snapshot_guard();
|
||||
assert_eq!(
|
||||
snapshot_from_guard(&guard).blocks,
|
||||
vec![InFlightBlock::Thinking {
|
||||
text: "still running".into(),
|
||||
finished: false,
|
||||
}]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn snapshot_omits_empty_finished_thinking_blocks() {
|
||||
let (event_tx, _) = broadcast::channel(16);
|
||||
let in_flight = InFlightEvents::new(event_tx);
|
||||
let empty_finished = in_flight.thinking_start();
|
||||
in_flight.thinking_done(empty_finished, "".into());
|
||||
let empty_running = in_flight.thinking_start();
|
||||
let visible_finished = in_flight.thinking_start();
|
||||
in_flight.thinking_delta(visible_finished, "visible".into());
|
||||
in_flight.thinking_done(visible_finished, "".into());
|
||||
|
||||
let guard = in_flight.snapshot_guard();
|
||||
assert_eq!(
|
||||
snapshot_from_guard(&guard).blocks,
|
||||
vec![
|
||||
InFlightBlock::Thinking {
|
||||
text: String::new(),
|
||||
finished: false,
|
||||
},
|
||||
InFlightBlock::Thinking {
|
||||
text: "visible".into(),
|
||||
finished: true,
|
||||
}
|
||||
]
|
||||
);
|
||||
assert_ne!(empty_running, empty_finished);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1863,6 +1863,26 @@ impl<C: LlmClient, St: Store> Pod<C, St> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Abandon a paused/interrupted turn without resuming it.
|
||||
///
|
||||
/// This uses the same explicit interrupt preparation as the next fresh
|
||||
/// `run` would have used, then clears the worker's interrupted marker so
|
||||
/// future input is treated as a normal new turn instead of a resume.
|
||||
/// The explicit `PausedTurnAbandoned` marker preserves durable lifecycle
|
||||
/// semantics without claiming another `run` / `resume` completed.
|
||||
pub fn cancel_paused_turn(&mut self) -> Result<(), PodError> {
|
||||
if !self.worker().last_run_interrupted() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
self.apply_interrupt_prep()?;
|
||||
self.worker_mut().set_last_run_interrupted(false);
|
||||
self.commit_entry(LogEntry::PausedTurnAbandoned {
|
||||
ts: segment_log::now_millis(),
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Validate explicit workflow invocations without reading dependency
|
||||
/// bodies. Called from `Pod::run` entry so an invalid slug aborts
|
||||
/// the turn before any session-log commit or interrupt-prep side
|
||||
|
||||
@@ -739,7 +739,7 @@ compact_system = "PREFIX\n{% include \"$yoi/internal/compact_system\" %}"
|
||||
assert!(rendered.contains("spawned Pod notifications are background signals"));
|
||||
assert!(rendered.contains("does not need to keep a turn open"));
|
||||
assert!(rendered.contains("Do not use `sleep` or polling loops"));
|
||||
assert!(rendered.contains("worktree status, diff, and test results"));
|
||||
assert!(rendered.contains("worktree state, diff, and test results"));
|
||||
assert!(rendered.contains("not scheduler or auto-maintain authorization"));
|
||||
assert!(rendered.contains("bypass user/workflow authorization"));
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user