feat: add d601 recovery guardrails

Adds read-only D601 recovery diagnostics, fixture coverage, CLI wiring, and recovery hotfix runbook updates. Validated with recovery contract, check --files, scripts tsc, artifact matrix direct contract, and read-only live diagnostic.
This commit is contained in:
Lyon
2026-05-23 21:18:44 +08:00
committed by GitHub
parent 6c44f66289
commit e2646763c0
9 changed files with 1406 additions and 5 deletions
+36 -1
View File
@@ -3,6 +3,7 @@ import { extname } from "node:path";
import { runCommand } from "./command";
import { type UniDeskConfig, repoRoot, rootPath } from "./config";
import { composeConfig } from "./docker";
import { compactD601RecoveryGuardrails, runD601RecoveryGuardrails } from "./recovery-guardrails";
interface CheckItem {
name: string;
@@ -27,6 +28,7 @@ const syntaxFiles = [
"scripts/src/e2e.ts",
"scripts/src/help.ts",
"scripts/src/commander.ts",
"scripts/src/recovery-guardrails.ts",
"scripts/src/server-cleanup.ts",
"scripts/src/remote.ts",
"scripts/host-codex-commander-contract-test.ts",
@@ -42,6 +44,7 @@ const syntaxFiles = [
"scripts/code-queue-submit-summary-contract-test.ts",
"scripts/code-queue-cli-read-terminal-contract-test.ts",
"scripts/code-queue-gh-auth-redaction-contract-test.ts",
"scripts/d601-recovery-guardrails-contract-test.ts",
"scripts/microservice-health-output-contract-test.ts",
"scripts/code-queue-supervisor-disclosure-contract-test.ts",
"scripts/code-queue-commander-view-contract-test.ts",
@@ -70,6 +73,7 @@ export interface CheckOptions {
components: boolean;
compose: boolean;
logs: boolean;
recoveryGuardrails: boolean;
rust: boolean;
}
@@ -80,6 +84,7 @@ const defaultCheckOptions: CheckOptions = {
components: false,
compose: false,
logs: false,
recoveryGuardrails: false,
rust: false,
};
@@ -87,7 +92,10 @@ export function checkHelp(): Record<string, unknown> {
return {
ok: true,
command: "check",
usage: "bun scripts/cli.ts check [--syntax-only|--full|--files|--scripts-typecheck|--components|--compose|--logs|--rust]",
usage: [
"bun scripts/cli.ts check [--syntax-only|--full|--files|--scripts-typecheck|--components|--compose|--logs|--recovery-guardrails|--rust]",
"bun scripts/cli.ts check recovery-guardrails",
],
defaultMode: "syntax/config only; Rust is never compiled on the master server by default",
options: [
{ name: "--syntax-only|--basic", description: "Run only config validation, Bun version and TypeScript syntax transpile." },
@@ -97,12 +105,18 @@ export function checkHelp(): Record<string, unknown> {
{ name: "--components", description: "Run component TypeScript typecheck." },
{ name: "--compose", description: "Render Docker Compose config." },
{ name: "--logs", description: "Check unified log rotation policy." },
{ name: "--recovery-guardrails", description: "Run D601 k3s/Code Queue reboot recovery diagnostics in read-only mode." },
{ name: "--rust", description: "Run cargo check only when UNIDESK_D601_RUST_CHECK=1 is set inside D601 CI/dev execution." },
],
rustBoundary: {
masterServer: "do not run cargo check/build here",
d601: "use deploy apply --env dev --service backend-core and CI with UNIDESK_D601_RUST_CHECK=1",
},
recoveryGuardrailsBoundary: {
command: "bun scripts/cli.ts check recovery-guardrails",
mutation: false,
forbidden: ["restart k3s", "delete CRI sandboxes or pods", "modify hostPath directories", "deploy/rollout", "destructive prune/reset"],
},
};
}
@@ -116,6 +130,7 @@ export function parseCheckOptions(args: string[]): CheckOptions {
options.components = true;
options.compose = true;
options.logs = true;
options.recoveryGuardrails = true;
} else if (arg === "--files") {
options.files = true;
} else if (arg === "--scripts-typecheck") {
@@ -126,6 +141,8 @@ export function parseCheckOptions(args: string[]): CheckOptions {
options.compose = true;
} else if (arg === "--logs") {
options.logs = true;
} else if (arg === "--recovery-guardrails") {
options.recoveryGuardrails = true;
} else if (arg === "--rust") {
options.rust = true;
} else if (arg === "--basic" || arg === "--syntax-only") {
@@ -277,6 +294,10 @@ function skippedItem(name: string, reason: string, enableWith: string): CheckIte
return { name, ok: true, detail: { skipped: true, reason, enableWith } };
}
export function runRecoveryGuardrailsCheck(config: UniDeskConfig): ReturnType<typeof compactD601RecoveryGuardrails> {
return compactD601RecoveryGuardrails(runD601RecoveryGuardrails(config));
}
export function runChecks(config: UniDeskConfig, options: CheckOptions = defaultCheckOptions): { ok: boolean; mode: string; options: CheckOptions; items: CheckItem[] } {
const items: CheckItem[] = [
{ name: "config:validated", ok: true, detail: { project: config.project.name, runtime: config.runtime } },
@@ -352,8 +373,10 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
fileItem("scripts/server-cleanup-plan-contract-test.ts"),
fileItem("scripts/src/artifact-registry.ts"),
fileItem("scripts/src/server-cleanup.ts"),
fileItem("scripts/src/recovery-guardrails.ts"),
fileItem("scripts/src/auth-broker.ts"),
fileItem("scripts/auth-broker-contract-test.ts"),
fileItem("scripts/d601-recovery-guardrails-contract-test.ts"),
fileItem("src/components/microservices/auth-broker/Cargo.toml"),
fileItem("src/components/microservices/auth-broker/Dockerfile"),
fileItem("src/components/microservices/auth-broker/src/main.rs"),
@@ -403,6 +426,7 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
items.push(commandItem("gh:pr-contract", ["bun", "scripts/gh-cli-pr-contract-test.ts"], 30_000));
items.push(commandItem("playwright:cli-wrapper-contract", ["bun", "scripts/playwright-cli-contract-test.ts"], 30_000));
items.push(commandItem("auth-broker:p0-contract", ["bun", "scripts/auth-broker-contract-test.ts"], 30_000));
items.push(commandItem("d601:recovery-guardrails-contract", ["bun", "scripts/d601-recovery-guardrails-contract-test.ts"], 30_000));
} else {
items.push(skippedItem("typescript:scripts", "scripts TypeScript typecheck is opt-in", "--scripts-typecheck or --full"));
items.push(skippedItem("code-queue:prompt-observation-contract", "prompt observation contract is opt-in with script checks", "--scripts-typecheck or --full"));
@@ -439,12 +463,23 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
items.push(skippedItem("gh:pr-contract", "GitHub PR CLI contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("playwright:cli-wrapper-contract", "Playwright wrapper/headless/session contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("auth-broker:p0-contract", "Auth Broker P0 skeleton and CLI adapter contract is opt-in with script checks", "--scripts-typecheck or --full"));
items.push(skippedItem("d601:recovery-guardrails-contract", "D601 recovery guardrails fixture contract is opt-in with script checks", "--scripts-typecheck or --full"));
}
if (options.logs) {
items.push(unifiedLogRotationItem());
} else {
items.push(skippedItem("logs:unified-hourly-rotation", "policy scan is opt-in", "--logs or --full"));
}
if (options.recoveryGuardrails) {
const recovery = runRecoveryGuardrailsCheck(config);
items.push({
name: "d601:recovery-guardrails",
ok: recovery.ok,
detail: recovery,
});
} else {
items.push(skippedItem("d601:recovery-guardrails", "D601 reboot recovery diagnostics are opt-in and read-only", "--recovery-guardrails or --full"));
}
if (options.components) {
items.push(commandItem("typescript:components", ["bunx", "tsc", "-p", "src/tsconfig.check.json", "--pretty", "false"], 180_000));
} else {
+1 -1
View File
@@ -9,7 +9,7 @@ export function rootHelp(): unknown {
{ command: "help", description: "List supported commands." },
{ command: "--main-server-ip <ip> <command>", description: "Run selected commands through the public frontend API; use --main-server-key only for legacy SSH transport." },
{ command: "config show", description: "Validate and print config.json as the single source of truth." },
{ command: "check [--full|--files|--scripts-typecheck|--components|--compose|--logs|--rust]", description: "Run the lightweight default syntax/config gate; Rust is opt-in and only allowed from D601 CI/dev execution." },
{ command: "check [--full|--files|--scripts-typecheck|--components|--compose|--logs|--recovery-guardrails|--rust] | check recovery-guardrails", description: "Run the lightweight default syntax/config gate or the low-noise read-only D601 recovery guardrails; Rust is opt-in and only allowed from D601 CI/dev execution." },
{ command: "server start", description: "Fire-and-forget build/start for database, backend-core, frontend, provider gateway, and managed main-server user services." },
{ command: "server stop", description: "Fire-and-forget docker-compose down for the fixed UniDesk stack." },
{ command: "server status", description: "Show fixed ports, containers, service health, and public URLs." },
File diff suppressed because it is too large Load Diff