Conversation
…canopy issues CLI F-7 (P0) — provider-aware alias resolver ========================================== `canopy issue 5` and `canopy issue '#5'` against a github_issues provider failed with `unknown_alias` because the resolver was hardcoded to look for Linear-shaped IDs. M5 shipped the Provider Protocol but the alias-resolution layer above it never learned about non-Linear shapes. This PR: - Adds `IssueProvider.parse_alias(alias) -> str | None` to the Protocol. Returns the canonicalised id when the provider recognises the shape, None otherwise (so the resolver falls through to feature-lane lookup). - LinearProvider.parse_alias matches `[A-Z]+-\d+` (case-insensitive). - GitHubIssuesProvider.parse_alias matches bare-N, `#N`, `owner/repo#N`, and the full GH URL form (extracts `owner/repo#N`). - Renames the alias resolver: `resolve_linear_id` → `resolve_issue_id`. The new resolver calls `provider.parse_alias(alias)` first; if no provider match, falls back to feature-name lookup with provider-aware error messages. The old `resolve_linear_id` is kept as a deprecated wrapper (preserves the legacy `no_linear_id` error code for back-compat). - The MCP `issue_get` tool now also routes through `resolve_issue_id`, so feature aliases work there too (was provider-only before). Smoke against canopy-test (with [issue_provider] = github_issues): canopy issue 5 → returns issue #5 ✓ canopy issue '#5' → returns issue #5 ✓ canopy issue 'https://.../issues/5' → returns issue #5 ✓ F-10 (incidental) — gh search query construction was malformed ============================================================== While verifying F-5, found that GitHubIssuesProvider.list_my_issues was building a query string like `repo:owner/repo is:open assignee:@me` and passing it positionally to `gh search issues`. But the search verb treats positional args as search *text* — the qualifiers got quoted as a single text token and GitHub returned `Invalid search query.` Unit tests at the `_gh_json` boundary mocked the call and asserted on constructed args, so they happily passed even though the args were nonsense to the real CLI. This is exactly the gap the integration test plan was meant to catch — and did. Fix: switch to `gh issue list --repo ... --state open --assignee @me --label ...` (the right verb form). Matches Phil's branch. F-5 (P2) — `canopy issues` (plural) CLI ======================================== Added `cmd_issues` mirroring `mcp__canopy__issue_list_my_issues`. Renders the canonical Issue shape in human-readable form; `--json` emits the list directly. Empty when no provider configured (no auto-complete signal) — matches MCP behavior. Tests: +21 across test_aliases (resolve_issue_id behaviour, deprecated wrapper preserves legacy error code), test_providers_linear (parse_alias recognises Linear IDs only), test_providers_github_issues (parse_alias recognises bare/hash/owner-repo/URL; gh issue list call shape — F-10 regression test). Suite: 628 → 644 passing. After this PR: F-1, F-2 (retracted), F-5, F-6, F-7, F-9, F-10 all fixed. Remaining from test-findings: F-3 (doctor mcp_orphans — backlog), F-4 (mcp.md OAuth-headless doc — separate small PR).
This was referenced May 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Three related fixes from docs/test-findings.md. The headline is F-7 — provider-aware alias resolver (the test plan's P0). F-10 was found incidentally while smoke-testing F-5.
F-7 (P0) —
canopy issueworks for any providerBefore:
canopy issue 5against a github_issues provider failed withunknown_aliasbecause the resolver was hardcoded to look for Linear-shaped IDs (SIN-412). M5 shipped the Provider Protocol but the alias-resolution layer above it never learned about non-Linear shapes.After: every alias form works:
Design: new
IssueProvider.parse_alias(alias) -> str | NoneProtocol method. Returns canonicalised id when the provider recognises the shape; None falls through to feature-lane lookup.LinearProvider.parse_aliasmatches[A-Z]+-\d+;GitHubIssuesProvider.parse_aliasmatches bare/hash/owner-repo/URL.resolve_linear_idrenamed toresolve_issue_id(provider-aware); old name kept as deprecated wrapper that preserves the legacyno_linear_iderror code for back-compat. The MCPissue_gettool now also routes throughresolve_issue_id, so feature aliases work there too.F-10 (incidental) —
gh search issuesquery was malformedFound while verifying F-5.
GitHubIssuesProvider.list_my_issuesbuilt a query string likerepo:owner/repo is:open assignee:@meand passed it positionally togh search issues. But the search verb treats positional args as search text — the qualifiers got quoted as a single text token and the GitHub API returnedInvalid search query.Unit tests mocked
_gh_jsonand asserted on constructed args, so they happily passed even though the args were nonsense to the real CLI. This is exactly the gap the integration test plan was meant to catch — and did.Fix: switch to
gh issue list --repo ... --state open --assignee @me --label ...(the right verb form, matches Phil's branch).F-5 (P2) —
canopy issuespluralAdded
cmd_issuesmirroringmcp__canopy__issue_list_my_issues. Empty list when no provider configured. Both--jsonand human-readable rendering of canonical Issue shape.Tests
+21 across:
test_aliases.py—resolve_issue_idbehaviour (Linear path, GH path with mocked provider, feature-lookup fallback, error codes); deprecatedresolve_linear_idwrapper preserves legacy code.test_providers_linear.py—parse_aliasmatches Linear IDs only, returns None for GH-shaped / feature-name input.test_providers_github_issues.py—parse_aliasmatches bare/hash/owner-repo/URL; F-10 regression:list_my_issuesusesgh issue listwith the right flag set.test_providers_types.py+test_providers_registry.py— Protocol stubs gainparse_aliassoisinstance(stub, IssueProvider)still passes.Suite: 628 → 644 passing.
Test plan
python -m pytest -q(644 pass)[issue_provider] = github_issues:canopy issue 5,canopy issue '#5',canopy issue '<URL>'all return the canonical Issue shapecanopy issues --jsonreturns[](no assigned issues)canopy issuesrenders#5 in_progress Test: ...After this PR
Remaining from test-findings.md: