You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(jira): post final status comments with cost, turns, and duration (#573) (#603)
* feat(jira): post final status comments with cost, turns, and duration (#573)
Mirror the Linear final-status fan-out for Jira. Jira-origin terminal
tasks now get a deterministic platform-side comment with outcome, cost,
turns, duration, task id, and the PR link — posted by the fan-out plane,
not the agent, so it fires even when the agent crashes before completing
(max-turns, OOM).
- fanout: add `jira` NotificationChannel + CHANNEL_DEFAULTS (terminal
events + task_timed_out) + `dispatchToJira`, structurally mirroring
`dispatchToLinear` (env guard -> load task -> channel_source gate ->
metadata read -> post-once marker -> post). New renderer
`renderJiraFinalStatusComment` emits ADF paragraphs with the same
three-outcome framing (completed / shipped-but-stopped / failed); the
PR link renders on the success path too (Jira has no other surviving
PR-link surface once the agent terminal comment is demoted).
- jira-feedback: add `buildAdfDocument` (multi-paragraph ADF with
strong/em marks) + `postIssueCommentAdf` returning a classified
`JiraPostResult` (retryable vs terminal), reusing the 401 forced-
refresh-and-retry-once path. `postIssueComment` keeps its boolean API.
- TaskRecord: add `jira_final_comment_event_id` post-once marker;
TaskNotificationsConfig gains a `jira` channel.
- construct/stack: wire JiraWorkspaceRegistryTable +
`bgagent-jira-oauth-*` Get/Put grant into FanOutConsumer (guarded).
- agent: demote the Jira terminal comment — remove
`comment_task_finished` and its two pipeline call sites so fanout owns
the terminal comment (no double-post); keep the start comment.
- docs: update JIRA_SETUP_GUIDE for the platform-side final comment.
Tests: fanout Jira success / failure / shipped-but-stopped / timed_out /
missing-metadata / non-Jira skip / idempotent retry / retryable escalation
/ marker persistence / missing-env; ADF builder + classified post result;
construct grant guards; agent terminal-comment-demoted guard.
* feat(jira): render the PR link in the final-status comment as a clickable hyperlink
ADF — unlike Linear's Markdown — does not auto-linkify a bare URL in a
plain text node, so the PR link in the Jira final-status comment rendered
as unclickable text the requester had to copy-paste.
Add an optional `href` to `AdfTextRun`; `buildAdfDocument` maps it to an
ADF `link` mark (composes with strong/em). The Jira final-status renderer
splits the PR line into a "PR: " label run + a URL run carrying `href`, so
it renders as a real hyperlink on both the ✅ and ⚠️ paths.
Tests: buildAdfDocument link-mark emission + href/strong composition;
renderer asserts the URL run carries the href.
* fix(jira): address #603 review — reframe ✅ PR-link rationale, humanize task_timed_out header, match Linear bold scope
Review feedback on #603 (all from isadeks' approve-with-notes):
1. Drop the "diverges from Linear" framing for rendering the PR link on
the ✅ success path. The real reason is general (ABCA-584): the agent's
own "PR opened" comment isn't guaranteed to fire, so the platform
comment must always carry the link. #601 lands the same fix for Linear,
so this is no longer a Jira-specific divergence — reframed the docstring
+ renamed the test accordingly to avoid a stale-comment / semantic
merge conflict with #601.
2. Humanize the ❌ header subtype: strip `task_` AND turn underscores into
spaces so `task_timed_out` renders "Task timed out", not the raw
"Task timed_out". Jira is the only channel routing task_timed_out
through this renderer, so it's a case the copied-from-Linear code never
hit. Added a test.
4. Match Linear's ⚠️ bold scope: bold only through the reason and leave
the trailing "— review and decide…" advice unbolded (two runs), instead
of bolding the whole header. Added a test.
(#3 — adding task_timed_out to CHANNEL_DEFAULTS.linear for parity — is an
optional follow-up the reviewer flagged as out of scope; tracked separately.)
---------
Co-authored-by: Sphia Sadek <isadeks@gmail.com>
0 commit comments