From 2ee3820d42bda03f9b93fa3749637cd3aaa8bf42 Mon Sep 17 00:00:00 2001 From: Codex Date: Sat, 20 Jun 2026 09:23:13 +0000 Subject: [PATCH] fix: compact agentrun status diagnostics --- scripts/src/agentrun.ts | 136 ++++++++++++++++++++++++++++++++++------ scripts/src/jobs.ts | 9 ++- 2 files changed, 125 insertions(+), 20 deletions(-) diff --git a/scripts/src/agentrun.ts b/scripts/src/agentrun.ts index 675ae720..7a842e67 100644 --- a/scripts/src/agentrun.ts +++ b/scripts/src/agentrun.ts @@ -2115,6 +2115,7 @@ async function statusYamlLane(config: UniDeskConfig, options: StatusOptions, tar const secrets = record(runtimePayload.secrets); const localPostgres = record(runtimePayload.localPostgres); const expectedGitopsRevision = stringOrNull(mirrorPayload.gitopsCommit); + const mirrorSourceCommit = stringOrNull(mirrorPayload.sourceCommit); const pipelineRunSourceCommit = stringOrNull(pipelineRunStatus.sourceCommit); const sourceCommit = options.sourceCommit ?? (options.pipelineRun !== null ? pipelineRunSourceCommit ?? initialSourceCommit : initialSourceCommit); @@ -2167,16 +2168,94 @@ async function statusYamlLane(config: UniDeskConfig, options: StatusOptions, tar ...(secrets.ready === true ? [] : ["lane-secret-missing"]), ...(spec.database.localPostgresExpectedAbsent && localPostgres.absent !== true ? ["local-postgres-present"] : []), ]; + const ciBlockerNames = new Set(["ci-namespace-missing", "pipeline-missing", "pipelinerun-missing", "pipelinerun-not-succeeded", "ci-serviceaccount-missing"]); + const ciBlockers = blockers.filter((blocker) => ciBlockerNames.has(blocker)); + const runtimeBlockers = blockers.filter((blocker) => !ciBlockerNames.has(blocker)); const aligned = blockers.length === 0 && pipelineSucceeded && argoSyncedToGitops && managerSourceMatchesExpected; + const runtimeAligned = runtimeBlockers.length === 0 && argoSyncedToGitops && managerSourceMatchesExpected; + const ciEvidenceMissing = pipelineRunName !== null && pipelineRunStatus.exists !== true; + const mirrorAlreadySynced = mirrorPayload.readReady === true + && mirrorPayload.writeReady === true + && sourceCommit !== null + && mirrorSourceCommit === sourceCommit + && expectedGitopsRevision !== null; const runtimeAlignment = { pipelineSucceeded, argoRevision: stringOrNull(argo.revision), argoSyncedToGitops, managerSourceCommit: stringOrNull(manager.sourceCommit), managerSourceMatchesExpected, + runtimeAligned, }; - const summary = { + const statusFullCommand = agentRunControlPlaneStatusCommand(spec, options, true); + const triggerCurrentCommand = `bun scripts/cli.ts agentrun control-plane trigger-current --node ${spec.nodeId} --lane ${spec.lane} --confirm`; + const nextAction = aligned + ? { code: "none", summary: "lane aligned; no action required", command: null } + : ciEvidenceMissing && runtimeAligned && mirrorAlreadySynced + ? { code: "ci-evidence-missing", summary: "runtime and git mirror are aligned, but the expected PipelineRun evidence is missing; rerun trigger-current to recreate CI evidence", command: triggerCurrentCommand } + : sourceBranchAdvanced + ? { code: "target-superseded", summary: "target commit is no longer the branch tip; trigger-current against latest source before closeout", command: triggerCurrentCommand } + : ciBlockers.length > 0 + ? { code: "ci-blocked", summary: `CI evidence is blocked: ${ciBlockers.join(", ")}`, command: statusFullCommand } + : runtimeBlockers.length > 0 + ? { code: "runtime-blocked", summary: `runtime alignment is blocked: ${runtimeBlockers.join(", ")}`, command: statusFullCommand } + : { code: "inspect-full-status", summary: "alignment is inconclusive; inspect full status details", command: statusFullCommand }; + const compactSourceStatus = { + workspaceExists: sourcePayload.workspaceExists ?? false, + workspaceClean: sourcePayload.workspaceClean ?? null, + branch: sourcePayload.branch ?? null, + remoteBranchExists: sourcePayload.remoteBranchExists ?? false, + remoteBranchCommit: sourcePayload.remoteBranchCommit ?? null, + workspaceDetached: sourceWorktreeDetached, + }; + const compactGitMirrorStatus = { + readReady: mirrorPayload.readReady ?? false, + writeReady: mirrorPayload.writeReady ?? false, + cachePvcExists: mirrorPayload.cachePvcExists ?? false, + sourceCommit: mirrorSourceCommit, + gitopsCommit: expectedGitopsRevision, + alreadySynced: mirrorAlreadySynced, + }; + const compactCiStatus = { + namespaceExists: runtimePayload.ciNamespaceExists ?? false, + serviceAccountExists: runtimePayload.serviceAccountExists ?? false, + pipelineExists: pipeline.exists ?? false, + pipelineRun: { + name: pipelineRunName, + exists: pipelineRunStatus.exists ?? false, + status: pipelineRunStatus.status ?? null, + reason: pipelineRunStatus.reason ?? null, + sourceCommit: pipelineRunSourceCommit, + }, + evidenceMissing: ciEvidenceMissing, + blockers: ciBlockers, + }; + const compactArgoStatus = { + exists: argo.exists ?? false, + application: argo.application ?? null, + revision: stringOrNull(argo.revision), + syncStatus: argo.syncStatus ?? null, + healthStatus: argo.healthStatus ?? null, + syncedToGitops: argoSyncedToGitops, + }; + const compactRuntimeStatus = { + namespaceExists: runtimePayload.runtimeNamespaceExists ?? false, + manager: { + deploymentExists: manager.deploymentExists ?? false, + serviceExists: manager.serviceExists ?? false, + sourceCommit: stringOrNull(manager.sourceCommit), + sourceMatchesExpected: managerSourceMatchesExpected, + }, + databaseSecretPresent: database.secretPresent ?? null, + secretsReady: secrets.ready ?? null, + localPostgresAbsent: localPostgres.absent ?? null, + blockers: runtimeBlockers, + }; + const detailedSummary = { aligned, + runtimeAligned, + ciEvidenceMissing, + mirrorAlreadySynced, blockers, warnings, sourceCommit, @@ -2198,14 +2277,17 @@ async function statusYamlLane(config: UniDeskConfig, options: StatusOptions, tar writeReady: mirrorPayload.writeReady ?? false, cachePvcExists: mirrorPayload.cachePvcExists ?? false, repositoryCount: Array.isArray(mirrorPayload.repositories) ? mirrorPayload.repositories.length : null, - sourceCommit: stringOrNull(mirrorPayload.sourceCommit), + sourceCommit: mirrorSourceCommit, gitopsCommit: expectedGitopsRevision, + alreadySynced: mirrorAlreadySynced, }, ci: { namespaceExists: runtimePayload.ciNamespaceExists ?? false, serviceAccountExists: runtimePayload.serviceAccountExists ?? false, pipeline, pipelineRun: pipelineRunStatus, + evidenceMissing: ciEvidenceMissing, + blockers: ciBlockers, }, argo, runtime: { @@ -2223,17 +2305,39 @@ async function statusYamlLane(config: UniDeskConfig, options: StatusOptions, tar secrets: compactLaneSecretsStatus(secrets), localPostgres, }, + nextAction, + }; + const commanderSummary = { + aligned, + runtimeAligned, + ciEvidenceMissing, + mirrorAlreadySynced, + blockers, + warnings, + sourceCommit, + expectedPipelineRun: pipelineRunName, + expectedGitopsRevision, + runtimeAlignment, + branchDrift, + source: compactSourceStatus, + gitMirror: compactGitMirrorStatus, + ci: compactCiStatus, + argo: compactArgoStatus, + runtime: compactRuntimeStatus, + nextAction, }; - const statusFullCommand = agentRunControlPlaneStatusCommand(spec, options, true); const result: Record = { ok: sourceProbe.value.exitCode === 0 && runtimeProbe.value.exitCode === 0 && mirrorProbe.value.exitCode === 0 && blockers.length === 0, command: "agentrun control-plane status", mode: "yaml-declared-node-lane", configPath: target.configPath, target: options.full || options.raw ? agentRunLaneSummary(spec) : compactAgentRunLaneStatusTarget(spec), - summary, + summary: options.full || options.raw ? detailedSummary : commanderSummary, alignment: { aligned, + runtimeAligned, + ciEvidenceMissing, + mirrorAlreadySynced, blockers, warnings, sourceCommit, @@ -2248,29 +2352,33 @@ async function statusYamlLane(config: UniDeskConfig, options: StatusOptions, tar gitMirrorMs: mirrorProbe.elapsedMs, totalMs: sourceProbe.elapsedMs + Math.max(runtimeProbe.elapsedMs, mirrorProbe.elapsedMs), }, - captures: { - source: compactCapture(sourceProbe.value, { full: options.full || options.raw || sourceProbe.value.exitCode !== 0 }), - runtime: compactCapture(runtimeProbe.value, { full: options.full || options.raw || runtimeProbe.value.exitCode !== 0 }), - gitMirror: compactCapture(mirrorProbe.value, { full: options.full || options.raw || mirrorProbe.value.exitCode !== 0 }), - }, disclosure: { output: options.full || options.raw ? "full" : "compact-summary", full: options.full, raw: options.raw, - omittedWhenCompact: options.full || options.raw ? [] : ["full target YAML summary", "source", "runtime", "gitMirror", "capture stdout/stderr tails for successful probes"], + omittedWhenCompact: options.full || options.raw ? [] : ["full target YAML summary", "detailed source/runtime/gitMirror objects", "capture stdout/stderr tails for successful probes"], fullCommand: statusFullCommand, }, next: { + action: nextAction, plan: `bun scripts/cli.ts agentrun control-plane plan --node ${spec.nodeId} --lane ${spec.lane}`, postgresStatus: spec.database.configRef ? `bun scripts/cli.ts platform-db postgres status --config ${spec.database.configRef}` : null, postgresApply: spec.database.configRef ? `bun scripts/cli.ts platform-db postgres apply --config ${spec.database.configRef} --confirm` : null, secretSync: `bun scripts/cli.ts agentrun control-plane secret-sync --node ${spec.nodeId} --lane ${spec.lane} --confirm`, restart: `bun scripts/cli.ts agentrun control-plane restart --node ${spec.nodeId} --lane ${spec.lane} --confirm`, statusFull: statusFullCommand, + triggerCurrent: ciEvidenceMissing || sourceBranchAdvanced ? triggerCurrentCommand : null, triggerLatest: sourceBranchAdvanced ? `bun scripts/cli.ts agentrun control-plane trigger-current --node ${spec.nodeId} --lane ${spec.lane} --confirm` : null, }, valuesPrinted: false, }; + if (options.full || options.raw || sourceProbe.value.exitCode !== 0 || runtimeProbe.value.exitCode !== 0 || mirrorProbe.value.exitCode !== 0) { + result.captures = { + source: compactCapture(sourceProbe.value, { full: options.full || options.raw || sourceProbe.value.exitCode !== 0 }), + runtime: compactCapture(runtimeProbe.value, { full: options.full || options.raw || runtimeProbe.value.exitCode !== 0 }), + gitMirror: compactCapture(mirrorProbe.value, { full: options.full || options.raw || mirrorProbe.value.exitCode !== 0 }), + }; + } if (options.full || options.raw) { result.source = sourcePayload; result.runtime = runtimePayload; @@ -2322,24 +2430,19 @@ function compactAgentRunLaneStatusTarget(spec: AgentRunLaneSpec): Record parseJsonLineEvents(text, event).length > 0); +} + function summarizeAgentRunYamlLaneTriggerJobProgress(job: JobRecord, stdoutTail: string, stderrTail: string, nowMs = Date.now()): JobProgressSummary { const events = agentRunYamlLaneProgressEvents .flatMap(({ event, stage }) => parseJsonLineEvents(stderrTail, event).map((item) => ({ ...item, stage })))