chore: update orchestration and plugin tickets

This commit is contained in:
Keisuke Hirata 2026-06-14 23:49:45 +09:00
parent adebedc021
commit d66dfbbbc2
No known key found for this signature in database
35 changed files with 410 additions and 70 deletions

View File

@ -2,7 +2,7 @@
title: 'Plugin distribution package format and discovery' title: 'Plugin distribution package format and discovery'
state: 'planning' state: 'planning'
created_at: '2026-06-01T06:49:53Z' created_at: '2026-06-01T06:49:53Z'
updated_at: '2026-06-13T15:29:21Z' updated_at: '2026-06-14T14:34:33Z'
--- ---
## Background ## Background
@ -13,8 +13,8 @@ MCP is intentionally not modeled as a Plugin package/runtime in this Ticket. MCP
The desired initial direction is a single-file plugin package that can be placed in user or workspace plugin stores, for example: The desired initial direction is a single-file plugin package that can be placed in user or workspace plugin stores, for example:
- `~/.config/yoi/plugins/<id>.yoi-plugin` - `${XDG_DATA_HOME:-~/.local/share}/yoi/plugins/<id>.yoi-plugin`
- `./.yoi/plugins/<id>.yoi-plugin` - `<workspace>/.yoi/plugins/<id>.yoi-plugin`
The package should be easy to copy, inspect, cache, and pin while preserving Yoi's scope, permission, history, prompt-context, and trust invariants. Workspace plugins may come from a repository checkout and must not execute merely because an archive exists under `./.yoi/plugins`. The package should be easy to copy, inspect, cache, and pin while preserving Yoi's scope, permission, history, prompt-context, and trust invariants. Workspace plugins may come from a repository checkout and must not execute merely because an archive exists under `./.yoi/plugins`.
@ -26,10 +26,11 @@ The package should be easy to copy, inspect, cache, and pin while preserving Yoi
- Support packaged assets such as `module.wasm`, JSON schemas, README, and license files. - Support packaged assets such as `module.wasm`, JSON schemas, README, and license files.
- Specify archive safety rules, including path traversal rejection, bounded extraction, and deterministic digest calculation. - Specify archive safety rules, including path traversal rejection, bounded extraction, and deterministic digest calculation.
- Define plugin stores and source/trust mapping. - Define plugin stores and source/trust mapping.
- User plugin store: `~/.config/yoi/plugins/`. - User plugin store: `${XDG_DATA_HOME:-~/.local/share}/yoi/plugins/`.
- Workspace/project plugin store: `./.yoi/plugins/`. - Workspace/project plugin store: `<workspace>/.yoi/plugins/`.
- Map stores to the existing source vocabulary (`User`, `Project`/workspace, and future `Builtin`). - Builtin plugin source: Yoi-distributed `builtin:` registry.
- Treat `user:<id>` and `project:<id>` as distinct plugin references; ambiguous unqualified IDs should fail closed. - Map stores to the source vocabulary (`user`, `project`, `builtin`).
- Treat `user:<id>` and `project:<id>` as distinct plugin references; ambiguous unqualified IDs fail closed.
- Separate discovery from enablement. - Separate discovery from enablement.
- Yoi may discover plugin packages in configured stores. - Yoi may discover plugin packages in configured stores.
- Discovered packages must not register Tools/Hooks, initialize WASM, start services, or start MCP servers until explicitly enabled by manifest/profile configuration. - Discovered packages must not register Tools/Hooks, initialize WASM, start services, or start MCP servers until explicitly enabled by manifest/profile configuration.
@ -80,7 +81,7 @@ The package should be easy to copy, inspect, cache, and pin while preserving Yoi
## Acceptance criteria ## Acceptance criteria
- The repository has a documented plugin distribution/package proposal covering user and workspace plugin stores, single-file archive format, manifest fields, archive safety, cache/digest behavior, and discovery vs enablement. - The repository has a documented plugin distribution/package proposal covering user and workspace plugin stores, single-file archive format, manifest fields, archive safety, cache/digest behavior, and discovery vs enablement.
- The proposal explicitly states that placing a package in `~/.config/yoi/plugins/` or `./.yoi/plugins/` is discovery only, not execution or registration. - The proposal explicitly states that placing a package in `${XDG_DATA_HOME:-~/.local/share}/yoi/plugins/` or `<workspace>/.yoi/plugins/` is discovery only, not execution or registration.
- The design maps package sources to user/project/builtin trust categories and defines how ID collisions and ambiguous selectors are handled. - The design maps package sources to user/project/builtin trust categories and defines how ID collisions and ambiguous selectors are handled.
- The design explains Plugin permission requests/grants as Plugin-layer policy, distinct from `pod::feature` authority/grant concepts. - The design explains Plugin permission requests/grants as Plugin-layer policy, distinct from `pod::feature` authority/grant concepts.
- Runtime-specific notes cover declarative hooks and WASM packages; MCP is called out as a separate feature-backed integration, not part of initial Plugin packaging. - Runtime-specific notes cover declarative hooks and WASM packages; MCP is called out as a separate feature-backed integration, not part of initial Plugin packaging.

