Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions go/pkg/agentic/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,13 @@ func TestCommandsforge_CmdIssueCreate_Good_WithLabelsAndMilestone(t *testing.T)
callPaths := []string{}
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
callPaths = append(callPaths, r.URL.Path)
switch {
case r.URL.Path == "/api/v1/repos/core/go-io/milestones":
switch r.URL.Path {
case "/api/v1/repos/core/go-io/milestones":
w.Write([]byte(core.JSONMarshalString([]map[string]any{
{"id": 1, "title": "v0.8.0"},
{"id": 2, "title": "v0.9.0"},
})))
case r.URL.Path == "/api/v1/repos/core/go-io/labels":
case "/api/v1/repos/core/go-io/labels":
w.Write([]byte(core.JSONMarshalString([]map[string]any{
{"id": 10, "name": "agentic"},
{"id": 11, "name": "bug"},
Expand Down Expand Up @@ -1187,8 +1187,8 @@ func TestCommands_CmdScan_Bad_NoForgeToken(t *testing.T) {

func TestCommands_CmdScan_Ugly_EmptyResults(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch {
case r.URL.Path == "/api/v1/orgs/core/repos":
switch r.URL.Path {
case "/api/v1/orgs/core/repos":
_, _ = w.Write([]byte(core.JSONMarshalString([]map[string]any{
{"name": "go-io"},
})))
Expand Down
89 changes: 0 additions & 89 deletions go/pkg/agentic/compat_adapters_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,10 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"
)

func (s *PrepSubsystem) dispatch(ctx context.Context, request *mcp.CallToolRequest, input DispatchInput) (*mcp.CallToolResult, DispatchOutput, error) {
return dispatch(s, ctx, request, input)
}

func (s *PrepSubsystem) watch(ctx context.Context, request *mcp.CallToolRequest, input WatchInput) (*mcp.CallToolResult, WatchOutput, error) {
return watch(s, ctx, request, input)
}

func (s *PrepSubsystem) status(ctx context.Context, request *mcp.CallToolRequest, input StatusInput) (*mcp.CallToolResult, StatusOutput, error) {
return status(s, ctx, request, input)
}

func (s *PrepSubsystem) createEpic(ctx context.Context, request *mcp.CallToolRequest, input EpicInput) (*mcp.CallToolResult, EpicOutput, error) {
return createEpic(s, ctx, request, input)
}

func (s *PrepSubsystem) createPR(ctx context.Context, request *mcp.CallToolRequest, input CreatePRInput) (*mcp.CallToolResult, CreatePROutput, error) {
return createPR(s, ctx, request, input)
}
Expand Down Expand Up @@ -65,26 +53,6 @@ func (s *PrepSubsystem) runWorkspaceLanguagePrep(ctx context.Context, workspaceD
return runWorkspaceLanguagePrep(s, ctx, workspaceDir, repoDir)
}

func (s *PrepSubsystem) templateCreatePlan(ctx context.Context, request *mcp.CallToolRequest, input TemplateCreatePlanInput) (*mcp.CallToolResult, TemplateCreatePlanOutput, error) {
return templateCreatePlan(s, ctx, request, input)
}

func (s *PrepSubsystem) planFromIssue(ctx context.Context, request *mcp.CallToolRequest, input PlanFromIssueInput) (*mcp.CallToolResult, PlanFromIssueOutput, error) {
return planFromIssue(s, ctx, request, input)
}

func (s *PrepSubsystem) dispatchStart(ctx context.Context, request *mcp.CallToolRequest, input ShutdownInput) (*mcp.CallToolResult, ShutdownOutput, error) {
return dispatchStart(s, ctx, request, input)
}

func (s *PrepSubsystem) shutdownGraceful(ctx context.Context, request *mcp.CallToolRequest, input ShutdownInput) (*mcp.CallToolResult, ShutdownOutput, error) {
return shutdownGraceful(s, ctx, request, input)
}

func (s *PrepSubsystem) shutdownNow(ctx context.Context, request *mcp.CallToolRequest, input ShutdownInput) (*mcp.CallToolResult, ShutdownOutput, error) {
return shutdownNow(s, ctx, request, input)
}

func (s *PrepSubsystem) pipelineEpicCreate(ctx context.Context, input PipelineEpicCreateInput) (PipelineEpicCreateOutput, error) {
return pipelineEpicCreate(s, ctx, input)
}
Expand Down Expand Up @@ -117,10 +85,6 @@ func (s *PrepSubsystem) pipelineFixReviews(ctx context.Context, input PipelineFi
return pipelineFixReviews(s, ctx, input)
}

func (s *PrepSubsystem) pipelineFixConflicts(ctx context.Context, input PipelineFixInput) (PipelineFixOutput, error) {
return pipelineFixConflicts(s, ctx, input)
}

func (s *PrepSubsystem) pipelineFixFormat(ctx context.Context, input PipelineFixInput) (PipelineFixOutput, error) {
return pipelineFixFormat(s, ctx, input)
}
Expand All @@ -133,26 +97,10 @@ func (s *PrepSubsystem) pipelineOnboard(ctx context.Context, input PipelineOnboa
return pipelineOnboard(s, ctx, input)
}

func (s *PrepSubsystem) pipelineOnboardDispatchDirect(ctx context.Context, input PipelineOnboardInput, issues []PipelineIssueRef) ([]PipelineIssueRef, error) {
return pipelineOnboardDispatchDirect(s, ctx, input, issues)
}

func (s *PrepSubsystem) pipelineTrainingCapture(ctx context.Context, input PipelineTrainingCaptureInput) (PipelineTrainingCaptureOutput, error) {
return pipelineTrainingCapture(s, ctx, input)
}

func (s *PrepSubsystem) pipelineTrainingReadDiff(ctx context.Context, org, repo string, number int, meta PipelinePRMeta) (string, string, error) {
return pipelineTrainingReadDiff(s, ctx, org, repo, number, meta)
}

func (s *PrepSubsystem) pipelineTrainingReadGitDiff(ctx context.Context, org, repo string, meta PipelinePRMeta) (string, string, error) {
return pipelineTrainingReadGitDiff(s, ctx, org, repo, meta)
}

func (s *PrepSubsystem) pipelineMonitorWithReader(ctx context.Context, input PipelineMonitorInput, reader *MetaReader) (PipelineMonitorOutput, error) {
return pipelineMonitorWithReader(s, ctx, input, reader)
}

func (s *PrepSubsystem) phaseGet(ctx context.Context, request *mcp.CallToolRequest, input PhaseGetInput) (*mcp.CallToolResult, PhaseOutput, error) {
return phaseGet(s, ctx, request, input)
}
Expand Down Expand Up @@ -209,10 +157,6 @@ func (s *PrepSubsystem) prGet(ctx context.Context, request *mcp.CallToolRequest,
return prGet(s, ctx, request, input)
}

func (s *PrepSubsystem) prList(ctx context.Context, request *mcp.CallToolRequest, input ListPRsInput) (*mcp.CallToolResult, ListPRsOutput, error) {
return prList(s, ctx, request, input)
}

func (s *PrepSubsystem) prMerge(ctx context.Context, request *mcp.CallToolRequest, input PRMergeInput) (*mcp.CallToolResult, PRMergeOutput, error) {
return prMerge(s, ctx, request, input)
}
Expand Down Expand Up @@ -241,14 +185,6 @@ func (s *PrepSubsystem) listRepoPRs(ctx context.Context, org, repo, state string
return listRepoPRs(s, ctx, org, repo, state)
}

func (s *PrepSubsystem) templateList(ctx context.Context, request *mcp.CallToolRequest, input TemplateListInput) (*mcp.CallToolResult, TemplateListOutput, error) {
return templateList(s, ctx, request, input)
}

func (s *PrepSubsystem) templatePreview(ctx context.Context, request *mcp.CallToolRequest, input TemplatePreviewInput) (*mcp.CallToolResult, TemplatePreviewOutput, error) {
return templatePreview(s, ctx, request, input)
}

func (s *PrepSubsystem) taskCreate(ctx context.Context, request *mcp.CallToolRequest, input TaskCreateInput) (*mcp.CallToolResult, TaskCreateOutput, error) {
return taskCreate(s, ctx, request, input)
}
Expand Down Expand Up @@ -277,10 +213,6 @@ func (s *PrepSubsystem) HandleGooglebotVisit(ctx context.Context, pageID, userAg
return HandleGooglebotVisit(s, ctx, pageID, userAgent)
}

func (s *PrepSubsystem) contentSEOStore() (*store.Store, error) {
return contentSEOStore(s)
}

func (s *PrepSubsystem) contentSEORevisionRecords(storeInstance *store.Store, pageID string, pendingOnly bool) ([]seoRevisionRecord, error) {
return contentSEORevisionRecords(s, storeInstance, pageID, pendingOnly)
}
Expand All @@ -301,31 +233,10 @@ func (s *PrepSubsystem) syncPullInput(ctx context.Context, input SyncPullInput)
return syncPullInput(s, ctx, input)
}

type pipelineForgeMetaReader struct {
subsystem *PrepSubsystem
org string
}

func (c RemoteClient) Initialize(ctx context.Context) (string, error) {
return InitializeRemoteClient(c, ctx)
}

func (c RemoteClient) Call(ctx context.Context, sessionID string, body []byte) ([]byte, error) {
return CallRemoteClient(c, ctx, sessionID, body)
}

func (r *pipelineForgeMetaReader) GetPRMeta(ctx context.Context, repo string, prNumber int) (PipelinePRMeta, error) {
return newPipelineForgeMetaReader(r.subsystem, r.org).GetPRMeta(ctx, repo, prNumber)
}

func (r *pipelineForgeMetaReader) GetEpicMeta(ctx context.Context, repo string, issueNumber int) (PipelineEpicMeta, error) {
return newPipelineForgeMetaReader(r.subsystem, r.org).GetEpicMeta(ctx, repo, issueNumber)
}

func (r *pipelineForgeMetaReader) GetIssueState(ctx context.Context, repo string, issueNumber int) (PipelineIssueState, error) {
return newPipelineForgeMetaReader(r.subsystem, r.org).GetIssueState(ctx, repo, issueNumber)
}

func (r *pipelineForgeMetaReader) GetCommentReactions(ctx context.Context, repo string, commentID int64) ([]PipelineReactionMeta, error) {
return newPipelineForgeMetaReader(r.subsystem, r.org).GetCommentReactions(ctx, repo, commentID)
}
10 changes: 8 additions & 2 deletions go/pkg/agentic/dispatch.go
Original file line number Diff line number Diff line change
Expand Up @@ -668,7 +668,9 @@ func (s *PrepSubsystem) broadcastComplete(agent, workspaceDir, finalStatus strin

func (s *PrepSubsystem) onAgentComplete(agent, workspaceDir, outputFile string, exitCode int, processStatus, output string) {
if output != "" {
fs.Write(outputFile, output)
if r := fs.Write(outputFile, output); !r.OK {
core.Warn("agentic: failed to write agent output", "path", outputFile, "reason", r.Value)
}
}

repoDir := WorkspaceRepoDir(workspaceDir)
Expand Down Expand Up @@ -930,7 +932,11 @@ var dispatch = func(s *PrepSubsystem, ctx context.Context, callRequest *mcp.Call
Runs: 1,
}
preserveStatusNote(workspaceDir, workspaceStatus) // keep VZ→OCI downgrade note (SP2.4)
writeStatusResult(workspaceDir, workspaceStatus)
// Reported: the status file is what the monitor polls, so a silent write
// failure leaves the workspace looking stuck indefinitely.
Comment on lines +935 to +936

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Apply the comment-format rule to all newly added Go comments.

The listed comments explain internal control flow instead of showing usage with real values. Replace each comment with a usage example or remove it.

  • go/pkg/agentic/dispatch.go#L935-L936: Replace the descriptive status-write rationale.
  • go/pkg/agentic/dispatch_sync.go#L110-L111: Replace the descriptive polling rationale.
  • go/pkg/agentic/prep.go#L443-L444: Replace the descriptive registry rationale.
  • go/pkg/agentic/prep.go#L468-L469: Replace the descriptive status-write rationale.
  • go/pkg/agentic/prep.go#L474-L475: Replace the descriptive registry rationale.
  • go/pkg/agentic/prep.go#L491-L491: Replace the descriptive best-effort rationale.
  • go/pkg/agentic/prep.go#L493-L494: Replace the descriptive registry rationale.
  • go/pkg/agentic/prep.go#L833-L836: Replace the descriptive Git rationale.
  • go/pkg/agentic/prep.go#L913-L914: Replace the descriptive documentation-clone rationale.
  • go/pkg/runner/runner.go#L340-L341: Replace the descriptive registry rationale.
  • go/pkg/runner/runner.go#L415-L416: Replace the descriptive registry rationale.
  • go/pkg/runner/runner.go#L433-L433: Replace the descriptive deletion rationale.
  • go/pkg/runner/runner.go#L478-L479: Replace the descriptive best-effort rationale.
  • go/pkg/runner/runner.go#L500-L501: Replace the descriptive registry rationale.
  • go/pkg/agentic/queue.go#L479-L480: Replace the descriptive status-write rationale.
  • go/pkg/agentic/resume.go#L101-L102: Replace the descriptive status-write rationale.
  • go/pkg/agentic/status.go#L218-L219: Replace the descriptive status-write rationale.
  • go/pkg/agentic/pr.go#L151-L152: Replace the descriptive status-write rationale.

As per coding guidelines, Go comments must be usage examples showing how to use the code with real values, rather than descriptive explanations.

📍 Affects 8 files
  • go/pkg/agentic/dispatch.go#L935-L936 (this comment)
  • go/pkg/agentic/dispatch_sync.go#L110-L111
  • go/pkg/agentic/prep.go#L443-L444
  • go/pkg/agentic/prep.go#L468-L469
  • go/pkg/agentic/prep.go#L474-L475
  • go/pkg/agentic/prep.go#L491-L491
  • go/pkg/agentic/prep.go#L493-L494
  • go/pkg/agentic/prep.go#L833-L836
  • go/pkg/agentic/prep.go#L913-L914
  • go/pkg/runner/runner.go#L340-L341
  • go/pkg/runner/runner.go#L415-L416
  • go/pkg/runner/runner.go#L433-L433
  • go/pkg/runner/runner.go#L478-L479
  • go/pkg/runner/runner.go#L500-L501
  • go/pkg/agentic/queue.go#L479-L480
  • go/pkg/agentic/resume.go#L101-L102
  • go/pkg/agentic/status.go#L218-L219
  • go/pkg/agentic/pr.go#L151-L152
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go/pkg/agentic/dispatch.go` around lines 935 - 936, Replace or remove the
descriptive comments at go/pkg/agentic/dispatch.go:935-936,
go/pkg/agentic/dispatch_sync.go:110-111, go/pkg/agentic/prep.go:443-444,
468-469, 474-475, 491, 493-494, 833-836, 913-914,
go/pkg/runner/runner.go:340-341, 415-416, 433, 478-479, 500-501,
go/pkg/agentic/queue.go:479-480, go/pkg/agentic/resume.go:101-102,
go/pkg/agentic/status.go:218-219, and go/pkg/agentic/pr.go:151-152. Any retained
comment must be a concrete usage example with realistic values; otherwise remove
it, without changing the surrounding status, polling, registry, Git, deletion,
or best-effort logic.

Source: Coding guidelines

if r := writeStatusResult(workspaceDir, workspaceStatus); !r.OK {
core.Warn("agentic: failed to write workspace status", "reason", r.Value)
}
Comment on lines +937 to +939

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Handle status persistence failures before completing state-changing work.

All listed callers treat a failed writeStatusResult as a warning while continuing with the new state or success result. This breaks the durable status contract between status.json, monitors, registries, and retries.

  • go/pkg/agentic/dispatch.go#L937-L939: Do not report successful dispatch or track the running workspace until the initial status is durable.
  • go/pkg/agentic/dispatch_sync.go#L112-L114: Do not poll stale status after the initial write fails.
  • go/pkg/agentic/prep.go#L470-L478: Do not store a failed registry state while status.json still contains the previous state.
  • go/pkg/agentic/queue.go#L481-L483: Do not return from drainOne as successful after a failed write; prevent duplicate dispatch.
  • go/pkg/agentic/resume.go#L103-L105: Do not return core.Ok while the status file still permits another resume.
  • go/pkg/agentic/status.go#L220-L222: Do not report a derived status as durable when persistence failed.
  • go/pkg/agentic/pr.go#L153-L155: Do not report PR success or complete cleanup until PRURL is durably recorded.
📍 Affects 7 files
  • go/pkg/agentic/dispatch.go#L937-L939 (this comment)
  • go/pkg/agentic/dispatch_sync.go#L112-L114
  • go/pkg/agentic/prep.go#L470-L478
  • go/pkg/agentic/queue.go#L481-L483
  • go/pkg/agentic/resume.go#L103-L105
  • go/pkg/agentic/status.go#L220-L222
  • go/pkg/agentic/pr.go#L153-L155
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@go/pkg/agentic/dispatch.go` around lines 937 - 939, Handle writeStatusResult
failures as blocking errors rather than warnings at
go/pkg/agentic/dispatch.go:937-939, preventing successful dispatch and
running-workspace tracking; go/pkg/agentic/dispatch_sync.go:112-114, preventing
stale-status polling; go/pkg/agentic/prep.go:470-478, preventing failed
registry-state storage; go/pkg/agentic/queue.go:481-483, preventing successful
drainOne completion and duplicate dispatch; go/pkg/agentic/resume.go:103-105,
preventing core.Ok while resume remains possible;
go/pkg/agentic/status.go:220-222, preventing derived-status success reporting;
and go/pkg/agentic/pr.go:153-155, preventing PR success and cleanup until PRURL
is durable. Propagate or return the persistence failure through each caller’s
existing error path.

if s.ServiceRuntime != nil {
if runnerResult := s.Core().Service("runner"); runnerResult.OK {
if runnerSvc, ok := runnerResult.Value.(workspaceTracker); ok {
Expand Down
6 changes: 5 additions & 1 deletion go/pkg/agentic/dispatch_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,11 @@ func (s *PrepSubsystem) DispatchSync(ctx context.Context, input DispatchSyncInpu
if existing, ok := workspaceStatusValue(ReadStatusResult(workspaceDir)); ok {
fillMissingDispatchStatus(dispatched, existing)
}
writeStatusResult(workspaceDir, dispatched)
// Reported: the status file is what the monitor polls, so a silent write
// failure leaves the workspace looking stuck indefinitely.
if r := writeStatusResult(workspaceDir, dispatched); !r.OK {
core.Warn("agentic: failed to write workspace status", "reason", r.Value)
}

core.Print(nil, " pid: %d", pid)
core.Print(nil, " waiting for completion...")
Expand Down
15 changes: 7 additions & 8 deletions go/pkg/agentic/dispatch_sync_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"time"

core "dappco.re/go"
"github.com/modelcontextprotocol/go-sdk/mcp"
mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp"
)

Expand Down Expand Up @@ -40,7 +39,7 @@ func TestDispatchsync_HandleDispatchSync_Good_Completed(t *testing.T) {
workspaceDir := core.JoinPath(WorkspaceRoot(), "core", "go-io", "task-7")
s := &PrepSubsystem{dispatchSyncTick: 10 * time.Millisecond}

s.dispatchSyncPrep = func(ctx context.Context, _ *mcp.CallToolRequest, input PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
s.dispatchSyncPrep = func(ctx context.Context, _ *mcpsdk.CallToolRequest, input PrepInput) (*mcpsdk.CallToolResult, PrepOutput, error) {
core.AssertEqual(t, "core", input.Org)
core.AssertEqual(t, "go-io", input.Repo)
core.AssertEqual(t, "codex", input.Agent)
Expand Down Expand Up @@ -85,7 +84,7 @@ func TestDispatchsync_HandleDispatchSync_Good_Completed(t *testing.T) {

func TestDispatchsync_HandleDispatchSync_Bad_PrepFailure(t *testing.T) {
s := &PrepSubsystem{}
s.dispatchSyncPrep = func(context.Context, *mcp.CallToolRequest, PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
s.dispatchSyncPrep = func(context.Context, *mcpsdk.CallToolRequest, PrepInput) (*mcpsdk.CallToolResult, PrepOutput, error) {
return nil, PrepOutput{}, core.E("prepWorkspace", "boom", nil)
}

Expand All @@ -101,7 +100,7 @@ func TestDispatchsync_HandleDispatchSync_Bad_PrepFailure(t *testing.T) {

func TestDispatchsync_HandleDispatchSync_Bad_PrepIncomplete(t *testing.T) {
s := &PrepSubsystem{}
s.dispatchSyncPrep = func(context.Context, *mcp.CallToolRequest, PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
s.dispatchSyncPrep = func(context.Context, *mcpsdk.CallToolRequest, PrepInput) (*mcpsdk.CallToolResult, PrepOutput, error) {
return nil, PrepOutput{
Success: false,
}, nil
Expand All @@ -124,7 +123,7 @@ func TestDispatchsync_HandleDispatchSync_Ugly_SpawnFailure(t *testing.T) {
workspaceDir := core.JoinPath(WorkspaceRoot(), "core", "go-io", "task-7")
s := &PrepSubsystem{dispatchSyncTick: 10 * time.Millisecond}

s.dispatchSyncPrep = func(context.Context, *mcp.CallToolRequest, PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
s.dispatchSyncPrep = func(context.Context, *mcpsdk.CallToolRequest, PrepInput) (*mcpsdk.CallToolResult, PrepOutput, error) {
core.RequireTrue(t, fs.EnsureDir(workspaceDir).OK)
core.RequireTrue(t, fs.Write(core.JoinPath(workspaceDir, "status.json"), core.JSONMarshalString(&WorkspaceStatus{
Status: "running",
Expand Down Expand Up @@ -196,7 +195,7 @@ func TestDispatchSync_PrepSubsystem_DispatchSync_Ugly_WritesInitialStatusWhenPre
// Real-like prep: creates the workspace but does NOT pre-write status.json
// (the actual prepWorkspace doesn't — the async dispatch() writes it after
// spawn, which the sync path used to skip → "status not found" crash).
s.dispatchSyncPrep = func(context.Context, *mcp.CallToolRequest, PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
s.dispatchSyncPrep = func(context.Context, *mcpsdk.CallToolRequest, PrepInput) (*mcpsdk.CallToolResult, PrepOutput, error) {
core.RequireTrue(t, fs.EnsureDir(workspaceDir).OK)
return nil, PrepOutput{Success: true, WorkspaceDir: workspaceDir, Branch: "agent/x", Prompt: "prompt"}, nil
}
Expand All @@ -221,7 +220,7 @@ func TestDispatchSync_PrepSubsystem_DispatchSync_Good(t *testing.T) {
workspaceDir := core.JoinPath(WorkspaceRoot(), "core", "go-io", "task-9")
subsystem := &PrepSubsystem{dispatchSyncTick: 10 * time.Millisecond}

subsystem.dispatchSyncPrep = func(_ context.Context, _ *mcp.CallToolRequest, input PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
subsystem.dispatchSyncPrep = func(_ context.Context, _ *mcpsdk.CallToolRequest, input PrepInput) (*mcpsdk.CallToolResult, PrepOutput, error) {
core.AssertEqual(t, "core", input.Org)
core.AssertEqual(t, "go-io", input.Repo)
core.AssertEqual(t, "codex", input.Agent)
Expand Down Expand Up @@ -321,7 +320,7 @@ func TestDispatchSync_PrepSubsystem_DispatchSync_Ugly_VZFillsFullStatus(t *testi
workspaceDir := core.JoinPath(WorkspaceRoot(), "core", "go-io", "task-vz")
s := &PrepSubsystem{dispatchSyncTick: 5 * time.Millisecond}

s.dispatchSyncPrep = func(context.Context, *mcp.CallToolRequest, PrepInput) (*mcp.CallToolResult, PrepOutput, error) {
s.dispatchSyncPrep = func(context.Context, *mcpsdk.CallToolRequest, PrepInput) (*mcpsdk.CallToolResult, PrepOutput, error) {
core.RequireTrue(t, fs.EnsureDir(workspaceDir).OK)
return nil, PrepOutput{Success: true, WorkspaceDir: workspaceDir, Branch: "agent/vz", Prompt: "prompt"}, nil
}
Expand Down
62 changes: 0 additions & 62 deletions go/pkg/agentic/fetch_loop_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,49 +181,12 @@ func waitForFetchLoopCalls(t *testing.T, state *fetchLoopCallState, repo string,
core.AssertGreaterOrEqual(t, state.count(repo), want)
}

func fetchLoopWriteGitScript(t *testing.T, logPath, badRepo string) {
t.Helper()

binDir := t.TempDir()
gitPath := core.JoinPath(binDir, "git")
script := core.Concat(
"#!/bin/sh\n",
"repo=$(basename \"$(pwd)\")\n",
"printf '%s|%s\\n' \"$repo\" \"$*\" >> ", logPath, "\n",
"if [ \"$1\" = \"symbolic-ref\" ]; then\n",
" printf 'origin/dev\\n'\n",
" exit 0\n",
"fi\n",
"if [ \"$1\" = \"fetch\" ] && [ \"$repo\" = \"", badRepo, "\" ]; then\n",
" exit 1\n",
"fi\n",
"exit 0\n",
)
core.RequireTrue(t, fs.Write(gitPath, script).OK)
core.RequireTrue(t, testCore.Process().RunIn(context.Background(), binDir, "chmod", "+x", gitPath).OK)
t.Setenv("PATH", core.Concat(binDir, ":", core.Env("PATH")))
}

func fetchLoopCreateRepo(t *testing.T, codePath, org, repo string) {
t.Helper()
repoDir := core.JoinPath(codePath, org, repo)
core.RequireTrue(t, fs.EnsureDir(core.JoinPath(repoDir, ".git")).OK)
}

func fetchLoopWaitForCount(t *testing.T, logPath, repo, snippet string, want int, timeout time.Duration) {
t.Helper()

deadline := time.Now().Add(timeout)
for time.Now().Before(deadline) {
if fetchLoopLogCount(logPath, repo, snippet) >= want {
return
}
time.Sleep(5 * time.Millisecond)
}

core.AssertGreaterOrEqual(t, fetchLoopLogCount(logPath, repo, snippet), want)
}

func fetchLoopWaitForDone(t *testing.T, done <-chan struct{}) {
t.Helper()

Expand All @@ -233,28 +196,3 @@ func fetchLoopWaitForDone(t *testing.T, done <-chan struct{}) {
t.Fatal("fetch loop did not stop after cancellation")
}
}

func fetchLoopLogCount(logPath, repo, snippet string) int {
readResult := fs.Read(logPath)
if !readResult.OK {
return 0
}

content := core.Trim(readResult.Value.(string))
if content == "" {
return 0
}

count := 0
for _, line := range core.Split(content, "\n") {
if repo != "" && !core.HasPrefix(line, core.Concat(repo, "|")) {
continue
}
if snippet != "" && !core.Contains(line, snippet) {
continue
}
count++
}

return count
}
Loading
Loading