{
"meta": {
"agent": "planner",
"task_id": "551",
"title": "BJ-11: Tenant config routing — platform → service triple",
"created_at": "2026-04-23T17:12:58Z"
},
"inputs": [
{
"name": "issue",
"type": "link",
"ref": "AgentSDE/agent-core#551",
"notes": "Wave 3 prerequisite for Bitbucket/Jira dispatch routing"
},
{
"name": "epic",
"type": "link",
"ref": "AgentSDE/agent-core#539",
"notes": "Atlassian integration EPIC"
},
{
"name": "AGENTS.md",
"type": "context",
"ref": "src root",
"notes": "Multi-tenant consumer migration rules (3-layer update)"
}
],
"outputs": [
{
"name": "plan.md",
"type": "spec",
"format": "md",
"content": "See plan.md"
}
],
"files": [
{
"path": "src/tenant/platform-services.ts",
"action": "create",
"reason": "PLATFORM_SERVICES injection token + PlatformServicesMap type"
},
{
"path": "src/tenant/tenant-config.service.ts",
"action": "modify",
"reason": "Add getPlatformServices(platform) returning {adapter, service, authProvider}"
},
{
"path": "src/tenant/tenant-config.service.spec.ts",
"action": "create",
"reason": "Unit tests for new method: happy path, unknown platform, missing platform"
},
{
"path": "src/tenant/tenant.module.ts",
"action": "modify",
"reason": "Register PLATFORM_SERVICES provider and expose AdapterRegistry"
},
{
"path": "src/phase-router/phase-router.service.ts",
"action": "modify",
"reason": "Resolve service via tenant config; drop direct GitHubService import"
},
{
"path": "src/phase-router/phase-router.service.spec.ts",
"action": "modify",
"reason": "Swap GitHubService mock for TenantConfigService stub"
},
{
"path": "src/hooks/phase-hooks.service.ts",
"action": "modify",
"reason": "Same refactor as phase-router"
},
{
"path": "src/hooks/phase-hooks.service.spec.ts",
"action": "modify",
"reason": "Swap GitHubService mock for TenantConfigService stub"
},
{
"path": "src/hooks/compound.service.ts",
"action": "modify",
"reason": "Same refactor as phase-router"
},
{
"path": "src/hooks/compound.service.spec.ts",
"action": "modify",
"reason": "Swap GitHubService mock for TenantConfigService stub"
}
],
"steps": [
{
"id": "S1",
"summary": "Add PLATFORM_SERVICES token and getPlatformServices() method on TenantConfigService",
"acceptance": [
"PLATFORM_SERVICES token exported from src/tenant/platform-services.ts",
"getPlatformServices('github') returns {adapter, service, authProvider} triple",
"Unknown platform throws NotFoundException; missing/empty platform throws BadRequestException",
"TenantModule registers PLATFORM_SERVICES as {github: GitHubService} and exposes AdapterRegistry",
"Unit tests cover happy path, unknown platform, and missing platform cases"
],
"depends_on": []
},
{
"id": "S2",
"summary": "Refactor PhaseRouterService, PhaseHooksService, CompoundService to resolve service via tenant config",
"acceptance": [
"No `from '../github/github.service'` or `from '../github'` imports remain in phase-router/ or hooks/ dispatch-path files",
"Each consumer injects TenantConfigService and calls getPlatformServices(platform).service",
"Existing GitHub method calls continue to work (typed via platform service map)",
"All three specs updated: inject TenantConfigService stub returning a triple; all tests pass",
"npm run lint passes with zero warnings; npm run test passes"
],
"depends_on": [
"S1"
]
}
],
"risks": [
{
"risk": "AdapterRegistry lives in WebhookModule — importing it into TenantModule may cause a circular dependency",
"mitigation": "If circular, promote AdapterRegistry to src/platform/ as a shared module in this PR"
},
{
"risk": "PlatformProvider interface is minimal; dispatch consumers call many GitHubService-specific methods",
"mitigation": "Type the service key in PLATFORM_SERVICES as the concrete service per platform (e.g. GitHubService for 'github'); PlatformProvider expansion is deferred to sibling Wave 3 tickets"
}
],
"assumptions": [
"Base branch for the PR is `rc/atlassian-integration` (issue body states this)",
"`event.source` on the queue DispatchEvent carries the platform name (it is populated from webhook `platform` field)",
"Default platform when not specified on PhaseTask is 'github' for now"
],
"open_questions": [
"Should PhaseTask gain a `platform` field in this PR, or defer and hard-default to 'github'?"
]
}