Skip to content

Jira poll adapter (NormalizedEvent extension) ​

Poll input driver mapping for Jira work items, defined in ADR 0063. This document extends NormalizedEvent v1 for jira-poll input drivers until the changes are merged into normalized-event.schema.json.

Scope ​

  • In scope: Jira issues polled by fullsend poll --input-driver jira-poll. Events use entity.kind: work_item only.
  • Out of scope: Jira webhooks, Service Desk, sprint/board events, and forge change-proposal routing (e.g. /fs-fix) — those stages require a change_proposal entity and are triggered from forge webhooks or poll drivers on the code repo, not from Jira issue comments alone.

Schema extensions ​

The following fields are defined in normalized-event.schema.json:

FieldDefinition
source.systemEnum includes jira
entity.keyOptional for GitHub; required when source.system is jira

When source.system is jira, entity.key MUST be present (e.g. PROJ-123).

Top-level fields ​

FieldJira poll value
repoTarget repo slug from poll context (GITHUB_REPOSITORY or config).
source.systemjira
source.raw_typeNative Jira object: issue, comment, changelog
source.raw_actionNative action when applicable: created, updated, deleted
entity.kindwork_item
entity.idJira numeric issue id (fields or search result id)
entity.keyIssue key (PROJ-123)
entity.urlBrowse URL ({base}/browse/{key})
entity.linked_change_proposalOmitted — Jira poll emits work-item events only
actorComment/changelog author (see below)
transitionMapped semantic transition (see below)
state.labelsCurrent Jira label names at event time

Transition mapping ​

Jira signaltransition.kindSub-fields
Issue createdopened—
Issue reopenedreopened—
Summary/description/fields updatededited—
Label addedlabel_changedlabel.name, label.action: added
Label removedlabel_changedlabel.name, label.action: removed
Comment addedcomment_addedcomment.body, optional command / instruction
Issue closedclosed—

Comment parsing matches the gha-event adapter: command is the first whitespace-delimited token of the first line; instruction is the remainder of the first line after the command (same rules as README — execution ref projection).

Actor mapping ​

ADR 0107 target contract — not yet implemented: The bot-role and role_verified rows describe the post-migration adapter output. Current Jira polling remains on its existing compatibility path until the resolver is integrated.

FieldSource
actor.idJira accountId (preferred) or name when accountId unavailable
actor.kindFor the target adapter contract, bot only when Jira's authoritative account metadata identifies an app or the adapter configuration identifies the authenticated poller as a verified service identity; otherwise human. A display-name automation pattern alone is insufficient. The current compatibility poller may retain its legacy heuristics until it adopts the ADR 0107 target implementation.
actor.rolenone for target bots; for humans, derived from the actor's Jira project role: admin for Administrators, write for Developers, read for other named project roles, external when the actor does not hold any project role. Cross-system identity resolution (Jira user → GitHub user → repo permission) is not performed; the Jira project is the authorization boundary for Jira-sourced events.
actor.bot_roleProvider lookup of the verified bot identity; the canonical Fullsend role when recognized, otherwise null
actor.role_verifiedtrue when bot-role or Jira project-role lookup completed, including a no-match result; false when resolution failed
actor.is_entity_authortrue when actor is the issue reporter

Authorization is enforced by fullsend dispatch per ADR 0054after normalization. The poll loop does not bypass the gate.

State ​

  • state.labels — label names from fields.labels at event time.
  • state.change_proposal — omitted. Change-proposal stages (fix, PR-linked review, merge retro) are forge-scoped; harness CEL triggers for those stages MUST require entity.kind == 'change_proposal' or equivalent guards.

Execution ref projection ​

When source.system is jira, projection supplements the GitHub-shaped event_payload fields:

Execution ref / envSource
FULLSEND_WORK_ITEM_URLentity.url
FULLSEND_WORK_ITEM_SOURCEjira
FULLSEND_WORK_ITEM_KEYentity.key
ISSUE_NUMBEROmit or empty — a Jira key is not a GitHub issue number
event_payload.commenttransition.comment when present
GITHUB_ISSUE_URLOmit or empty — not a GitHub issue
status-numberentity.id (numeric Jira id)

Harnesses and pre-scripts that require forge-agnostic work item URLs SHOULD use FULLSEND_WORK_ITEM_* rather than forge-specific variables like GITHUB_ISSUE_URL. The dispatch workflow sets FULLSEND_WORK_ITEM_URL and FULLSEND_WORK_ITEM_KEY from the normalized entity for Jira events. For forge-native events, the generic key and ISSUE_NUMBER carry the same value.

Example ​

Issue comment with slash command:

json
{
  "repo": "acme/platform",
  "source": {
    "system": "jira",
    "raw_type": "comment",
    "raw_action": "created"
  },
  "entity": {
    "kind": "work_item",
    "id": 10042,
    "key": "PROJ-123",
    "url": "https://acme.atlassian.net/browse/PROJ-123"
  },
  "actor": {
    "id": "557058:abc123def456",
    "kind": "human",
    "role": "write",
    "is_entity_author": false
  },
  "transition": {
    "kind": "comment_added",
    "comment": {
      "command": "/fs-triage",
      "body": "/fs-triage check acceptance criteria",
      "instruction": "check acceptance criteria"
    }
  },
  "state": {
    "labels": ["needs-info", "bug"]
  }
}

CEL triggers ​

Harness trigger expressions use the same event root variable as GitHub events. Example:

yaml
trigger: event.source.system == 'jira' && event.transition.kind == 'comment_added' && event.transition.comment.command == '/fs-triage'

Routing logic lives on harness files per ADR 0061, not in poll config.