fix: compact agentrun status diagnostics

This commit is contained in:
Codex
2026-06-20 09:23:13 +00:00
parent 5ea8493df9
commit 2ee3820d42
2 changed files with 125 additions and 20 deletions
+118 -18
View File
@@ -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<string, unknown> = {
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<string,
source: {
repository: spec.source.repository,
branch: spec.source.branch,
workspace: spec.source.workspace,
},
runtime: {
namespace: spec.runtime.namespace,
managerDeployment: spec.runtime.managerDeployment,
managerService: spec.runtime.managerService,
internalBaseUrl: spec.runtime.internalBaseUrl,
},
ci: {
namespace: spec.ci.namespace,
pipeline: spec.ci.pipeline,
pipelineRunPrefix: spec.ci.pipelineRunPrefix,
registryPrefix: spec.ci.registryPrefix,
},
gitops: {
branch: spec.gitops.branch,
path: spec.gitops.path,
argoNamespace: spec.gitops.argoNamespace,
argoApplication: spec.gitops.argoApplication,
},
gitMirror: {
@@ -2352,9 +2455,6 @@ function compactAgentRunLaneStatusTarget(spec: AgentRunLaneSpec): Record<string,
mode: spec.database.mode,
provider: spec.database.provider,
configRef: spec.database.configRef,
database: spec.database.database,
user: spec.database.user,
secretRef: spec.database.secretRef,
localPostgresExpectedAbsent: spec.database.localPostgresExpectedAbsent,
valuesPrinted: false,
},
+7 -2
View File
@@ -241,13 +241,14 @@ function summarizeJobProgress(job: JobRecord, maxBytes = 96_000, tails?: { stdou
|| /^hwlab_nodes_v[0-9]{2}_git-mirror_(sync|flush)$/u.test(job.name);
const ciInstallWorkflow = job.name === "ci_install";
if (ciInstallWorkflow) return summarizeCiInstallJobProgress(job, tails?.stderrTail, nowMs);
if (!knownWorkflow && !v02PrMonitorWorkflow && !runtimeLaneTriggerWorkflow && !agentRunYamlLaneTriggerWorkflow && !gitMirrorWorkflow) return genericJobProgress(job, tails?.stderrTail);
const progressTailBytes = Math.max(4096, Math.floor(maxBytes));
const stderrTail = tails?.stderrTail ?? tailFile(job.stderrFile, progressTailBytes);
const agentRunYamlLaneProgressObserved = agentRunYamlLaneTriggerWorkflow || hasAgentRunYamlLaneProgressEvents(stderrTail);
if (!knownWorkflow && !v02PrMonitorWorkflow && !runtimeLaneTriggerWorkflow && !agentRunYamlLaneProgressObserved && !gitMirrorWorkflow) return genericJobProgress(job, stderrTail);
const stdoutTail = tails?.stdoutTail ?? tailFile(job.stdoutFile, progressTailBytes);
if (gitMirrorWorkflow) return summarizeGitMirrorJobProgress(job, stdoutTail, stderrTail, nowMs);
if (runtimeLaneTriggerWorkflow) return summarizeRuntimeLaneTriggerJobProgress(job, stdoutTail, stderrTail, nowMs);
if (agentRunYamlLaneTriggerWorkflow) return summarizeAgentRunYamlLaneTriggerJobProgress(job, stdoutTail, stderrTail, nowMs);
if (agentRunYamlLaneProgressObserved) return summarizeAgentRunYamlLaneTriggerJobProgress(job, stdoutTail, stderrTail, nowMs);
const events = v02PrMonitorWorkflow
? [
...parseJsonLineEvents(stderrTail, "hwlab.v02.pr-monitor.progress"),
@@ -509,6 +510,10 @@ const agentRunYamlLaneProgressEvents = [
{ event: "agentrun.yaml-lane.git-mirror.progress", stage: "git-mirror" },
] as const;
function hasAgentRunYamlLaneProgressEvents(text: string): boolean {
return agentRunYamlLaneProgressEvents.some(({ event }) => 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 })))