fix: align ticket flat-state surfaces
This commit is contained in:
parent
21114fdd6f
commit
8fe4b822ee
|
|
@ -70,7 +70,7 @@ Intake は以下を行う。
|
||||||
- `TicketComment`: 既存 Ticket refinement / decision / plan の記録。
|
- `TicketComment`: 既存 Ticket refinement / decision / plan の記録。
|
||||||
- `TicketDoctor`: 必要に応じた整合性確認。
|
- `TicketDoctor`: 必要に応じた整合性確認。
|
||||||
|
|
||||||
Intake は `TicketReview`, `TicketStatus`, `TicketClose` を通常使わない。review / state transition / close は Orchestrator または reviewer / maintainer workflow の責務である。
|
Intake は `TicketReview`, `TicketWorkflowState`, `TicketClose` を通常使わない。review / state transition / close は Orchestrator または reviewer / maintainer workflow の責務である。
|
||||||
|
|
||||||
Ticket tools が利用できない環境では、勝手に file write で代替しない。ユーザーまたは Orchestrator に「Ticket tools がないため materialize できない」と報告し、必要なら `yoi ticket` を使える人間/親 workflow に戻す。
|
Ticket tools が利用できない環境では、勝手に file write で代替しない。ユーザーまたは Orchestrator に「Ticket tools がないため materialize できない」と報告し、必要なら `yoi ticket` を使える人間/親 workflow に戻す。
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ Ticket tools が利用できない環境では、勝手に file write で代替
|
||||||
|
|
||||||
確認観点:
|
確認観点:
|
||||||
|
|
||||||
- 同じ目的の open / pending Ticket がないか。
|
- 同じ目的の未完了 Ticket がないか。
|
||||||
- closed Ticket の判断・resolution と矛盾しないか。
|
- closed Ticket の判断・resolution と矛盾しないか。
|
||||||
- 既存の umbrella/progress-container Ticket が、superseded/decomposed として退役できる状態か。
|
- 既存の umbrella/progress-container Ticket が、superseded/decomposed として退役できる状態か。
|
||||||
- 既存 concrete follow-up Ticket や Objective context で足りるか、新規 concrete Ticket が必要か。
|
- 既存 concrete follow-up Ticket や Objective context で足りるか、新規 concrete Ticket が必要か。
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ Panel Queue / queued notification は、人間が Orchestrator に routing を
|
||||||
```text
|
```text
|
||||||
TicketCreate / TicketComment
|
TicketCreate / TicketComment
|
||||||
-> Ticket Orchestrator Routing Workflow
|
-> Ticket Orchestrator Routing Workflow
|
||||||
-> planning return / requirements sync / spike / implementation / review / blocked / close / pending
|
-> planning return / requirements sync / spike / implementation / review / blocked / close
|
||||||
-> 必要に応じて他 Workflow へ接続
|
-> 必要に応じて他 Workflow へ接続
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -71,7 +71,6 @@ Orchestrator は以下を行う。
|
||||||
- `TicketList`: routing 候補や関連 Ticket の確認。
|
- `TicketList`: routing 候補や関連 Ticket の確認。
|
||||||
- `TicketShow`: 対象 Ticket の body / thread / artifacts / resolution 確認。
|
- `TicketShow`: 対象 Ticket の body / thread / artifacts / resolution 確認。
|
||||||
- `TicketComment`: routing decision / intent packet / blocked reason / next question の記録。
|
- `TicketComment`: routing decision / intent packet / blocked reason / next question の記録。
|
||||||
- `TicketStatus`: pending/open などの状態整理が明示的に許可された場合だけ使う。
|
|
||||||
- `TicketWorkflowState`: `queued -> inprogress` acceptance、`inprogress -> done`、または concrete missing decision/information reason を伴う `ready|queued -> planning` に使う。
|
- `TicketWorkflowState`: `queued -> inprogress` acceptance、`inprogress -> done`、または concrete missing decision/information reason を伴う `ready|queued -> planning` に使う。
|
||||||
- `TicketOrchestrationPlanQuery`: 対象 Ticket や関連 Ticket の ordering / blocker / conflict / waiting-capacity / accepted-plan 記録を読む。queued acceptance 前に必ず確認する。
|
- `TicketOrchestrationPlanQuery`: 対象 Ticket や関連 Ticket の ordering / blocker / conflict / waiting-capacity / accepted-plan 記録を読む。queued acceptance 前に必ず確認する。
|
||||||
- `TicketOrchestrationPlanRecord`: Orchestrator が routing 中に project-relevant な ordering / dependency / conflict / capacity/waiting / accepted-plan decision を残す。これは queue reorder、自動起動、state 変更ではない。
|
- `TicketOrchestrationPlanRecord`: Orchestrator が routing 中に project-relevant な ordering / dependency / conflict / capacity/waiting / accepted-plan decision を残す。これは queue reorder、自動起動、state 変更ではない。
|
||||||
|
|
@ -88,7 +87,7 @@ Orchestrator は以下を行う。
|
||||||
- `before` / `after` / `blocked_by` / `blocks` / `conflicts_with` / `do_not_parallelize` / waiting-capacity 記録がある場合、それを acceptance 判断の入力にする。記録は自動 scheduler ではないため、実際に進めるかどうかは Orchestrator が読んだうえで明示的に決める。
|
- `before` / `after` / `blocked_by` / `blocks` / `conflicts_with` / `do_not_parallelize` / waiting-capacity 記録がある場合、それを acceptance 判断の入力にする。記録は自動 scheduler ではないため、実際に進めるかどうかは Orchestrator が読んだうえで明示的に決める。
|
||||||
- risk flags / risky domain がある場合は、IntentPacket に invariants / reviewer focus / escalation conditions を入れる。risk flag だけを `queued -> planning` の理由にしない。
|
- risk flags / risky domain がある場合は、IntentPacket に invariants / reviewer focus / escalation conditions を入れる。risk flag だけを `queued -> planning` の理由にしない。
|
||||||
- concrete missing decision / information がある場合: `TicketWorkflowState` で `queued -> planning` を記録し、reason/body と `TicketComment` に不足項目、checked context、なぜ coder の implementation latitude では解決できないか、次の planning question/action を残す。既存の claimed live/restorable Intake/Planning Pod があり、既存通知経路が使える場合は同じ理由を通知する。
|
- concrete missing decision / information がある場合: `TicketWorkflowState` で `queued -> planning` を記録し、reason/body と `TicketComment` に不足項目、checked context、なぜ coder の implementation latitude では解決できないか、次の planning question/action を残す。既存の claimed live/restorable Intake/Planning Pod があり、既存通知経路が使える場合は同じ理由を通知する。
|
||||||
- external action 待ちなど planning では解決しない blocker の場合: concise な理由を Ticket thread に記録し、queued のまま待つか、既存の Ticket state/state mechanism で明示的に defer/block する。
|
- external action 待ちなど planning では解決しない blocker の場合: concise な理由を Ticket thread に記録し、必要に応じて attention / action-required frontmatter や `TicketOrchestrationPlanRecord` の blocker/waiting-capacity 記録で明示する。lifecycle 外の storage bucket を routing target にしない。
|
||||||
|
|
||||||
Invariant:
|
Invariant:
|
||||||
|
|
||||||
|
|
@ -214,7 +213,7 @@ Action:
|
||||||
|
|
||||||
- 必要な判断・外部 action を短く書く。
|
- 必要な判断・外部 action を短く書く。
|
||||||
- `TicketComment` に blocked reason と next question を記録する。
|
- `TicketComment` に blocked reason と next question を記録する。
|
||||||
- 必要なら `TicketStatus` で pending に移す(許可がある場合だけ)。
|
- 必要に応じて attention / action-required frontmatter や orchestration plan の blocker/waiting-capacity 記録で、待ち理由を current state とは別に表す。lifecycle 外の storage bucket へ移す route は使わない。
|
||||||
|
|
||||||
### `close_ready`
|
### `close_ready`
|
||||||
|
|
||||||
|
|
@ -234,21 +233,6 @@ Action:
|
||||||
- umbrella/progress-container Ticket を退役する close resolution では、関連作業がすべて完了したという意味ではなく container role を retired したことを明記し、完了済み concrete Ticket と残る follow-up Ticket / Objective を列挙する。
|
- umbrella/progress-container Ticket を退役する close resolution では、関連作業がすべて完了したという意味ではなく container role を retired したことを明記し、完了済み concrete Ticket と残る follow-up Ticket / Objective を列挙する。
|
||||||
- close 権限がない場合は merge-ready / close-ready dossier を親/人間に提出する。
|
- close 権限がない場合は merge-ready / close-ready dossier を親/人間に提出する。
|
||||||
|
|
||||||
### `defer_pending`
|
|
||||||
|
|
||||||
今は進めないが blocked ではない。
|
|
||||||
|
|
||||||
条件:
|
|
||||||
|
|
||||||
- 優先度・タイミングの理由で後回し。
|
|
||||||
- 依存はあるが active blocker として扱うほどではない。
|
|
||||||
- broad request が concrete implementable Ticket に分解され、Objective context や split decision record の作成待ちである。
|
|
||||||
|
|
||||||
Action:
|
|
||||||
|
|
||||||
- defer reason を `TicketComment` に記録する。
|
|
||||||
- 必要なら `TicketStatus` で pending に移す(許可がある場合だけ)。
|
|
||||||
|
|
||||||
### `closed_or_noop`
|
### `closed_or_noop`
|
||||||
|
|
||||||
routing 不要。
|
routing 不要。
|
||||||
|
|
@ -395,7 +379,6 @@ IntentPacket が短く書けない場合、`implementation_ready` ではなく `
|
||||||
- `review_needed` → reviewer Pod / review workflow
|
- `review_needed` → reviewer Pod / review workflow
|
||||||
- `blocked_action_required` → human / parent Orchestrator
|
- `blocked_action_required` → human / parent Orchestrator
|
||||||
- `close_ready` → close workflow / maintainer decision
|
- `close_ready` → close workflow / maintainer decision
|
||||||
- `defer_pending` → pending / Objective or split-decision follow-up management
|
|
||||||
|
|
||||||
## 完了条件
|
## 完了条件
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,14 +110,6 @@ impl TicketFeature {
|
||||||
if !root.is_dir() {
|
if !root.is_dir() {
|
||||||
return Err("ticket backend root is not a directory".to_string());
|
return Err("ticket backend root is not a directory".to_string());
|
||||||
}
|
}
|
||||||
for state_dir in ["open", "pending", "closed"] {
|
|
||||||
let dir = root.join(state_dir);
|
|
||||||
if !dir.is_dir() {
|
|
||||||
return Err(format!(
|
|
||||||
"ticket backend root is missing required {state_dir}/ directory"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(root)
|
Ok(root)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -194,9 +186,6 @@ fn tool_description(name: &str) -> &'static str {
|
||||||
"TicketWorkflowState" => {
|
"TicketWorkflowState" => {
|
||||||
"Transition Ticket state; queued -> inprogress is the accepted implementation start, so implementation side effects should happen only after that transition is accepted and recorded."
|
"Transition Ticket state; queued -> inprogress is the accepted implementation start, so implementation side effects should happen only after that transition is accepted and recorded."
|
||||||
}
|
}
|
||||||
"TicketStateCompat" => {
|
|
||||||
"Move a Ticket between open and pending; use TicketClose for closed."
|
|
||||||
}
|
|
||||||
"TicketClose" => "Close a Ticket with a resolution through the typed local Ticket backend.",
|
"TicketClose" => "Close a Ticket with a resolution through the typed local Ticket backend.",
|
||||||
"TicketOrchestrationPlanRecord" => {
|
"TicketOrchestrationPlanRecord" => {
|
||||||
"Append a durable typed Ticket orchestration plan record without changing state or starting work."
|
"Append a durable typed Ticket orchestration plan record without changing state or starting work."
|
||||||
|
|
@ -228,9 +217,7 @@ mod tests {
|
||||||
use tempfile::TempDir;
|
use tempfile::TempDir;
|
||||||
|
|
||||||
fn make_ticket_root(root: &Path) {
|
fn make_ticket_root(root: &Path) {
|
||||||
std::fs::create_dir_all(root.join("open")).unwrap();
|
std::fs::create_dir_all(root).unwrap();
|
||||||
std::fs::create_dir_all(root.join("pending")).unwrap();
|
|
||||||
std::fs::create_dir_all(root.join("closed")).unwrap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_ticket_config(workspace: &Path, content: &str) {
|
fn write_ticket_config(workspace: &Path, content: &str) {
|
||||||
|
|
@ -469,21 +456,21 @@ provider = "github"
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn does_not_register_ticket_tools_when_root_lacks_state_dirs() {
|
fn registers_ticket_tools_for_flat_backend_root() {
|
||||||
let temp = TempDir::new().unwrap();
|
let temp = TempDir::new().unwrap();
|
||||||
std::fs::create_dir_all(temp.path().join(DEFAULT_TICKET_BACKEND_RELATIVE_PATH)).unwrap();
|
let root = temp.path().join(DEFAULT_TICKET_BACKEND_RELATIVE_PATH);
|
||||||
|
std::fs::create_dir_all(&root).unwrap();
|
||||||
let mut pending_tools = Vec::new();
|
let mut pending_tools = Vec::new();
|
||||||
let mut hooks = HookRegistryBuilder::default();
|
let mut hooks = HookRegistryBuilder::default();
|
||||||
let report = FeatureRegistryBuilder::new()
|
let report = FeatureRegistryBuilder::new()
|
||||||
.with_module(ticket_tools_feature(temp.path()))
|
.with_module(ticket_tools_feature(temp.path()))
|
||||||
.install_into_pending(&mut pending_tools, &mut hooks);
|
.install_into_pending(&mut pending_tools, &mut hooks);
|
||||||
|
|
||||||
assert!(pending_tools.is_empty());
|
assert_eq!(pending_tools.len(), TICKET_TOOL_NAMES.len());
|
||||||
assert!(report.reports[0].installed_tools.is_empty());
|
assert_eq!(report.reports[0].installed_tools, TICKET_TOOL_NAMES);
|
||||||
assert!(
|
assert!(report.reports[0].diagnostics.is_empty());
|
||||||
report.reports[0].diagnostics[0]
|
assert!(!root.join("open").exists());
|
||||||
.message
|
assert!(!root.join("pending").exists());
|
||||||
.contains("missing required open/ directory")
|
assert!(!root.join("closed").exists());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
Yoi project work is tracked through Tickets. For normal use, interact with Tickets through `yoi panel`, Ticket tools, the `yoi ticket ...` CLI, and Ticket workflows. Git history plus Ticket files remain the authoritative state-transition record behind those interfaces.
|
Yoi project work is tracked through Tickets. For normal use, interact with Tickets through `yoi panel`, Ticket tools, the `yoi ticket ...` CLI, and Ticket workflows. Git history plus Ticket files remain the authoritative state-transition record behind those interfaces.
|
||||||
|
|
||||||
The current local backend stores Ticket files under `.yoi/tickets/`. That storage detail matters for maintainers and backend compatibility, but it is not the primary user-facing workflow.
|
The current local backend stores each Ticket in the flat `.yoi/tickets/<ticket-id>/` layout. The directory name is the canonical opaque Ticket id; slugs and frontmatter `id`/`slug` fields are not current-state authority. That storage detail matters for maintainers and backend compatibility, but it is not the primary user-facing workflow.
|
||||||
|
|
||||||
Do not treat ad-hoc chat summaries, memory records, or Pod notifications as the final source of project state. Notifications are hints to inspect concrete state, not proof of completion.
|
Do not treat ad-hoc chat summaries, memory records, or Pod notifications as the final source of project state. Notifications are hints to inspect concrete state, not proof of completion.
|
||||||
|
|
||||||
|
|
@ -36,7 +36,7 @@ Pods with the Ticket built-in feature can use typed Ticket tools:
|
||||||
- `TicketShow`
|
- `TicketShow`
|
||||||
- `TicketComment`
|
- `TicketComment`
|
||||||
- `TicketReview`
|
- `TicketReview`
|
||||||
- `TicketStatus`
|
- `TicketWorkflowState`
|
||||||
- `TicketClose`
|
- `TicketClose`
|
||||||
- `TicketDoctor`
|
- `TicketDoctor`
|
||||||
|
|
||||||
|
|
@ -156,14 +156,13 @@ Routing classifications include:
|
||||||
- `review_needed`
|
- `review_needed`
|
||||||
- `blocked_action_required`
|
- `blocked_action_required`
|
||||||
- `close_ready`
|
- `close_ready`
|
||||||
- `defer_pending`
|
|
||||||
- `closed_or_noop`
|
- `closed_or_noop`
|
||||||
|
|
||||||
Routing decisions should be recorded with `TicketComment` using `plan` or `decision` role. The decision should state the classification, evidence checked, reason, next action, and escalation conditions. For `return_to_planning`, the record must also state the concrete missing decision/information, context checked, why implementation latitude is insufficient, and the next planning question/action.
|
Routing decisions should be recorded with `TicketComment` using `plan` or `decision` role. The decision should state the classification, evidence checked, reason, next action, and escalation conditions. For `return_to_planning`, the record must also state the concrete missing decision/information, context checked, why implementation latitude is insufficient, and the next planning question/action.
|
||||||
|
|
||||||
### 3. Planning/requirements sync
|
### 3. Planning/requirements sync
|
||||||
|
|
||||||
Use `ticket-preflight-workflow` only as a legacy compatibility canonical id for planning/requirements sync. Return `ready` or `queued` Tickets to `planning` only when the Orchestrator can name a concrete missing decision or information item after bounded project-context checks; risk flags and risky domains are context-lookup and reviewer-focus signals, not automatic stop gates.
|
Use `ticket-preflight-workflow` only as a legacy-compatible planning/requirements sync entry. Return `ready` or `queued` Tickets to `planning` only when the Orchestrator can name a concrete missing decision or information item after bounded project-context checks; risk flags and risky domains are context-lookup and reviewer-focus signals, not automatic stop gates.
|
||||||
|
|
||||||
Planning sync should resolve or record:
|
Planning sync should resolve or record:
|
||||||
|
|
||||||
|
|
@ -333,17 +332,17 @@ Do not store secrets, credentials, private prompt contents, or raw logs containi
|
||||||
The product CLI exposes the typed Ticket backend for repository maintenance and validation. It operates on the configured `.yoi/tickets/` storage and is the preferred command-line surface when editing Tickets outside a Pod.
|
The product CLI exposes the typed Ticket backend for repository maintenance and validation. It operates on the configured `.yoi/tickets/` storage and is the preferred command-line surface when editing Tickets outside a Pod.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
yoi ticket create --title "..." [--canonical id canonical id] [--kind task] [--priority P2] [--label a,b]
|
yoi ticket create --title "..." [--priority P2]
|
||||||
yoi ticket list [--state planning|ready|queued|inprogress|done|closed|all]
|
yoi ticket list [--state planning|ready|queued|inprogress|done|closed|all]
|
||||||
yoi ticket show <id>
|
yoi ticket show <id>
|
||||||
yoi ticket comment <id> [--role comment|plan|decision|implementation_report] [--file path]
|
yoi ticket comment <id> [--role comment|plan|decision|implementation_report] [--file path]
|
||||||
yoi ticket review <id> --approve|--request-changes [--file path]
|
yoi ticket review <id> --approve|--request-changes [--file path]
|
||||||
yoi ticket state <id> open|pending
|
yoi ticket state <id> <planning|ready|queued|inprogress|done>
|
||||||
yoi ticket close <id> [--resolution text|--file path]
|
yoi ticket close <id> [--resolution text|--file path]
|
||||||
yoi ticket doctor
|
yoi ticket doctor
|
||||||
```
|
```
|
||||||
|
|
||||||
`yoi ticket state` intentionally does not close Tickets. Closing must use `yoi ticket close` so the backend writes the required `resolution.md` and passes `yoi ticket doctor`.
|
`yoi ticket state` records current lifecycle transitions among active states. Closing must use `yoi ticket close` so the backend writes the required `resolution.md` and passes `yoi ticket doctor`; `done` and `closed` remain distinct states.
|
||||||
|
|
||||||
The current LocalTicketBackend stores records under:
|
The current LocalTicketBackend stores records under:
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user