View File

@ -37,4 +37,17 @@ Distribution direction from user discussion:
- `00001KSXRQ4G8``00001KT0Z4BK8` は Plugin permission を Plugin layer として扱い、MCP を初期 Plugin packaging/runtime から分離する。 - `00001KSXRQ4G8``00001KT0Z4BK8` は Plugin permission を Plugin layer として扱い、MCP を初期 Plugin packaging/runtime から分離する。
---
<!-- event: decision author: hare at: 2026-06-14T14:34:33Z -->
## Decision
決定:
- Plugin discovery stores, source-qualified identity, discovery/enablement separation, Pod-startup initialization timing, restore behavior, and MCP boundaryをこの `00001KT0Z4BK8` の安定 contract として統合した。
- User Plugin package store は `${XDG_DATA_HOME:-~/.local/share}/yoi/plugins/` とし、`~/.config/yoi/plugins/` は使わない。
- Package presence は discovery only であり、実行・登録・runtime initialization は explicit enablement 後の Pod startup に限定する。
- Restore は metadata snapshot の enabled Plugin plan を正本とし、fresh discovery で silent upgrade しない。
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: "Preserve active workflows across compaction" title: "Preserve active workflows across compaction"
state: "planning" state: 'ready'
created_at: "2026-06-07T02:23:28Z" created_at: "2026-06-07T02:23:28Z"
updated_at: "2026-06-07T02:23:28Z" updated_at: '2026-06-14T14:13:43Z'
--- ---
## Background ## Background

View File

@ -5,3 +5,61 @@
Created by LocalTicketBackend create. Created by LocalTicketBackend create.
--- ---
<!-- event: comment author: ticket-intake at: 2026-06-14T14:13:35Z -->
## Comment
## Intake refinement
既存 Ticket `00001KTFY8V80` を確認した。新規 duplicate Ticket は作成しない。
### Readiness
- readiness: implementation_ready
- risk_flags: [prompt-context, persistence, workflow-state, compaction]
この Ticket は、active workflow を compaction / rehydration 後も継続可能にする concrete work item として十分に bounded されている。実装戦術の調査余地は残るが、Orchestrator が implementation routing できる要件・受け入れ条件・検証観点は揃っている。
### Binding decisions / invariants
- active workflow の進行中状態を、history に残らない transient context 注入だけで復元してはならない。
- compaction / restore 後に「どの workflow が継続中か」「どの手順段階・義務が残っているか」をモデルが説明可能でなければならない。
- workflow state の復元は、prompt context 加工原則に反しない形で durable source から再構成する。
- missing / corrupt / obsolete workflow state は fail-closed または bounded diagnostic として扱い、silently stale instructions を実行しない。
- Ticket / Pod history / workflow record / compaction output の authority boundary を混同しない。
### Implementation latitude
- workflow state の永続化先・schema・snapshot 粒度は、既存 Pod/session/compaction architecture に合わせて選んでよい。
- active workflow body を invocation-time snapshot として保持するか、rehydration 時に最新 resource を参照するかは、実装時に明示的に決定し、互換性・安全性の理由をコードまたは docs / Ticket 報告に残す。
- UI/diagnostic 表示の具体的な文言や internal field 名は、既存設計に沿って調整してよい。
### Escalation conditions
- workflow snapshot vs latest body の選択が authority boundary または backward compatibility を大きく変える場合。
- compaction が workflow obligations を再現するために hidden context injection を必要としそうな場合。
- persisted workflow state の migration / compatibility 方針が既存 records を破壊する場合。
- implementation が Ticket lifecycle / Orchestrator queue semantics / workflow invocation semantics を広げる必要を見つけた場合。
### Related context checked
- closed `00001KTG3AZQ8` / `00001KTG3BX0R` は Orchestrator routing / merge completion の完了済み関連文脈であり、本 Ticket の duplicate ではない。
---
<!-- event: intake_summary author: ticket-intake at: 2026-06-14T14:13:43Z -->
## Intake summary
既存 Ticket `00001KTFY8V80` を精査し、duplicate は作成しない方針で refinement を記録した。対象は active Workflow invocation/state/obligations を durable state/history と compaction/rehydration 経路に載せ、compaction 後も `/multi-agent-workflow` / `/worktree-workflow` などの active obligations を traceable に継続できるようにする実装 work item。readiness は implementation_ready。risk flags は prompt-context / persistence / workflow-state / compaction。Orchestrator は implementation routing 可能だが、snapshot vs latest workflow body の選択、hidden context injection 回避、missing/corrupt persisted state の fail-closed diagnostic、Ticket/Pod/history/workflow authority boundary を reviewer focus に含める。
---
<!-- event: state_changed author: ticket-intake at: 2026-06-14T14:13:43Z from: planning to: ready reason: intake_ready field: state -->
## State changed
Intake refinement が完了し、要件・受け入れ条件・binding invariants・escalation conditions が Ticket thread に記録されたため `planning -> ready` にします。実装 side effects は Orchestrator routing 後に行います。
---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Extend pod::feature API for external protocol-backed capability providers' title: 'Extend pod::feature API for external protocol-backed capability providers'
state: 'done' state: 'closed'
created_at: '2026-06-10T07:48:14Z' created_at: '2026-06-10T07:48:14Z'
updated_at: '2026-06-14T06:39:48Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['feature-api', 'tool-registry', 'permission-scope', 'prompt-context', 'dynamic-registry', 'service-lifecycle'] risk_flags: ['feature-api', 'tool-registry', 'permission-scope', 'prompt-context', 'dynamic-registry', 'service-lifecycle']

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -178,4 +178,22 @@ Next:
Implementation branch was reviewed, approved, merged into the Orchestrator branch as `3d140dbb`, and validated in the Orchestrator worktree. Feature-provider focused tests, formatting, diff check, and workspace check passed. Ticket implementation work is done; closure remains separate. Implementation branch was reviewed, approved, merged into the Orchestrator branch as `3d140dbb`, and validated in the Orchestrator worktree. Feature-provider focused tests, formatting, diff check, and workspace check passed. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Profile extend API を廃止して import + Lua 代入に寄せる' title: 'Profile extend API を廃止して import + Lua 代入に寄せる'
state: 'done' state: 'closed'
created_at: '2026-06-13T07:31:09Z' created_at: '2026-06-13T07:31:09Z'
updated_at: '2026-06-14T06:34:34Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['profiles', 'lua-api', 'builtin-resources', 'migration'] risk_flags: ['profiles', 'lua-api', 'builtin-resources', 'migration']

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -179,4 +179,22 @@ Next:
Implementation branch was reviewed, approved, merged into the Orchestrator branch as `58b15ee6`, and validated in the Orchestrator worktree. Focused manifest profile tests, formatting, diff check, `cargo build -p yoi`, and `nix build .#yoi` passed after cleanup freed disk space. Ticket implementation work is done; closure remains separate. Implementation branch was reviewed, approved, merged into the Orchestrator branch as `58b15ee6`, and validated in the Orchestrator worktree. Focused manifest profile tests, formatting, diff check, `cargo build -p yoi`, and `nix build .#yoi` passed after cleanup freed disk space. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Workspace panel: show Ticket-associated Intake Pods adjacent to Ticket rows' title: 'Workspace panel: show Ticket-associated Intake Pods adjacent to Ticket rows'
state: 'planning' state: 'ready'
created_at: '2026-06-13T10:54:31Z' created_at: '2026-06-13T10:54:31Z'
updated_at: '2026-06-13T10:54:31Z' updated_at: '2026-06-14T14:12:11Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['panel-ux', 'local-role-session-registry', 'pod-session-state'] risk_flags: ['panel-ux', 'local-role-session-registry', 'pod-session-state']

