Skip to content

Commit c68f7ab

Browse files
committed
Merge origin/main into agent/atomic-actor-corpus-tools
2 parents 2ebec8d + 94b3aac commit c68f7ab

47 files changed

Lines changed: 826 additions & 303 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.golangci.yml

Lines changed: 101 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -90,25 +90,6 @@ linters:
9090
- LICENSES
9191
- third_party$
9292
rules:
93-
- path: _test\.go$
94-
linters:
95-
- funlen
96-
- gocognit
97-
- dupl
98-
- errcheck
99-
- noctx
100-
- contextcheck
101-
- gosec
102-
- errname
103-
- errorlint
104-
- bodyclose
105-
- cyclop
106-
- nilnil
107-
- perfsprint
108-
- prealloc
109-
- revive
110-
- staticcheck
111-
- unconvert
11293
# These boundaries intentionally create/close context-owning services;
11394
# contextcheck cannot model their lifecycle contracts.
11495
- path: ^cmd/gitcontribute/main\.go$|^internal/app/(app|discovery|hydration|jobs)\.go$
@@ -133,3 +114,104 @@ linters:
133114
- path: ^internal/corpus/(frontier|jobs|tracking)\.go$
134115
linters:
135116
- sqlclosecheck
117+
# These tests intentionally model raw RoundTripper responses and use
118+
# repeated status-specific fixtures; the production transport owns the
119+
# response lifecycle and the duplicated fixtures keep each rate-limit
120+
# contract readable.
121+
- path: ^internal/github/(retry|retry_replay)_test\.go$
122+
linters:
123+
- bodyclose
124+
- dupl
125+
- noctx
126+
# MCP subprocess fixtures own their service lifetime inside the test
127+
# process and deliberately use the convenience constructor.
128+
- path: ^internal/app/mcp_stdio_e2e_test\.go$
129+
linters:
130+
- contextcheck
131+
# These test helpers intentionally use the project convenience
132+
# constructor and close services at the test boundary.
133+
- path: ^internal/app/read_boundary_test\.go$
134+
linters:
135+
- contextcheck
136+
# These are subprocess and filesystem boundary harnesses. Their command
137+
# paths and permissions are test-controlled, while the production
138+
# adapters remain subject to the security linters.
139+
- path: ^internal/app/mcp_stdio_e2e_test\.go$|^internal/app/tui_capture_test\.go$|^internal/app/app_test\.go$|^internal/acquire/acquire_test\.go$|^internal/codeindex/codeindex_test\.go$|^internal/workspace/workspace_test\.go$|^internal/corpus/lifecycle_test\.go$|^internal/app/setup_verification_test\.go$|^internal/managedbinary/install_test\.go$|^internal/tui/snapshot_test\.go$
140+
linters:
141+
- gosec
142+
- noctx
143+
# These compact fakes and HTTP fixtures intentionally omit unrelated
144+
# arguments or return zero values for capabilities under test elsewhere.
145+
- path: ^internal/app/hydration_test\.go$|^internal/app/job_executor_reconciliation_test\.go$|^internal/discovery/gharchive_fetcher_test\.go$|^internal/discovery/search_test\.go$|^internal/github/client_test\.go$|^internal/tui/tui_test\.go$
146+
linters:
147+
- revive
148+
- errcheck
149+
- dupl
150+
- path: ^internal/app/job_executor_test\.go$|^internal/github/retry_test\.go$
151+
linters:
152+
- revive
153+
- path: ^internal/app/job_executor_test\.go$|^internal/cli/cli_test\.go$
154+
linters:
155+
- nilnil
156+
# These local test servers and teardown-only writes are intentionally
157+
# best effort; their assertions cover the observable operation.
158+
- path: ^internal/app/app_test\.go$|^internal/app/control_test\.go$|^internal/app/corpus_lifecycle_test\.go$|^internal/app/discovery_test\.go$|^internal/app/mcp_stdio_e2e_test\.go$|^internal/app/setup_verification_test\.go$|^internal/buflimit/buflimit_test\.go$|^internal/cli/setup_prompt_internal_test\.go$|^internal/corpus/lifecycle_test\.go$|^internal/corpus/tracking_test\.go$|^internal/discovery/gharchive_fetcher_test\.go$|^internal/discovery/gharchive_test\.go$|^internal/github/pull_request_workflows_test\.go$|^internal/log/log_test\.go$
159+
linters:
160+
- errcheck
161+
# These test handlers and nested JSON assertions are fixture plumbing;
162+
# their surrounding behavior is asserted by the test cases.
163+
- path: ^internal/app/guidance_test\.go$|^internal/app/mcp_github_acquisition_test\.go$|^internal/app/read_boundary_test\.go$|^internal/app/setup_test\.go$|^internal/tracking/sanitize_test\.go$
164+
linters:
165+
- errcheck
166+
- path: ^internal/app/commitplan_test\.go$|^internal/app/control_test\.go$|^internal/tui/snapshot_test\.go$
167+
linters:
168+
- gosec
169+
- path: ^internal/app/setup_test\.go$|^internal/buflimit/buflimit_test\.go$|^internal/cli/surfaces_test\.go$|^internal/discovery/gharchive_fetcher_test\.go$|^internal/log/log_test\.go$
170+
linters:
171+
- gosec
172+
- path: ^internal/app/tui_test\.go$|^internal/tui/actions_test\.go$
173+
linters:
174+
- errcheck
175+
- path: ^internal/tui/snapshot_test\.go$
176+
linters:
177+
- errcheck
178+
- path: ^internal/cli/extended_test\.go$
179+
linters:
180+
- revive
181+
- path: ^internal/app/sync_metadata_test\.go$
182+
linters:
183+
- revive
184+
# These final fixture-only writes use executable or world-readable
185+
# permissions to emulate installed artifacts and serialized outputs.
186+
- path: ^internal/app/discovery_test\.go$|^internal/app/surfaces_test\.go$|^internal/app/upgrade_activation_test\.go$|^internal/app/upgrade_registration_test\.go$|^internal/github/client_test\.go$
187+
linters:
188+
- gosec
189+
# Type assertions in these protocol fixtures are the assertions under
190+
# test; failure is reported by the surrounding test assertion.
191+
- path: ^cmd/gitcontribute/main_test\.go$|^internal/mcpserver/server_test\.go$|^internal/setup/setup_test\.go$
192+
linters:
193+
- errcheck
194+
- path: ^internal/app/guidance_test\.go$|^internal/app/upgrade_setup_test\.go$|^internal/app/upgrade_test\.go$|^internal/corpus/tracking_test\.go$
195+
linters:
196+
- gosec
197+
- path: ^internal/cli/surfaces_test\.go$
198+
linters:
199+
- revive
200+
- path: ^internal/app/mcp_pr_workflows_test\.go$|^internal/app/mcp_thread_facets_test\.go$
201+
linters:
202+
- errcheck
203+
- path: ^internal/app/mcp_github_acquisition_test\.go$
204+
linters:
205+
- gosec
206+
- path: ^internal/cli/cli_test\.go$
207+
linters:
208+
- revive
209+
- path: ^internal/app/surfaces_test\.go$
210+
linters:
211+
- errcheck
212+
- path: ^internal/discovery/gharchive_test\.go$
213+
linters:
214+
- gosec
215+
- path: ^internal/app/upgrade_test\.go$|^internal/evidence/mcp_runner_test\.go$
216+
linters:
217+
- noctx

