feat: comments marked as decisions, on top of the ticket and searchable

Whoever can change the ticket flags a comment as a decision (new event
CommentDecisionMarkedEvent on the comment). The ticket page lists its
decisions above the description, with a link to the comment in the
conversation (`?comment=<id>` scrolls to it and points at it), and the
search palette finds them by their text across my projects.

API: markDecision / PUT-DELETE /api/comments/{id}/decision; Issue.decisions
and GET /api/issues/{issue}/decisions; decisions(projectId?, search) and
GET /api/projects/{project}/decisions, GET /api/me/decisions. MCP:
mark_decision, search_decisions, and get_issue includes them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-17 11:32:07 +02:00
parent 8f83fdefb6
commit 70e4fbd399
45 changed files with 2515 additions and 84 deletions

View File

@@ -270,6 +270,13 @@ type Comment {
"""Empty on a deleted comment kept for its replies"""
body: String!
createdAt: String!
decidedAt: String
"""Who marked it as a decision"""
decidedBy: UserRef
"""Marked as a decision of the ticket (shown above it)"""
decision: Boolean!
"""Deleted, but kept (without its text) while it has replies"""
deleted: Boolean!
@@ -475,6 +482,12 @@ type DashboardShare {
token: String!
}
"""A comment marked as a decision, with its ticket"""
type Decision {
comment: Comment!
issue: IssueParent!
}
"""A commit, branch or pull request that mentions the ticket"""
type DevLink {
at: String!
@@ -640,6 +653,9 @@ type Issue {
"""Values of the project's custom fields (only those set)"""
customFields: [CustomFieldValue!]!
"""Its comments marked as decisions, oldest first"""
decisions: [Comment!]!
description: String
"""Commits, branches and pull requests that mention it"""
@@ -973,6 +989,11 @@ type Mutation {
"""Relate tickets, e.g. FE DEPENDS_ON BE, QA TESTS FE"""
linkIssues(input: LinkIssuesInput!): CommandResult!
"""
Mark a comment as a decision of its ticket, or unmark it (on: false). Whoever can change the ticket
"""
markDecision(commentId: ID!, on: Boolean! = true): CommandResult!
"""Mark these as read, or all of them when `ids` is omitted"""
markNotificationsRead(ids: [ID!]): Boolean!
@@ -1491,6 +1512,11 @@ type Query {
"""The project's link for clients, if any (owners and admins)"""
dashboardShare(projectId: ID!): DashboardShare
"""
Decisions by their text, most recent first: of a project, or of all my projects without one
"""
decisions(limit: Int! = 20, projectId: ID, search: String): [Decision!]!
"""
A project's epics: top-level tickets that group others, with the progress of those
"""