wip(tickets): backend createdBy (#5) + bulk status/priority/delete (#6)

Ajoute created_by sur IssueIndexEntry/TicketSummaryDto + filtre createdBy
(#5), et les use cases BulkUpdateIssueStatus/Priority + BulkDeleteIssues
avec les DTO/outils MCP idea_ticket_bulk_* associés (#6).

NON VERT : BulkDeleteIssues::execute référence BatchIssueResult::deleted(),
constructeur pas encore ajouté à BatchIssueResult (seuls ok/err existent) ->
`cargo check` échoue (E0599 dans application::issues::mod). Reste à
DevBackend avant toute QA/merge.

Branché sur feature/sdk-integration (dépend du commit #2 dans
orchestrator/mcp/server.rs et tools.rs) ; à rebaser sur develop une fois
feature/sdk-integration mergé.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-28 18:28:39 +02:00
parent 1ef1fd9e40
commit 6da52c6a02
20 changed files with 1061 additions and 34 deletions

View File

@ -59,6 +59,9 @@ fn is_ticket_mutation_tool(tool: &str) -> bool {
"idea_ticket_update"
| "idea_ticket_update_status"
| "idea_ticket_update_priority"
| "idea_ticket_bulk_update_status"
| "idea_ticket_bulk_update_priority"
| "idea_ticket_bulk_delete"
| "idea_ticket_update_carnet"
| "idea_ticket_link"
| "idea_ticket_unlink"
@ -101,6 +104,17 @@ mod tests {
assert!(!policy.permits_ticket_mutation("idea_ticket_update", issue_ref("#8")));
}
#[test]
fn ticket_bulk_mutation_is_bound_to_the_configured_issue() {
let policy = AgentToolPolicy::new(
vec!["idea_ticket_bulk_delete".to_owned()],
Some(issue_ref("#7")),
true,
);
assert!(policy.permits_ticket_mutation("idea_ticket_bulk_delete", issue_ref("#7")));
assert!(!policy.permits_ticket_mutation("idea_ticket_bulk_delete", issue_ref("#8")));
}
#[test]
fn ticket_mutation_requires_the_tool_itself_to_be_allowed() {
let policy = AgentToolPolicy::new(

View File

@ -399,6 +399,9 @@ pub struct IssueIndexEntry {
pub sprint: Option<SprintId>,
/// Assigned agent ids.
pub assigned_agent_ids: Vec<AgentId>,
/// Actor that created the issue.
#[serde(default = "default_issue_actor_user")]
pub created_by: IssueActor,
/// Last update time.
pub updated_at: u64,
}
@ -418,11 +421,16 @@ impl From<&Issue> for IssueIndexEntry {
.filter(|r| r.role == AgentIssueRole::Assigned)
.map(|r| r.agent_id)
.collect(),
created_by: issue.created_by.clone(),
updated_at: issue.updated_at,
}
}
}
fn default_issue_actor_user() -> IssueActor {
IssueActor::User
}
/// Store-side list filter.
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct IssueListFilter {
@ -432,6 +440,8 @@ pub struct IssueListFilter {
pub priorities: Vec<IssuePriority>,
/// Optional assigned agent filter.
pub assigned_agent_id: Option<AgentId>,
/// Optional creator filter.
pub created_by: Option<IssueActor>,
/// Optional sprint membership filter.
pub sprint: Option<SprintId>,
/// Optional case-insensitive text query.