fix(trail): flag onboarding-created runners left un-tailored · Entire
fix(trail): flag onboarding-created runners left un-tailored
9ddaef9·
Soph·3w ago·5 files·+88 added/-27 removed
Onboarding writes the default runner set, then tune tailors in place. If a runner's tailoring is skipped, omitted by the model, or returned verbatim, it stays a generic default — and the previous "Updated N… review with git diff" nudged the user to commit those generic placeholders as if they were repo-specific.
ensureRunnersPresent now reports which runners it created; applyTuneWithAgent tracks which were actually tailored and warns about any created-but-untailored ("…still generic defaults, not tailored to this repo: …; re-run or edit/remove before committing"). The --print path likewise notes that freshly-created defaults are untracked and not yet tailored.
Sessions
d87e5916f664View transcript
Changes
5
cmd/entire/cli
Mtrail_tune_apply.go+15
- Mtrail_tune_apply_test.go+18
- Mtrail_tune_cmd.go+29/-12
- Mtrail_tune_init.go+16/-13
- Mtrail_tune_init_test.go+10/-2
// untailoredRunners returns the created runner IDs that tuning did NOT tailor
// (still generic defaults), sorted. These were scaffolded by onboarding but
// left unchanged — skipped, omitted by the model, or returned verbatim — so
// they must not be presented as repo-tailored.
func untailoredRunners(createdIDs []string, tailored map[string]bool) []string {
var out []string
for _, id := range createdIDs {
if !tailored[normalizeRunnerID(id)] {
out = append(out, id)
}
}
sort.Strings(out)
return out
}
// droppedPlaceholders returns the placeholders present in oldTemplate but not in
// newTemplate, sorted. Used to inform the user when a rewrite stops using one.
func droppedPlaceholders(oldTemplate, newTemplate string) []string {
func TestUntailoredRunners(t *testing.T) {
t.Parallel()
created := []string{"trail-risk", "trail-drift", "trail-review"}
tailored := map[string]bool{"risk": true} // normalized IDs (no "trail-" prefix)
got := untailoredRunners(created, tailored)
want := []string{"trail-drift", "trail-review"}
if len(got) != len(want) || got[0] != want[0] || got[1] != want[1] {
t.Errorf("untailoredRunners = %v, want %v", got, want)
}
// Nothing created → nothing untailored, even with no tailoring recorded.
if u := untailoredRunners(nil, map[string]bool{}); len(u) != 0 {
t.Errorf("expected empty, got %v", u)
}
}
func TestParseTuneOutput(t *testing.T) {
t.Parallel()
// ensureRunnersPresent scaffolds the default runner set when a repo has none
// yet, so `tune` doubles as onboarding. It is a no-op when runners already
// exist, and returns an error when the user declined or creation failed.
// Writing is gated on confirmation (interactive prompt, or the --yes flag for
// non-interactive runs).
func ensureRunnersPresent(w, errW io.Writer, repoRoot string, assumeYes bool) (created []string, err error) {
dir := runnersDir(repoRoot)
existing, _ := filepath.Glob(filepath.Join(dir, "*.json")) //nolint:errcheck // bad pattern only; treated as "none found"
if len(existing) > 0 {
return nil, nil
}
defaults, err := runnerdefaults.Files()
if err != nil {
return nil, fmt.Errorf("loading default runners: %w", err)
}
if !assumeYes {
if !interactive.CanPromptInteractively() {
return fmt.Errorf("no runner configs found under %s; re-run with --yes to create the default set (%d runners)", dir, len(defaults))
}
confirmed, err := confirmCreateRunners(len(defaults))
if err != nil {
return nil, err
}
if !confirmed {
return nil, errors.New("no runner configs created (declined)")
}
}
if err := os.MkdirAll(dir, 0o755); err != nil { //nolint:gosec // config dir, conventional perms
return fmt.Errorf("creating %s: %w", dir, err)
}
for _, f := range defaults {
dest := filepath.Join(dir, f.Name)
if err := os.WriteFile(dest, f.Data, 0o644); err != nil { //nolint:gosec // runner configs are repo-committed, world-readable config
return fmt.Errorf("writing %s: %w", dest, err)
}
fmt.Fprintf(w, "created %s\n", filepath.Join(paths.EntireDir, "runners", f.Name))
created = append(created, strings.TrimSuffix(f.Name, ".json"))
}
fmt.Fprintf(errW, "Created %d default runner(s); tailoring them to this repo…\n", len(defaults))
return created, nil
}
func confirmCreateRunners(n int) (bool, error) {}