ticket: remove fixed investigator role

This commit is contained in:
Keisuke Hirata 2026-06-08 20:42:37 +09:00
parent dc65b7d4a1
commit 427a270722
No known key found for this signature in database
6 changed files with 57 additions and 34 deletions

View File

@ -22,7 +22,7 @@ User request / conversation
- `Ticket` は durable orchestration record。
- `Task` は session-local progress tracking。
- `Assignment` は Orchestrator から coder / reviewer / investigator Pod への具体的委譲。
- `Assignment` は Orchestrator から coder / reviewer Pod、または task-specific helper Pod への具体的委譲。
- `IntentPacket` は Ticket から抽出して Assignment に渡す短い実装・レビュー契約。
Intake は、要件同期と Ticket 化を担当する。実装の起動・worktree 作成・review 委譲・merge 判断は Orchestrator 側の責務である。`ready` は Orchestrator が routing できる状態を意味し、実装戦術がすべて事前固定されていることを意味しない。
@ -47,7 +47,7 @@ Intake は以下を行う。
## Intake がしないこと
- coder / reviewer / investigator Pod を起動しない。
- coder / reviewer Pod や read-only investigation helper Pod を起動しない。
- worktree を作らない。
- merge / close / branch cleanup をしない。
- implementation-ready でない Ticket を実装に投げない。

View File

@ -50,7 +50,7 @@ Orchestrator は以下を行う。
- 自動 scheduler として unattended に実行しない。
- Panel Queue / queued notification だけを unattended scheduler trigger として扱わない。
- `queued -> inprogress` acceptance なしに worktree 作成、implementation Pod `SpawnPod`、coder/reviewer routing を行わない。
- 人間/上位 Orchestrator の許可または明示的な routing acceptance なしに coder / reviewer / investigator Pod を起動しない。
- 人間/上位 Orchestrator の許可または明示的な routing acceptance なしに coder / reviewer Pod や read-only investigation helper Pod を起動しない。
- 設計境界の未決定を勝手に implementation-ready として固定しない。
- merge / close / cleanup 権限を持たない場面で勝手に完了処理しない。
- Ticket tools があるからといって arbitrary filesystem write を行わない。
@ -139,7 +139,7 @@ Action:
Action:
- read-only investigation を提案する。
- 許可があれば investigator Pod を read-only scope で起動できる。
- 許可があれば task-specific read-only helper Pod を普通の scoped Pod として起動できる。
- `TicketComment` に調査問い・scope・完了条件を記録する。
- 実装 worktree はまだ作らない。

View File

@ -553,7 +553,7 @@ fn append_role_execution_guidance(out: &mut String, role: TicketRole) {
TicketRole::Orchestrator => append_orchestrator_agent_routing_guidance(out),
TicketRole::Coder => append_coder_agent_routing_guidance(out),
TicketRole::Reviewer => append_reviewer_agent_routing_guidance(out),
TicketRole::Intake | TicketRole::Investigator => {}
TicketRole::Intake => {}
}
}

View File

@ -194,25 +194,26 @@ pub enum TicketRole {
Orchestrator,
Coder,
Reviewer,
Investigator,
}
impl TicketRole {
pub const ALL: [TicketRole; 5] = [
pub const ALL: [TicketRole; 4] = [
TicketRole::Intake,
TicketRole::Orchestrator,
TicketRole::Coder,
TicketRole::Reviewer,
TicketRole::Investigator,
];
pub fn supported_names() -> Vec<&'static str> {
Self::ALL.iter().map(|role| role.as_str()).collect()
}
pub fn as_str(self) -> &'static str {
match self {
Self::Intake => "intake",
Self::Orchestrator => "orchestrator",
Self::Coder => "coder",
Self::Reviewer => "reviewer",
Self::Investigator => "investigator",
}
}
@ -222,7 +223,6 @@ impl TicketRole {
"orchestrator" => Some(Self::Orchestrator),
"coder" => Some(Self::Coder),
"reviewer" => Some(Self::Reviewer),
"investigator" => Some(Self::Investigator),
_ => None,
}
}
@ -232,7 +232,6 @@ impl TicketRole {
Self::Intake => "ticket-intake-workflow",
Self::Orchestrator => "ticket-orchestrator-routing",
Self::Coder | Self::Reviewer => "multi-agent-workflow",
Self::Investigator => "ticket-orchestrator-routing",
}
}
}
@ -550,7 +549,10 @@ impl RawTicketConfig {
for (name, raw_role) in self.roles {
let role = TicketRole::parse(&name).ok_or_else(|| TicketConfigError::Invalid {
path: path.to_path_buf(),
message: format!("unknown Ticket role `{name}`"),
message: format!(
"unsupported Ticket role `{name}`; supported fixed roles: {}",
TicketRole::supported_names().join(", ")
),
})?;
let profile_configured = raw_role.profile.is_some();
roles.inner.insert(role, raw_role.resolve(role));
@ -711,11 +713,6 @@ workflow = "multi-agent-workflow"
profile = "project:reviewer"
launch_prompt = "$workspace/ticket/reviewer/launch"
workflow = "multi-agent-workflow"
[roles.investigator]
profile = "default"
launch_prompt = "$workspace/ticket/investigator/launch"
workflow = "ticket-orchestrator-routing"
"#,
);
@ -738,8 +735,8 @@ workflow = "ticket-orchestrator-routing"
"$workspace/ticket/reviewer/launch"
);
assert_eq!(
config.workflow_for(TicketRole::Investigator).as_str(),
"ticket-orchestrator-routing"
config.workflow_for(TicketRole::Reviewer).as_str(),
"multi-agent-workflow"
);
}
@ -759,6 +756,7 @@ workflow = "ticket-orchestrator-routing"
role.default_workflow()
)));
}
assert!(!scaffold.contains("[roles.investigator]"));
let config = TicketConfig::from_toml(
temp.path(),
@ -899,7 +897,41 @@ profile = "inherit"
);
let error = TicketConfig::load_workspace(temp.path()).unwrap_err();
assert!(error.to_string().contains("unknown Ticket role `operator`"));
assert!(
error
.to_string()
.contains("unsupported Ticket role `operator`")
);
assert!(
error
.to_string()
.contains("intake, orchestrator, coder, reviewer")
);
}
#[test]
fn stale_investigator_role_config_is_rejected() {
let temp = TempDir::new().unwrap();
write_config(
temp.path(),
r#"
[roles.investigator]
profile = "builtin:default"
workflow = "ticket-orchestrator-routing"
"#,
);
let error = TicketConfig::load_workspace(temp.path()).unwrap_err();
assert!(
error
.to_string()
.contains("unsupported Ticket role `investigator`")
);
assert!(
error
.to_string()
.contains("intake, orchestrator, coder, reviewer")
);
}
#[test]