internal/acquire/acquire_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ func TestWriteMetadataAtomicallyWithPrivatePermissions(t *testing.T) {
218218

219219
func runGit(t *testing.T, dir string, args ...string) string {
220220
t.Helper()
221-
cmd := exec.Command("git", append([]string{"--no-pager"}, args...)...)
221+
cmd := exec.CommandContext(context.Background(), "git", append([]string{"--no-pager"}, args...)...)
222222
cmd.Dir = dir
223223
cmd.Env = append(os.Environ(),
224224
"GIT_TERMINAL_PROMPT=0",
@@ -295,7 +295,7 @@ func TestAcquireMirrorLockCancelsWhileHeld(t *testing.T) {
295295
if err != nil || !ok {
296296
t.Fatalf("failed to hold test lock: ok=%v err=%v", ok, err)
297297
}
298-
defer fl.Close()
298+
defer func() { _ = fl.Close() }()
299299

300300
mgr, err := NewManager(root, nil)
301301
if err != nil {

internal/app/app_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ func setupAppGitRemote(t *testing.T) (remoteURL, baseSHA, candidateSHA string) {
690690

691691
func runGitApp(t *testing.T, dir string, args ...string) string {
692692
t.Helper()
693-
cmd := exec.Command("git", append([]string{"--no-pager"}, args...)...)
693+
cmd := exec.CommandContext(context.Background(), "git", append([]string{"--no-pager"}, args...)...)
694694
cmd.Dir = dir
695695
cmd.Env = append(os.Environ(),
696696
"GIT_TERMINAL_PROMPT=0",

internal/app/control_test.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,7 @@ func TestDoctorReportsOlderRegistrationWhenNewerPrivateRuntimeIsInstalled(t *tes
345345
if err != nil {
346346
t.Fatal(err)
347347
}
348+
var registeredPath string
348349
for _, version := range []string{"0.15.0", "0.16.0"} {
349350
path, err := managedbinary.Destination(dataDir, version)
350351
if err != nil {
@@ -356,8 +357,11 @@ func TestDoctorReportsOlderRegistrationWhenNewerPrivateRuntimeIsInstalled(t *tes
356357
if err := os.WriteFile(path, []byte(version), 0o755); err != nil {
357358
t.Fatal(err)
358359
}
360+
if version == "0.15.0" {
361+
registeredPath = path
362+
}
359363
}
360-
writeCodexConfig(t, home, filepath.Join(dataDir, "bin", "0.15.0", "gitcontribute"))
364+
writeCodexConfig(t, home, registeredPath)
361365

362366
result, err := svc.Doctor(context.Background())
363367
if err != nil {

internal/app/corpus_lifecycle_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,10 @@ func TestSetupFailsFastForUnmarkedCorpusInDryRunAndRealModes(t *testing.T) {
9494
if err != nil {
9595
t.Fatal(err)
9696
}
97-
if _, err := db.Exec("CREATE TABLE goose_db_version (id INTEGER PRIMARY KEY, version_id INTEGER)"); err != nil {
97+
if _, err := db.ExecContext(context.Background(), "CREATE TABLE goose_db_version (id INTEGER PRIMARY KEY, version_id INTEGER)"); err != nil {
9898
t.Fatal(err)
9999
}
100-
if _, err := db.Exec("INSERT INTO goose_db_version (id, version_id) VALUES (1, 9999)"); err != nil {
100+
if _, err := db.ExecContext(context.Background(), "INSERT INTO goose_db_version (id, version_id) VALUES (1, 9999)"); err != nil {
101101
t.Fatal(err)
102102
}
103103
if err := db.Close(); err != nil {

internal/app/hydration_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,15 @@ func (f *fakeHydrationReader) ListIssueTimeline(_ context.Context, _, _ string,
4141
return github.ListResult[github.IssueTimelineEvent]{Items: f.issueTimelinePages[idx], Page: page}, nil
4242
}
4343

44-
func (f *fakeHydrationReader) GetRepository(ctx context.Context, owner, name string) (github.Repository, github.RateInfo, error) {
44+
func (f *fakeHydrationReader) GetRepository(_ context.Context, owner, name string) (github.Repository, github.RateInfo, error) {
4545
return github.Repository{Owner: owner, Name: name, NodeID: "R_1", UpdatedAt: time.Now()}, github.RateInfo{}, nil
4646
}
4747

48-
func (f *fakeHydrationReader) ListIssues(ctx context.Context, owner, name string, opts github.ListIssueOptions) (github.ListResult[github.Issue], error) {
48+
func (f *fakeHydrationReader) ListIssues(_ context.Context, owner, name string, opts github.ListIssueOptions) (github.ListResult[github.Issue], error) {
4949
return github.ListResult[github.Issue]{}, nil
5050
}
5151

52-
func (f *fakeHydrationReader) ListIssueComments(ctx context.Context, owner, name string, issueNumber int, opts github.PageOptions) (github.ListResult[github.IssueComment], error) {
52+
func (f *fakeHydrationReader) ListIssueComments(_ context.Context, owner, name string, issueNumber int, opts github.PageOptions) (github.ListResult[github.IssueComment], error) {
5353
if f.failWith != nil && f.issueCommentsCalls >= f.failAfterIssueCalls {
5454
return github.ListResult[github.IssueComment]{}, f.failWith
5555
}
@@ -66,14 +66,14 @@ func (f *fakeHydrationReader) ListIssueComments(ctx context.Context, owner, name
6666
return github.ListResult[github.IssueComment]{Items: f.issueCommentsPages[idx], Page: page}, nil
6767
}
6868

69-
func (f *fakeHydrationReader) GetPullRequestDetails(ctx context.Context, owner, name string, number int) (github.PullRequestDetails, github.RateInfo, error) {
69+
func (f *fakeHydrationReader) GetPullRequestDetails(_ context.Context, owner, name string, number int) (github.PullRequestDetails, github.RateInfo, error) {
7070
if f.failWith != nil {
7171
return github.PullRequestDetails{}, github.RateInfo{}, f.failWith
7272
}
7373
return f.prDetails, github.RateInfo{}, nil
7474
}
7575

76-
func (f *fakeHydrationReader) ListPullRequestReviews(ctx context.Context, owner, name string, number int, opts github.PageOptions) (github.ListResult[github.Review], error) {
76+
func (f *fakeHydrationReader) ListPullRequestReviews(_ context.Context, owner, name string, number int, opts github.PageOptions) (github.ListResult[github.Review], error) {
7777
if f.failWith != nil && f.prReviewsCalls >= f.failAfterIssueCalls {
7878
return github.ListResult[github.Review]{}, f.failWith
7979
}
@@ -90,7 +90,7 @@ func (f *fakeHydrationReader) ListPullRequestReviews(ctx context.Context, owner,
9090
return github.ListResult[github.Review]{Items: f.prReviewsPages[idx], Page: page}, nil
9191
}
9292

93-
func (f *fakeHydrationReader) ListPullRequestComments(ctx context.Context, owner, name string, number int, opts github.PageOptions) (github.ListResult[github.ReviewComment], error) {
93+
func (f *fakeHydrationReader) ListPullRequestComments(_ context.Context, owner, name string, number int, opts github.PageOptions) (github.ListResult[github.ReviewComment], error) {
9494
if f.failWith != nil && f.prReviewCommentsCalls >= f.failAfterIssueCalls {
9595
return github.ListResult[github.ReviewComment]{}, f.failWith
9696
}
@@ -365,7 +365,7 @@ func TestHydrateBoundsPagination(t *testing.T) {
365365
repo, thread := seedRepoAndThread(t, svc, corpus.ThreadKindIssue, 1)
366366
pages := make([][]github.IssueComment, 10)
367367
for i := range pages {
368-
pages[i] = []github.IssueComment{{ID: int64(i + 1), UpdatedAt: time.Date(2024, 1, 1, 0, 0, int(i), 0, time.UTC)}}
368+
pages[i] = []github.IssueComment{{ID: int64(i + 1), UpdatedAt: time.Date(2024, 1, 1, 0, 0, i, 0, time.UTC)}}
369369
}
370370
reader := &fakeHydrationReader{issueCommentsPages: pages}
371371
svc.SetGitHubReader(reader)

internal/app/job_executor_lifecycle_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ func TestJobExecutorCloseCancelsAndWaits(t *testing.T) {
3535
}
3636

3737
started := make(chan struct{})
38-
id, err := jobs.Submit(ctx, "block", nil, func(ctx context.Context, report func(progress, statistics string) error) (any, error) {
38+
id, err := jobs.Submit(ctx, "block", nil, func(ctx context.Context, _ func(progress, statistics string) error) (any, error) {
3939
close(started)
4040
<-ctx.Done()
4141
return nil, ctx.Err()

internal/app/job_executor_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ func TestJobCancellation(t *testing.T) {
271271
}
272272

273273
blocked := make(chan struct{})
274-
id, err := jobs.Submit(ctx, "block", nil, func(ctx context.Context, report func(progress, statistics string) error) (any, error) {
274+
id, err := jobs.Submit(ctx, "block", nil, func(ctx context.Context, _ func(progress, statistics string) error) (any, error) {
275275
close(blocked)
276276
<-ctx.Done()
277277
return nil, ctx.Err()
@@ -309,7 +309,7 @@ func TestCancelQueuedJob(t *testing.T) {
309309
}
310310

311311
// Delayed function that will never be started before cancel.
312-
id, err := jobs.Submit(ctx, "never", nil, func(ctx context.Context, report func(progress, statistics string) error) (any, error) {
312+
id, err := jobs.Submit(ctx, "never", nil, func(ctx context.Context, _ func(progress, statistics string) error) (any, error) {
313313
select {
314314
case <-ctx.Done():
315315
return nil, ctx.Err()
@@ -365,7 +365,7 @@ func TestJobExecutorBoundsRunningAndPendingJobs(t *testing.T) {
365365
queuedRan := make(chan struct{}, 1)
366366
third, err := jobs.Submit(ctx, "third", nil, func(context.Context, func(string, string) error) (any, error) {
367367
queuedRan <- struct{}{}
368-
return nil, nil
368+
return struct{}{}, nil
369369
})
370370
if err != nil {
371371
t.Fatalf("submit third: %v", err)
@@ -539,7 +539,7 @@ func TestRemoteCancellationReleasesQueuedAdmission(t *testing.T) {
539539
queuedRan := make(chan struct{}, 1)
540540
queued, err := jobs.Submit(ctx, "queued", nil, func(context.Context, func(string, string) error) (any, error) {
541541
queuedRan <- struct{}{}
542-
return nil, nil
542+
return struct{}{}, nil
543543
})
544544
if err != nil {
545545
t.Fatalf("submit queued: %v", err)

0 commit comments

Comments
 (0)