{
"meta": {
"agent": "planner",
"task_id": "555",
"title": "BJ-15: E2E harness — webhook clients + fixtures",
"created_at": "2026-04-23T17:15:37Z"
},
"inputs": [
{
"name": "issue",
"type": "link",
"ref": "https://github.com/AgentSDE/agent-core/issues/555",
"notes": "BJ-15 tracking issue in agent-core; implementation lands in agent-core-e2e"
},
{
"name": "dep_bj6",
"type": "link",
"ref": "https://github.com/AgentSDE/agent-core/issues/546",
"notes": "Defines BitbucketAdapter: URL-embedded ?secret=... + X-Event-Key + X-Request-UUID"
},
{
"name": "dep_bj7",
"type": "link",
"ref": "https://github.com/AgentSDE/agent-core/issues/547",
"notes": "Defines JiraAdapter: HMAC-SHA256 over raw body via X-Hub-Signature header"
},
{
"name": "template",
"type": "file",
"ref": "AgentSDE/agent-core-e2e:test/helpers/webhook-client.ts",
"notes": "Structural template — native fetch, crypto.createHmac, returns WebhookResponse"
}
],
"outputs": [
{
"name": "plan",
"type": "spec",
"format": "md",
"content": "plan.md"
},
{
"name": "stories",
"type": "spec",
"format": "json",
"content": "prd.json"
}
],
"files": [
{
"path": "agent-core-e2e/test/helpers/bitbucket-webhook-client.ts",
"action": "create",
"reason": "Helper exporting sendBitbucketWebhook(eventType, body)"
},
{
"path": "agent-core-e2e/test/helpers/jira-webhook-client.ts",
"action": "create",
"reason": "Helper exporting sendJiraWebhook(eventType, body)"
},
{
"path": "agent-core-e2e/test/fixtures/bitbucket/pr_created.json",
"action": "create",
"reason": "pullrequest:created fixture"
},
{
"path": "agent-core-e2e/test/fixtures/bitbucket/pr_updated.json",
"action": "create",
"reason": "pullrequest:updated fixture"
},
{
"path": "agent-core-e2e/test/fixtures/bitbucket/pr_approved.json",
"action": "create",
"reason": "pullrequest:approved fixture"
},
{
"path": "agent-core-e2e/test/fixtures/bitbucket/pr_merged.json",
"action": "create",
"reason": "pullrequest:fulfilled fixture"
},
{
"path": "agent-core-e2e/test/fixtures/bitbucket/pr_comment.json",
"action": "create",
"reason": "pullrequest:comment_created fixture"
},
{
"path": "agent-core-e2e/test/fixtures/bitbucket/push.json",
"action": "create",
"reason": "repo:push fixture"
},
{
"path": "agent-core-e2e/test/fixtures/jira/issue_created.json",
"action": "create",
"reason": "jira:issue_created fixture"
},
{
"path": "agent-core-e2e/test/fixtures/jira/issue_updated.json",
"action": "create",
"reason": "jira:issue_updated fixture with changelog"
},
{
"path": "agent-core-e2e/test/fixtures/jira/issue_deleted.json",
"action": "create",
"reason": "jira:issue_deleted fixture"
},
{
"path": "agent-core-e2e/test/fixtures/jira/comment_created.json",
"action": "create",
"reason": "comment_created fixture"
},
{
"path": "agent-core-e2e/test/smoke/bitbucket.smoke.e2e-spec.ts",
"action": "create",
"reason": "Smoke test verifying /webhooks/bitbucket returns 200 + dispatch"
},
{
"path": "agent-core-e2e/test/smoke/jira.smoke.e2e-spec.ts",
"action": "create",
"reason": "Smoke test verifying /webhooks/jira returns 200 + dispatch"
}
],
"steps": [
{
"id": "S1",
"summary": "Implement Bitbucket webhook client helper and the 4 PR-lifecycle fixtures (created/updated/approved/merged)",
"acceptance": [
"test/helpers/bitbucket-webhook-client.ts exports sendBitbucketWebhook(eventType, body) and POSTs to /webhooks/bitbucket?secret=... with X-Event-Key and X-Request-UUID headers",
"Helper reads BITBUCKET_WEBHOOK_SECRET from env and throws clear error when unset",
"Fixtures pr_created/pr_updated/pr_approved/pr_merged exist under test/fixtures/bitbucket/ and parse as valid JSON",
"Each fixture contains minimum fields BitbucketAdapter.normalize() reads (pullrequest.id, repository.full_name, actor.nickname)"
],
"depends_on": []
},
{
"id": "S2",
"summary": "Add Bitbucket pr_comment + push fixtures and a Bitbucket smoke test under test/smoke/",
"acceptance": [
"pr_comment.json and push.json exist under test/fixtures/bitbucket/ and parse as valid JSON",
"test/smoke/bitbucket.smoke.e2e-spec.ts loads one fixture, calls sendBitbucketWebhook, asserts status === 'dispatched'",
"Smoke test passes against a local agent-core instance with BJ-6 merged"
],
"depends_on": [
"S1"
]
},
{
"id": "S3",
"summary": "Implement Jira webhook client helper and the 4 Jira fixtures",
"acceptance": [
"test/helpers/jira-webhook-client.ts exports sendJiraWebhook(eventType, body) and signs the raw JSON body with HMAC-SHA256 under X-Hub-Signature: sha256=<hex>",
"Helper reads JIRA_WEBHOOK_SECRET from env and throws clear error when unset",
"Fixtures issue_created/issue_updated/issue_deleted/comment_created exist under test/fixtures/jira/ and parse as valid JSON",
"Each fixture includes webhookEvent and the minimum issue/comment/changelog fields JiraAdapter.normalize() reads"
],
"depends_on": []
},
{
"id": "S4",
"summary": "Add a Jira smoke test under test/smoke/ that verifies the end-to-end dispatch",
"acceptance": [
"test/smoke/jira.smoke.e2e-spec.ts loads one fixture, calls sendJiraWebhook, asserts status === 'dispatched'",
"Smoke test passes against a local agent-core instance with BJ-7 merged"
],
"depends_on": [
"S3"
]
}
],
"risks": [
{
"risk": "BJ-6/BJ-7 server adapters unmerged when smoke tests run",
"mitigation": "Plan assumes dependencies are merged; if not, smoke tests fail loudly (404/401) rather than silently skip"
},
{
"risk": "Fixture payloads too minimal to satisfy adapter normalize() field reads",
"mitigation": "Implementer cross-references adapter source on rc/atlassian-integration when authoring fixtures; expand only on real failures"
}
],
"assumptions": [
"rc/atlassian-integration branch does not yet exist in agent-core-e2e; implementer creates it from main",
"The agent-core-e2e test:smoke Jest config picks up files under test/smoke/ or test/**/*.smoke.e2e-spec.ts",
"BITBUCKET_WEBHOOK_SECRET and JIRA_WEBHOOK_SECRET env vars mirror the agent-core config and are available to the test runner"
],
"open_questions": [
"Use real documented Bitbucket/Jira webhook sample bodies or the minimum shape normalize() requires? Plan favours minimum-viable."
]
}