fix: 收敛 PaC 自动交付提示

This commit is contained in:
Codex
2026-07-11 11:42:16 +02:00
parent b12dd85375
commit b607c3a996
55 changed files with 2953 additions and 1472 deletions
@@ -72,6 +72,9 @@ export type WebProbeSentinelOptions =
readonly wait: boolean;
readonly timeoutSeconds: number;
readonly rerun: boolean;
readonly manualRecovery: boolean;
readonly reason: string | null;
readonly internalExecution: "pac-controller" | null;
readonly sourceOverride: WebProbeSentinelSourceOverrideOptions;
}
| {
@@ -465,14 +468,16 @@ export function renderPublishResult(publish: Record<string, unknown>): string {
lines.push(
"",
"PUBLISH_DRILLDOWN",
` status: ${commands.cliStatus ?? "-"}`,
` logs: ${commands.logs ?? "-"}`,
` describe: ${commands.describe ?? "-"}`,
` manual-recovery: ${commands.publishCurrent ?? "-"}`,
` git-mirror: ${commands.gitMirrorStatus ?? "-"}`,
` sync: ${commands.gitMirrorSync ?? "-"}`,
` flush: ${commands.gitMirrorFlush ?? "-"}`,
` apply: ${commands.controlPlaneApply ?? "-"}`,
...commandRows([
["status", commands.cliStatus],
["logs", commands.logs],
["describe", commands.describe],
["manual-recovery", commands.publishCurrent],
["git-mirror", commands.gitMirrorStatus],
["sync", commands.gitMirrorSync],
["flush", commands.gitMirrorFlush],
["apply", commands.controlPlaneApply],
]),
);
}
return lines.join("\n");
@@ -592,43 +597,14 @@ export function renderPublishCurrentResult(result: Record<string, unknown>): str
"",
Object.keys(blocker).length === 0 ? "BLOCKER\n-" : ["BLOCKER", table(["CODE", "REASON"], [[blocker.code, blocker.reason]])].join("\n"),
"",
Object.keys(drillDown).length === 0 ? "DRILLDOWN\n-" : [
"DRILLDOWN",
table(["PIPELINERUN", "ASYNC_FLUSH_JOB"], [[drillDown.pipelineRun ?? "-", drillDown.asyncFlushJob ?? "-"]]),
` pipeline-run: ${drillDown.pipelineRunStatus ?? "-"}`,
` pipeline-run-full: ${drillDown.pipelineRunFull ?? "-"}`,
` pac-status: ${drillDown.consumerStatus ?? "-"}`,
` image-status: ${drillDown.imageStatus ?? "-"}`,
` git-mirror: ${drillDown.gitMirrorStatus ?? "-"}`,
` flush: ${drillDown.gitMirrorFlush ?? "-"}`,
` async-flush-status: ${drillDown.asyncFlushStatus ?? "-"}`,
].join("\n"),
renderSentinelDrillDown(drillDown),
"",
Object.keys(recoveryNext).length === 0 ? "RECOVERY_NEXT\n-" : [
"RECOVERY_NEXT",
table(["REASON", "PIPELINERUN", "DIGEST", "GITOPS"], [[recoveryNext.reason, recoveryNext.pipelineRun ?? "-", short(recoveryNext.digestRef), short(recoveryNext.gitopsCommit)]]),
` pac-closeout: ${recoveryNext.pacCloseout ?? "-"}`,
` manual-recovery: ${recoveryNext.publishCurrent ?? "-"}`,
` status: ${recoveryNext.nextStatus ?? "-"}`,
` git-mirror: ${recoveryNext.gitMirrorStatus ?? "-"}`,
` sync: ${recoveryNext.gitMirrorSync ?? "-"}`,
` flush: ${recoveryNext.gitMirrorFlush ?? "-"}`,
` apply: ${recoveryNext.controlPlaneApply ?? "-"}`,
].join("\n"),
renderSentinelRecoveryNext(recoveryNext),
"",
"NEXT",
` pac-closeout: ${next.pacCloseout ?? "-"}`,
` pac-status: ${next.pacStatus ?? "-"}`,
` pac-history: ${next.pacHistory ?? "-"}`,
` status: ${next.controlPlaneStatus ?? "-"}`,
` post-deploy-dashboard: ${next.dashboardVerify ?? "-"}`,
` git-mirror: ${next.gitMirrorStatus ?? "-"}`,
` sync: ${next.gitMirrorSync ?? "-"}`,
` flush: ${next.gitMirrorFlush ?? "-"}`,
renderSentinelNext(next),
"",
"DISCLOSURE",
" formal closeout for migrated JD01 sentinel CI/CD is platform-infra pipelines-as-code closeout/status/history.",
" publish-current is a debug/test/recovery step only; operator-side recovery must be explicit.",
" migrated PaC output only exposes status/history and the stable automatic-chain repair reference.",
` end-to-end and stage budgets are read from ${Object.keys(validationPlan).length > 0 ? "publishCurrent YAML and runtime.healthPath" : "YAML-required publishCurrent fields"}.`,
" CI/CD validation only checks the configured health endpoint; web-probe, Playwright and browser dashboard checks are post-deploy evidence, not this gate.",
" image build uses Tekton PipelineRun and BuildKit; this command does not require Docker daemon/socket/build.",
@@ -670,12 +646,7 @@ export function renderImageResult(result: Record<string, unknown>): string {
"",
Object.keys(blocker).length === 0 ? "BLOCKER\n-" : ["BLOCKER", table(["CODE", "REASON"], [[blocker.code, blocker.reason]])].join("\n"),
"",
"NEXT",
` status: ${next.status ?? "-"}`,
` dry-run: ${next.dryRun ?? "-"}`,
` confirm: ${next.confirm ?? "-"}`,
` trigger: ${next.controlPlaneTrigger ?? "-"}`,
` control-plane: ${next.controlPlanePlan ?? "-"}`,
renderSentinelNext(next),
"",
"DISCLOSURE",
" valuesRedacted=true; image status shows refs, hashes and object names only.",
@@ -758,13 +729,7 @@ export function renderControlPlaneResult(result: Record<string, unknown>): strin
"",
flush.mode === "async-job" ? `ASYNC_FLUSH_STATUS\n ${flushNext.status ?? "-"}` : "ASYNC_FLUSH_STATUS\n-",
"",
"NEXT",
` pac-closeout: ${next.pacCloseout ?? "-"}`,
` pac-status: ${next.pacStatus ?? "-"}`,
` pac-history: ${next.pacHistory ?? "-"}`,
` pipeline-run: ${drillDown.pipelineRunStatus ?? "-"}`,
` status: ${next.controlPlaneStatus ?? next.status ?? "-"}`,
` post-deploy-dashboard: ${next.dashboardVerify ?? "-"}`,
renderSentinelNext({ ...next, pipelineRunStatus: drillDown.pipelineRunStatus }),
"",
"DISCLOSURE",
" compact success view keeps CI/CD closeout fields below the global stdout guard.",
@@ -801,17 +766,7 @@ export function renderControlPlaneResult(result: Record<string, unknown>): strin
]]),
].join("\n"),
"",
Object.keys(drillDown).length === 0 ? "DRILLDOWN\n-" : [
"DRILLDOWN",
table(["PIPELINERUN", "ASYNC_FLUSH_JOB"], [[drillDown.pipelineRun ?? "-", drillDown.asyncFlushJob ?? "-"]]),
` pipeline-run: ${drillDown.pipelineRunStatus ?? "-"}`,
` pipeline-run-full: ${drillDown.pipelineRunFull ?? "-"}`,
` pac-status: ${drillDown.consumerStatus ?? "-"}`,
` image-status: ${drillDown.imageStatus ?? "-"}`,
` git-mirror: ${drillDown.gitMirrorStatus ?? "-"}`,
` flush: ${drillDown.gitMirrorFlush ?? "-"}`,
` async-flush-status: ${drillDown.asyncFlushStatus ?? "-"}`,
].join("\n"),
renderSentinelDrillDown(drillDown),
"",
Object.keys(sourceMirrorSync).length === 0 ? "SOURCE_MIRROR_SYNC\n-" : table(["OK", "PHASE", "JOB", "COMMIT", "STAGE_REF", "ELAPSED"], [[sourceMirrorSync.ok, sourceMirrorSync.phase, sourceMirrorSync.jobName, short(record(sourceMirrorSync.payload).mirrorCommit), short(record(sourceMirrorSync.payload).stageRef), sourceMirrorSync.elapsedMs ?? "-"]]),
"",
@@ -850,32 +805,9 @@ export function renderControlPlaneResult(result: Record<string, unknown>): strin
"",
Object.keys(blocker).length === 0 ? "BLOCKER\n-" : ["BLOCKER", table(["CODE", "REASON"], [[blocker.code, blocker.reason]])].join("\n"),
"",
Object.keys(recoveryNext).length === 0 ? "RECOVERY_NEXT\n-" : [
"RECOVERY_NEXT",
table(["REASON", "PIPELINERUN", "DIGEST", "GITOPS"], [[recoveryNext.reason, recoveryNext.pipelineRun ?? "-", short(recoveryNext.digestRef), short(recoveryNext.gitopsCommit)]]),
` pac-closeout: ${recoveryNext.pacCloseout ?? "-"}`,
` manual-recovery: ${recoveryNext.publishCurrent ?? "-"}`,
` status: ${recoveryNext.nextStatus ?? "-"}`,
` git-mirror: ${recoveryNext.gitMirrorStatus ?? "-"}`,
` sync: ${recoveryNext.gitMirrorSync ?? "-"}`,
` flush: ${recoveryNext.gitMirrorFlush ?? "-"}`,
` apply: ${recoveryNext.controlPlaneApply ?? "-"}`,
].join("\n"),
renderSentinelRecoveryNext(recoveryNext),
"",
"NEXT",
` pac-closeout: ${next.pacCloseout ?? "-"}`,
` pac-status: ${next.pacStatus ?? "-"}`,
` pac-history: ${next.pacHistory ?? "-"}`,
` plan: ${next.plan ?? "-"}`,
` status: ${next.status ?? "-"}`,
` image: ${next.image ?? "-"}`,
` trigger-current: ${next.triggerCurrent ?? "-"}`,
` apply: ${next.apply ?? "-"}`,
` validate: ${next.validate ?? "-"}`,
` quick-verify: ${next.quickVerify ?? "-"}`,
` git-mirror: ${next.gitMirrorStatus ?? "-"}`,
` sync: ${next.gitMirrorSync ?? "-"}`,
` flush: ${next.gitMirrorFlush ?? "-"}`,
renderSentinelNext(next),
"",
"DISCLOSURE",
" default view is a bounded CI/CD summary; full manifest content is represented by object counts and sha256.",
@@ -883,6 +815,89 @@ export function renderControlPlaneResult(result: Record<string, unknown>): strin
].join("\n");
}
function renderSentinelNext(next: Record<string, unknown>): string {
const status = commandText(next.pacStatus) ?? commandText(next.status) ?? commandText(next.controlPlaneStatus);
const controlPlaneStatus = commandText(next.controlPlaneStatus);
const history = commandText(next.pacHistory) ?? commandText(next.history);
const fix = commandText(next.fixAutomaticDelivery) ?? commandText(record(next.fixAutomaticDelivery).reference);
const rows: Array<[string, unknown]> = [
["status", status],
["control-plane-status", controlPlaneStatus === status ? null : controlPlaneStatus],
["history", history],
["fix-automatic-delivery", fix],
["pipeline-run", next.pipelineRunStatus],
["events", next.events],
["logs", next.logs],
["pac-closeout", next.pacCloseout],
["plan", next.plan ?? next.controlPlanePlan],
["image", next.image],
["image-status", next.imageStatus],
["dry-run", next.dryRun],
["confirm", next.confirm],
["trigger", next.controlPlaneTrigger ?? next.triggerCurrent],
["apply", next.apply],
["validate", next.validate],
["quick-verify", next.quickVerify],
["post-deploy-dashboard", next.dashboardVerify],
["git-mirror", next.gitMirrorStatus],
["sync", next.gitMirrorSync],
["flush", next.gitMirrorFlush],
];
const lines = commandRows(rows);
return ["NEXT", ...(lines.length === 0 ? ["-"] : lines)].join("\n");
}
function renderSentinelDrillDown(drillDown: Record<string, unknown>): string {
if (Object.keys(drillDown).length === 0) return "DRILLDOWN\n-";
const lines = commandRows([
["pipeline-run", drillDown.pipelineRunStatus],
["pipeline-run-full", drillDown.pipelineRunFull],
["pac-status", drillDown.consumerStatus],
["image-status", drillDown.imageStatus],
["git-mirror", drillDown.gitMirrorStatus],
["flush", drillDown.gitMirrorFlush],
["async-flush-status", drillDown.asyncFlushStatus],
]);
return [
"DRILLDOWN",
table(["PIPELINERUN", "ASYNC_FLUSH_JOB"], [[drillDown.pipelineRun ?? "-", drillDown.asyncFlushJob ?? "-"]]),
...lines,
].join("\n");
}
function renderSentinelRecoveryNext(recoveryNext: Record<string, unknown>): string {
if (Object.keys(recoveryNext).length === 0) return "RECOVERY_NEXT\n-";
const lines = commandRows([
["status", recoveryNext.nextStatus ?? recoveryNext.pacStatus ?? recoveryNext.status],
["history", recoveryNext.pacHistory ?? recoveryNext.history],
["fix-automatic-delivery", commandText(recoveryNext.fixAutomaticDelivery) ?? commandText(record(recoveryNext.fixAutomaticDelivery).reference)],
["git-mirror", recoveryNext.gitMirrorStatus],
["pac-closeout", recoveryNext.pacCloseout],
["manual-recovery", recoveryNext.publishCurrent],
["sync", recoveryNext.gitMirrorSync],
["flush", recoveryNext.gitMirrorFlush],
["apply", recoveryNext.controlPlaneApply],
]);
return [
"RECOVERY_NEXT",
table(["REASON", "PIPELINERUN", "DIGEST", "GITOPS"], [[recoveryNext.reason ?? "-", recoveryNext.pipelineRun ?? "-", short(recoveryNext.digestRef), short(recoveryNext.gitopsCommit)]]),
...lines,
].join("\n");
}
function commandRows(rows: Array<[string, unknown]>): string[] {
return rows.flatMap(([label, value]) => {
const command = commandText(value);
return command === null ? [] : [` ${label}: ${command}`];
});
}
function commandText(value: unknown): string | null {
if (typeof value !== "string") return null;
const command = value.trim();
return command.length === 0 || command === "-" ? null : command;
}
export function renderObservedStatus(observed: Record<string, unknown>): string {
const rows = [
observedStatusRow("source", observed.sourceMirror),