From dcbeb33dfcdc0dbe1123953bd3579c6a547a73c1 Mon Sep 17 00:00:00 2001 From: npc0-hue Date: Thu, 27 Aug 2026 17:48:51 +0800 Subject: [PATCH] Normalize legacy file list job results --- platform/service/job_channel.go | 16 +++++++ platform/service/job_channel_test.go | 62 ++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/platform/service/job_channel.go b/platform/service/job_channel.go index 743a7e8..f9421e4 100644 --- a/platform/service/job_channel.go +++ b/platform/service/job_channel.go @@ -278,6 +278,7 @@ func (svc *CoreService) CompleteRunJob(result domain.RunJobResult) (domain.RunJo if err != nil { return domain.RunJobResultResult{}, err } + result = normalizeLegacyExecutionResultForJob(job, result) fingerprint := terminalFingerprint(result) if isTerminalJobState(job.State) { if job.TerminalFingerprint == fingerprint { @@ -358,6 +359,21 @@ func (svc *CoreService) CompleteRunJob(result domain.RunJobResult) (domain.RunJo return domain.RunJobResultResult{Accepted: true, Job: assignmentFromJob(job, result.LeaseToken), ServerTime: stamp}, nil } +func normalizeLegacyExecutionResultForJob(job domain.Job, result domain.RunJobResult) domain.RunJobResult { + if result.ExecutionResult.Kind != "file" { + return result + } + switch job.Capability { + case domain.JobCapabilityFilesList: + result.ExecutionResult.Kind = "file.list" + case domain.JobCapabilityFilesRead: + result.ExecutionResult.Kind = "file.read" + case domain.JobCapabilityFilesWrite, domain.JobCapabilityConfigWrite: + result.ExecutionResult.Kind = "file.write" + } + return result +} + func validateExecutionResultForJob(job domain.Job, result domain.RunJobResult) error { if definition := job.ExecutionInput.Deployment; definition != nil { receipt := result.ExecutionResult.DeploymentReceipt diff --git a/platform/service/job_channel_test.go b/platform/service/job_channel_test.go index 65cc25e..4186a1f 100644 --- a/platform/service/job_channel_test.go +++ b/platform/service/job_channel_test.go @@ -196,6 +196,68 @@ func TestCoreServiceRunJobClaimSkipsServerFileCapabilityWithoutDeclaration(t *te } } +func TestCoreServiceNormalizesLegacyFileListResultKind(t *testing.T) { + svc := newTestCoreService() + plugin, endpoint := createPluginAndRunEndpoint(t, svc) + instance, err := svc.CreateServerInstance(domain.ServerInstance{ + ID: "server-file-list-legacy-kind", + PluginID: plugin.ID, + RunEndpointID: endpoint.ID, + Name: "Legacy File List Server", + State: domain.ServerInstanceStateRunning, + }) + if err != nil { + t.Fatalf("create server instance: %v", err) + } + helloRequest := validRunControlHello() + helloRequest.CapabilityReport.Capabilities = append(helloRequest.CapabilityReport.Capabilities, domain.JobCapabilityFilesList) + helloRequest.CapabilityReport.Fingerprint = "cap-file-list-legacy-kind" + hello, err := svc.RegisterRunHello(helloRequest) + if err != nil { + t.Fatalf("register run hello: %v", err) + } + job, err := svc.CreateJob(domain.Job{ + ID: "job-file-list-legacy-kind", + ServerInstanceID: instance.ID, + RunEndpointID: endpoint.ID, + Capability: domain.JobCapabilityFilesList, + TargetKey: "server-root", + IdempotencyKey: "idem-file-list-legacy-kind", + }) + if err != nil { + t.Fatalf("create file list job: %v", err) + } + claim, err := svc.ClaimRunJob(domain.RunJobClaim{RunEndpointID: endpoint.ID, SessionToken: hello.SessionToken, Capabilities: []string{domain.JobCapabilityFilesList}, Capacity: domain.RunCapacity{MaxJobs: 4}}) + if err != nil || !claim.HasJob || claim.Job.JobID != job.ID { + t.Fatalf("claim file list job: claim=%+v err=%v", claim, err) + } + completed, err := svc.CompleteRunJob(domain.RunJobResult{ + RunEndpointID: endpoint.ID, + SessionToken: hello.SessionToken, + JobID: claim.Job.JobID, + LeaseToken: claim.Job.LeaseToken, + Attempt: claim.Job.Attempt, + State: domain.JobStateSucceeded, + Progress: domain.RunJobProgressReport{Percent: 100, Message: "listed"}, + Message: "listed", + ExecutionResult: domain.JobExecutionResult{ + Kind: "file", + Content: runFileListFixture("server-root", "", "SCUM"), + Summary: "legacy bounded logical file listing", + }, + }) + if err != nil { + t.Fatalf("complete legacy file list job: %v", err) + } + if !completed.Accepted || completed.Job.State != domain.JobStateSucceeded { + t.Fatalf("expected legacy file list result to be accepted, got %+v", completed) + } + stored, err := svc.GetJob(job.ID) + if err != nil || stored.ExecutionResult.Kind != "file.list" { + t.Fatalf("expected stored legacy file kind to be normalized, job=%+v err=%v", stored, err) + } +} + func TestCoreServiceRunJobRejectsInvalidSessionAndLease(t *testing.T) { svc, sessionToken := newRegisteredRunJobService(t) createQueuedRunJob(t, svc, "job-1", "idem-1")