Skip to content

fix: fuzzy schedule scattering works with non-origin remote names#24390

Merged
pelikhan merged 3 commits intomainfrom
copilot/fix-fuzzy-schedule-origin-remote
Apr 3, 2026
Merged

fix: fuzzy schedule scattering works with non-origin remote names#24390
pelikhan merged 3 commits intomainfrom
copilot/fix-fuzzy-schedule-origin-remote

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 3, 2026

Fuzzy schedule scattering silently fell back to a context-free (and collision-prone) seed when the repo had no remote named origin, even if a perfectly usable remote was configured under a different name.

Changes

  • New resolveRemoteURL(dir string) helper — encapsulates remote resolution with priority:

    1. origin remote (backward compatible)
    2. Any single configured remote, regardless of name
    3. Error (multiple non-origin remotes → existing warning behavior preserved)
  • Updated consumers to use the new helper:

    • getRepositorySlugFromRemote() — used for schedule scattering seed
    • getRepositorySlugFromRemoteForPath() — used during per-file compilation
    • getHostFromOriginRemote() — used for GHES host detection
  • New --schedule-seed owner/repo flag on gh aw compile — explicitly overrides the repository slug used as the fuzzy schedule scattering seed, bypassing all git remote detection. Useful when multiple remotes exist with no origin. Invalid values (not in owner/repo format) emit a warning and fall back to automatic detection.

Behavior

Remote config Before After
origin exists ✅ uses origin ✅ uses origin
Single non-origin remote (e.g. myorg) ⚠️ warning, no context ✅ uses myorg
Multiple remotes, no origin ⚠️ warning ⚠️ warning (ambiguous) — use --schedule-seed
Multiple remotes, origin present ✅ uses origin ✅ uses origin
--schedule-seed owner/repo provided N/A ✅ uses provided slug, skips remote detection

Copilot AI linked an issue Apr 3, 2026 that may be closed by this pull request
The fuzzy schedule scattering previously required a remote named 'origin'
to determine the repository context. This commit adds a smarter fallback:

1. First tries the 'origin' remote for backward compatibility
2. If 'origin' is not configured but exactly one other remote exists,
   that remote is used automatically
3. If multiple remotes exist without 'origin', falls through to the
   existing warning behavior

Adds a new `resolveRemoteURL(dir)` helper function that encapsulates
this logic, and updates `getRepositorySlugFromRemote()`,
`getRepositorySlugFromRemoteForPath()`, and `getHostFromOriginRemote()`
to use it.

Fixes: fuzzy schedule scattering without repository context warning
when using non-'origin' remote names.

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/b2039ff1-76de-419b-9155-60b3110faf4b

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix fuzzy schedule to support custom remote names fix: fuzzy schedule scattering works with non-origin remote names Apr 3, 2026
Copilot AI requested a review from pelikhan April 3, 2026 22:32
@pelikhan
Copy link
Copy Markdown
Collaborator

pelikhan commented Apr 3, 2026

@copilot Add a compile command CLI argument --schedule-seed as a string to override the origin search and provide an origin name via the argument.

Allows users to override the repository slug used as the seed for
fuzzy schedule scattering, bypassing git remote detection entirely.
This is useful when no 'origin' remote is configured and multiple
remotes exist (where automatic detection is ambiguous).

Usage: gh aw compile --schedule-seed owner/repo

The value is validated to be in 'owner/repo' format; an invalid
value emits a warning and falls back to automatic detection.

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/301bc69e-22a6-4499-8a41-de8b59db9c50

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 3, 2026

@copilot Add a compile command CLI argument --schedule-seed as a string to override the origin search and provide an origin name via the argument.

Added in commit 01b6668. The new --schedule-seed owner/repo flag bypasses all git remote detection and uses the provided value directly as the schedule scattering seed. The value is validated to be in owner/repo format; an invalid value emits a warning and falls back to automatic detection.

