# Jira Internal Comment Multi-turn Continuation

## Original Design

- The active Jira poller discovers newly created, non-Done issues and enqueues one
  `initial` job per issue and trigger version.
- The worker applies the L1 Oncaller Gate and Auto Coverage Gate, creates a live
  workspace, starts a new Codex thread, and writes one idempotent Jira internal
  comment.
- The Codex thread ID is written only to workspace trace files. It is not stored
  in the database and cannot currently be selected by a later Jira event.
- Jira internal comments are already fetched through the paginated JSM comment
  API, but no poller treats an internal comment as an analysis trigger.
- Staging persists `CODEX_HOME` on a PVC. Prod uses an `emptyDir`, has automation
  disabled, and cannot safely promise resume across Pod restarts.

## Data and State Flow

1. Jira is the canonical source for comment ID, visibility, author, body, and ADF
   mention nodes.
2. A continuation poll cursor selects recently updated issues, including Done
   issues and issues outside the autonomous initial allowlist. The poller joins
   paginated JSM comment metadata with paginated Jira platform ADF comments.
3. A comment is eligible only when it is internal, authored by someone other
   than the authenticated bot, and contains an exact ADF mention of that bot's
   Jira account ID.
4. `auto_oncall_jobs` is the canonical queue. One source comment ID maps to at
   most one `continuation` job.
5. `auto_oncall_conversations` is the canonical issue-to-Codex-thread mapping.
   A continuation resumes that thread when present. If an initial diagnostic
   preflight created no thread, it starts one bounded thread from the canonical
   Jira timeline and persists the resulting mapping.
6. After exact trigger validity checks, the explicit continuation bypasses Done,
   the autonomous issue allowlist, L1 Oncaller, and Enabled Coverage filtering,
   classifies the case for safety/audit context, materializes the complete Jira
   timeline through the trigger, and passes that bounded context as the new
   Codex turn input.
7. One source comment maps to one idempotent bot response comment. Retries update
   that response by its stored Jira comment ID and never overwrite the initial
   response or another turn.
8. `auto_oncall_runs` remains the immutable execution/delivery audit source.
   Daily reports and initial-answer comparisons continue to read only `initial`
   jobs.

## Risks

- Plain-text `@name` matching can be spoofed or collide with renamed users; only
  structured ADF mention account IDs are accepted.
- The issue `comment` field can be truncated; both comment APIs must be paginated
  instead of relying on the issue snapshot.
- Timestamp cursors have race and precision boundaries; polling uses overlap and
  DB uniqueness by source comment ID for correctness.
- A missing conversation row is distinct from an invalid persisted thread. Only
  the former may start a bounded thread; resume failures remain explicit job
  failures rather than silently replacing a known conversation.
- Codex execution, DB persistence, and Jira writes are separate transactions.
  The design provides durable idempotency for job creation and Jira delivery but
  does not claim exactly-once model execution across a process crash.
- Bot-authored comments must never trigger another continuation loop.

## Target Contract and Invariants

- Continuation is enabled only when automation is active and
  `AUTO_ONCALL_CONTINUATION_ENABLED=true`.
- Continuation discovery includes recently updated Done issues and ignores the
  autonomous initial issue allowlist.
- The authenticated Jira user's account ID is the sole bot mention identity.
- Only `public=false` comments with an exact structured mention trigger a job.
- `source_comment_id` is required for continuation jobs and forbidden for
  initial jobs.
- The trigger body has an explicit byte limit and is stored only in the bounded
  continuation workspace input, not copied into reports or notification bodies.
- A read/poll path never creates or repairs a Codex conversation.
- `resumeThread` is used whenever a persisted conversation exists. If the
  initial diagnostic preflight produced no Codex thread, continuation may start
  one thread from the canonical bounded Jira timeline and persist it. There is
  no display-name, body-regex, or truncated issue-comment fallback.
- One continuation trigger creates a new internal response. Initial comment
  idempotency remains `auto-live:v1:<issueKey>:initial`; continuation idempotency
  is `auto-live:v1:<issueKey>:continuation:<sourceCommentId>`.
- Customer-visible comments, issue transitions, production operations, and prod
  automation remain unchanged.

## Implementation Steps

1. Extend Jira comment fetching with paginated ADF mention extraction and add a
   cached authenticated-user lookup.
2. Add continuation config, JQL/cursor handling, deterministic eligibility, and
   per-comment job enqueueing.
3. Extend job/store contracts with continuation source metadata and add the
   canonical issue-to-thread conversation table.
4. Persist the initial Codex thread ID, add a bounded continuation workspace and
   prompt, and execute later turns with `Codex.resumeThread`.
5. Validate exact continuation triggers, bypass autonomous L1/Coverage filtering,
   write a distinct idempotent internal reply, and keep initial
   reports/comparisons unchanged.
6. Enable continuation only in the staging source template; leave prod disabled.

## Verification Checklist

- [x] Exact internal ADF mention enqueues one continuation job.
- [x] Exact internal ADF mention on a Done issue bypasses the Done filter and
      autonomous issue allowlist.
- [x] Public comments, text-only `@name`, other-account mentions, bot-authored
      comments, empty comments, and oversized comments do not enqueue jobs.
- [x] Repeated/overlapping polls do not duplicate a source comment job.
- [x] Multiple eligible comments on one issue create ordered independent jobs.
- [x] Initial analysis persists its Codex thread ID as the conversation source.
- [x] Continuation calls `resumeThread` when a persisted thread exists.
- [x] Missing initial thread starts one bounded continuation thread and persists
      it for later turns.
- [x] Retry uses the same continuation Jira response mapping and never creates a
      second response or updates the initial response.
- [x] Continuation workspace contains the complete ordered Jira timeline through
      the trigger and excludes comments after it.
- [x] Empty/missing fields and large payload limits are covered locally.
- [x] Daily reports and answer comparisons exclude continuation jobs.
- [x] `npm run typecheck`, focused tests, full `npm test`, and
      `git diff --check` pass before deployment.

## Out of Scope

- No webhook receiver, Jira Automation rule, customer-visible reply, issue
  transition, ticket close, or production operation.
- No fallback from missing structured mention metadata to display-name or body
  matching.
- No reconstruction of old Codex messages when a persisted thread exists.

The live-context and missing-thread recovery changes are tracked in
`docs/plans/2026-07-15-live-comment-context-and-continuation-recovery.md`.
- No prod cutover or prod storage-model change.