View File

@ -5,3 +5,19 @@
LocalTicketBackend によって作成されました。 LocalTicketBackend によって作成されました。
--- ---
<!-- event: intake_summary author: ticket-intake at: 2026-06-14T14:12:11Z -->
## Intake summary
既存 Ticket 00001KV09WYC6 の body/thread/artifacts を確認した。要件、受け入れ条件、binding decisions / invariants、implementation latitude、escalation conditions、validation が揃っており、readiness は `implementation_ready` と判断できる。未解決の blocking open question はない。risk_flags は `panel-ux`, `local-role-session-registry`, `pod-session-state`。次は Orchestrator が routing し、実装時は Panel の selection/keyboard semantics、one-active-claim-per-Ticket invariant、pre-Ticket Intake の誤関連付け回避、registry schema migration 不要の維持を重点確認する。
---
<!-- event: state_changed author: ticket-intake at: 2026-06-14T14:12:11Z from: planning to: ready reason: planning_ready field: state -->
## State changed
Intake 確認により、既存 Ticket の要件は実装 routing 可能な状態と判断した。実装 side effect は Orchestrator の queue/routing flow に委ねる。
---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Panel から ready Ticket を指示付きで planning に戻して Intake を再開できるようにする' title: 'Panel から ready Ticket を指示付きで planning に戻して Intake を再開できるようにする'
state: 'done' state: 'closed'
created_at: '2026-06-13T10:54:34Z' created_at: '2026-06-13T10:54:34Z'
updated_at: '2026-06-14T05:09:07Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['panel-action', 'ticket-lifecycle', 'role-session', 'authority-boundary'] risk_flags: ['panel-action', 'ticket-lifecycle', 'role-session', 'authority-boundary']

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -182,4 +182,22 @@ Next:
Implementation branch was reviewed, approved, merged into the Orchestrator branch as `7a6321d9`, and validated in the Orchestrator worktree. Focused TUI planning-return/intake/workspace-panel tests, Ticket tests, formatting, and diff check passed. Ticket implementation work is done; closure remains separate. Implementation branch was reviewed, approved, merged into the Orchestrator branch as `7a6321d9`, and validated in the Orchestrator worktree. Focused TUI planning-return/intake/workspace-panel tests, Ticket tests, formatting, and diff check passed. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Remove feature-layer HostAuthority model' title: 'Remove feature-layer HostAuthority model'
state: 'done' state: 'closed'
created_at: '2026-06-13T15:30:22Z' created_at: '2026-06-13T15:30:22Z'
updated_at: '2026-06-13T19:02:01Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['feature-api', 'tool-registry', 'ticket-tools'] risk_flags: ['feature-api', 'tool-registry', 'ticket-tools']

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -205,4 +205,22 @@ Next:
Implementation branch was reviewed, approved, merged into the Orchestrator branch as `297e95ef`, and validated in the Orchestrator worktree. Focused pod/ticket tests, formatting, diff check, and `cargo check --workspace --all-targets` passed after cleanup freed disk space. Ticket implementation work is done; closure remains separate. Implementation branch was reviewed, approved, merged into the Orchestrator branch as `297e95ef`, and validated in the Orchestrator worktree. Focused pod/ticket tests, formatting, diff check, and `cargo check --workspace --all-targets` passed after cleanup freed disk space. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Panel Orchestrator の orchestration branch 名を ticket.config.toml で設定可能にする' title: 'Panel Orchestrator の orchestration branch 名を ticket.config.toml で設定可能にする'
state: 'done' state: 'closed'
created_at: '2026-06-13T16:29:25Z' created_at: '2026-06-13T16:29:25Z'
updated_at: '2026-06-14T05:05:57Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['config-schema', 'git-worktree', 'panel-orchestration'] risk_flags: ['config-schema', 'git-worktree', 'panel-orchestration']

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -189,4 +189,22 @@ Next:
Implementation branch was reviewed, approved, merged into the Orchestrator branch as `290c4230`, and validated in the Orchestrator worktree. Focused ticket config / TUI orchestration worktree / configured branch / queue action tests, formatting, diff check, `cargo build -p yoi`, and `yoi ticket doctor` passed. Ticket implementation work is done; closure remains separate. Implementation branch was reviewed, approved, merged into the Orchestrator branch as `290c4230`, and validated in the Orchestrator worktree. Focused ticket config / TUI orchestration worktree / configured branch / queue action tests, formatting, diff check, `cargo build -p yoi`, and `yoi ticket doctor` passed. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'E2E harness を完全な tmp runtime/data/workspace 隔離と cleanup に対応させる' title: 'E2E harness を完全な tmp runtime/data/workspace 隔離と cleanup に対応させる'
state: 'done' state: 'closed'
created_at: '2026-06-13T16:56:11Z' created_at: '2026-06-13T16:56:11Z'
updated_at: '2026-06-13T17:33:53Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'ready' readiness: 'ready'
queued_by: 'yoi ticket' queued_by: 'yoi ticket'

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -192,4 +192,22 @@ Next:
E2E tmp/runtime isolation follow-up was reviewed, merged into the Orchestrator branch as `20184eeb`, and validated in the Orchestrator worktree. Panel E2E now uses clean per-scenario tmp workspace/data/runtime fixtures, preserves artifacts under `target/e2e-artifacts`, removes fixture temp roots after runs, and does not inherit host runtime/credential environment. Ticket implementation work is done; closure remains separate. E2E tmp/runtime isolation follow-up was reviewed, merged into the Orchestrator branch as `20184eeb`, and validated in the Orchestrator worktree. Panel E2E now uses clean per-scenario tmp workspace/data/runtime fixtures, preserves artifacts under `target/e2e-artifacts`, removes fixture temp roots after runs, and does not inherit host runtime/credential environment. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'E2E: close remaining critical-path gaps after panel harness' title: 'E2E: close remaining critical-path gaps after panel harness'
state: 'done' state: 'closed'
created_at: '2026-06-13T17:34:41Z' created_at: '2026-06-13T17:34:41Z'
updated_at: '2026-06-14T05:39:03Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['e2e', 'tui', 'pty', 'quit-latency', 'mouse-input', 'rewind'] risk_flags: ['e2e', 'tui', 'pty', 'quit-latency', 'mouse-input', 'rewind']

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -298,4 +298,22 @@ Next:
Implementation branch was reviewed, approved, merged into the Orchestrator branch as `059b1fd4`, and validated in the Orchestrator worktree. Focused E2E, TUI rewind/mouse tests, formatting, diff check, `cargo build -p yoi`, and `nix build .#yoi` passed. Ticket implementation work is done; closure remains separate. Implementation branch was reviewed, approved, merged into the Orchestrator branch as `059b1fd4`, and validated in the Orchestrator worktree. Focused E2E, TUI rewind/mouse tests, formatting, diff check, `cargo build -p yoi`, and `nix build .#yoi` passed. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Profile から concrete scope を外して launch policy で付与する' title: 'Profile から concrete scope を外して launch policy で付与する'
state: 'done' state: 'closed'
created_at: '2026-06-13T17:45:32Z' created_at: '2026-06-13T17:45:32Z'
updated_at: '2026-06-14T07:04:22Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['scope', 'delegation-scope', 'profiles', 'launch-policy', 'orchestrator', 'spawnpod', 'restore'] risk_flags: ['scope', 'delegation-scope', 'profiles', 'launch-policy', 'orchestrator', 'spawnpod', 'restore']

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -210,4 +210,22 @@ Next:
Implementation branch was reviewed, approved, merged into the Orchestrator branch as `3a67b95b`, and validated in the Orchestrator worktree. Focused manifest/client/pod launch-policy/scope/restore tests, build, formatting, diff check, and `nix build .#yoi` passed. Ticket implementation work is done; closure remains separate. Implementation branch was reviewed, approved, merged into the Orchestrator branch as `3a67b95b`, and validated in the Orchestrator worktree. Focused manifest/client/pod launch-policy/scope/restore tests, build, formatting, diff check, and `nix build .#yoi` passed. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -1,8 +1,8 @@
--- ---
title: 'Panel Ticket rows を2行表示にして gate 情報を分離する' title: 'Panel Ticket rows を2行表示にして gate 情報を分離する'
state: 'done' state: 'closed'
created_at: '2026-06-13T18:10:57Z' created_at: '2026-06-13T18:10:57Z'
updated_at: '2026-06-14T06:42:04Z' updated_at: '2026-06-14T14:00:13Z'
assignee: null assignee: null
readiness: 'implementation_ready' readiness: 'implementation_ready'
risk_flags: ['tui', 'workspace-panel', 'ticket-relations', 'mouse-input', 'layout'] risk_flags: ['tui', 'workspace-panel', 'ticket-relations', 'mouse-input', 'layout']

