feat(mcp): add provider-neutral change request tools (#3671)
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# ADR-2026-09-14-provider-neutral-change-request-mcp: Share the change request MCP contract
|
||||
|
||||
**Status:** accepted
|
||||
**Date:** 2026-09-14
|
||||
**Area:** backend, protocol, integrations
|
||||
**Introducing release:** 0.95.0 (planned)
|
||||
|
||||
## Context
|
||||
|
||||
PR #3506 introduced shared association services under PR-named MCP tools.
|
||||
Automation tools still split by provider, while their operations largely overlap.
|
||||
GitLab supports automation but lacks GitHub's server-bound outcome protocol.
|
||||
Both providers store custom prompts per task and switches per association.
|
||||
|
||||
## Decision
|
||||
|
||||
Use four tools: read change requests, manage an association, update automation,
|
||||
and report a dispatched auto-fix outcome. Keep outcome reporting separately bound
|
||||
to server execution identity. Report actual capabilities for each provider.
|
||||
|
||||
Use `provider`, canonical `repository_id`, and `number` for contribution identity.
|
||||
Require an explicit automation target. Task targets require a provider list.
|
||||
Prompts remain task/provider settings, and association targets reject prompt changes.
|
||||
Cross-provider automation reports partial application without a shared transaction.
|
||||
Keep provider services and stores behind the shared MCP contract.
|
||||
|
||||
Remove legacy MCP names at cutover. Retain backend transport compatibility for
|
||||
one release transition, then require old runtimes to resume before its removal.
|
||||
The [system design](../specs/integrations/system-design/task-change-link-mcp.md)
|
||||
defines this transition and its validation.
|
||||
|
||||
This decision amends the generic-tool rejection in the
|
||||
[provider-scoped runtime ADR](2026-08-03-provider-scoped-task-mcp-tools.md).
|
||||
Backend provider derivation and transport remain unchanged.
|
||||
It also changes the tool name in the
|
||||
[explicit-outcome ADR](2026-09-06-explicit-pr-auto-fix-outcomes.md), without changing attempt semantics.
|
||||
The amendments take effect in the planned 0.95.0 release. The retained backend
|
||||
transport handlers are removed in the first stable release after 0.95.0.
|
||||
|
||||
## Consequences
|
||||
|
||||
New providers add capabilities and adapters instead of more tool families.
|
||||
Agents can distinguish an association update from a task/provider update.
|
||||
A mixed-provider write can partially succeed. Its response must identify remaining work.
|
||||
Cached callers must rediscover tools or resume with the current runtime.
|
||||
The implementation does not require a store migration or GitLab outcome tracker.
|
||||
|
||||
## Alternatives Considered
|
||||
|
||||
- Keep eight names: provider growth expands discovery and duplicates tool selection.
|
||||
- Use one universal tool: reporting would share a schema with ordinary management despite different execution authority.
|
||||
- Keep link, unlink, and replace separate: slightly shorter schemas cost two names without removing identity validation.
|
||||
- Merge provider prompts: this changes durable settings and can overwrite different user instructions.
|
||||
- Omit target identity for task fan-out: a missing field could affect every linked contribution.
|
||||
- Make mixed writes atomic: this requires cross-store coordination outside the requested MCP boundary.
|
||||
- Hide callable aliases with SDK filters: the installed SDK filters calls too, so this cannot preserve old invocation.
|
||||
|
||||
These choices retain the preferred four-tool surface. No fifth operation has a
|
||||
separate authority or lifecycle that requires another tool.
|
||||
@@ -47,3 +47,9 @@ Focused Go suites for the coordinator, MCP handler/server, GitHub, and GitLab
|
||||
packages, plus race-enabled focused tests for identity, authorization,
|
||||
idempotency, rollback, detach, and projection behavior. Public documentation
|
||||
validation via `Validate public docs`.
|
||||
|
||||
## Successor package
|
||||
|
||||
The [provider-neutral MCP plan](../provider-neutral-change-request-mcp/plan.md)
|
||||
uses PR #3506's merged implementation as its baseline. This completed package
|
||||
retains its historical scope and results; it does not track the successor's work.
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
---
|
||||
created: 2026-09-14
|
||||
status: complete
|
||||
requirements:
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-006
|
||||
system_design:
|
||||
- ../../specs/integrations/system-design/task-change-link-mcp.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Implementation plan: Provider-neutral change request MCP tools
|
||||
|
||||
## Overview
|
||||
|
||||
Deliver the four-tool contract through five sequential work orders.
|
||||
Implement management and reads first, then automation and bound outcomes.
|
||||
Finish with caller migration, catalog cutover, and protocol evidence.
|
||||
Intermediate commits may retain old registrations until the final cutover.
|
||||
|
||||
Baseline: PR [#3506](https://github.com/kdlbs/kandev/pull/3506), merged
|
||||
2026-09-14 at 14:00:36 UTC, commit `262ecdf270b5171538a68e9937dda7894ee01673`.
|
||||
Fetched `origin/main` and HEAD both matched that commit. The working tree was clean.
|
||||
Maintainer fixes in that merge are included. Contributor review and CI remediation are excluded.
|
||||
Refresh the base before implementation and reconcile only relevant later changes.
|
||||
|
||||
The integration system owns this package because it owns contribution identity,
|
||||
automation settings, and provider capabilities. No rendered UI changes are required.
|
||||
|
||||
## Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- Shared discovery, strict schemas, backend dispatch, and provider adapters.
|
||||
- Explicit automation targeting and provider-scoped prompts.
|
||||
- Existing principal, origin, credentials, cleanup, and replacement guarantees.
|
||||
- Bound GitHub outcome reporting under the neutral name.
|
||||
- Caller migration, transport retirement, public reference updates, and protocol tests.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Provider-store rewrite, new schema, cross-provider replacement, or GitLab outcome tracking.
|
||||
- UI changes, automation algorithm changes, new providers, or a broad verification audit.
|
||||
|
||||
## Technical approach
|
||||
|
||||
Use [the system design](../../specs/integrations/system-design/task-change-link-mcp.md)
|
||||
for exact request/response contracts and failure semantics.
|
||||
Reuse `TaskChangeLinkRequest`, `taskChangeLinkCoordinator`, provider automation
|
||||
service methods, existing event publishers, and orchestrator active-turn resolution.
|
||||
Add neutral DTOs and backend actions without exporting provider persistence shapes.
|
||||
|
||||
The read exposes provider-labelled capabilities and prompt settings. Automation
|
||||
uses `target.scope` and an explicit task `providers` array. The outcome tool
|
||||
accepts only outcome and summary. Keep list-task projections unchanged.
|
||||
|
||||
The new catalog removes all eight old names in task 05. Existing WS actions
|
||||
remain for one release transition, with original scope and principal checks.
|
||||
Remove compatibility in the first stable release after introduction. At delivery,
|
||||
record the introducing version and this removal obligation in the release notes.
|
||||
No aliases remain advertised by the new runtime. Old processes require resume
|
||||
before the compatibility-removal release; registry refresh cannot upgrade binaries.
|
||||
|
||||
## Tests
|
||||
|
||||
The following tests provide the implementation evidence for the mapped criteria.
|
||||
|
||||
| Acceptance criteria suffixes in `AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-*` | Implementation evidence |
|
||||
| --- | --- |
|
||||
| 001.1, 001.2, 001.5; 003.1 | `mcp/server/task_change_request_tools_test.go:TestManageTaskChangeRequestSchemaAndDispatch`; `mcp/handlers/task_change_request_test.go:TestManageTaskChangeRequestDispatchesWithTrustedCaller` |
|
||||
| 001.3, 001.4, 001.6; 003.2, 003.3 | `backendapp/task_change_link_coordinator_test.go:TestTaskChangeCoordinatorReplaceRollsBackNewLinkWhenOldUnlinkFails`; `TestTaskChangeCoordinatorReportsRollbackFailure`; retained provider detach/unlink tests |
|
||||
| 002.1, 002.3, 002.4 | `backendapp/task_change_request_read_test.go:TestTaskChangeRequestReaderPreservesProviderAvailabilityAndFailures`; `mcp/handlers/task_change_request_read_test.go:TestGetTaskChangeRequestsUsesBoundPrincipal` |
|
||||
| 002.2; 006.1, 006.2 | `mcp/server/server_test.go:TestServerSurfaceAutomationHasFixedCoordinatorCatalog`; `mcp/server/task_change_request_protocol_test.go:TestTaskChangeRequestProtocolCatalogAndCallAcrossProtocolEras` |
|
||||
| 004.1, 004.2, 004.3 | `mcp/server/task_change_request_tools_test.go:TestChangeRequestAutomationToolSchemaAndDispatch`; `backendapp/task_change_request_automation_test.go:TestChangeRequestAutomationTargetMatrix` |
|
||||
| 004.4, 004.5 | `backendapp/task_change_request_automation_test.go:TestChangeRequestAutomationPreflightRejectsUnresolvedWithoutWrites`; `TestChangeRequestAutomationPartialFailure`; `TestGitLabTaskChangeRequestReadResolvesOnlyVerifiedIdentity` |
|
||||
| 005.1, 005.2, 005.3 | `mcp/server/pr_auto_fix_outcome_scope_test.go`; `mcp/handlers/task_pr_automation_outcome_scope_test.go`; `orchestrator/ci_automation_outcome_scope_test.go`; `github/store_ci_outcome_scope_test.go` |
|
||||
|
||||
Paths in this table are relative to `apps/backend/internal/`.
|
||||
|
||||
Preserve existing tests that prove the merged guarantees:
|
||||
`TestTaskChangeCoordinatorUnlinksStaleAssociationWithoutCurrentRepository`,
|
||||
`TestTaskChangeCoordinatorReportsRollbackFailure`,
|
||||
`TestTaskPRDetachRetiresOnlyExactAutomationAndCIState`, and
|
||||
`TestUnlinkTaskMRPublishesWorkspaceScopedDeletedEvent`.
|
||||
Their provider suites also cover persistence, tombstones, and workspace routing.
|
||||
|
||||
## End-to-end protocol evidence
|
||||
|
||||
The changed user surface is MCP. The implementation uses the existing in-process
|
||||
protocol harness instead of introducing a browser test for unchanged UI.
|
||||
`mcp/server/task_change_request_protocol_test.go` exercises serialized modern
|
||||
direct requests and legacy initialize/list/call requests, verifies the neutral
|
||||
catalog in both protocol eras, and proves superseded calls do not reach the
|
||||
backend. Focused coordinator and handler tests cover provider writes, read
|
||||
failures, identity resolution, authorization, replacement failures, mixed
|
||||
provider partial results, and bound outcomes. Orchestrator tests cover queued
|
||||
protocol delivery, edited prompt preservation, catalog selection, and current
|
||||
turn scope.
|
||||
|
||||
The implemented package covers 001.1–001.6, 002.1–002.4, 003.1–003.3,
|
||||
004.1–004.5, 005.1–005.3, and 006.1–006.2 through focused coordinator,
|
||||
handler, catalog, and protocol tests. The serialized protocol fixture covers
|
||||
both MCP protocol eras, the neutral catalog, bound task dispatch, and rejection
|
||||
of a superseded tool call without a backend mutation.
|
||||
|
||||
## Representative agent requests
|
||||
|
||||
Use fixture IDs from discovery. These examples assess intended tool selection;
|
||||
argument schema tests and serialized-call tests provide executable evidence.
|
||||
|
||||
| Agent intent | Tool and arguments | Required result |
|
||||
| --- | --- | --- |
|
||||
| Show this task's PRs and MRs and available automation | `get_task_change_requests_kandev {}` | Both providers, separate prompts, truthful capabilities |
|
||||
| Link GitLab MR 42 to sibling task B | `manage_task_change_request_kandev {"operation":"link","task_id":"B","provider":"gitlab","repository_id":"repo-gl","number":42}` | Workspace-authorized link; no agent project path |
|
||||
| Remove that MR after detaching its repository | Same tool with `operation:"unlink"` and the same triple | Exact stale association removed |
|
||||
| Replace GitHub PR 7 with PR 8 | Same tool with `operation:"replace"`, explicit new triple and `old_provider`, `old_repository_id`, `old_number` | One call; link-before-unlink |
|
||||
| Disable auto-fix only for PR 8 | `update_task_change_request_automation_kandev {"target":{"scope":"association","provider":"github","repository_id":"repo-gh","number":8},"patch":{"auto_fix_enabled":false}}` | Other contributions unchanged |
|
||||
| Enable merge notifications for this task's GitHub PRs and GitLab MRs | Same tool with `target:{"scope":"task","providers":["github","gitlab"]}`, `patch:{"prompt_on_merged":true}` | Explicit mixed-provider update |
|
||||
| Clear the task's GitLab custom prompt | Same tool with `target:{"scope":"task","providers":["gitlab"]}`, `patch:{"auto_fix_prompt_override":""}` | GitHub prompt unchanged; valid without MRs |
|
||||
| Give only PR 8 a different auto-fix prompt | Association target with prompt patch | Reject; explain task/provider prompt scope |
|
||||
| Fix PR 8 manually, then report completion | No outcome tool call | Ordinary completion does not report an automation outcome |
|
||||
| Report a Kandev-dispatched GitHub fix | `report_change_request_auto_fix_outcome_kandev {"outcome":"action_taken","summary":"Pushed the check fix."}` | Exact bound attempt recorded |
|
||||
| Report a GitLab auto-fix turn | No outcome call; GitLab capability is false | No accidental GitHub report |
|
||||
| Enable auto-merge with no target | Automation patch without `target` | Reject before writes |
|
||||
| Replace GitHub PR with GitLab MR | Manage replace with different providers | Reject before writes |
|
||||
| Set automation on sibling task B | Automation request with `task_id:"B"` | Reject supplied execution identity |
|
||||
|
||||
Also test typo operations, unknown providers, fractional/zero numbers, null fields,
|
||||
partial triples, duplicate provider selections, unknown patch keys, and empty patches.
|
||||
Assessment passes only if each valid intent selects one tool and each invalid
|
||||
intent fails without a broader target or side effect. Record any ambiguity in task 05.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [x] [Task 01: Shared management contract](task-01-management.md) (`done`)
|
||||
- [x] [Task 02: Read contributions and capabilities](task-02-read-capabilities.md) (`done`)
|
||||
- [x] [Task 03: Explicit automation targets](task-03-automation-targets.md) (`done`)
|
||||
- [x] [Task 04: Bound outcome tool](task-04-bound-outcome.md) (`done`)
|
||||
- [x] [Task 05: Catalog and caller cutover](task-05-catalog-cutover.md) (`done`)
|
||||
|
||||
Work orders were executed sequentially: 01 → 02 → 03 → 04 → 05.
|
||||
Each work order specifies its source and test ownership.
|
||||
|
||||
## Release follow-up
|
||||
|
||||
- Introducing stable release: `0.95.0` (planned).
|
||||
- [ ] Before the first stable release after `0.95.0`, remove the retained
|
||||
provider-specific backend WebSocket action handlers and their tests.
|
||||
- [ ] Verify that no old MCP registration or active caller reference remains
|
||||
after the compatibility handlers are removed.
|
||||
|
||||
## Verification results
|
||||
|
||||
Implementation validation on 2026-09-14:
|
||||
|
||||
- `make -C apps/backend lint`: passed.
|
||||
- `make -C apps/backend build`: passed.
|
||||
- `go test ./internal/backendapp ./internal/mcp/handlers ./internal/mcp/server ./internal/orchestrator ./config/workflows ./internal/task/dto ./pkg/api/v1 -count=1`: passed.
|
||||
- Provider and orchestration focused tests: passed.
|
||||
- MCP server and backend application race checks: passed.
|
||||
- Review regressions passed:
|
||||
- `go test ./internal/mcp/handlers -run 'TestManageTaskChangeRequest' -count=1`
|
||||
- `go test ./internal/mcp/server -run 'TestManageTaskChangeRequest|TestTaskChangeRequestTool' -count=1`
|
||||
- `go test ./internal/backendapp -run 'TestTaskChangeManagementDispatches|TestTaskChangeCoordinator|TestChangeRequestAutomationAssociation' -count=1`
|
||||
- `go test ./internal/orchestrator -run 'TestReplaceCIAutoFixOutcomeProtocol' -count=1`
|
||||
These cover rich handler-to-coordinator replacement dispatch, serialized
|
||||
management failure details, historical queued protocol migration for wrapped
|
||||
and passthrough prompts, targeted GitLab affected identities, and read-to-
|
||||
management cleanup of legacy GitLab associations.
|
||||
|
||||
Review remediation also covers GitLab connection and repository lookup errors,
|
||||
unresolved legacy rows that must not block unrelated mutations, principal
|
||||
binding before task lookup, task/provider membership preflight, typed Kandev
|
||||
catalog source checks, schema/backend agreement for prompt scope, and a real
|
||||
no-catalog CI automation path. Stable public mutation details keep raw provider
|
||||
errors in logs while preserving operation, rollback, link, and state-known
|
||||
fields for callers.
|
||||
- `make -C apps/backend test`: the changed packages passed, but the aggregate
|
||||
target returned nonzero on existing environment-sensitive config, launcher,
|
||||
Office migration, and process-probe tests. Config and launcher passed when
|
||||
rerun without inherited internal config variables; the Office migration test
|
||||
passed in isolation, and deterministic process-probe tests passed. None of
|
||||
those packages are changed by this implementation.
|
||||
- `git diff --check`: passed.
|
||||
|
||||
Documentation and design-package validation on 2026-09-14:
|
||||
|
||||
- `python3 scripts/list-docs.py validate`: passed (268 decisions, 909 specifications).
|
||||
- `python3 scripts/lint-spec-files.test.py`: passed (36 tests).
|
||||
- `python3 scripts/lint-spec-files.py --all`: passed.
|
||||
- Catalog discovery includes the updated pair and accepted ADR.
|
||||
- `git diff --check -- docs/specs docs/decisions docs/plans`: passed.
|
||||
- Work-order links, requirement IDs, and acceptance IDs: validated locally.
|
||||
|
||||
Public docs, workflow callers, requirements, system design, and the decision
|
||||
record were updated during task 05. The implementation adds permanent backend,
|
||||
handler, protocol, and coordinator tests.
|
||||
|
||||
## Risks
|
||||
|
||||
- Old runtime binaries keep their catalog until resume; migration must not emit an unavailable tool name.
|
||||
- Historical GitLab rows can lack canonical identity. Ambiguous rows must remain visible and fail closed.
|
||||
- Provider transactions are independent. Readback can fail after a successful write.
|
||||
- Repeated switch writes can reset provider checkpoints; avoid replaying already-applied mixed updates.
|
||||
- Another main-branch change can alter provider capabilities or caller inventory before implementation.
|
||||
@@ -0,0 +1,116 @@
|
||||
---
|
||||
id: "01-management"
|
||||
title: "Shared management contract"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003
|
||||
acceptance_criteria:
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.3
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.4
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.5
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.6
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.3
|
||||
system_design:
|
||||
- ../../specs/integrations/system-design/task-change-link-mcp.md
|
||||
---
|
||||
|
||||
# Task 01: Shared management contract
|
||||
|
||||
## Summary
|
||||
|
||||
Expose `manage_task_change_request_kandev` with strict operation branches and complete canonical identity.
|
||||
Preserve the merged coordinator and its provider cleanup contracts.
|
||||
|
||||
## In scope
|
||||
|
||||
- Register the neutral tool and backend action; retain legacy registration until task 05.
|
||||
- Require trusted principal and same-workspace target; reject forged internal caller identity.
|
||||
- Preserve same-provider replacement, exact no-op, absent unlink, stale removal, and preexisting-new-link compensation ownership.
|
||||
- Carry typed failure/readback state through WS and MCP errors without exposing raw provider errors.
|
||||
- Extend both-provider failure tests: new-link failure, old-unlink failure, compensation success/failure, preexisting new link, and failed final listing.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Provider-store redesign, new UI, cross-provider replacement, and GitLab outcome tracking.
|
||||
Do not change unrelated provider algorithms or historical transcripts.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Strict schema rejects unknown keys, fractional numbers, partial old identity, and old fields on link/unlink before writes.
|
||||
- Both providers retain persisted exact cleanup and committed deletion events after restart.
|
||||
- Replacement returns original/rollback failures and known links without reporting uncertain state as success.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root. Add failing tests first, then implement and run these checks.
|
||||
Use existing package fixtures; keep all new tests inside this work order's listed suites.
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test ./internal/mcp/server ./internal/mcp/handlers ./internal/backendapp -count=1)
|
||||
(cd apps/backend && go test ./internal/github ./internal/gitlab -run 'TaskPRDetach|DetachTaskPR|UnlinkTaskMR|TaskChange|AssociateExisting' -count=1)
|
||||
(cd apps/backend && go test -race ./internal/backendapp -run 'TaskChange|ChangeRequest' -count=1)
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/mcp/server/server.go`
|
||||
- `apps/backend/internal/mcp/server/handlers.go`
|
||||
- `apps/backend/internal/mcp/server/task_change_request_tools_test.go (new)`
|
||||
- `apps/backend/internal/mcp/handlers/task_change_link.go`
|
||||
- `apps/backend/internal/mcp/handlers/handlers.go`
|
||||
- `apps/backend/internal/mcp/handlers/task_change_request_test.go (new)`
|
||||
- `apps/backend/internal/backendapp/task_change_link_coordinator.go`
|
||||
- `apps/backend/internal/backendapp/task_change_link_coordinator_test.go`
|
||||
- `apps/backend/pkg/websocket/actions.go`
|
||||
|
||||
## Dependencies
|
||||
|
||||
None. Read the merged baseline before changing code.
|
||||
|
||||
## Risks
|
||||
|
||||
Compensation must not remove a preexisting association. A committed write can outlive a failed readback.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`. Shared schemas and registration files prevent parallel ownership.
|
||||
|
||||
## Inputs
|
||||
|
||||
- [Requirements](../../specs/integrations/requirements/task-change-link-mcp.md), frontmatter IDs.
|
||||
- [System design](../../specs/integrations/system-design/task-change-link-mcp.md), relevant contract sections.
|
||||
- [Plan](plan.md), baseline, test matrix, and agent requests.
|
||||
- Existing adjacent tests named in the plan and `apps/backend/AGENTS.md`.
|
||||
- `.agents/skills/tdd/SKILL.md` and its backend testing reference before implementation.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented the neutral management action and tool with strict operation and
|
||||
identity validation, trusted principal and workspace checks, and typed
|
||||
replacement failure state with operation and rollback errors. The final
|
||||
cutover removed the legacy MCP registrations while retaining the old backend
|
||||
transport handlers for the documented transition release.
|
||||
|
||||
Validation passed:
|
||||
|
||||
- `go test ./internal/mcp/server ./internal/mcp/handlers ./internal/backendapp -count=1`
|
||||
- `go test ./internal/github ./internal/gitlab -run 'TaskPRDetach|DetachTaskPR|UnlinkTaskMR|TaskChange|AssociateExisting' -count=1`
|
||||
- `go test -race ./internal/backendapp -run 'TaskChange|ChangeRequest' -count=1`
|
||||
- Review regression commands passed:
|
||||
- `go test ./internal/mcp/handlers -run 'TestManageTaskChangeRequest' -count=1`
|
||||
- `go test ./internal/mcp/server -run 'TestManageTaskChangeRequest|TestTaskChangeRequestTool' -count=1`
|
||||
- `go test ./internal/backendapp -run 'TestTaskChangeManagementDispatches|TestTaskChangeCoordinator' -count=1`
|
||||
These cover rich replacement old-identity forwarding, serialized rollback
|
||||
and unknown-state details, and WebSocket handler-to-coordinator success and
|
||||
compensation paths.
|
||||
- Additional coordinator regressions cover exact cleanup when a legacy GitLab
|
||||
row is resolved from its stored host and project path, while unrelated
|
||||
unresolved rows remain visible without blocking the requested mutation.
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
id: "02-read-capabilities"
|
||||
title: "Read contributions and capabilities"
|
||||
status: done
|
||||
wave: 2
|
||||
depends_on: ['01-management']
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002
|
||||
acceptance_criteria:
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.3
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.4
|
||||
system_design:
|
||||
- ../../specs/integrations/system-design/task-change-link-mcp.md
|
||||
---
|
||||
|
||||
# Task 02: Read contributions and capabilities
|
||||
|
||||
## Summary
|
||||
|
||||
Add the bound read tool and a small provider adapter at the composition boundary.
|
||||
Return status, switches, prompts, and actual capabilities without altering task-list projections.
|
||||
|
||||
## In scope
|
||||
|
||||
- Add shared response DTOs and provider adapters using existing listers and automation read services.
|
||||
- Expose provider-level prompt settings separately from association switches.
|
||||
- Represent incomplete reads, unavailable providers, and unresolved/ambiguous historical identity explicitly.
|
||||
- Resolve GitLab canonical identity only from verified unique persisted evidence.
|
||||
- Keep discovery profile-gated; preserve existing list_tasks and list_related_tasks fields.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Provider-store redesign, new UI, cross-provider replacement, and GitLab outcome tracking.
|
||||
Do not change unrelated provider algorithms or historical transcripts.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- GitHub-only, GitLab-only, mixed, empty, unavailable, and failed-provider fixtures return accurate status and capability values.
|
||||
- GitLab outcome capability is false; no aggregate prompt conceals provider differences.
|
||||
- Read calls reject public task/session fields, enforce backend principal binding, and preserve list projections.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root. Add failing tests first, then implement and run these checks.
|
||||
Use existing package fixtures; keep all new tests inside this work order's listed suites.
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test ./internal/mcp/server ./internal/mcp/handlers ./internal/backendapp ./internal/task/dto ./pkg/api/v1 -count=1)
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/mcp/server/server.go`
|
||||
- `apps/backend/internal/mcp/server/handlers.go`
|
||||
- `apps/backend/internal/mcp/handlers/handlers.go`
|
||||
- `apps/backend/internal/mcp/handlers/task_change_request.go (new)`
|
||||
- `apps/backend/internal/backendapp/task_change_request_read.go (new)`
|
||||
- `apps/backend/internal/backendapp/task_change_request_read_test.go (new)`
|
||||
- `apps/backend/internal/mcp/handlers/task_pr_enrich_test.go`
|
||||
- `apps/backend/pkg/websocket/actions.go`
|
||||
|
||||
## Dependencies
|
||||
|
||||
Task 01. Use its DTOs and validated backend boundary.
|
||||
|
||||
## Risks
|
||||
|
||||
Historical MR rows may have empty repository identity or multiple project paths for one canonical triple.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`. Shared schemas and registration files prevent parallel ownership.
|
||||
|
||||
## Inputs
|
||||
|
||||
- [Requirements](../../specs/integrations/requirements/task-change-link-mcp.md), frontmatter IDs.
|
||||
- [System design](../../specs/integrations/system-design/task-change-link-mcp.md), relevant contract sections.
|
||||
- [Plan](plan.md), baseline, test matrix, and agent requests.
|
||||
- Existing adjacent tests named in the plan and `apps/backend/AGENTS.md`.
|
||||
- `.agents/skills/tdd/SKILL.md` and its backend testing reference before implementation.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented the bound read contract and provider adapters behind the existing
|
||||
task-list lister and automation service seams. Provider availability, read
|
||||
failures, prompt settings, per-association switches, capability reasons, and
|
||||
verified GitLab identity resolution are represented independently.
|
||||
|
||||
Validation passed:
|
||||
|
||||
- `go test ./internal/mcp/server ./internal/mcp/handlers ./internal/backendapp ./internal/task/dto ./pkg/api/v1 -count=1`
|
||||
- `go test -race ./internal/backendapp -run 'TaskChange|ChangeRequest' -count=1`
|
||||
- Read regressions cover GitLab connection failures, failed repository identity
|
||||
lookups, unresolved legacy identities, and principal binding before task
|
||||
existence lookup.
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
id: "03-automation-targets"
|
||||
title: "Explicit automation targets"
|
||||
status: done
|
||||
wave: 3
|
||||
depends_on: ['02-read-capabilities']
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004
|
||||
acceptance_criteria:
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.3
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.4
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.5
|
||||
system_design:
|
||||
- ../../specs/integrations/system-design/task-change-link-mcp.md
|
||||
---
|
||||
|
||||
# Task 03: Explicit automation targets
|
||||
|
||||
## Summary
|
||||
|
||||
Implement one neutral automation update tool with explicit association and task/provider targets.
|
||||
Reuse provider transactions and report cross-provider partial application.
|
||||
|
||||
## In scope
|
||||
|
||||
- Add strict target/patch schemas and typed backend validation.
|
||||
- Map canonical GitHub identity to PRNumber and unique GitLab identity to ProjectPath/MRIID internally.
|
||||
- Enforce principal binding, origin checks, live membership, provider capabilities, and workspace credentials.
|
||||
- Preflight every selected provider before writes; reject empty switch targets and all invalid fields.
|
||||
- Apply providers in lexical order; stop after failure and preserve provider-specific events.
|
||||
- Expose affected identities and applied/failed/not_attempted results, including unknown state after readback failure.
|
||||
- Keep prompt scope at task/provider and reject prompt fields with association targets.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Provider-store redesign, new UI, cross-provider replacement, and GitLab outcome tracking.
|
||||
Do not change unrelated provider algorithms or historical transcripts.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Tests cover one association, one provider, both providers, prompt-only empty tasks, mixed patches, and false/empty-string values.
|
||||
- Unsupported, ambiguous, foreign-workspace, partial-identity, and missing-credential requests cause no preflight writes.
|
||||
- Second-provider failure preserves the first provider's result without rollback or a false all-or-nothing claim.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root. Add failing tests first, then implement and run these checks.
|
||||
Use existing package fixtures; keep all new tests inside this work order's listed suites.
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test ./internal/mcp/server ./internal/mcp/handlers ./internal/backendapp -count=1)
|
||||
(cd apps/backend && go test ./internal/github ./internal/gitlab -run 'TaskCIOptions|TaskMRAutomation|UpdateTaskMRAutomation|UpdateTaskCIOptions' -count=1)
|
||||
(cd apps/backend && go test -race ./internal/backendapp -run 'ChangeRequestAutomation|ChangeRequestGitLab' -count=1)
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/mcp/server/server.go`
|
||||
- `apps/backend/internal/mcp/server/handlers.go`
|
||||
- `apps/backend/internal/mcp/server/task_change_request_tools_test.go`
|
||||
- `apps/backend/internal/mcp/handlers/task_change_request.go`
|
||||
- `apps/backend/internal/backendapp/task_change_request_automation.go (new)`
|
||||
- `apps/backend/internal/backendapp/task_change_request_automation_test.go (new)`
|
||||
- `apps/backend/internal/mcp/handlers/handlers.go`
|
||||
- `apps/backend/pkg/websocket/actions.go`
|
||||
|
||||
## Dependencies
|
||||
|
||||
Task 02. Use its DTOs and validated backend boundary.
|
||||
|
||||
## Risks
|
||||
|
||||
Retries can reset provider checkpoints. Return precise partial state and avoid automatic compensation.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`. Shared schemas and registration files prevent parallel ownership.
|
||||
|
||||
## Inputs
|
||||
|
||||
- [Requirements](../../specs/integrations/requirements/task-change-link-mcp.md), frontmatter IDs.
|
||||
- [System design](../../specs/integrations/system-design/task-change-link-mcp.md), relevant contract sections.
|
||||
- [Plan](plan.md), baseline, test matrix, and agent requests.
|
||||
- Existing adjacent tests named in the plan and `apps/backend/AGENTS.md`.
|
||||
- `.agents/skills/tdd/SKILL.md` and its backend testing reference before implementation.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented explicit association and task/provider automation targets. The
|
||||
coordinator preflights every selected provider before writing, applies providers
|
||||
in lexical order, preserves partial results after a later provider failure, and
|
||||
keeps prompts at task/provider scope.
|
||||
|
||||
Validation passed:
|
||||
|
||||
- `go test ./internal/backendapp -run 'TestChangeRequestAutomation' -count=1`
|
||||
- `go test ./internal/mcp/handlers -run 'Test(ParseTaskChangeRequestAutomationPayload|UpdateTaskChangeRequestAutomation)' -count=1`
|
||||
- `go test -race ./internal/backendapp -run 'TaskChange|ChangeRequest' -count=1`
|
||||
- `go test ./internal/backendapp -run 'TestChangeRequestAutomationAssociationReportsOnlyTargetedGitLabMR' -count=1`
|
||||
passed with a production-shaped task-wide provider response containing two
|
||||
MRs.
|
||||
- Task-scope preflight now verifies that each selected provider is attached to
|
||||
the bound task before any provider write; the regression covers a prompt-only
|
||||
update for a provider absent from the task.
|
||||
- The MCP schema rejects association-scoped prompt overrides before backend
|
||||
dispatch, matching the handler validation contract.
|
||||
@@ -0,0 +1,100 @@
|
||||
---
|
||||
id: "04-bound-outcome"
|
||||
title: "Bound outcome tool"
|
||||
status: done
|
||||
wave: 4
|
||||
depends_on: ['03-automation-targets']
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005
|
||||
acceptance_criteria:
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.3
|
||||
system_design:
|
||||
- ../../specs/integrations/system-design/task-change-link-mcp.md
|
||||
---
|
||||
|
||||
# Task 04: Bound outcome tool
|
||||
|
||||
## Summary
|
||||
|
||||
Expose the neutral outcome tool through the existing trusted GitHub reporting path.
|
||||
Preserve the active-turn and attempt lifecycle without introducing GitLab reporting.
|
||||
|
||||
## In scope
|
||||
|
||||
- Add the neutral tool/action with only outcome and summary; retain old registration until task 05.
|
||||
- Derive task/session from the principal and turn/contribution from the existing attempt service.
|
||||
- Reuse first-write/replay and provider-progress semantics.
|
||||
- Keep unmatched-turn guidance and fail closed on ordinary, stale, mismatched, or GitLab turns.
|
||||
- Prepare outcome protocol generation to select the tool name supported by the bound runtime catalog; task 05 activates caller cutover.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Provider-store redesign, new UI, cross-provider replacement, and GitLab outcome tracking.
|
||||
Do not change unrelated provider algorithms or historical transcripts.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- All three outcomes reach the same server-bound attempt and preserve duplicate/conflicting-report rules.
|
||||
- Spoofed identity fields and reports from ordinary or GitLab turns cannot change GitHub attempt state.
|
||||
- Protocol descriptions distinguish dispatched auto-fix from manual fixup and tool availability.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root. Add failing tests first, then implement and run these checks.
|
||||
Use existing package fixtures; keep all new tests inside this work order's listed suites.
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test ./internal/mcp/server ./internal/mcp/handlers -count=1)
|
||||
(cd apps/backend && go test ./internal/orchestrator ./internal/github -run 'AutoFix|CIAuto|Outcome' -count=1)
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/mcp/server/server.go`
|
||||
- `apps/backend/internal/mcp/server/handlers.go`
|
||||
- `apps/backend/internal/mcp/server/pr_auto_fix_outcome_scope_test.go`
|
||||
- `apps/backend/internal/mcp/handlers/task_pr_automation.go`
|
||||
- `apps/backend/internal/mcp/handlers/task_pr_automation_outcome_scope_test.go`
|
||||
- `apps/backend/internal/mcp/handlers/handlers.go`
|
||||
- `apps/backend/internal/orchestrator/ci_automation_attempt.go`
|
||||
- `apps/backend/internal/orchestrator/ci_automation_outcome_scope_test.go`
|
||||
- `apps/backend/internal/orchestrator/event_handlers_github_ci_automation.go`
|
||||
- `apps/backend/pkg/websocket/actions.go`
|
||||
|
||||
## Dependencies
|
||||
|
||||
Task 03. Use its DTOs and validated backend boundary.
|
||||
|
||||
## Risks
|
||||
|
||||
A neutral tool visible on a mixed task must not authorize a GitLab turn to report against a GitHub attempt.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`. Shared schemas and registration files prevent parallel ownership.
|
||||
|
||||
## Inputs
|
||||
|
||||
- [Requirements](../../specs/integrations/requirements/task-change-link-mcp.md), frontmatter IDs.
|
||||
- [System design](../../specs/integrations/system-design/task-change-link-mcp.md), relevant contract sections.
|
||||
- [Plan](plan.md), baseline, test matrix, and agent requests.
|
||||
- Existing adjacent tests named in the plan and `apps/backend/AGENTS.md`.
|
||||
- `.agents/skills/tdd/SKILL.md` and its backend testing reference before implementation.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented the neutral bound outcome action and tool. It reuses the existing
|
||||
active-turn and GitHub attempt semantics, rejects injected identity, keeps
|
||||
GitLab outcome capability disabled, and selects the protocol wording from the
|
||||
current execution catalog while preserving queued and edited prompt content.
|
||||
|
||||
Validation passed:
|
||||
|
||||
- `go test ./internal/mcp/server ./internal/mcp/handlers -count=1`
|
||||
- `go test ./internal/orchestrator ./internal/github -run 'AutoFix|CIAuto|Outcome' -count=1`
|
||||
- Outcome protocol selection now compares the typed Kandev MCP source constant,
|
||||
with the historical queued-block fixture retained independently from the
|
||||
current protocol template.
|
||||
@@ -0,0 +1,156 @@
|
||||
---
|
||||
id: "05-catalog-cutover"
|
||||
title: "Catalog and caller cutover"
|
||||
status: done
|
||||
wave: 5
|
||||
depends_on: ['04-bound-outcome']
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-006
|
||||
acceptance_criteria:
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.3
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.4
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.5
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001.6
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.3
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.4
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.3
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.3
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.4
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.5
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.2
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.3
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-006.1
|
||||
- AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-006.2
|
||||
system_design:
|
||||
- ../../specs/integrations/system-design/task-change-link-mcp.md
|
||||
---
|
||||
|
||||
# Task 05: Catalog and caller cutover
|
||||
|
||||
## Summary
|
||||
|
||||
Remove superseded discovery names, migrate callers, and prove the serialized MCP workflow.
|
||||
Document upgrade behavior and the internal transport retirement boundary.
|
||||
|
||||
## In scope
|
||||
|
||||
- Remove all eight legacy registrations; update catalog counts and dynamic profile tests.
|
||||
- Migrate built-in workflow and immutable outcome protocol references with runtime-catalog-aware delivery.
|
||||
- Use current-execution `SessionMetaKeyMCPAttachmentState` through `LoadMCPAttachmentHistory` to choose old versus neutral outcome name for old/new processes; do not infer binary version from provider presence.
|
||||
- For missing current-execution evidence, leave dispatch retryable without a new round or delivered-attempt binding. Preserve existing error visibility and retry scheduling.
|
||||
- Cover queued trusted blocks, unchanged historical transcripts, edited prompts, and current-runtime resume.
|
||||
- Keep original scoped backend WS actions for one transition release, with principal enforcement.
|
||||
- Add protocol fixtures described in plan.md for both MCP eras and all agent examples.
|
||||
- Update public reference pages, coverage metadata, and superseded discovery criteria at cutover.
|
||||
- Reconcile the ADR and system design against implementation; preserve historical plan results.
|
||||
|
||||
## Out of scope
|
||||
|
||||
Provider-store redesign, new UI, cross-provider replacement, and GitLab outcome tracking.
|
||||
Do not change unrelated provider algorithms or historical transcripts.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Both protocol eras expose the same new names; all old calls to a new runtime fail without mutation.
|
||||
- Serialized workflows prove both providers, mixed targeting, authorization, replacement failures, and exact bound reporting.
|
||||
- Caller inventory has no active old-name use except tested old-runtime transport compatibility; upgrade and retirement instructions are explicit.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root. Add failing tests first, then implement and run these checks.
|
||||
Use existing package fixtures; keep all new tests inside this work order's listed suites.
|
||||
|
||||
```bash
|
||||
(cd apps/backend && go test ./internal/mcp/server ./internal/mcp/handlers ./internal/backendapp ./config/workflows -count=1)
|
||||
(cd apps/backend && go test ./internal/orchestrator ./internal/github ./internal/gitlab -run 'AutoFix|CIAuto|Outcome|TaskMR|TaskPRDetach|DetachTaskPR' -count=1)
|
||||
(cd apps/backend && go test -race ./internal/mcp/server -run 'ChangeRequestProtocol|ChangeRequestCatalog|SetProviders' -count=1)
|
||||
node --test scripts/validate-public-docs.test.mjs
|
||||
node scripts/validate-public-docs.mjs
|
||||
python3 scripts/list-docs.py validate
|
||||
python3 scripts/lint-spec-files.test.py
|
||||
python3 scripts/lint-spec-files.py --all
|
||||
git diff --check
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/backend/internal/mcp/server/server.go`
|
||||
- `apps/backend/internal/mcp/server/server_test.go`
|
||||
- `apps/backend/internal/mcp/server/handlers_test.go`
|
||||
- `apps/backend/internal/mcp/server/task_change_request_catalog_test.go (new)`
|
||||
- `apps/backend/internal/mcp/server/task_change_request_protocol_test.go (new)`
|
||||
- `apps/backend/internal/mcp/handlers/handlers.go`
|
||||
- `apps/backend/internal/orchestrator/event_handlers_github_ci_automation.go`
|
||||
- `apps/backend/internal/orchestrator/event_handlers_github_ci_automation_test.go`
|
||||
- `apps/backend/config/workflows/pr-review.yml`
|
||||
- `apps/backend/config/workflows/loader_test.go`
|
||||
- `docs/public/automation-and-mcp.md`
|
||||
- `docs/public/integrations.md`
|
||||
- `docs/public/coverage.json`
|
||||
- `docs/specs/integrations/requirements/provider-aware-review-automation.md`
|
||||
- `docs/specs/integrations/requirements/task-change-link-mcp.md`
|
||||
- `docs/specs/integrations/system-design/task-change-link-mcp.md`
|
||||
- `docs/decisions/2026-09-14-provider-neutral-change-request-mcp.md`
|
||||
|
||||
## Dependencies
|
||||
|
||||
Task 04. Use its DTOs and validated backend boundary.
|
||||
|
||||
## Risks
|
||||
|
||||
Old binaries cannot learn new handlers through catalog refresh. The SDK cannot provide callable hidden aliases with ToolFilter.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`. Shared schemas and registration files prevent parallel ownership.
|
||||
|
||||
## Inputs
|
||||
|
||||
- [Requirements](../../specs/integrations/requirements/task-change-link-mcp.md), frontmatter IDs.
|
||||
- [System design](../../specs/integrations/system-design/task-change-link-mcp.md), relevant contract sections.
|
||||
- [Plan](plan.md), baseline, test matrix, and agent requests.
|
||||
- Existing adjacent tests named in the plan and `apps/backend/AGENTS.md`.
|
||||
- `.agents/skills/tdd/SKILL.md` and its backend testing reference before implementation.
|
||||
|
||||
## Results
|
||||
|
||||
Removed the eight legacy MCP registrations, migrated workflow and public
|
||||
references, added catalog-aware outcome protocol delivery, and retained the
|
||||
legacy backend WS actions for the one-release transition. Both MCP protocol
|
||||
eras support the neutral catalog, while superseded calls fail without reaching
|
||||
the backend.
|
||||
|
||||
Validation passed:
|
||||
|
||||
- `go test ./internal/mcp/server ./internal/mcp/handlers ./internal/backendapp ./config/workflows -count=1`
|
||||
- `go test ./internal/orchestrator ./internal/github ./internal/gitlab -run 'AutoFix|CIAuto|Outcome|TaskMR|TaskPRDetach|DetachTaskPR' -count=1`
|
||||
- `go test -race ./internal/mcp/server -run 'ChangeRequestProtocol|ChangeRequestCatalog|SetProviders' -count=1`
|
||||
- `node --test scripts/validate-public-docs.test.mjs`
|
||||
- `node scripts/validate-public-docs.mjs`
|
||||
- `python3 scripts/list-docs.py validate`
|
||||
- `python3 scripts/lint-spec-files.test.py`
|
||||
- `python3 scripts/lint-spec-files.py --all`
|
||||
- `git diff --check`
|
||||
- `go test ./internal/orchestrator -run 'TestReplaceCIAutoFixOutcomeProtocol' -count=1`
|
||||
passed for wrapped and passthrough prompts using the literal pre-cutover
|
||||
protocol.
|
||||
- `go test ./internal/backendapp -run 'TestTaskChangeCoordinator(Unlinks|Replaces)ReadResolvedLegacyGitLabAssociation' -count=1`
|
||||
passed with canonical identity resolution and stale-association cleanup.
|
||||
- A production-shaped CI automation regression clears the session catalog and
|
||||
verifies that the missing-catalog error is recorded before dispatch, with no
|
||||
fix attempt or merge operation.
|
||||
@@ -236,21 +236,45 @@ The same data is available directly over REST for scripting: `GET /api/v1/worksp
|
||||
|
||||
Kandev automatically injects a task-aware MCP server into supported agent sessions. You do not need to add it to the profile. It lets the active agent use current IDs and structured operations instead of inferring board state from text.
|
||||
|
||||
### Link an existing pull or merge request
|
||||
### Manage linked pull and merge requests
|
||||
|
||||
Task MCP provides `link_task_pr_kandev`, `unlink_task_pr_kandev`, and
|
||||
`replace_task_pr_kandev` for GitHub pull requests and GitLab merge requests.
|
||||
Each request needs `task_id`, `provider` (`github` or `gitlab`), the canonical
|
||||
`repository_id`, and a positive request number. A number by itself is rejected,
|
||||
so a fork and its canonical repository can safely have the same number.
|
||||
Task MCP provides one shared contract for GitHub pull requests and GitLab merge
|
||||
requests. Use `get_task_change_requests_kandev` to read the current task's
|
||||
linked requests, automation settings, and provider capabilities.
|
||||
|
||||
Use `manage_task_change_request_kandev` with `operation` set to `link`, `unlink`,
|
||||
or `replace`. Every mutation needs `task_id`, `provider` (`github` or `gitlab`),
|
||||
the canonical `repository_id`, and a positive request number. A number by itself
|
||||
is rejected, so a fork and its canonical repository can safely have the same
|
||||
number. For example:
|
||||
|
||||
```json
|
||||
{
|
||||
"operation": "link",
|
||||
"task_id": "…",
|
||||
"provider": "gitlab",
|
||||
"repository_id": "…",
|
||||
"number": 42
|
||||
}
|
||||
```
|
||||
|
||||
`replace` also requires `old_provider`, `old_repository_id`, and `old_number`.
|
||||
Replacement supports one provider at a time. Every successful mutation returns
|
||||
the resulting active link set, and the target task must be reachable from the
|
||||
the calling task's workspace. For replacement, `old_provider` must equal
|
||||
`provider`; cross-provider replacement is rejected.
|
||||
|
||||
Use `update_task_change_request_automation_kandev` for an exact association or
|
||||
for all current links of explicitly selected providers on the current task.
|
||||
Association targets require `provider`, `repository_id`, and `number`. Task
|
||||
targets require a nonempty `providers` list. Prompt overrides are task/provider
|
||||
settings and can be changed only with a task target. The tool does not create
|
||||
defaults for future links.
|
||||
|
||||
`report_change_request_auto_fix_outcome_kandev` is available only when GitHub is
|
||||
among the task's supported providers. It reports the outcome of a server-bound
|
||||
GitHub auto-fix turn; it does not report manual work or GitLab auto-fix turns.
|
||||
|
||||
For example, link GitLab merge request 42 to its target task with
|
||||
`{ "task_id": "…", "provider": "gitlab", "repository_id": "…", "number": 42 }`.
|
||||
`replace_task_pr_kandev` also requires `old_provider`, `old_repository_id`, and
|
||||
`old_number`. Replacement supports associations from the same provider only;
|
||||
to switch between GitHub and GitLab, unlink the current association and then
|
||||
link the new one. Every successful mutation returns the resulting active link set.
|
||||
The target task must be reachable from the calling task's workspace.
|
||||
`list_tasks_kandev` and `list_related_tasks_kandev` expose active GitHub PR and
|
||||
GitLab MR associations in the provider-neutral `change_requests` field; the
|
||||
legacy `prs` field remains GitHub-only for compatibility.
|
||||
@@ -574,20 +598,21 @@ Task-mode review automation tools follow the providers attached to the task's
|
||||
repositories. Kandev computes their union when the session launches or
|
||||
resumes:
|
||||
|
||||
| Attached providers | Discoverable tools |
|
||||
| ------------------- | ------------------------------------------------------------------- |
|
||||
| GitHub only | `get_task_pr_automation_kandev`, `update_task_pr_automation_kandev` |
|
||||
| GitLab only | `get_task_mr_automation_kandev`, `update_task_mr_automation_kandev` |
|
||||
| GitHub and GitLab | Both provider-specific pairs |
|
||||
| None or unsupported | Neither pair |
|
||||
| Attached providers | Discoverable tools |
|
||||
| ------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| GitHub only | `get_task_change_requests_kandev`, `manage_task_change_request_kandev`, `update_task_change_request_automation_kandev`, and `report_change_request_auto_fix_outcome_kandev` |
|
||||
| GitLab only | `get_task_change_requests_kandev`, `manage_task_change_request_kandev`, and `update_task_change_request_automation_kandev` |
|
||||
| GitHub and GitLab | The four tools above |
|
||||
| None or unsupported | None of these change-request tools |
|
||||
|
||||
Adding a repository source successfully to an idle task can update the live
|
||||
session's task MCP tool list after materialization. If live refresh is
|
||||
temporarily unavailable, the source attachment remains committed and the next
|
||||
launch or resume reconciles the tool list. Tool discovery only describes the
|
||||
available surface; backend authorization and task/provider validation remain
|
||||
authoritative for every call. The existing automation request and response
|
||||
payloads are unchanged.
|
||||
authoritative for every call. After an upgrade, rediscover the catalog or resume
|
||||
the task so cached clients use the shared names. An already-running older
|
||||
agentctl keeps its old catalog until it resumes on the new runtime.
|
||||
|
||||
`spawn_session_kandev` creates a named sibling session on the current task by default and can target another task in the same workspace. `message_task_kandev` can address a task's primary session or an explicit session ID: a running agent receives queued input, an idle/created session can be started, and a failed or cancelled session rejects the message.
|
||||
|
||||
|
||||
@@ -470,14 +470,10 @@
|
||||
"/settings/integrations/sentry"
|
||||
],
|
||||
"mcpTools": [
|
||||
"get_task_mr_automation_kandev",
|
||||
"get_task_pr_automation_kandev",
|
||||
"link_task_pr_kandev",
|
||||
"replace_task_pr_kandev",
|
||||
"unlink_task_pr_kandev",
|
||||
"report_pr_auto_fix_outcome_kandev",
|
||||
"update_task_mr_automation_kandev",
|
||||
"update_task_pr_automation_kandev"
|
||||
"get_task_change_requests_kandev",
|
||||
"manage_task_change_request_kandev",
|
||||
"report_change_request_auto_fix_outcome_kandev",
|
||||
"update_task_change_request_automation_kandev"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -413,7 +413,7 @@ These actions use the connected GitLab user's permissions and do not bypass prot
|
||||
|
||||
For a task with a linked GitLab merge request, open the MR topbar control. The **Automation** group has the same two controls as GitHub's PRs: **Auto-fix CI and address comments** and **Auto-merge when ready**. Below it, expand **Review follow-up** for three lifecycle booleans: **Your review is requested**, **MR merged**, and **MR closed without merging**.
|
||||
|
||||
All five belong to a single merge request. A task with several linked MRs shows one **Automation** group per MR, each labelled with its MR number, so you can automate one MR and leave the rest untouched; Kandev tracks delivery and deduplication separately for each. The auto-fix prompt override is the one setting that stays task-level; editing it applies to every linked MR. An agent calling `update_task_mr_automation_kandev` can name a merge request to target it alone, or omit the merge-request fields to apply the change to every MR linked to the task.
|
||||
All five belong to a single merge request. A task with several linked MRs shows one **Automation** group per MR, each labelled with its MR number, so you can automate one MR and leave the rest untouched; Kandev tracks delivery and deduplication separately for each. The auto-fix prompt override is the one setting that stays task-level; editing it applies to every linked MR. An agent can call `update_task_change_request_automation_kandev` with an association target for one MR, or with a task target and `providers: ["gitlab"]` for every MR linked to the task.
|
||||
|
||||
Kandev reuses the existing lightweight task MR poller, which checks linked MRs roughly once per minute; it does not add a separate scheduler. Saving enabled options also evaluates the task's current linked MRs without waiting for the next poll.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
status: active
|
||||
system: integrations
|
||||
created: 2026-08-03
|
||||
updated: 2026-08-03
|
||||
updated: 2026-09-14
|
||||
owners:
|
||||
- kandev
|
||||
---
|
||||
@@ -21,10 +21,10 @@ Task agents currently discover both GitHub pull-request automation tools and Git
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.1:** The backend derives a normalized set of review-automation providers from all repositories attached to the task. The primary repository has no special precedence.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.2:** A GitHub-only task exposes `get_task_pr_automation_kandev` and `update_task_pr_automation_kandev`, but not the corresponding MR tools.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.3:** A GitLab-only task exposes `get_task_mr_automation_kandev` and `update_task_mr_automation_kandev`, but not the corresponding PR tools.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.4:** A mixed GitHub/GitLab task exposes both pairs.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.5:** A task with only local, empty, unknown, or currently unsupported providers exposes neither pair. Provider names are normalized and matched against an explicit allowlist; unknown values fail closed.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.2:** **Superseded at the 2026-09-14 cutover by AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.2.** A GitHub-only task exposes `get_task_pr_automation_kandev` and `update_task_pr_automation_kandev`, but not the corresponding MR tools.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.3:** **Superseded at the 2026-09-14 cutover by AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.2.** A GitLab-only task exposes `get_task_mr_automation_kandev` and `update_task_mr_automation_kandev`, but not the corresponding PR tools.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.4:** **Superseded at the 2026-09-14 cutover by AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.2.** A mixed GitHub/GitLab task exposes both pairs.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.5:** **Superseded at the 2026-09-14 cutover by AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.2.** A task with only local, empty, unknown, or currently unsupported providers exposes neither pair. Provider names are normalized and matched against an explicit allowlist; unknown values fail closed.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.6:** All provider-neutral task tools remain available according to the existing MCP mode.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.7:** Tool visibility is capability discovery, not authorization. Backend handlers remain registered and enforce task, workspace, provider, and credential rules for direct or stale calls.
|
||||
- **AC-INTEGRATIONS-PROVIDER-AWARE-REVIEW-AUTOMATION-001.8:** Initial launch and resume carry the normalized provider set from the orchestrator through lifecycle into agentctl. Agentctl enforces the supplied set and does not infer provider identity from filesystem remotes.
|
||||
@@ -53,22 +53,16 @@ different GitHub and GitLab feature sets.
|
||||
|
||||
### Provider-scoped MCP discovery
|
||||
|
||||
- The backend derives a normalized set of review-automation providers from all
|
||||
repositories attached to the task. The primary repository has no special
|
||||
precedence.
|
||||
- A GitHub-only task exposes `get_task_pr_automation_kandev` and
|
||||
`update_task_pr_automation_kandev`, but not the corresponding MR tools.
|
||||
- A GitLab-only task exposes `get_task_mr_automation_kandev` and
|
||||
`update_task_mr_automation_kandev`, but not the corresponding PR tools.
|
||||
- A mixed GitHub/GitLab task exposes both pairs.
|
||||
- A task with only local, empty, unknown, or currently unsupported providers
|
||||
exposes neither pair. Provider names are normalized and matched against an
|
||||
explicit allowlist; unknown values fail closed.
|
||||
- All provider-neutral task tools remain available according to the existing MCP
|
||||
mode.
|
||||
- Tool visibility is capability discovery, not authorization. Backend handlers
|
||||
remain registered and enforce task, workspace, provider, and credential rules
|
||||
for direct or stale calls.
|
||||
The provider-neutral change-request contract supersedes the old provider-specific
|
||||
tool-name discovery criteria at cutover. See the [task change request MCP system
|
||||
design](../system-design/task-change-link-mcp.md) for the four released tools,
|
||||
provider capability rules, and the old-runtime transport transition.
|
||||
|
||||
The backend still derives a normalized provider union from every repository
|
||||
attached to the task. The primary repository has no special precedence. All
|
||||
provider-neutral task tools remain subject to the existing MCP mode, and tool
|
||||
visibility remains discovery rather than authorization. Backend handlers enforce
|
||||
task, workspace, provider, and credential rules for direct or stale calls.
|
||||
|
||||
### Runtime propagation and refresh
|
||||
|
||||
@@ -262,3 +256,12 @@ releases the per-MR singleflight for later work.
|
||||
- Concurrent GitLab poller fan-out.
|
||||
- Live provider refresh after repository removal.
|
||||
- Persisting reviewer snapshots or changing public automation data models.
|
||||
|
||||
## Proposed contract transition
|
||||
|
||||
The [task change request MCP contract](task-change-link-mcp.md) defines the
|
||||
provider-neutral discovery criteria implemented for the planned 0.95.0 cutover.
|
||||
The four neutral management, read, automation, and outcome tools supersede the
|
||||
provider-specific discovery criteria at that cutover. Current runtime
|
||||
propagation, provider union, authorization, and lifecycle behavior remain the
|
||||
baseline for the successor implementation.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
status: active
|
||||
system: integrations
|
||||
created: 2026-09-14
|
||||
updated: 2026-09-14
|
||||
owners:
|
||||
- kandev
|
||||
---
|
||||
@@ -12,8 +13,8 @@ owners:
|
||||
|
||||
Agents coordinating task delivery need to attach, swap, or remove the external
|
||||
change request (a GitHub pull request or a GitLab merge request) that carries
|
||||
the task's delivery after a task already exists. The MCP surface exposes three
|
||||
provider-neutral operations so an agent can state intent without learning
|
||||
the task's delivery after a task already exists. The MCP surface exposes provider-neutral
|
||||
operations so an agent can state intent without learning
|
||||
provider-specific store mechanics, and every mutation answers with the
|
||||
resulting canonical linked set so the caller can verify immediately.
|
||||
|
||||
@@ -33,6 +34,13 @@ attachment.
|
||||
provider-specific change request; historical receipts (terminal transcripts,
|
||||
conversation history) are unaffected by unlinking.
|
||||
|
||||
## Design status
|
||||
|
||||
This requirement extends the association contract merged in PR #3506. The
|
||||
existing association guarantees remain required. The four-tool contract is
|
||||
implemented in the 0.95.0 release transition. The integration system owns
|
||||
contribution identity, automation, and provider capabilities.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001: Manage task change requests through MCP
|
||||
@@ -77,3 +85,75 @@ without me editing task records by hand.
|
||||
query surfaces and connected clients observe the new linked state after a
|
||||
restart, and unlinking changes only the active association, never
|
||||
conversation or terminal-receipt history.
|
||||
|
||||
### REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002: Discover change requests and capabilities
|
||||
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.1:** `get_task_change_requests_kandev` shall return the current task's linked contributions, status, automation settings, and provider capabilities.
|
||||
Each contribution shall include `provider`, canonical `repository_id`, and positive integer `number`.
|
||||
Missing or ambiguous historical identity shall be reported explicitly, without guessing a repository.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.2:** The task catalog shall advertise one shared management, read, and automation tool set for supported providers.
|
||||
GitHub-capable tasks shall also expose the outcome-reporting tool. GitLab-only tasks shall not expose that tool.
|
||||
Unsupported providers shall not gain capabilities through tool visibility. Existing mode restrictions shall remain effective.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.3:** `list_tasks_kandev` and `list_related_tasks_kandev` shall retain `change_requests` and the legacy GitHub-only `prs` field.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002.4:** Failed provider reads shall identify incomplete results. They shall not appear as an empty linked set or disabled settings.
|
||||
Capability support shall remain distinct from temporary credential or provider availability.
|
||||
|
||||
### REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003: Manage associations with explicit intent
|
||||
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.1:** `manage_task_change_request_kandev` shall require `operation: link | unlink | replace`, target task, and complete contribution identity.
|
||||
Replacement shall additionally require complete old identity. Other operations shall reject old identity fields.
|
||||
Unknown fields, unsupported providers, fractional numbers, and incomplete identities shall fail before mutation.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.2:** Replacement shall remain a single call and permit only the same provider.
|
||||
It shall establish the new link before removing the old link. An identical replacement shall be a no-op.
|
||||
Compensation shall never remove a new link that already existed before the request.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003.3:** Stale associations shall remain removable after repository detachment.
|
||||
Removal events shall describe committed deletion only. Failed replacement shall report original failure, compensation failure, and known remaining associations.
|
||||
When remaining state cannot be read, the response shall identify that uncertainty.
|
||||
|
||||
### REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004: Target automation explicitly
|
||||
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.1:** `update_task_change_request_automation_kandev` shall require an explicit association target or task target with a nonempty provider selection.
|
||||
Association targets shall require complete canonical identity. Task targets shall reject association identity.
|
||||
Read and automation operations shall remain bound to the current task. Supplied execution identity shall be rejected.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.2:** Association updates shall change only that association's auto-fix, auto-merge, or lifecycle notification switches.
|
||||
Task updates shall change those switches for currently linked contributions of explicitly selected providers, including both providers on mixed tasks.
|
||||
They shall not establish defaults for future links. An empty switch target shall be rejected.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.3:** Custom auto-fix prompts shall remain task-level and provider-scoped.
|
||||
Only task targets shall accept `auto_fix_prompt_override`. Selecting both providers shall update each provider's prompt separately.
|
||||
An empty string shall clear the override. Prompt-only updates shall work without linked contributions.
|
||||
Omitted fields shall remain unchanged. Null fields, empty patches, and lifecycle prompt overrides shall be rejected.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.4:** Unsupported fields or unresolved targets shall fail preflight without writes.
|
||||
Cross-provider runtime failures shall report applied, failed, and unattempted providers, plus known resulting state.
|
||||
The response shall not claim cross-provider atomicity or encourage retry of already-applied updates.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004.5:** Trusted principal checks, task workspace authorization, workspace credentials, and provider-origin checks shall apply to every call.
|
||||
GitLab project paths shall be resolved internally only from verified association or repository identity.
|
||||
Ambiguous identity shall fail closed without affecting another contribution.
|
||||
|
||||
### REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005: Report a bound auto-fix outcome
|
||||
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.1:** `report_change_request_auto_fix_outcome_kandev` shall accept only `outcome` and a nonempty `summary`.
|
||||
Outcomes shall remain `action_taken`, `non_actionable`, and `blocked`. Task, session, turn, provider, and contribution identity shall remain server-owned.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.2:** Reports shall preserve the existing GitHub attempt protocol, first-write behavior, replay rules, and provider-progress requirements.
|
||||
Ordinary turns, stale turns, foreign sessions, and conflicting reports shall not mutate attempts or enable automation.
|
||||
Unmatched reports shall explain that ordinary work must finish without retrying the report or enabling auto-fix.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005.3:** GitLab shall report outcome-protocol support as false until its own bound implementation exists.
|
||||
A mixed task's GitLab turn shall not report against a GitHub attempt because the tool is visible.
|
||||
|
||||
### REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-006: Migrate callers and discovery
|
||||
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-006.1:** The released catalog shall remove all eight superseded tool names.
|
||||
New injected instructions, built-in workflows, skills, and public examples shall use the shared contract.
|
||||
- **AC-INTEGRATIONS-TASK-CHANGE-LINK-MCP-006.2:** The migration shall document cached catalogs, old runtime binaries, queued prompts, and user-edited callers.
|
||||
It shall preserve user-edited prompts and historical transcripts. Any temporary transport compatibility shall have a release-bound retirement rule.
|
||||
Both supported MCP protocol eras shall expose the same contract and validation behavior.
|
||||
|
||||
## Exclusions
|
||||
|
||||
Provider stores, REST/WebSocket UI settings, rendered UI, provider automation algorithms,
|
||||
and cross-provider replacement are unchanged. GitLab outcome tracking is excluded.
|
||||
No new provider, database migration, or generic provider persistence framework is required.
|
||||
|
||||
## Implementation Plans
|
||||
|
||||
- [Provider-neutral change request tools](../../../plans/provider-neutral-change-request-mcp/plan.md): the implementation package.
|
||||
- [Merged association delivery](../../../plans/manage-task-pr-and-m/plan.md): historical baseline, completed in PR #3506.
|
||||
|
||||
@@ -3,75 +3,94 @@ status: current
|
||||
system: integrations
|
||||
requirements:
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-002
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-003
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-004
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-005
|
||||
- REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-006
|
||||
created: 2026-09-14
|
||||
owners:
|
||||
- kandev
|
||||
---
|
||||
|
||||
# Manage task change requests through MCP System Design
|
||||
# Task change request MCP system design
|
||||
|
||||
## Purpose and boundaries
|
||||
|
||||
This design gives agents one provider-neutral MCP surface for managing a
|
||||
task's GitHub pull request and GitLab merge request associations. The MCP
|
||||
tool surface and the task-facing handler are owned here; provider stores,
|
||||
webhook discovery, and automation handling stay owned by their existing
|
||||
GitHub and GitLab designs, and task identity, workspace reach authorization,
|
||||
and list/serialization surfaces stay owned by the task system.
|
||||
The integration system owns the shared contribution contract. Provider services
|
||||
retain their persistence, credentials, automation algorithms, and events.
|
||||
The MCP layer translates explicit agent intent into those existing services.
|
||||
This design replaces the MCP surface after PR #3506. It describes the
|
||||
implementation introduced for the planned 0.95.0 stable release.
|
||||
|
||||
## Requirement mapping
|
||||
|
||||
| Requirement | Design section |
|
||||
| Requirement suffix in `REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-*` | Design sections |
|
||||
| --- | --- |
|
||||
| `REQ-INTEGRATIONS-TASK-CHANGE-LINK-MCP-001` | [Components and responsibilities](#components-and-responsibilities), [Control flow](#control-flow) |
|
||||
| 001, 003 | Management, Security and identity, Failure and recovery |
|
||||
| 002 | Read contract, Capabilities and discovery |
|
||||
| 004 | Automation targeting, Security and identity |
|
||||
| 005 | Bound outcome reporting |
|
||||
| 006 | Compatibility and migration |
|
||||
|
||||
## Verified baseline
|
||||
|
||||
PR [#3506](https://github.com/kdlbs/kandev/pull/3506) merged on
|
||||
2026-09-14 at 14:00:36 UTC as `262ecdf270b5171538a68e9937dda7894ee01673`.
|
||||
That commit was both HEAD and fetched `origin/main` during investigation.
|
||||
|
||||
The merged coordinator preserves same-identity no-op, same-provider replacement,
|
||||
new-link-first ordering, and compensation only for newly created links.
|
||||
Its tests cover stale unlink, workspace boundaries, host spoofing, and failed compensation.
|
||||
GitHub detach persists tombstones and exact automation cleanup. GitLab unlink
|
||||
removes exact automation state and publishes a workspace event after persistence.
|
||||
|
||||
`TaskCIOptionsPatch` supports one PR internally. The current MCP server handler
|
||||
forwards only switches and prompt, so it cannot target that PR through MCP.
|
||||
The GitLab MCP handler forwards `repository_id`, `project_path`, and `mr_iid`.
|
||||
Both provider services keep five switches per association and a prompt per task/provider.
|
||||
|
||||
`orchestrator.Service.ReportTaskPRAutoFixOutcome` resolves the active turn and
|
||||
calls the GitHub attempt store. GitLab has fix-attempt counters and checkpoints,
|
||||
but no equivalent bound outcome reporter. A neutral name does not add that capability.
|
||||
|
||||
## Components and responsibilities
|
||||
|
||||
- `apps/backend/internal/mcp/handlers/task_change_link.go` validates the
|
||||
request shape, binds the caller task identity through the ordinary task
|
||||
reach path, and forwards one provider-neutral request to the coordinator.
|
||||
- `apps/backend/internal/backendapp/task_change_link_coordinator.go`
|
||||
resolves the canonical repository from the task's workspace, rejects
|
||||
unknown or unverified provider hosts, dispatches to the provider service,
|
||||
and returns the resulting linked set. Replacement compensates a failed
|
||||
post-establishment exchange by removing the newly created association and
|
||||
reports both errors when compensation itself fails.
|
||||
- `apps/backend/internal/github` and `apps/backend/internal/gitlab` own
|
||||
association persistence, idempotent link/removal, and exact automation
|
||||
retirement scoped to one provider, repository, and change-request number.
|
||||
GitHub detach keeps durable tombstones; GitLab unlink publishes a
|
||||
workspace-scoped deletion event after persistence.
|
||||
- `apps/backend/internal/mcp/server/server.go` registers
|
||||
`link_task_pr_kandev`, `unlink_task_pr_kandev`, and
|
||||
`replace_task_pr_kandev` with provider-aware availability.
|
||||
Existing source boundaries:
|
||||
|
||||
## Data and contracts
|
||||
- `internal/mcp/server/server.go`: profile registration and tool schemas.
|
||||
- `internal/mcp/server/handlers.go`: tool-to-backend dispatch and bound task identity.
|
||||
- `internal/mcp/server/tool_argument_validation.go`: schema validation inside `wrapHandler`.
|
||||
- `internal/mcp/handlers/handlers.go`: backend action registration.
|
||||
- `internal/mcp/handlers/task_change_link.go`: association identity and principal checks.
|
||||
- `internal/mcp/handlers/task_change_request.go`: shared read and automation DTOs and validation.
|
||||
- `internal/backendapp/task_change_link_coordinator.go`: association operations and provider dispatch.
|
||||
- `internal/backendapp/task_change_request_read.go`: provider-neutral read projection and capabilities.
|
||||
- `internal/backendapp/task_change_request_automation.go`: explicit target preflight and provider fan-out.
|
||||
- `internal/mcp/handlers/task_pr_automation.go` and `task_mr_automation.go`: existing provider service interfaces and events.
|
||||
- `internal/mcp/handlers/task_pr_enrich.go`: existing task-list projections.
|
||||
- `internal/orchestrator/ci_automation_attempt.go`: trusted active-turn resolution.
|
||||
- `pkg/websocket/actions.go`: internal action names, independent from MCP tool names.
|
||||
|
||||
Every mutation requires explicit `task_id`, a provider discriminator
|
||||
(`github` or `gitlab`), the canonical repository identity (`repository_id`),
|
||||
and the change-request number. A bare number is invalid. Replacement adds the
|
||||
old association triple (`old_provider`, `old_repository_id`,
|
||||
`old_number`). Responses return the current canonical linked set for the
|
||||
task.
|
||||
Paths in this section are relative to `apps/backend/`.
|
||||
Add a small shared automation/read coordinator at the `backendapp` composition boundary.
|
||||
Use concrete GitHub and GitLab adapters behind a narrow shared interface.
|
||||
Keep the existing association coordinator and provider services.
|
||||
Do not move provider tables, dedupe state, prompt defaults, or event ownership.
|
||||
|
||||
Unlinking changes only the active association row. Conversation history and
|
||||
terminal receipts remain untouched, and re-linking the same identity restores
|
||||
an active association.
|
||||
Add neutral backend actions and typed request/response DTOs for the four tools.
|
||||
Keep provider DTOs behind the adapters. Share identity validation between operations.
|
||||
Do not expose provider-specific request unions to agents.
|
||||
|
||||
## Control flow
|
||||
## Schema rules
|
||||
|
||||
1. The MCP server receives the tool call and resolves the caller task.
|
||||
2. The handler authorizes workspace reach for that task.
|
||||
3. The handler validates provider, repository identity, and number, rejecting
|
||||
a bare number or unresolved repository before any store mutation.
|
||||
4. The coordinator loads the task's repositories, verifies the requested
|
||||
canonical repository belongs to the task workspace and carries a verified
|
||||
provider host, and dispatches link, unlink, or replace.
|
||||
5. The provider service applies idempotent persistence, scoped automation
|
||||
cleanup, and deletion-event publication.
|
||||
6. The coordinator assembles the resulting linked set and the handler returns
|
||||
it. List/query surfaces read the same stores, so no extra invalidation is
|
||||
required for restart-consistent state.
|
||||
Use raw JSON Schema with object roots, `additionalProperties: false`, and nested
|
||||
closed objects. Require nonempty strings and integers with minimum 1.
|
||||
Declare every root property before applying `oneOf` branches for operations and targets.
|
||||
The existing schema compiler closes root objects, so branch-only properties would be rejected.
|
||||
Use enum values for providers and operations. Reject null instead of treating it as omission.
|
||||
Schema validation and backend validation must agree, including direct backend calls.
|
||||
Backend authorization must not depend on successful agentctl validation.
|
||||
|
||||
## GitHub caller identity
|
||||
|
||||
@@ -115,3 +134,292 @@ Delivery is tracked in the
|
||||
(`old_provider`, `old_repository_id`, `old_number`). See
|
||||
[docs/public/automation-and-mcp.md](../../../public/automation-and-mcp.md)
|
||||
for the operator-facing contract.
|
||||
|
||||
## Read contract
|
||||
|
||||
`get_task_change_requests_kandev` takes `{}`. It reads only the bound current task.
|
||||
It returns this stable envelope:
|
||||
|
||||
```json
|
||||
{
|
||||
"task_id": "task-1",
|
||||
"complete": true,
|
||||
"change_requests": [],
|
||||
"provider_settings": [],
|
||||
"provider_capabilities": [],
|
||||
"errors": []
|
||||
}
|
||||
```
|
||||
|
||||
Each `change_requests` item includes `provider`, `repository_id`, `number`,
|
||||
`url`, `title`, `state`, `draft`, `base_ref`, `head_ref`, and `head_sha`.
|
||||
State is `open | closed | merged | unknown`; preserve the provider state separately
|
||||
as `provider_state` when normalization loses information.
|
||||
Include nullable `merged_at`, `closed_at`, and `updated_at` where available.
|
||||
An absent observation stays null or unknown; never invent a fresh provider read.
|
||||
|
||||
Each item includes `identity_status: resolved | unresolved | ambiguous`, the five
|
||||
`automation` switches, and `capabilities`. Missing settings are null on read failure.
|
||||
Default false is valid only when the provider service confirms its default.
|
||||
An unresolved historical `repository_id` is null, never a guessed canonical identifier.
|
||||
Duplicate canonical triples with different GitLab paths are marked ambiguous.
|
||||
All mutations on an ambiguous triple fail before selecting a row.
|
||||
|
||||
`provider_settings` has one item per available provider: `provider`,
|
||||
`auto_fix_prompt_override`, `effective_auto_fix_prompt`, `using_default_prompt`,
|
||||
`auto_fix_max_rounds`, and `prompt_scope: task_provider`.
|
||||
Return available automation state such as round count and last error in a
|
||||
provider-labelled `automation_status` object. Do not rename opaque internal checkpoints into shared semantics.
|
||||
Lifecycle prompt text stays excluded. Do not combine different provider prompts or aggregate switches into misleading booleans.
|
||||
|
||||
An installed provider read failure sets `complete: false` and adds a sanitized
|
||||
provider error. Successful provider results remain usable. An unconfigured provider
|
||||
is marked unavailable rather than represented as an empty successful read.
|
||||
The read is a persisted snapshot; it does not trigger provider synchronization.
|
||||
Task-list `change_requests` and GitHub-only `prs` retain their existing shapes.
|
||||
|
||||
## Management
|
||||
|
||||
`manage_task_change_request_kandev` takes the existing flat identity fields plus
|
||||
`operation`. `task_id` remains explicit and can identify another task in the caller workspace.
|
||||
|
||||
```json
|
||||
{
|
||||
"operation": "replace",
|
||||
"task_id": "task-1",
|
||||
"provider": "gitlab",
|
||||
"repository_id": "repo-new",
|
||||
"number": 42,
|
||||
"old_provider": "gitlab",
|
||||
"old_repository_id": "repo-old",
|
||||
"old_number": 7
|
||||
}
|
||||
```
|
||||
|
||||
Link and unlink forbid all `old_*` fields. Replace requires all three and equal
|
||||
providers. Preserve `TaskChangeLinkRequest` and dispatch to its three service methods.
|
||||
Return `task_id` and `links` containing the resulting canonical triples.
|
||||
This preserves the merged association response without requiring a second automation read.
|
||||
|
||||
Reuse `taskChangeLinkCoordinator.ReplaceTaskChange` and its compensation order.
|
||||
Validate operation and cross-provider mismatch before mutation.
|
||||
An identical old/new identity returns current links without detachment.
|
||||
An absent old link preserves existing idempotent behavior: establish the new link.
|
||||
A new link that already existed is never compensation-owned by this request.
|
||||
|
||||
## Automation targeting
|
||||
|
||||
`update_task_change_request_automation_kandev` takes exactly `target` and `patch`.
|
||||
Task, session, and caller identifiers are forbidden public arguments.
|
||||
|
||||
Association target:
|
||||
|
||||
```json
|
||||
{
|
||||
"target": {"scope": "association", "provider": "github", "repository_id": "repo-gh", "number": 3506},
|
||||
"patch": {"auto_fix_enabled": false}
|
||||
}
|
||||
```
|
||||
|
||||
Task target:
|
||||
|
||||
```json
|
||||
{
|
||||
"target": {"scope": "task", "providers": ["github", "gitlab"]},
|
||||
"patch": {"prompt_on_merged": true, "auto_fix_prompt_override": "Run the focused checks before pushing."}
|
||||
}
|
||||
```
|
||||
|
||||
Task `providers` is required, nonempty, unique, and drawn from the supported enum.
|
||||
It is a deliberate selection, not an omitted identity or a wildcard that changes
|
||||
meaning when another provider is added. A single provider selects all current
|
||||
links for that provider. Both values explicitly select a mixed task.
|
||||
|
||||
`patch` allows these optional fields and requires at least one:
|
||||
|
||||
| Field | Type | Association target | Task target |
|
||||
| --- | --- | --- | --- |
|
||||
| `auto_fix_enabled` | boolean | Exact link | Current links of selected providers |
|
||||
| `auto_merge_enabled` | boolean | Exact link | Current links of selected providers |
|
||||
| `prompt_on_review_requested` | boolean | Exact link | Current links of selected providers |
|
||||
| `prompt_on_merged` | boolean | Exact link | Current links of selected providers |
|
||||
| `prompt_on_closed` | boolean | Exact link | Current links of selected providers |
|
||||
| `auto_fix_prompt_override` | string | Forbidden | Task/provider prompt; empty clears |
|
||||
|
||||
A task prompt applies to present and future links for that provider. Switches
|
||||
apply only to links present at the provider transaction. They do not become defaults.
|
||||
Prompt-only updates may select an available provider without linked contributions.
|
||||
A switch patch requires at least one link for every selected provider.
|
||||
For a mixed prompt/switch patch, an empty selected provider fails preflight for the entire request.
|
||||
|
||||
Preflight checks the full request, principal, provider availability, capabilities,
|
||||
link identities, and known credential prerequisites before any write.
|
||||
Each provider service still revalidates authoritative membership and credentials.
|
||||
Task fan-out uses each provider's existing transaction and membership checks.
|
||||
A link added between provider transactions may be included only in that provider's write;
|
||||
return actual affected identities rather than claiming a cross-provider snapshot.
|
||||
|
||||
Apply selected providers in lexical order (`github`, then `gitlab`). Stop after
|
||||
first runtime failure. Keep each provider's existing atomic prompt/switch transaction.
|
||||
Do not add cross-store transactions or reverse successful automation writes;
|
||||
reversal could reset checkpoints or race concurrent user changes.
|
||||
|
||||
Return `status: applied | partial | failed`, provider results with
|
||||
`status: applied | failed | not_attempted`, affected identities, and resulting
|
||||
settings where known. A failed provider readback uses `state_known: false`.
|
||||
A write followed by failed readback must not appear as a guaranteed rolled-back write.
|
||||
Return an MCP error result for partial/failed requests while preserving this structured
|
||||
payload in text as well as structured content. Never discard it at the WS adapter.
|
||||
The caller reads state and retries only failed/unattempted targets.
|
||||
|
||||
## Security and identity
|
||||
|
||||
Derive caller task, session, and workspace from `mcpscope.PrincipalFromContext`.
|
||||
Recheck target task workspace in backend handlers. Association operations retain
|
||||
same-workspace reach; read, automation, and outcome operations retain current-task binding.
|
||||
Reject injected public identity fields. Internal envelope identity must match the principal.
|
||||
Retain live permission/profile checks and provider-origin validation for direct calls.
|
||||
|
||||
Link and replacement's new link require the repository attached to the target task,
|
||||
its workspace match, and verified provider origin. Keep workspace-scoped GitHub
|
||||
user credentials and GitLab credentials in the existing services.
|
||||
Never construct a provider URL from an agent-supplied host or project path.
|
||||
|
||||
Unlink resolves the exact stored association without requiring the repository to
|
||||
remain attached. This preserves stale removal and avoids a new remote dependency.
|
||||
For GitLab automation, resolve `ProjectPath` from the unique stored `TaskMR` selected
|
||||
by the canonical triple. Verify it against stored origin/repository evidence.
|
||||
If a legacy row lacks repository identity, resolve only one verified workspace
|
||||
repository matching its host and full project path. Otherwise report unresolved identity.
|
||||
Do not persist guessed backfills or select by number alone.
|
||||
|
||||
## Capabilities and discovery
|
||||
|
||||
Expose provider support and current availability separately. Capabilities use
|
||||
`link`, `unlink`, `replace_same_provider`, `auto_fix`, `auto_merge`,
|
||||
`lifecycle_notifications`, `custom_auto_fix_prompt`, and `auto_fix_outcome_reporting`.
|
||||
Both implemented providers support the first seven. Only GitHub supports the last.
|
||||
Per-association eligibility can be false for unresolved identity, stale link
|
||||
operations, unavailable services, or credentials. Include a stable reason code.
|
||||
Feature support does not promise successful merge or provider access.
|
||||
|
||||
Retain backend-owned provider union, launch propagation, dynamic registry rebuild,
|
||||
and tool-list-changed notification from the provider-scoped discovery ADR.
|
||||
Register the first three tools once in task mode when GitHub or GitLab is present.
|
||||
Register the outcome tool only when GitHub is present. Local/unknown-only tasks
|
||||
receive none of these tools. Other modes retain their existing exclusion rules.
|
||||
A same-workspace association target still receives independent backend checks.
|
||||
Stale cleanup remains callable through the registered backend action and existing
|
||||
UI even when a local-only task catalog hides contribution tools.
|
||||
|
||||
A later provider adds one adapter and capability entry, not another tool family.
|
||||
A provider with different capabilities must reject unsupported patches explicitly.
|
||||
|
||||
## Bound outcome reporting
|
||||
|
||||
`report_change_request_auto_fix_outcome_kandev` accepts only:
|
||||
|
||||
```json
|
||||
{"outcome": "action_taken", "summary": "Pushed a fix for the failing integration check."}
|
||||
```
|
||||
|
||||
Preserve the existing handler principal check and orchestrator active-turn lookup.
|
||||
Route only to the provider of a server-bound unresolved attempt. Today this path
|
||||
has one implementation: GitHub. Do not accept a provider selector or fall back
|
||||
from an unmatched GitLab turn to an arbitrary GitHub association.
|
||||
|
||||
Keep first-write/replay handling, attempt identity, feedback signature, provider
|
||||
progress confirmation, retry rules, and round caps in the existing GitHub service.
|
||||
Preserve the unmatched-turn message and its instruction not to retry or enable auto-fix.
|
||||
Rename the tool reference in the immutable server-owned outcome protocol.
|
||||
Keep structured hidden context and passthrough terminal context equivalent.
|
||||
Manual review, sibling messages, and copied old instructions do not establish an obligation.
|
||||
|
||||
## Failure and recovery
|
||||
|
||||
Association errors preserve committed state. Add a narrow typed result at the
|
||||
coordinator/handler seam where current joined errors cannot carry machine-readable state.
|
||||
Report `operation_error`, `rollback_error`, `links`, and `state_known` on replacement failure.
|
||||
Sanitize provider errors and log full causes server-side.
|
||||
When final listing fails after a committed mutation, report uncertain readback rather
|
||||
than implying that no mutation occurred. Do not automatically repeat replacement.
|
||||
|
||||
Keep GitHub tombstones, exact automation retirement, GitLab refresh-watch cleanup,
|
||||
and committed provider deletion events. Event publication failure does not undo
|
||||
persistence; preserve existing provider logging and recovery behavior.
|
||||
No new database schema, cross-provider transaction, or metrics family is required.
|
||||
Log operation, provider, failure stage, and compensation status without prompt bodies or credentials.
|
||||
|
||||
## Compatibility and migration
|
||||
|
||||
The released catalog contains no legacy aliases. The SDK's `WithToolFilter`
|
||||
also filters invocation, so it cannot safely implement callable hidden aliases.
|
||||
Do not fork the protocol or add a second registry to hide these eight names.
|
||||
|
||||
Remove these tool registrations in the same release as caller migration:
|
||||
|
||||
- `link_task_pr_kandev`, `unlink_task_pr_kandev`, `replace_task_pr_kandev`.
|
||||
- `get_task_pr_automation_kandev`, `update_task_pr_automation_kandev`.
|
||||
- `get_task_mr_automation_kandev`, `update_task_mr_automation_kandev`.
|
||||
- `report_pr_auto_fix_outcome_kandev`.
|
||||
|
||||
Old names on a new runtime return the normal unknown-tool result without mutation.
|
||||
Document rediscovery and session resume with the new runtime. Do not claim that
|
||||
registry refresh updates the executable of an already-running old agentctl.
|
||||
|
||||
Retain existing backend WS action handlers for one release transition to serve
|
||||
old agentctl processes. These are internal transport compatibility, not new MCP aliases.
|
||||
They keep their original provider scope and response shape. Do not translate omitted
|
||||
legacy identity into a mixed-provider update. Apply trusted principal checks there too.
|
||||
Remove these compatibility handlers in the first stable release after the
|
||||
planned 0.95.0 release that introduces the neutral tools. The removal obligation
|
||||
is recorded in the implementation plan.
|
||||
Old agentctl processes must resume on a current runtime before that removal release.
|
||||
|
||||
Migrate `config/workflows/pr-review.yml`, its loader tests, and
|
||||
`internal/orchestrator/event_handlers_github_ci_automation.go` with its protocol tests.
|
||||
Search `.agents`, built-in prompt sources, public docs, and all runtime source for old names.
|
||||
The inspected `.agents` skills contain no matches; repeat the scan at implementation.
|
||||
Preserve edited workflow/prompt records. Use existing guarded seed refresh patterns
|
||||
only where a persisted built-in has a known historical value.
|
||||
|
||||
Select the outcome tool name from the current execution's Kandev tool observation.
|
||||
The existing `SessionMetaKeyMCPAttachmentState` and `LoadMCPAttachmentHistory`
|
||||
provide execution-scoped tool evidence. This evidence selects wording only, never authorization.
|
||||
Ignore previous attempts and foreign MCP servers. Prefer the neutral name when present.
|
||||
If only the legacy name exists, retain legacy wording for that old runtime.
|
||||
If current evidence is missing, leave dispatch retryable without consuming a round
|
||||
or binding an attempt to an undelivered prompt. Retry through the existing dispatcher,
|
||||
not a new polling loop. Surface the missing-catalog reason in existing automation errors.
|
||||
|
||||
Queued trusted protocol blocks must use the new name at delivery on a new runtime.
|
||||
Do not rewrite user text or stored transcripts. An already-delivered old block
|
||||
can remain in history; the new catalog and resume guidance identify the replacement.
|
||||
Test an old binary against retained actions and a resumed session against the new catalog.
|
||||
Do not emit instructions to a tool absent from that runtime's catalog.
|
||||
|
||||
`docs/public/automation-and-mcp.md`, `docs/public/integrations.md`, and
|
||||
`docs/public/coverage.json` were updated during implementation and describe the
|
||||
neutral catalog after cutover.
|
||||
|
||||
The provider-aware runtime requirement's old tool-name criteria were marked
|
||||
superseded by this contract's 002.2 at cutover, preserving the backend union and
|
||||
transport requirements.
|
||||
Replace duplicate legacy discovery prose with a link to this design.
|
||||
The existing explicit-outcome ADR remains authoritative for attempt semantics;
|
||||
only its tool name changes through the new ADR.
|
||||
|
||||
## Related decisions and implementation
|
||||
|
||||
- [Neutral contribution contract decision](../../../decisions/2026-09-14-provider-neutral-change-request-mcp.md).
|
||||
- [Provider-scoped runtime](../../../decisions/2026-08-03-provider-scoped-task-mcp-tools.md).
|
||||
- [Explicit outcomes](../../../decisions/2026-09-06-explicit-pr-auto-fix-outcomes.md).
|
||||
- [Dual-era MCP](../../../decisions/2026-08-30-dual-era-mcp-protocol.md).
|
||||
- [Implementation package](../../../plans/provider-neutral-change-request-mcp/plan.md).
|
||||
|
||||
## Implementation record
|
||||
|
||||
The neutral catalog and caller migration are implemented for the planned
|
||||
0.95.0 stable release. The legacy backend WebSocket actions remain during that
|
||||
release transition and are scheduled for removal in the first stable release
|
||||
after 0.95.0.
|
||||
|
||||
Reference in New Issue
Block a user