7.0 KiB
created, status, requirements, system_design, legacy_specs
| created | status | requirements | system_design | legacy_specs | ||||
|---|---|---|---|---|---|---|---|---|
| 2026-08-27 | complete |
|
|
Fix Plan: Resolve GitHub Clone Protocol Per Host At Use Time
Overview
Replace the backend-startup Git protocol snapshots with one host-aware resolver. Evaluate this resolver when Kandev constructs a clone URL or an executor-inherited managed-checkout origin. Then route the long-lived cloner and review-repository adapter through it. The tests prove that all paths observe configuration changes without a restart.
Confirmed root cause
repoclone.DetectGitProtocol runs only gh config get git_protocol. Thus, a global https value
wins when gh config get -h github.com git_protocol reports the effective ssh preference.
backendapp/main.go passes that incorrect startup result into one long-lived repoclone.Cloner.
backendapp/orchestrator.go stores a second startup result on repositoryResolverAdapter.
Executor-inherited origin reconciliation selects the wrong transport. It cannot observe later gh
configuration changes until the backend restarts.
The smallest reproduction uses an isolated GH_CONFIG_DIR. Set global git_protocol=https and
host-specific github.com git_protocol=ssh. The current detector reads https.
gh config get -h github.com git_protocol reads ssh.
Scope
In scope
- Resolve the
github.comclone protocol from host-specific configuration first. Use global configuration second. Use SSH by default when neither scope yieldssshorhttps. - Resolve the protocol at clone URL construction and Local/Worktree launch or resume origin reconciliation, not backend startup.
- Remove the cached protocol field from
repositoryResolverAdapterand route it through the same live resolver asrepoclone.Cloner. - Preserve canonical HTTPS for managed task credentials and preserve user-managed local origins.
- Add deterministic tests with injected command and protocol resolvers.
Out of scope
- Executor-mode credential-helper or token bridging tracked by #3072.
- Discovering or validating the actor behind inherited SSH agents or credential managers.
- GitHub Enterprise Server or hosts other than the existing
github.comcontract. - Frontend, API, persistence, schema, or workspace-policy changes.
Technical approach
Host-aware protocol resolver
- In
apps/backend/internal/repoclone/protocol.go, make protocol resolution accept a context and a provider host. Querygh config get -h <host> git_protocolfirst. Then querygh config get git_protocol. Accept onlysshandhttps. Otherwise, return the existing SSH default. Bound the complete host-plus-global resolution operation with one five-second command context. - Isolate command execution behind an injected runner. Unit tests control the results and assert
command order without reading the developer's
ghconfiguration. Keep one five-second command timeout for the complete resolution operation.
Use-boundary resolution
- In
apps/backend/internal/repoclone/clone.go, store an injected protocol resolver, not a resolved protocol string. Make protocol-aware URL construction resolve the normalized provider host on every call. - In
apps/backend/internal/backendapp/main.go, construct the cloner with the live resolver and remove the startup call toDetectGitProtocol. - In
apps/backend/internal/orchestrator/executor/executor.goandexecutor_resume.go, thread the operation context through the protocol-awareRepoClonerURL builder. The shared launch and resume path continues to reconcile only Kandev-managed GitHub checkouts. Managed mode remains explicitly HTTPS. - In
apps/backend/internal/backendapp/orchestrator.go, replace the adapter's concrete cached protocol field with a narrow cloner interface that builds the URL atResolveForReviewuse time. Production wiring supplies the samerepoclone.Cloner. Tests supply a deterministic fake.
Tests
TestDetectGitProtocolPrefersHostConfigurationinapps/backend/internal/repoclone/protocol_test.gois the primary regression. Before the correction, the command runner observes no host-specific lookup. The result is HTTPS. Companion cases cover global fallback, unsupported values, command failures, and SSH default.TestClonerBuildCloneURLUsesCurrentProtocolinapps/backend/internal/repoclone/clone_test.gomutates an injected resolver between calls and proves one long-lived cloner does not cache a result.TestEnsureRepoLocalPathReevaluatesGitHubProtocolinapps/backend/internal/orchestrator/executor/executor_resume_clone_transport_test.goperforms two preparation passes with different resolver results. It proves that the managed origin changes without executor recreation. Existing managed-HTTPS and user-managed-local cases cover the exclusions.TestRepositoryResolverAdapterUsesCurrentGitProtocolinapps/backend/internal/backendapp/adapters_test.goperforms two resolutions through an injected fake and proves the adapter has no independent startup cache.
Execution checklist
- Audit the current plan, specifications, work order, and working tree.
- Implement the live host-aware protocol resolver and use-time URL construction.
- Update executor origin reconciliation and review-repository wiring.
- Add and pass the specified regression tests.
- Update plan/work-order verification results.
- Commit with hooks, push the branch, and create a ready-for-review PR.
- Wait 15 minutes, run PR fixup, and report the final PR state.
Work orders
Verification results
rtk go test -race ./internal/repoclone ./internal/orchestrator/executor ./internal/backendapp -run 'Test(DetectGitProtocol|ClonerBuildCloneURLUsesCurrentProtocol|EnsureRepoLocalPathReevaluatesGitHubProtocol|RepositoryResolverAdapterUsesCurrentGitProtocol)' -count=1passed with 11 tests in 3 packages, including the total-timeout regression.rtk go test -race ./internal/repoclone ./internal/orchestrator/executor ./internal/backendapppassed with 1,316 tests in 3 packages.- PR 3078 at
662d3c98d3ddd560ff46cab83e2d8cf965571f65completed with 44 checks passed, 0 failed, 0 pending, and 0 unresolved review threads. GitHub reportsMERGEABLE / CLEAN.
Risks
- Adding context to protocol-aware URL construction touches executor test fakes. All implementations must preserve the same host and operation context.
- A
ghlookup now occurs on each relevant URL construction. One five-second bound covers the complete host-plus-global resolution, and the sharedghsubprocess throttle limits the cost. Correctness requires no process cache. - Provider-host normalization must pass
github.com, not an HTTPS URL, togh --host. Clone URL construction must retain the canonical persisted provider origin.