View File

@ -0,0 +1 @@
Closed after prior done-state completion.

View File

@ -147,4 +147,22 @@ Next:
Implementation branch was reviewed, approved, merged into the Orchestrator branch as `a9ece1dc`, and validated in the Orchestrator worktree. Focused TUI row/mouse/gate tests, Panel E2E tests, build, formatting, and diff check passed. Ticket implementation work is done; closure remains separate. Implementation branch was reviewed, approved, merged into the Orchestrator branch as `a9ece1dc`, and validated in the Orchestrator worktree. Focused TUI row/mouse/gate tests, Panel E2E tests, build, formatting, and diff check passed. Ticket implementation work is done; closure remains separate.
---
<!-- event: state_changed author: hare at: 2026-06-14T14:00:13Z from: done to: closed reason: closed field: state -->
## State changed
Ticket を closed にしました。
---
<!-- event: close author: hare at: 2026-06-14T14:00:13Z status: closed -->
## 完了
Closed after prior done-state completion.
--- ---

View File

@ -8,7 +8,7 @@
use std::collections::{BTreeMap, BTreeSet}; use std::collections::{BTreeMap, BTreeSet};
use std::fmt; use std::fmt;
use std::fs; use std::fs;
use std::path::{Path, PathBuf}; use std::path::{Component, Path, PathBuf};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use thiserror::Error; use thiserror::Error;
@ -16,6 +16,9 @@ use thiserror::Error;
pub const TICKET_CONFIG_RELATIVE_PATH: &str = ".yoi/ticket.config.toml"; pub const TICKET_CONFIG_RELATIVE_PATH: &str = ".yoi/ticket.config.toml";
/// Workspace-relative default root for the built-in local Ticket backend. /// Workspace-relative default root for the built-in local Ticket backend.
pub const DEFAULT_TICKET_BACKEND_RELATIVE_PATH: &str = ".yoi/tickets"; pub const DEFAULT_TICKET_BACKEND_RELATIVE_PATH: &str = ".yoi/tickets";
const DEFAULT_ORCHESTRATION_BRANCH: &str = "orchestration";
const DEFAULT_ORCHESTRATION_WORKTREE_DIR: &str = ".worktree";
const DEFAULT_ORCHESTRATION_WORKTREE_NAME: &str = "orchestration";
/// Return the explicit workspace Ticket config scaffold written by `yoi ticket init`. /// Return the explicit workspace Ticket config scaffold written by `yoi ticket init`.
/// ///
@ -36,7 +39,7 @@ pub fn ticket_config_scaffold() -> String {
"\n# Optional durable Ticket record language. When unset, generated Ticket text keeps current defaults.\n# [ticket]\n# language = \"Japanese\"\n", "\n# Optional durable Ticket record language. When unset, generated Ticket text keeps current defaults.\n# [ticket]\n# language = \"Japanese\"\n",
); );
out.push_str( out.push_str(
"\n# Optional Panel Orchestrator worktree branch. When unset, Panel uses orchestration/<workspace-orchestrator-pod-name>.\n# [orchestration]\n# branch = \"orchestration/<workspace-orchestrator-pod-name>\"\n", "\n# Optional Panel Orchestrator worktree settings. When unset, Panel uses branch `orchestration` at `.worktree/orchestration`.\n# [orchestration]\n# branch = \"orchestration\"\n# worktree_dir = \".worktree\"\n# worktree_name = \"orchestration\"\n",
); );
for role in TicketRole::ALL { for role in TicketRole::ALL {
out.push_str(&format!( out.push_str(&format!(
@ -77,12 +80,30 @@ pub struct TicketConfig {
#[derive(Debug, Clone, PartialEq, Eq, Default)] #[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct TicketOrchestrationConfig { pub struct TicketOrchestrationConfig {
pub branch: Option<GitBranchName>, pub branch: Option<GitBranchName>,
pub worktree_dir: Option<PathBuf>,
pub worktree_name: Option<PathBuf>,
} }
impl TicketOrchestrationConfig { impl TicketOrchestrationConfig {
pub fn branch_name(&self) -> Option<&str> { pub fn branch_name(&self) -> Option<&str> {
self.branch.as_ref().map(GitBranchName::as_str) self.branch.as_ref().map(GitBranchName::as_str)
} }
pub fn effective_branch_name(&self) -> &str {
self.branch_name().unwrap_or(DEFAULT_ORCHESTRATION_BRANCH)
}
pub fn worktree_dir(&self) -> &Path {
self.worktree_dir
.as_deref()
.unwrap_or_else(|| Path::new(DEFAULT_ORCHESTRATION_WORKTREE_DIR))
}
pub fn worktree_name(&self) -> &Path {
self.worktree_name
.as_deref()
.unwrap_or_else(|| Path::new(DEFAULT_ORCHESTRATION_WORKTREE_NAME))
}
} }
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
@ -167,6 +188,27 @@ fn validate_git_branch_name_value(value: &str) -> Result<(), String> {
Ok(()) Ok(())
} }
fn validate_orchestration_relative_path(path: &Path, label: &str) -> Result<(), String> {
if path.as_os_str().is_empty() {
return Err(format!("{label} must not be empty"));
}
if path.is_absolute() {
return Err(format!("{label} must be workspace-relative"));
}
for component in path.components() {
match component {
Component::Normal(_) => {}
Component::CurDir | Component::ParentDir => {
return Err(format!("{label} must not contain `.` or `..` components"));
}
Component::RootDir | Component::Prefix(_) => {
return Err(format!("{label} must be workspace-relative"));
}
}
}
Ok(())
}
impl TicketConfig { impl TicketConfig {
pub fn default_for_workspace(workspace_root: impl AsRef<Path>) -> Self { pub fn default_for_workspace(workspace_root: impl AsRef<Path>) -> Self {
let workspace_root = workspace_root.as_ref(); let workspace_root = workspace_root.as_ref();
@ -636,13 +678,25 @@ struct RawTicketConfig {
struct RawTicketOrchestrationConfig { struct RawTicketOrchestrationConfig {
#[serde(default)] #[serde(default)]
branch: Option<GitBranchName>, branch: Option<GitBranchName>,
#[serde(default)]
worktree_dir: Option<PathBuf>,
#[serde(default)]
worktree_name: Option<PathBuf>,
} }
impl RawTicketOrchestrationConfig { impl RawTicketOrchestrationConfig {
fn resolve(self) -> TicketOrchestrationConfig { fn resolve(self) -> Result<TicketOrchestrationConfig, String> {
TicketOrchestrationConfig { if let Some(path) = &self.worktree_dir {
branch: self.branch, validate_orchestration_relative_path(path, "orchestration.worktree_dir")?;
} }
if let Some(path) = &self.worktree_name {
validate_orchestration_relative_path(path, "orchestration.worktree_name")?;
}
Ok(TicketOrchestrationConfig {
branch: self.branch,
worktree_dir: self.worktree_dir,
worktree_name: self.worktree_name,
})
} }
} }
@ -691,7 +745,12 @@ impl RawTicketConfig {
} }
})?, })?,
ticket: self.ticket.resolve(), ticket: self.ticket.resolve(),
orchestration: self.orchestration.resolve(), orchestration: self.orchestration.resolve().map_err(|message| {
TicketConfigError::Invalid {
path: path.to_path_buf(),
message,
}
})?,
roles, roles,
}) })
} }
@ -797,6 +856,15 @@ mod tests {
); );
assert_eq!(config.ticket_record_language(), None); assert_eq!(config.ticket_record_language(), None);
assert_eq!(config.orchestration.branch_name(), None); assert_eq!(config.orchestration.branch_name(), None);
assert_eq!(
config.orchestration.effective_branch_name(),
"orchestration"
);
assert_eq!(config.orchestration.worktree_dir(), Path::new(".worktree"));
assert_eq!(
config.orchestration.worktree_name(),
Path::new("orchestration")
);
for role in TicketRole::ALL { for role in TicketRole::ALL {
let role_config = config.role(role); let role_config = config.role(role);
assert_eq!(role_config.profile.as_str(), "inherit"); assert_eq!(role_config.profile.as_str(), "inherit");
@ -820,6 +888,8 @@ language = "Japanese"
[orchestration] [orchestration]
branch = "orchestration/custom-panel" branch = "orchestration/custom-panel"
worktree_dir = "custom-worktrees"
worktree_name = "custom-orchestrator"
[roles.intake] [roles.intake]
profile = "project:intake" profile = "project:intake"
@ -854,6 +924,18 @@ workflow = "multi-agent-workflow"
config.orchestration.branch_name(), config.orchestration.branch_name(),
Some("orchestration/custom-panel") Some("orchestration/custom-panel")
); );
assert_eq!(
config.orchestration.effective_branch_name(),
"orchestration/custom-panel"
);
assert_eq!(
config.orchestration.worktree_dir(),
Path::new("custom-worktrees")
);
assert_eq!(
config.orchestration.worktree_name(),
Path::new("custom-orchestrator")
);
assert_eq!( assert_eq!(
config.profile_for(TicketRole::Intake).as_str(), config.profile_for(TicketRole::Intake).as_str(),
"project:intake" "project:intake"
@ -881,7 +963,7 @@ workflow = "multi-agent-workflow"
assert!(scaffold.contains("root = \".yoi/tickets\"")); assert!(scaffold.contains("root = \".yoi/tickets\""));
assert!(scaffold.contains("# [ticket]\n# language = \"Japanese\"")); assert!(scaffold.contains("# [ticket]\n# language = \"Japanese\""));
assert!(scaffold.contains( assert!(scaffold.contains(
"# [orchestration]\n# branch = \"orchestration/<workspace-orchestrator-pod-name>\"" "# [orchestration]\n# branch = \"orchestration\"\n# worktree_dir = \".worktree\"\n# worktree_name = \"orchestration\""
)); ));
for role in TicketRole::ALL { for role in TicketRole::ALL {
assert!(scaffold.contains(&format!("[roles.{role}]"))); assert!(scaffold.contains(&format!("[roles.{role}]")));
@ -901,6 +983,15 @@ workflow = "multi-agent-workflow"
.unwrap(); .unwrap();
assert_eq!(config.backend_root(), temp.path().join(".yoi/tickets")); assert_eq!(config.backend_root(), temp.path().join(".yoi/tickets"));
assert_eq!(config.orchestration.branch_name(), None); assert_eq!(config.orchestration.branch_name(), None);
assert_eq!(
config.orchestration.effective_branch_name(),
"orchestration"
);
assert_eq!(config.orchestration.worktree_dir(), Path::new(".worktree"));
assert_eq!(
config.orchestration.worktree_name(),
Path::new("orchestration")
);
for role in TicketRole::ALL { for role in TicketRole::ALL {
let role_config = config.role_launch_config(role).unwrap(); let role_config = config.role_launch_config(role).unwrap();
assert_eq!(role_config.profile.as_str(), role.default_profile()); assert_eq!(role_config.profile.as_str(), role.default_profile());

View File

@ -27,7 +27,7 @@ use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph, Widget, Wrap}; use ratatui::widgets::{Block, Borders, Clear, Paragraph, Widget, Wrap};
use serde::Serialize; use serde::Serialize;
use session_store::FsStore; use session_store::FsStore;
use ticket::config::{GitBranchName, TicketConfig}; use ticket::config::{GitBranchName, TicketConfig, TicketOrchestrationConfig};
use ticket::{ use ticket::{
LocalTicketBackend, MarkdownText, TicketBackend, TicketIdOrSlug, TicketStateChange, LocalTicketBackend, MarkdownText, TicketBackend, TicketIdOrSlug, TicketStateChange,
TicketWorkflowState, TicketWorkflowState,
@ -2517,40 +2517,37 @@ struct OrchestrationWorktreeReady {
status: OrchestrationWorktreeStatus, status: OrchestrationWorktreeStatus,
} }
fn orchestration_worktree_layout_for_branch( fn orchestration_worktree_layout_for_config(
workspace_root: &Path, workspace_root: &Path,
branch: String, orchestration: &TicketOrchestrationConfig,
) -> OrchestrationWorktreeLayout { ) -> OrchestrationWorktreeLayout {
let stem = workspace_orchestrator_pod_name(workspace_root);
OrchestrationWorktreeLayout { OrchestrationWorktreeLayout {
path: workspace_root path: workspace_root
.join(".worktree") .join(orchestration.worktree_dir())
.join("orchestration") .join(orchestration.worktree_name()),
.join(&stem), branch: orchestration.effective_branch_name().to_string(),
branch,
} }
} }
#[cfg(test)]
fn orchestration_worktree_layout(workspace_root: &Path) -> OrchestrationWorktreeLayout { fn orchestration_worktree_layout(workspace_root: &Path) -> OrchestrationWorktreeLayout {
let stem = workspace_orchestrator_pod_name(workspace_root); OrchestrationWorktreeLayout {
orchestration_worktree_layout_for_branch(workspace_root, format!("orchestration/{stem}")) path: workspace_root.join(".worktree").join("orchestration"),
branch: "orchestration".to_string(),
}
} }
fn resolved_orchestration_worktree_layout( fn resolved_orchestration_worktree_layout(
workspace_root: &Path, workspace_root: &Path,
) -> Result<OrchestrationWorktreeLayout, String> { ) -> Result<OrchestrationWorktreeLayout, String> {
let config = TicketConfig::load_workspace(workspace_root) let config = TicketConfig::load_workspace(workspace_root)
.map_err(|err| format!("failed to load ticket config for orchestration branch: {err}"))?; .map_err(|err| format!("failed to load ticket config for orchestration worktree: {err}"))?;
let branch = if let Some(branch) = config.orchestration.branch_name() { let branch = config.orchestration.effective_branch_name();
branch.to_string() GitBranchName::new(branch.to_string())
} else {
orchestration_worktree_layout(workspace_root).branch
};
GitBranchName::new(branch.clone())
.map_err(|message| format!("invalid orchestration branch `{branch}`: {message}"))?; .map_err(|message| format!("invalid orchestration branch `{branch}`: {message}"))?;
Ok(orchestration_worktree_layout_for_branch( Ok(orchestration_worktree_layout_for_config(
workspace_root, workspace_root,
branch, &config.orchestration,
)) ))
} }
@ -5757,9 +5754,9 @@ mod tests {
let layout = orchestration_worktree_layout(root); let layout = orchestration_worktree_layout(root);
assert_eq!( assert_eq!(
layout.path, layout.path,
PathBuf::from("/tmp/Yoi Workspace/.worktree/orchestration/yoi-workspace-orchestrator") PathBuf::from("/tmp/Yoi Workspace/.worktree/orchestration")
); );
assert_eq!(layout.branch, "orchestration/yoi-workspace-orchestrator"); assert_eq!(layout.branch, "orchestration");
} }
#[test] #[test]
@ -5834,7 +5831,7 @@ mod tests {
} }
#[test] #[test]
fn ensure_and_restore_use_configured_orchestration_branch() { fn ensure_and_restore_use_configured_orchestration_layout() {
let temp = TempDir::new().unwrap(); let temp = TempDir::new().unwrap();
let root = temp.path().join("repo"); let root = temp.path().join("repo");
init_test_repo(&root); init_test_repo(&root);
@ -5843,6 +5840,8 @@ mod tests {
r#" r#"
[orchestration] [orchestration]
branch = "orchestration/custom-panel" branch = "orchestration/custom-panel"
worktree_dir = "custom-worktrees"
worktree_name = "panel"
"#, "#,
); );
run_test_git(&root, &["add", ".yoi/ticket.config.toml"]).unwrap(); run_test_git(&root, &["add", ".yoi/ticket.config.toml"]).unwrap();
@ -5850,11 +5849,7 @@ branch = "orchestration/custom-panel"
let resolved = resolved_orchestration_worktree_layout(&root).unwrap(); let resolved = resolved_orchestration_worktree_layout(&root).unwrap();
assert_eq!(resolved.branch, "orchestration/custom-panel"); assert_eq!(resolved.branch, "orchestration/custom-panel");
assert!( assert!(resolved.path.ends_with("custom-worktrees/panel"));
resolved
.path
.ends_with(".worktree/orchestration/repo-orchestrator")
);
let created = ensure_orchestration_worktree(&root).unwrap(); let created = ensure_orchestration_worktree(&root).unwrap();
assert_eq!(created.status, OrchestrationWorktreeStatus::Created); assert_eq!(created.status, OrchestrationWorktreeStatus::Created);
@ -5934,12 +5929,7 @@ branch = "orchestration/custom-panel"
assert_eq!(restored.status, OrchestrationWorktreeStatus::Reused); assert_eq!(restored.status, OrchestrationWorktreeStatus::Reused);
assert_eq!(restored.layout.path, created.layout.path); assert_eq!(restored.layout.path, created.layout.path);
assert_ne!(restored.layout.path, root); assert_ne!(restored.layout.path, root);
assert!( assert!(restored.layout.path.ends_with(".worktree/orchestration"));
restored
.layout
.path
.ends_with(".worktree/orchestration/repo-orchestrator")
);
} }
#[test] #[test]