fix(routing): default to Maintainer when no git remote exists (#1185)

When no git remote is configured, DetectUserRole() now defaults to
Maintainer instead of Contributor. This fixes issue routing for:

1. New personal projects (no remote configured yet)
2. Intentionally local-only repositories

Previously, issues would silently route to ~/.beads-planning instead
of the local .beads/ directory.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
aleiby
2026-01-19 10:11:00 -08:00
committed by GitHub
parent 460d2bf113
commit f4ee7ee73b
2 changed files with 30 additions and 7 deletions

View File

@@ -83,13 +83,13 @@ func TestDetermineTargetRepo(t *testing.T) {
}
func TestDetectUserRole_Fallback(t *testing.T) {
// Test fallback behavior when git is not available
// Test fallback behavior when git is not available - local projects default to maintainer
role, err := DetectUserRole("/nonexistent/path/that/does/not/exist")
if err != nil {
t.Fatalf("DetectUserRole() error = %v, want nil", err)
}
if role != Contributor {
t.Errorf("DetectUserRole() = %v, want %v (fallback)", role, Contributor)
if role != Maintainer {
t.Errorf("DetectUserRole() = %v, want %v (local project fallback)", role, Maintainer)
}
}
@@ -267,7 +267,7 @@ func TestDetectUserRole_HTTPSCredentialsMaintainer(t *testing.T) {
}
}
func TestDetectUserRole_DefaultContributor(t *testing.T) {
func TestDetectUserRole_HTTPSNoCredentialsContributor(t *testing.T) {
orig := gitCommandRunner
stub := &gitStub{t: t, responses: []gitResponse{
{expect: gitCall{"", []string{"config", "--get", "beads.role"}}, err: errors.New("missing")},
@@ -289,6 +289,29 @@ func TestDetectUserRole_DefaultContributor(t *testing.T) {
}
}
func TestDetectUserRole_NoRemoteMaintainer(t *testing.T) {
// When no git remote is configured, default to maintainer (local project)
orig := gitCommandRunner
stub := &gitStub{t: t, responses: []gitResponse{
{expect: gitCall{"/local", []string{"config", "--get", "beads.role"}}, err: errors.New("missing")},
{expect: gitCall{"/local", []string{"remote", "get-url", "--push", "origin"}}, err: errors.New("no remote")},
{expect: gitCall{"/local", []string{"remote", "get-url", "origin"}}, err: errors.New("no remote")},
}}
gitCommandRunner = stub.run
t.Cleanup(func() {
gitCommandRunner = orig
stub.verify()
})
role, err := DetectUserRole("/local")
if err != nil {
t.Fatalf("DetectUserRole error = %v", err)
}
if role != Maintainer {
t.Fatalf("expected %s for local project with no remote, got %s", Maintainer, role)
}
}
// TestFindTownRoutes_SymlinkedBeadsDir verifies that findTownRoutes correctly
// handles symlinked .beads directories by using findTownRootFromCWD() instead of
// walking up from the beadsDir path.