feat: add AI-powered fixing, MCP server, and fixture testing enhancements - #52
Merged
Conversation
…d of hardcoded model Replace aifix's hardcoded Claude model selection and cost tracking with captain's centralized AI configuration system. This allows gavel lint --ai-fix to honor the same defaults as captain ai prompt, including model, backend, budget, and request options from ~/.captain.yaml. Key changes: - Remove Model and MaxCostUSD fields from aifix.Request - Add AIConfig (captainai.Config) and AIRequestProto (captainai.Request) fields to allow callers to pass pre-built configuration - Replace direct claude-cli provider instantiation with generic NewProvider that validates streaming capability - Update lint and commit commands to build AIConfig and AIRequestProto from captain's AIRuntimeOptions - Add comprehensive tests verifying config propagation and error handling for non-streaming backends BREAKING CHANGE: aifix.Request.Model and aifix.Request.MaxCostUSD removed; callers must now provide AIConfig and AIRequestProto instead.
Extend aifix to work with any streaming AI provider (claude_cli, codex_cli, gemini_cli) instead of being Claude-specific. Provider selection is now determined by AIConfig.Backend. Key changes: - Remove hardcoded Claude references from package documentation - Remove unused Files field from aifix.Request - Improve ReLint error handling by capturing and surfacing errors instead of silently swallowing them, ensuring the loop stops fast - Extract common AI configuration logic into buildAIFixRequest helper for reuse across commit and lint flows - Add pr status --ai-fix command to feed PR status snapshots into the AI for fixing failures - Refactor pr status command to use clicky's structured option binding - Add comprehensive tests for ReLint error surfacing and PR status prompt generation BREAKING CHANGE: aifix.Request.Files field removed; callers should remove this field from their Request construction.
…cking Add RunTesting, RunGomega, RunGinkgo, and RegisterGinkgoSpecs methods to Runner for native Go testing integration. Implement FixtureOrigin struct to track source location (file, line, section path) for each fixture node. Convert table parsing to return a TableNode containing row nodes instead of flat fixture list. Add origin metadata to all fixture nodes during parsing. This enables: - Mirroring markdown structure as nested t.Run nodes - Better error reporting with source locations - Ginkgo and Gomega integration for BDD-style testing - Improved test organization and debugging Refs #fixture-testing
…CI migrator skill Add three major features: 1. Golden file updates: introduce --update-golden flag for fixtures to rewrite @file expectations with actual output instead of failing on mismatch. Supports per-row glob expansion in stdout/stderr cells. 2. Go mod tidy automation: add --tidy flag to `gavel commit` (enabled by default) to run `go mod tidy` in every Go module and stage updates. Includes linked-deps upgrade path to drop local replaces and pin requires to latest tagged versions, then restore replaces post-commit as unstaged edits. 3. Agent Skills: document gavel-ci-migrator skill for migrating GitHub Actions workflows to flanksource/gavel composite action. Also refactor status rendering to use new ttyrender package for in-place terminal updates, and improve logging verbosity control in betterleaks linter. Refs: gavel-ci-migrator skill documentation, golden file testing, go.mod management
…ibility and rich detail documents Introduce DisplayOptions to control which fixture results and output fields are shown based on verbosity level. Add OutputMode enum (Never, OnFailure, Always) for granular stdout/stderr visibility control. Implement DisplayOptionsForVerbosity to layer fixture-specific affordances on global logging verbosity. Add Detail type for rich clicky documents in test results, enabling syntax-highlighted source code and structured traces in the UI. Update fixtures command with --show-passed, --show-stdout, and --show-stderr flags. Modify FixtureResult.Pretty() to respect display options when rendering output. Add comprehensive tests for display option behavior and detail document serialization.
Replace inline go build / npm UI steps in release.yml and lint.yml with calls to Taskfile targets so build logic (LDFLAGS, version stamping, UI bundles) lives in one place. Generalize build:linux-amd64 into a parameterized build:cross task driven by GOOS/GOARCH and repoint deploy to it.
…enrichment Introduce RunLogOptions struct to FetchRunJobs to enable atomic log attachment before caching. This fixes a cache-poisoning issue where a run cached without logs would silently suppress --logs requests. Key changes: - Add RunLogOptions with FetchLogs and TailLines fields - Implement runHasFailureLogs to detect cached runs needing enrichment - Add persistCompletedRun helper to consolidate cache persistence logic - Extract IsFailureConclusion and RunHasFailedJob helpers for reusability - Update all FetchRunJobs callers to pass RunLogOptions - Add comprehensive tests for cache enrichment scenarios This ensures that --logs requests are never silently ignored due to stale cache entries, while maintaining the performance benefit of the immutable cache for completed runs. Refs: cache-poisoning fix for log fetching
Update multiple Go module dependencies including: - flanksource/captain to v0.0.7 - flanksource/clicky to v1.21.12 - flanksource/gomplate/v3 to v3.24.82 - flanksource/is-healthy to v1.0.88 - grpc-ecosystem/grpc-gateway/v2 to v2.27.7 - opentelemetry modules to latest versions - kubernetes modules from v0.35.4 to v0.36.1 - google.golang.org/protobuf to v1.36.12-0.20260120151049-f2248ac996af Remove local development replace directives for flanksource/clicky and flanksource/captain. Remove unused dependencies: gregjones/httpcache and mxk/go-flowrate.
Contributor
Gavel summary
Totals: 1791 passed · 2 failed · 11 skipped · 30.4s Failing lintersgolangci-lint — errortsc — error |
The UI now defaults to a failures-only status filter (!passed, !skipped), so passed/skipped tests are absent from the DOM on load. Specs that clicked or asserted on those nodes hung indefinitely because chromedp clicks had no deadline, wedging the whole suite until the go test panic timeout. - Navigate with ?status=all in specs that interact with passed/skipped tests - Add clickWithTimeout helper bounding each click so a missing selector fails the spec in seconds with the selector text, instead of hanging the suite - Bound each spec's chromedp context as an overall backstop
Commit the gitignored testrunner/ui/dist/testui.js and pr/ui/dist/prui.js so downstream modules that fetch gavel by tag/SHA can satisfy the //go:embed dist/*.js directives. Also build+commit them in release.yml before tagging so future tags stay self-contained.
…ix race conditions Isolate test environments from developer machine state and process-global registries to prevent flaky CI failures: - Configure git identity in test repos so git operations work on CI runners without global config - Isolate HOME and git excludesFile in tests to prevent developer's global settings from interfering - Fix race condition in supervisePackage by using atomic.Bool instead of pointer to bool for concurrent access - Prevent snapshot replay from consulting process-global clicky task registry, which leaks phantom tasks from concurrent runs - Add baseURL parameter to buildSearchQuery to enable deterministic testing of org resolution - Update clicky dependency to v1.21.13 - Fix TestRunnerNoTests to expect success (empty test tree) instead of error for directories with no tests These changes eliminate sources of test flakiness where CI failures occurred due to leaked state from previous runs or developer machine configuration.
Remove redundant Go dependency verification steps and test UI build from the workflow. Instead, build gavel once and use the resulting binary to run tests. This streamlines the CI pipeline and reduces build time by eliminating unnecessary steps.
The Test workflow now runs ./gavel test, which discovers the testrunner/ui and site vitest suites in addition to the Go tests. - testrunner/ui ships a pnpm-lock.yaml, so gavel invokes pnpm there; enable corepack and pnpm install it. Drop the stray npm package-lock.json so gavel resolves a single manager, and switch the Taskfile test-ui build to pnpm to match. - site has only a package-lock.json; npm ci it so its vitest suite runs. - Fix testrunner/ui config.ts reading window.__gavelBasePath at module load, which threw 'window is not defined' under vitest's node env. Guard with typeof window and rebuild the embedded bundle. Both vitest suites now pass (testrunner/ui 45, site 14).
The lint, go-mod-tidy, and gavel-action jobs run `task test-ui pr-ui` but only the Test job enabled pnpm via corepack, so test-ui's `pnpm install` failed with exit 127 everywhere else. Switch test-ui to npm to match pr-ui: replace pnpm-lock.yaml with package-lock.json, build via `npm install && npm run build`, and drop the corepack step. gavel's own runner auto-detects npm from the lockfile, so `./gavel test` keeps running the vitest suite. With the UIs building, golangci-lint runs for the first time on this branch and surfaced 22 findings, all fixed at the source: - errcheck/ineffassign: parse the vitest line via strconv.Atoi; drop the dead `err = nil`. - SA1012: pass the real parent context (cmd.Context()/opts.Context) to newStopContext/resolveLinterExecutable instead of nil. - SA4006/QF1001/QF1008/S1017: remove dead omitempty handling, apply De Morgan, drop redundant embedded selectors and HasPrefix guard. - unused: delete superseded helpers (applyGroupIgnores, printFailureDetails, collectFailed, prettyYAML/mustMarshalYAML/configOriginLabel, mergeBase, hasDuplicateLines, containsScope) and retarget their tests at the live code paths (applyPostLintFilters, collectLeaves, OutputMode.ShouldShow).
Resolve the remaining red CI jobs surfaced once the UIs build: - site: add the missing remark-frontmatter and remark-mdx-frontmatter deps that site/vite.config.ts imports, so `./gavel test`'s site vitest suite can load its config (was ERR_MODULE_NOT_FOUND). Refresh the npm lockfile. - testrunner/ui e2e: the BeforeSuite DeferCleanup removed Chrome's user-data dir while the browser still held its SingletonLock, failing the suite with "unlink ... DeferCleanup". Register teardown via ordered DeferCleanup (browser stop runs before dir removal, LIFO) and retry the RemoveAll briefly to absorb the lock-release window. - go-mod-tidy check: scope the post-tidy git diff to go.mod/go.sum. It previously built the UIs and diffed the whole tree, so the regenerated minified testui.js bundle (toolchain-dependent bytes) tripped the check. Tidy only needs go.mod/go.sum, not the embedded JS. - Commit the npm-built testui.js so the embedded bundle matches what `npm run build` produces.
The composite action runs `gavel test --lint --format json=gavel-results.json`
and then `gavel summary --input` on that file. clicky serializes the command
handler's return value, but runTests' clean non-UI completion returned
(nil, nil) — to avoid clicky rendering a duplicate one-line Snapshot.Pretty()
on the terminal. That nil was marshalled to the file as a bare `null`, so the
uploaded artifact and the sticky PR comment summary were empty (the action's
placeholder stub only triggers when the file is *missing*, not null).
Return the snapshot — which already serializes to the {"tests":..,"lint":..}
shape gavel summary expects — whenever a serialized format is requested, and
keep returning nil for the default pretty/terminal path so the summary isn't
printed twice. Gated on clicky.Flags.ResolveFormat() != "pretty".
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.
What
Why
Notes
handleCommitLintFindingsnow returnslintFindingsOutcome;aifix.Request.Model,MaxCostUSD, andFilesfields removedFixtureOrigintracking and table node structurettyrenderpackage