@pelikhan pelikhan marked this pull request as ready for review April 3, 2026 22:51
Copilot AI review requested due to automatic review settings April 3, 2026 22:51
@pelikhan pelikhan merged commit 127e47e into main Apr 3, 2026
52 checks passed
@pelikhan pelikhan deleted the copilot/fix-fuzzy-schedule-origin-remote branch April 3, 2026 22:52
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes fuzzy schedule scattering’s repository-context detection when a repo lacks an origin remote, and adds an explicit CLI override to control the scattering seed.

Changes:

  • Added resolveRemoteURL(dir) to prefer origin, otherwise use a single configured non-origin remote, otherwise error on ambiguity.
  • Updated git-remote consumers to use resolveRemoteURL (host detection and repo slug extraction).
  • Added --schedule-seed owner/repo flag wiring to override the schedule scattering seed and bypass git remote detection.
Show a summary per file
File Description
pkg/cli/git.go Introduces resolveRemoteURL and updates host/slug detection to support non-origin remotes.
pkg/cli/git_test.go Adds test coverage for resolveRemoteURL and non-origin/multi-remote behaviors.
pkg/cli/compile_config.go Adds ScheduleSeed to compilation config to support explicit seed overrides.
pkg/cli/compile_compiler_setup.go Implements --schedule-seed validation + repository slug override behavior.
cmd/gh-aw/main.go Plumbs the new --schedule-seed flag into CompileConfig.
pkg/agentdrain/data/default_weights.json Reformats JSON arrays (no functional behavior change).

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 6/6 changed files
  • Comments generated: 5