View File

@ -849,6 +849,7 @@ mod tests {
role.default_workflow()
)));
}
assert!(!config.contains("[roles.investigator]"));
}
#[test]

View File

@ -10,7 +10,7 @@ Do not treat ad-hoc chat summaries, memory records, or Pod notifications as the
- `Ticket`: durable project/orchestration record. It contains requirements, decisions, plans, implementation reports, reviews, artifacts, and resolution history.
- `Task`: session-local progress tracking inside a Pod. It is not the project record.
- `Assignment`: a concrete delegation from an Orchestrator to a coder/reviewer/investigator Pod.
- `Assignment`: a concrete delegation from an Orchestrator to a coder/reviewer Pod or task-specific helper Pod.
- `IntentPacket`: the short implementation/review contract derived from a Ticket and handed to an Assignment.
- `LocalTicketBackend`: the current `.yoi/tickets/` markdown/thread/artifacts storage backend.
@ -80,11 +80,6 @@ workflow = "multi-agent-workflow"
profile = "project:reviewer"
launch_prompt = "$workspace/ticket/reviewer/launch"
workflow = "multi-agent-workflow"
[roles.investigator]
profile = "project:investigator"
launch_prompt = "$workspace/ticket/investigator/launch"
workflow = "ticket-orchestrator-routing"
```
Fixed roles are:
@ -93,9 +88,10 @@ Fixed roles are:
- `orchestrator`
- `coder`
- `reviewer`
- `investigator`
This is not an arbitrary role registry. The fixed roles are the roles required by Ticket orchestration.
Stale `[roles.investigator]` config is rejected as an unsupported fixed role; remove it and,
when a spike is useful, let the Orchestrator create an ordinary task-specific read-only helper Pod.
`profile` selects the Pod runtime Profile for that role. The selected Profile owns durable role/system behavior. `ticket.config.toml` does not have a role-level `system_instruction` field.
@ -116,7 +112,6 @@ If `.yoi/ticket.config.toml` is missing, defaults are:
- orchestrator: `ticket-orchestrator-routing`
- coder: `multi-agent-workflow`
- reviewer: `multi-agent-workflow`
- investigator: `ticket-orchestrator-routing`
Important: top-level Ticket role launches cannot execute `profile = "inherit"` because top-level launch has no parent Profile to inherit from. Configure concrete role profiles in `.yoi/ticket.config.toml` before using `yoi panel` role-launch actions.
@ -227,7 +222,6 @@ Role actions map to the same fixed roles configured in `.yoi/ticket.config.toml`
- intake launches the intake role without an existing Ticket and requires freeform context.
- route launches the orchestrator role for an existing Ticket.
- investigate launches the investigator role for a read-only spike/investigation.
- implement launches the coder role for an implementation assignment.
- review launches the reviewer role for review.
@ -286,10 +280,6 @@ workflow = "multi-agent-workflow"
[roles.reviewer]
profile = "project:reviewer"
workflow = "multi-agent-workflow"
[roles.investigator]
profile = "project:investigator"
workflow = "ticket-orchestrator-routing"
```
If a role still uses `profile = "inherit"`, the panel fails closed with a diagnostic explaining that a concrete profile is required.
@ -298,7 +288,7 @@ If a role still uses `profile = "inherit"`, the panel fails closed with a diagno
- `profile = "inherit"`: configure a concrete role Profile in `.yoi/ticket.config.toml`.
- malformed `.yoi/ticket.config.toml`: fix the config and retry.
- missing Ticket id/slug for route, investigate, implement, or review actions: provide the target Ticket.
- missing Ticket id/slug for route, implement, or review actions: provide the target Ticket.
- launch success but no visible completion: attach to or inspect the launched Pod; completion notifications are hints, not authority.
## Granularity