fix: complete query and workflow alias cutover

This commit is contained in:
2026-08-17 06:35:24 +09:00
parent 7508d428b0
commit 45b7d0764d
3 changed files with 44 additions and 21 deletions
+3 -4
View File
@@ -70,11 +70,10 @@ Intake は以下を行う。
利用可能なら、以下の typed Ticket tools を使う。
- `TicketList`: 既存 Ticket の一覧・重複確認。
- `TicketShow`: 関連 Ticket の詳細確認。
- `QueryTicket`: 既存 Ticket の一覧・重複確認。
- `ShowTicket`: 関連 Ticket の詳細確認。
- `TicketCreate`: 合意済み Ticket の作成。
- `TicketComment`: 既存 Ticket refinement / decision / plan の記録。
- `TicketDoctor`: 必要に応じた整合性確認。
Intake は `MergeRequest*`, `TicketWorkflowState`, `TicketClose` を通常使わない。review authority は assigned Coder が起動した read-only direct-child Reviewer の immutable Merge Request attempt に属し、completion / merge / close は各guarded workflowの責務である。
@@ -96,7 +95,7 @@ Ticket tools が利用できない環境では、勝手に file write で代替
### 2. 既存 Ticket を確認する
`TicketList` / `TicketShow` で duplicate / related work を探す。
`QueryTicket` / `ShowTicket` で duplicate / related work を探す。
確認観点:
+10 -10
View File
@@ -36,8 +36,8 @@ TicketCreate / TicketComment
Orchestrator は以下を行う。
- Ticket を `TicketShow` で読む。
- 必要に応じて関連 Ticket を `TicketList` / `TicketShow` で確認する。
- Ticket を `ShowTicket` で読む。
- 必要に応じて関連 Ticket を `QueryTicket` / `ShowTicket` で確認する。
- Ticket body / thread / artifacts / resolution / review / implementation report を読む。
- Ticket が Objective context と結びついている場合は、Objective を medium-term goal / motivation / strategy / success criteria / decision context として読む。ただし Objective context は判断背景であり、Ticket body/thread/artifacts や explicit Ticket relations / OrchestrationPlan records を読む代替ではない。
- repository 状態、関連 docs/code、既存 worktree、visible Pods を必要に応じて明示的に確認する。
@@ -73,21 +73,21 @@ Orchestrator は以下を行う。
利用可能なら、以下を使う。
- `TicketList`: routing 候補関連 Ticket の確認
- `TicketShow`: 対象 Ticket の body / thread / artifacts / resolution / typed relation metadata と derived inverse/blocker view を確認。
- `QueryTicket`: routing 候補関連 Ticket、project-level forward relation (`depends_on` / `blocks` / `related` / `supersedes` / `duplicate_of`) と derived blocker summary を bounded filter/projection で確認する。`depends_on` と incoming unresolved `blocks` は queue/acceptance blocker であり、`related` は blocker ではない。`supersedes` / `duplicate_of` は visible diagnostic として扱い、自動的な lifecycle 変更や scheduler 判断にはしない
- `ShowTicket`: 対象 Ticket の body / thread / artifacts / resolution / typed relation metadata、linked Objective、assignment、implementation/review evidence を確認する
- `TicketComment`: routing decision / intent packet / blocked reason / next question の記録。
- `TicketWorkflowState`: `queued -> inprogress` acceptance、`inprogress -> done`、または concrete missing decision/information reason を伴う `ready|queued -> planning` に使う。
- `TicketRelationQuery`: project-level の forward relation (`depends_on` / `blocks` / `related` / `supersedes` / `duplicate_of`) を読む。`depends_on` と incoming unresolved `blocks` queue/acceptance blocker であり、`related` は blocker ではない。`supersedes` / `duplicate_of` は visible diagnostic として扱い、自動的な lifecycle 変更や scheduler 判断にはしない
- `TicketDependencyCheck`: queue/acceptance 直前の typed dependency readiness guard に使う
- `TicketRelationRecord` / `TicketRelationRemove`: ユーザー合意済みの durable project relation を明示的に更新する場合だけ使う。
- `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 変更ではない。
- `TicketClose`: 完了権限と resolution が揃っている場合だけ使う。
- `TicketDoctor`: routing 前後の整合性確認。
`TicketCreate` は通常 Intake の責務だが、routing 中に follow-up Ticket が必要だと判断した場合は、ユーザー/上位 Orchestrator の合意後にだけ使う。
## Queued acceptance contract
- `queued -> inprogress` acceptance の直前に `TicketShow` / `TicketRelationQuery` の relation blockers を再確認する。unresolved `depends_on` や incoming unresolved `blocks` が残る場合は implementation side effect を始めず、理由を thread に残して `planning` へ戻すか blocked diagnostic として停止する。
- `queued -> inprogress` acceptance の直前に `ShowTicket` / `QueryTicket` の relation blocker projection を再確認する。unresolved `depends_on` や incoming unresolved `blocks` が残る場合は implementation side effect を始めず、理由を thread に残して `planning` へ戻すか blocked diagnostic として停止する。
- Relation metadata は project-level constraint であり、OrchestrationPlan は runtime ordering/capacity decision である。relation を OrchestrationPlan で代替しないし、OrchestrationPlan を durable dependency authority として扱わない。
`state = queued` は、Ticket が routing 対象として人間により Orchestrator へ渡された状態である。Orchestrator は queued notification を受けたら、Ticket、workspace state、対象 Ticket の `TicketOrchestrationPlanQuery` 記録、risk domain に応じた bounded project context を読んで、次のどちらかを行う。
@@ -100,7 +100,7 @@ Orchestrator は以下を行う。
Parallel acceptance pass:
- 明示的な queue review 中に複数の queued Ticket が見える場合、Orchestrator は最初の1件の完了待ちを default にしない。各 Ticket について Ticket body/thread/artifacts、TicketRelationQuery、TicketOrchestrationPlanQuery、workspace/worktree dirty state、visible Pods、既存 branches、conflict/dependency notes を確認する。
- 明示的な queue review 中に複数の queued Ticket が見える場合、Orchestrator は最初の1件の完了待ちを default にしない。各 Ticket について Ticket body/thread/artifacts、QueryTicket の relation/blocker projection、TicketOrchestrationPlanQuery、workspace/worktree dirty state、visible Pods、既存 branches、conflict/dependency notes を確認する。
- 追加で開始してよいのは、blocking relation/dependency がなく、`do_not_parallelize` または applicable conflict record がなく、source/write surfaces が disjoint または conflict risk が小さく機械的で、coder/reviewer follow-up capacity があり、acceptance basis となる Ticket thread/plan/workspace records を side effect 前に記録・commit でき、別 worktree/branch/scope を切れる Ticket だけである。
- capacity が見えるのに queued Ticket を idle にする場合は、dependency / conflict / capacity / missing planning decision / dirty workspace / reviewer-coder bottleneck / migration boundary / human gate のいずれかの bounded reason を記録する。
- この pass は scheduler、background runner、resource graph solver、automatic queue drain loop ではない。unqueued Ticket を開始せず、各 Ticket の `queued -> inprogress` acceptance を個別に記録する。
@@ -269,8 +269,8 @@ Action:
### 1. 状態確認
- `git state --short --branch`
- `TicketShow <target>`
- 関連 Ticket の `TicketList` / `TicketShow`
- `ShowTicket <target>`
- 関連 Ticket の `QueryTicket` / `ShowTicket`
- 必要に応じて docs/code/workflow/history
- 必要に応じて visible Pods / worktrees / branches
+31 -7
View File
@@ -510,7 +510,8 @@ impl ObjectiveAuthority for SqliteWorkspaceAuthority {
objectives.truncate(1_000);
let mut items = Vec::new();
for objective in objectives {
if !objective_matches_query(&objective, &query) {
let body_md = self.objective_record(&objective.id)?.body_md;
if !objective_matches_query(&objective, &body_md, &query) {
continue;
}
let linked_tickets = self
@@ -530,6 +531,7 @@ impl ObjectiveAuthority for SqliteWorkspaceAuthority {
objective,
linked_tickets,
query.query.as_deref(),
&body_md,
));
}
sort_objective_query_items(&mut items, sort);
@@ -1465,7 +1467,11 @@ fn ticket_item_after_cursor(
}
}
fn objective_matches_query(objective: &ObjectiveSummary, query: &ObjectiveQueryRequest) -> bool {
fn objective_matches_query(
objective: &ObjectiveSummary,
body_md: &str,
query: &ObjectiveQueryRequest,
) -> bool {
if !query.states.is_empty() && !query.states.iter().any(|state| state == &objective.state) {
return false;
}
@@ -1482,8 +1488,7 @@ fn objective_matches_query(objective: &ObjectiveSummary, query: &ObjectiveQueryR
}
query.query.as_ref().is_none_or(|text| {
let needle = text.to_lowercase();
objective.title.to_lowercase().contains(&needle)
|| objective.summary.to_lowercase().contains(&needle)
objective.title.to_lowercase().contains(&needle) || body_md.to_lowercase().contains(&needle)
})
}
@@ -1491,6 +1496,7 @@ fn objective_query_item(
objective: ObjectiveSummary,
linked_tickets: Vec<String>,
text: Option<&str>,
body_md: &str,
) -> ObjectiveQueryItem {
let mut matched_fields = Vec::new();
let mut snippet = None;
@@ -1500,9 +1506,9 @@ fn objective_query_item(
matched_fields.push("title".to_string());
snippet = Some(objective.title.clone());
}
if objective.summary.to_lowercase().contains(&needle) {
if body_md.to_lowercase().contains(&needle) {
matched_fields.push("body".to_string());
snippet.get_or_insert_with(|| matching_snippet(&objective.summary, text));
snippet.get_or_insert_with(|| matching_snippet(body_md, text));
}
}
ObjectiveQueryItem {
@@ -1791,7 +1797,10 @@ mod tests {
objective_id: "00000000001J3".to_string(),
title: "Control plane".to_string(),
state: "active".to_string(),
body_md: "Objective body.\n".to_string(),
body_md: format!(
"Objective body. {}\n\nDeep objective marker.\n",
"x".repeat(300)
),
created_at: "2026-01-01T00:00:00Z".to_string(),
updated_at: "2026-01-02T00:00:00Z".to_string(),
})
@@ -1892,6 +1901,21 @@ mod tests {
assert_eq!(objective_query.items.len(), 1);
assert_eq!(objective_query.items[0].linked_ticket_count, 1);
assert_eq!(objective_query.page.limit, 1);
let body_query = authority
.query_objectives(ObjectiveQueryRequest {
query: Some("Deep objective marker".to_string()),
limit: Some(1),
..ObjectiveQueryRequest::default()
})
.unwrap();
assert_eq!(body_query.items.len(), 1);
assert_eq!(body_query.items[0].matched_fields, vec!["body"]);
assert!(
body_query.items[0]
.snippet
.as_deref()
.is_some_and(|snippet| snippet.contains("Deep objective marker"))
);
let memory = authority.ensure_memory_document().unwrap();
assert_eq!(memory.body_md, DEFAULT_MEMORY_DOCUMENT_BODY);
let updated = authority