Comment on lines +205 to +214
// Validate owner/repo format: must contain exactly one '/' with non-empty parts
parts := strings.SplitN(config.ScheduleSeed, "/", 2)
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
compileCompilerSetupLog.Printf("Invalid --schedule-seed value %q: expected 'owner/repo' format", config.ScheduleSeed)
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(
fmt.Sprintf("--schedule-seed %q is not in 'owner/repo' format; ignoring and falling back to git remote detection", config.ScheduleSeed),
))
} else {
compiler.SetRepositorySlug(config.ScheduleSeed)
compileCompilerSetupLog.Printf("Repository slug overridden via --schedule-seed: %s", config.ScheduleSeed)
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--schedule-seed validation does not enforce the documented “exactly one '/'” requirement. Using strings.SplitN(seed, "/", 2) allows values like owner/repo/extra to be treated as valid and used as the repository slug, which can lead to unexpected scattering seeds. Consider validating with strings.Count(seed, "/") == 1 (or splitting on all '/' and requiring exactly 2 non-empty parts) and optionally trimming surrounding whitespace before validation.

Suggested change
// Validate owner/repo format: must contain exactly one '/' with non-empty parts
parts := strings.SplitN(config.ScheduleSeed, "/", 2)
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
compileCompilerSetupLog.Printf("Invalid --schedule-seed value %q: expected 'owner/repo' format", config.ScheduleSeed)
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(
fmt.Sprintf("--schedule-seed %q is not in 'owner/repo' format; ignoring and falling back to git remote detection", config.ScheduleSeed),
))
} else {
compiler.SetRepositorySlug(config.ScheduleSeed)
compileCompilerSetupLog.Printf("Repository slug overridden via --schedule-seed: %s", config.ScheduleSeed)
seed := strings.TrimSpace(config.ScheduleSeed)
// Validate owner/repo format: must contain exactly one '/' with non-empty parts
parts := strings.Split(seed, "/")
if strings.Count(seed, "/") != 1 || len(parts) != 2 || parts[0] == "" || parts[1] == "" {
compileCompilerSetupLog.Printf("Invalid --schedule-seed value %q: expected 'owner/repo' format", config.ScheduleSeed)
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(
fmt.Sprintf("--schedule-seed %q is not in 'owner/repo' format; ignoring and falling back to git remote detection", config.ScheduleSeed),
))
} else {
compiler.SetRepositorySlug(seed)
compileCompilerSetupLog.Printf("Repository slug overridden via --schedule-seed: %s", seed)

Copilot uses AI. Check for mistakes.
Comment on lines +134 to +141
// First try 'origin' for backward compatibility
if output, err := gitArgs("config", "--get", "remote.origin.url").Output(); err == nil {
url := strings.TrimSpace(string(output))
if url != "" {
gitLog.Print("Using 'origin' remote")
return url, "origin", nil
}
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git config --get remote.<name>.url can return multiple lines when multiple URLs are configured for a remote. In that case strings.TrimSpace(string(output)) will contain embedded newlines, causing parseGitHubRepoSlugFromURL / extractHostFromRemoteURL to fail. Consider using --get-urlmatch/--get-all handling explicitly and selecting the first URL line (or erroring with a clear message) before returning from resolveRemoteURL.

Copilot uses AI. Check for mistakes.
return "", "", fmt.Errorf("failed to get URL for remote %q: %w", remoteName, err)
}

url := strings.TrimSpace(string(urlOutput))
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When falling back to the single configured remote, resolveRemoteURL returns success even if the resolved URL is empty (it doesn’t perform the non-empty check that the origin branch does). This can silently propagate an empty remote URL to callers. Consider validating url != "" here and returning an error if the remote has no URL configured.

Suggested change
url := strings.TrimSpace(string(urlOutput))
url := strings.TrimSpace(string(urlOutput))
if url == "" {
return "", "", fmt.Errorf("remote %q has no URL configured", remoteName)
}

Copilot uses AI. Check for mistakes.
Comment on lines +169 to +176
// getHostFromOriginRemote returns the hostname of the git remote.
// It prefers the 'origin' remote for backward compatibility. If 'origin' is not
// configured but exactly one other remote exists, that remote is used instead.
// For example, a remote URL of "https://ghes.example.com/org/repo.git" returns "ghes.example.com",
// and "git@github.com:owner/repo.git" returns "github.com".
// Returns "github.com" as the default if the remote URL cannot be determined.
func getHostFromOriginRemote() string {
cmd := exec.Command("git", "config", "--get", "remote.origin.url")
output, err := cmd.Output()
remoteURL, remoteName, err := resolveRemoteURL("")
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getHostFromOriginRemote now falls back to a non-origin remote when origin is absent, so the function name is no longer accurate. If this is an internal API, consider renaming to something like getHostFromRemote and keeping getHostFromOriginRemote as a thin backward-compatible wrapper (or update call sites to the new name) to avoid future confusion.

Copilot uses AI. Check for mistakes.
Comment on lines +203 to +216
// If a schedule seed is explicitly provided, use it directly
if config.ScheduleSeed != "" {
// Validate owner/repo format: must contain exactly one '/' with non-empty parts
parts := strings.SplitN(config.ScheduleSeed, "/", 2)
if len(parts) != 2 || parts[0] == "" || parts[1] == "" {
compileCompilerSetupLog.Printf("Invalid --schedule-seed value %q: expected 'owner/repo' format", config.ScheduleSeed)
fmt.Fprintln(os.Stderr, console.FormatWarningMessage(
fmt.Sprintf("--schedule-seed %q is not in 'owner/repo' format; ignoring and falling back to git remote detection", config.ScheduleSeed),
))
} else {
compiler.SetRepositorySlug(config.ScheduleSeed)
compileCompilerSetupLog.Printf("Repository slug overridden via --schedule-seed: %s", config.ScheduleSeed)
return
}
Copy link

Copilot AI Apr 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New --schedule-seed behavior in setupRepositoryContext isn’t covered by tests yet. Since schedule scattering behavior depends on Compiler.repositorySlug, consider adding unit tests that (1) a valid seed sets the repository slug and bypasses git detection, and (2) an invalid seed emits a warning and falls back to remote-based detection.

Copilot uses AI. Check for mistakes.
@jeffhandley
Copy link
Copy Markdown

Thanks!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fuzzy schedule requires an 'origin' remote

4 participants