#!/usr/bin/env node require('ts-node/register/transpile-only'); const crypto = require('node:crypto'); const fs = require('node:fs'); const path = require('node:path'); const { spawnSync } = require('node:child_process'); const { createLegacyShadowPrimaryGateReceipt, legacyShadowPrimaryEvidenceSha256, parseLegacyShadowPrimaryGateReceipt, } = require('../back/runtime/domain/legacyShadowPrimaryGate'); const { createManualPrimaryCanaryDisabledManifest, createManualPrimaryCanaryEnabledManifest, createManualPrimaryCanaryPlan, createManualPrimaryCanaryQualification, manualPrimaryCanarySha256, parseManualPrimaryCanaryPlan, parseManualPrimaryCanaryQualification, } = require('../back/runtime/domain/manualPrimaryCanaryCeremony'); const { parseRuntimeRolloutManifest, } = require('../back/runtime/domain/runtimeRolloutManifest'); const MAX_PRIVATE_JSON_BYTES = 1024 * 1024; const MODES = new Set([ 'prepare', 'observe', 'resource', 'qualify', 'approve', 'status', 'rollback', ]); const ROLLBACK_REASONS = new Set([ 'operator_request', 'runtime_failure', 'gate_rejected', 'approval_expired', ]); class ManualPrimaryCanaryError extends Error { constructor(code, message = code) { super(message); this.name = 'ManualPrimaryCanaryError'; this.code = code; } } function integer(name, value, minimum, maximum) { if (!/^\d+$/u.test(value)) { throw new ManualPrimaryCanaryError( 'argument_invalid', `${name} must be an integer`, ); } const parsed = Number(value); if (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) { throw new ManualPrimaryCanaryError( 'argument_invalid', `${name} must be between ${minimum} and ${maximum}`, ); } return parsed; } function parseArguments(argv) { const options = {}; for (const argument of argv) { if (argument === '--') continue; if (argument.startsWith('--mode=')) { options.mode = argument.slice('--mode='.length); } else if (argument.startsWith('--root=')) { const value = argument.slice('--root='.length); if (!value) throw new ManualPrimaryCanaryError('argument_invalid'); options.root = path.resolve(value); } else if (argument.startsWith('--session=')) { options.sessionId = argument.slice('--session='.length); } else if (argument.startsWith('--profile=')) { options.profile = argument.slice('--profile='.length); } else if (argument.startsWith('--admissions=')) { options.admissions = integer( '--admissions', argument.slice('--admissions='.length), 1, 128, ); } else if (argument.startsWith('--database=')) { const value = argument.slice('--database='.length); if (!value) throw new ManualPrimaryCanaryError('argument_invalid'); options.database = path.resolve(value); } else if (argument.startsWith('--approved-by=')) { options.approvedBy = argument.slice('--approved-by='.length); } else if (argument.startsWith('--approval-ms=')) { options.approvalMs = integer( '--approval-ms', argument.slice('--approval-ms='.length), 60_000, 24 * 60 * 60 * 1_000, ); } else if (argument.startsWith('--operator=')) { options.operator = argument.slice('--operator='.length); } else if (argument.startsWith('--reason=')) { options.reason = argument.slice('--reason='.length); } else { throw new ManualPrimaryCanaryError( 'argument_invalid', `Unsupported argument: ${argument}`, ); } } if (!MODES.has(options.mode)) { throw new ManualPrimaryCanaryError('argument_invalid', '--mode is invalid'); } if (!options.root || !path.isAbsolute(options.root)) { throw new ManualPrimaryCanaryError( 'argument_invalid', '--root must be an absolute path', ); } if (!options.sessionId) { throw new ManualPrimaryCanaryError( 'argument_invalid', '--session is required', ); } if (options.mode === 'prepare') { if (options.profile !== 'edge' && options.profile !== 'standalone') { throw new ManualPrimaryCanaryError( 'argument_invalid', '--profile must be edge or standalone', ); } if (options.admissions === undefined) { options.admissions = options.profile === 'edge' ? 8 : 32; } } if (options.mode === 'observe' && !options.database) { throw new ManualPrimaryCanaryError( 'argument_invalid', '--database is required for observe', ); } if (options.mode === 'approve') { if (!options.approvedBy) { throw new ManualPrimaryCanaryError( 'argument_invalid', '--approved-by is required for approve', ); } options.approvalMs ??= 60 * 60 * 1_000; } if (options.mode === 'rollback') { if ( !options.operator || options.operator.trim() !== options.operator || options.operator.length < 3 || options.operator.length > 128 || /[\u0000-\u001f\u007f]/u.test(options.operator) || !ROLLBACK_REASONS.has(options.reason) ) { throw new ManualPrimaryCanaryError( 'argument_invalid', '--operator and a supported --reason are required for rollback', ); } } return options; } function assertRoot(root) { if (!path.isAbsolute(root)) { throw new ManualPrimaryCanaryError('root_unsafe'); } const stat = fs.lstatSync(root); if ( !stat.isDirectory() || stat.isSymbolicLink() || (typeof process.getuid === 'function' && stat.uid !== process.getuid()) || (stat.mode & 0o022) !== 0 ) { throw new ManualPrimaryCanaryError( 'root_unsafe', 'Canary root must be an owner-controlled real directory', ); } } function filePath(root, fileName) { if (path.basename(fileName) !== fileName || fileName.includes('..')) { throw new ManualPrimaryCanaryError('file_name_invalid'); } return path.join(root, fileName); } function readPrivateJson(sourcePath, maximumBytes = MAX_PRIVATE_JSON_BYTES) { let descriptor; try { descriptor = fs.openSync( sourcePath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0), ); const stat = fs.fstatSync(descriptor); if ( !stat.isFile() || (stat.mode & 0o077) !== 0 || (typeof process.getuid === 'function' && stat.uid !== process.getuid()) || stat.size < 2 || stat.size > maximumBytes ) { throw new ManualPrimaryCanaryError('private_file_unsafe'); } const bytes = Buffer.alloc(stat.size); let offset = 0; while (offset < bytes.length) { const count = fs.readSync( descriptor, bytes, offset, bytes.length - offset, offset, ); if (count === 0) throw new ManualPrimaryCanaryError('private_file_stalled'); offset += count; } return { bytes, sha256: manualPrimaryCanarySha256(bytes), value: JSON.parse(bytes.toString('utf8')), }; } catch (error) { if (error instanceof ManualPrimaryCanaryError) throw error; throw new ManualPrimaryCanaryError( 'private_file_unavailable', error instanceof Error ? error.message : String(error), ); } finally { if (descriptor !== undefined) fs.closeSync(descriptor); } } function serialized(value) { return Buffer.from(`${JSON.stringify(value)}\n`, 'utf8'); } function syncDirectory(directory) { const descriptor = fs.openSync(directory, fs.constants.O_RDONLY); try { fs.fsyncSync(descriptor); } finally { fs.closeSync(descriptor); } } function publishNoReplace(targetPath, value) { const bytes = Buffer.isBuffer(value) ? value : serialized(value); const directory = path.dirname(targetPath); const temporaryPath = path.join( directory, `.ql3-canary-${process.pid}-${crypto.randomBytes(8).toString('hex')}.tmp`, ); let descriptor; try { descriptor = fs.openSync(temporaryPath, 'wx', 0o600); fs.writeFileSync(descriptor, bytes); fs.fsyncSync(descriptor); fs.closeSync(descriptor); descriptor = undefined; fs.linkSync(temporaryPath, targetPath); syncDirectory(directory); } finally { if (descriptor !== undefined) fs.closeSync(descriptor); try { fs.unlinkSync(temporaryPath); } catch (error) { if (error?.code !== 'ENOENT') throw error; } } return { bytes, sha256: manualPrimaryCanarySha256(bytes), state: 'created' }; } function publishOrVerify(targetPath, value) { const expected = Buffer.isBuffer(value) ? value : serialized(value); try { return publishNoReplace(targetPath, expected); } catch (error) { if (error?.code !== 'EEXIST') throw error; const existing = readPrivateJson(targetPath); if (!existing.bytes.equals(expected)) { throw new ManualPrimaryCanaryError('publication_conflict'); } return { ...existing, state: 'existing' }; } } function readPlan(root, sessionId) { const candidate = createManualPrimaryCanaryPlan({ sessionId, profile: 'edge', createdAtMs: 0, admissionTarget: 8, currentRollout: { state: 'absent' }, }); const planRead = readPrivateJson( filePath(root, candidate.files.plan), 64 * 1024, ); const plan = parseManualPrimaryCanaryPlan(planRead.value); if (plan.sessionId !== sessionId) { throw new ManualPrimaryCanaryError('plan_session_mismatch'); } return { plan, read: planRead }; } function currentRollout(root, now) { const target = filePath(root, 'qinglong3-rollout.json'); let read; try { read = readPrivateJson(target, 64 * 1024); } catch (error) { if (error.code === 'private_file_unavailable' && !fs.existsSync(target)) { return { state: 'absent', target }; } throw error; } const decision = parseRuntimeRolloutManifest(read.value, now); return { state: decision.manifest.enabled ? 'enabled' : 'disabled', target, read, manifest: decision.manifest, }; } function assertRolloutExpectation(plan, current) { if (plan.currentRollout.state !== current.state) { throw new ManualPrimaryCanaryError('rollout_changed'); } if ( current.state === 'disabled' && plan.currentRollout.sha256 !== current.read.sha256 ) { throw new ManualPrimaryCanaryError('rollout_changed'); } } function replaceRollout(targetPath, expected, nextBytes) { const directory = path.dirname(targetPath); const temporaryPath = path.join( directory, `.ql3-rollout-${process.pid}-${crypto.randomBytes(8).toString('hex')}.tmp`, ); let descriptor; try { descriptor = fs.openSync(temporaryPath, 'wx', 0o600); fs.writeFileSync(descriptor, nextBytes); fs.fsyncSync(descriptor); fs.closeSync(descriptor); descriptor = undefined; const current = fs.existsSync(targetPath) ? readPrivateJson(targetPath, 64 * 1024) : undefined; if ( (expected === undefined && current !== undefined) || (expected !== undefined && current?.sha256 !== expected) ) { throw new ManualPrimaryCanaryError('rollout_changed'); } if (current === undefined) { fs.linkSync(temporaryPath, targetPath); fs.unlinkSync(temporaryPath); } else { fs.renameSync(temporaryPath, targetPath); } syncDirectory(directory); } finally { if (descriptor !== undefined) fs.closeSync(descriptor); try { fs.unlinkSync(temporaryPath); } catch (error) { if (error?.code !== 'ENOENT') throw error; } } } function validateCapture(plan, value, now) { const evidence = value && typeof value === 'object' ? value : {}; const capture = evidence.capture ?? {}; const totals = capture.totals ?? {}; if ( evidence.schema !== 'qinglong/legacy-shadow-capture-evidence@v1' || evidence.profile !== plan.profile || evidence.qualification?.passed !== true || capture.profile !== plan.profile || capture.assessment !== 'captured' || capture.capturePermille !== 1_000 || capture.window?.basis !== 'process_local_legacy_admission' || !Number.isSafeInteger(capture.window?.startInclusiveMs) || !Number.isSafeInteger(capture.window?.endExclusiveMs) || capture.window.startInclusiveMs >= capture.window.endExclusiveMs || capture.configuredOriginCount !== 1 || capture.byOrigin?.length !== 1 || capture.byOrigin[0]?.origin !== 'manual' || capture.byOrigin[0]?.admitted !== plan.admissionTarget || capture.byOrigin[0]?.captured !== plan.admissionTarget || capture.byOrigin[0]?.failed !== 0 || capture.byOrigin[0]?.pending !== 0 || totals.admitted !== plan.admissionTarget || totals.captured !== plan.admissionTarget || totals.failed !== 0 || totals.pending !== 0 || capture.window?.startInclusiveMs < plan.createdAtMs || capture.window?.endExclusiveMs + plan.minimumSettlingAgeMs > now ) { throw new ManualPrimaryCanaryError('capture_not_ready'); } return capture.window; } function runJsonChild(script, arguments_, timeoutMs, dependencies) { const result = (dependencies.spawnSync ?? spawnSync)( process.execPath, [script, ...arguments_], { cwd: dependencies.workspaceRoot, encoding: 'utf8', timeout: timeoutMs, maxBuffer: MAX_PRIVATE_JSON_BYTES, env: process.env, }, ); if (result.error || result.signal || result.status !== 0) { throw new ManualPrimaryCanaryError('evidence_child_failed'); } if ( typeof result.stdout !== 'string' || Buffer.byteLength(result.stdout) > MAX_PRIVATE_JSON_BYTES ) { throw new ManualPrimaryCanaryError('evidence_child_output_invalid'); } try { return JSON.parse(result.stdout); } catch { throw new ManualPrimaryCanaryError('evidence_child_output_invalid'); } } function prepare(options, dependencies) { assertRoot(options.root); const now = dependencies.clock.now(); const current = currentRollout(options.root, now); if (current.state === 'enabled') { throw new ManualPrimaryCanaryError('primary_already_enabled'); } const expectedFiles = createManualPrimaryCanaryPlan({ sessionId: options.sessionId, profile: options.profile, createdAtMs: 0, admissionTarget: options.admissions, currentRollout: { state: 'absent' }, }).files; const existingPlanPath = filePath(options.root, expectedFiles.plan); if (existsRegular(existingPlanPath)) { const existing = parseManualPrimaryCanaryPlan( readPrivateJson(existingPlanPath, 64 * 1024).value, ); if ( existing.profile !== options.profile || existing.admissionTarget !== options.admissions ) { throw new ManualPrimaryCanaryError('publication_conflict'); } assertRolloutExpectation(existing, current); return { state: 'prepared', publication: 'existing', sessionId: existing.sessionId, profile: existing.profile, admissionTarget: existing.admissionTarget, environment: { QL_DEPLOYMENT_PROFILE: existing.profile, QL3_SHADOW_ORIGINS: 'manual', QL3_SHADOW_CAPTURE_EVIDENCE_FILE: existing.files.capture, }, automaticActivation: false, }; } const plan = createManualPrimaryCanaryPlan({ sessionId: options.sessionId, profile: options.profile, createdAtMs: now, admissionTarget: options.admissions, currentRollout: current.state === 'absent' ? { state: 'absent' } : { state: 'disabled', sha256: current.read.sha256 }, }); const publication = publishOrVerify( filePath(options.root, plan.files.plan), plan, ); return { state: 'prepared', publication: publication.state, sessionId: plan.sessionId, profile: plan.profile, admissionTarget: plan.admissionTarget, environment: { QL_DEPLOYMENT_PROFILE: plan.profile, QL3_SHADOW_ORIGINS: 'manual', QL3_SHADOW_CAPTURE_EVIDENCE_FILE: plan.files.capture, }, automaticActivation: false, }; } function observe(options, dependencies) { assertRoot(options.root); const { plan } = readPlan(options.root, options.sessionId); const now = dependencies.clock.now(); const capture = readPrivateJson(filePath(options.root, plan.files.capture)); const window = validateCapture(plan, capture.value, now); const terminalPath = filePath(options.root, plan.files.terminal); if (existsRegular(terminalPath)) { const terminal = readPrivateJson(terminalPath).value; if ( terminal?.schema !== 'qinglong/legacy-shadow-terminal-difference-report@v1' || terminal.profile !== plan.profile || terminal.assessment !== 'matched' || terminal.window?.startInclusiveMs !== window.startInclusiveMs || terminal.window?.endExclusiveMs !== window.endExclusiveMs || terminal.scanned !== plan.admissionTarget ) { throw new ManualPrimaryCanaryError('publication_conflict'); } return { state: 'terminal_observed', publication: 'existing', sessionId: plan.sessionId, profile: plan.profile, assessment: terminal.assessment, scanned: terminal.scanned, }; } const databaseStat = fs.lstatSync(options.database); if ( !databaseStat.isFile() || databaseStat.isSymbolicLink() || (typeof process.getuid === 'function' && databaseStat.uid !== process.getuid()) || (databaseStat.mode & 0o022) !== 0 ) { throw new ManualPrimaryCanaryError('database_unsafe'); } const terminal = runJsonChild( path.join( dependencies.workspaceRoot, 'scripts/ql3-legacy-shadow-terminal-audit.cjs', ), [ `--database=${options.database}`, `--profile=${plan.profile}`, '--origin=manual', `--window-start-ms=${window.startInclusiveMs}`, `--window-end-ms=${window.endExclusiveMs}`, `--observed-at-ms=${now}`, `--minimum-settling-age-ms=${plan.minimumSettlingAgeMs}`, '--json', '--fail-on-difference', ], 30_000, dependencies, ); const publication = publishOrVerify(terminalPath, terminal); return { state: 'terminal_observed', publication: publication.state, sessionId: plan.sessionId, profile: plan.profile, assessment: terminal.assessment, scanned: terminal.scanned, }; } function resource(options, dependencies) { assertRoot(options.root); const { plan } = readPlan(options.root, options.sessionId); const resourcePath = filePath(options.root, plan.files.resource); if (existsRegular(resourcePath)) { const existing = readPrivateJson(resourcePath).value; if ( existing?.fixture !== 'qinglong/legacy-shadow-resource-rollback-evidence@v1' || existing.profile !== plan.profile || existing.workload?.mode !== 'full' || existing.workload?.runtime !== 'compiled_backend' || existing.qualification?.passed !== true || existing.rollback?.performed !== true || existing.rollback?.legacyContinued !== true || existing.rollback?.shadowWritesStopped !== true || existing.rollback?.databaseIntegrity !== 'ok' ) { throw new ManualPrimaryCanaryError('publication_conflict'); } return { state: 'resource_proven', publication: 'existing', sessionId: plan.sessionId, profile: plan.profile, qualified: true, }; } const report = runJsonChild( path.join( dependencies.workspaceRoot, 'scripts/ql3-legacy-shadow-resource-rollback.cjs', ), [ `--profile=${plan.profile}`, '--mode=full', '--samples=8', '--require-compiled', '--json', ], plan.profile === 'edge' ? 120_000 : 180_000, dependencies, ); const publication = publishOrVerify(resourcePath, report); return { state: 'resource_proven', publication: publication.state, sessionId: plan.sessionId, profile: plan.profile, qualified: report.qualification?.passed === true, }; } function qualify(options, dependencies) { assertRoot(options.root); const { plan, read: planRead } = readPlan(options.root, options.sessionId); const gatePath = filePath(options.root, plan.files.primaryGate); const qualificationPath = filePath(options.root, plan.files.qualification); if (existsRegular(gatePath) && existsRegular(qualificationPath)) { const { qualification } = verifyQualification(options.root, plan, planRead); return { state: 'qualified', publication: 'existing', sessionId: plan.sessionId, profile: plan.profile, admitted: qualification.counts.admitted, automaticActivation: false, }; } const capture = readPrivateJson(filePath(options.root, plan.files.capture)); const terminal = readPrivateJson(filePath(options.root, plan.files.terminal)); const resourceRead = readPrivateJson( filePath(options.root, plan.files.resource), ); const now = dependencies.clock.now(); validateCapture(plan, capture.value, now); const gate = existsRegular(gatePath) ? parseLegacyShadowPrimaryGateReceipt( readPrivateJson(gatePath, 64 * 1024).value, ) : createLegacyShadowPrimaryGateReceipt({ profile: plan.profile, generatedAtMs: now, capture: capture.value, terminal: terminal.value, resource: resourceRead.value, }); if (gate.assessment !== 'eligible') { throw new ManualPrimaryCanaryError( 'primary_gate_ineligible', gate.violations.join(','), ); } if ( legacyShadowPrimaryEvidenceSha256(capture.value) !== gate.evidence.captureSha256 || legacyShadowPrimaryEvidenceSha256(terminal.value) !== gate.evidence.terminalSha256 || legacyShadowPrimaryEvidenceSha256(resourceRead.value) !== gate.evidence.resourceSha256 ) { throw new ManualPrimaryCanaryError('primary_gate_source_drift'); } const gatePublication = publishOrVerify(gatePath, gate); const qualification = createManualPrimaryCanaryQualification({ plan, planSha256: planRead.sha256, primaryGate: gate, primaryGateFileSha256: gatePublication.sha256, sourceFileSha256: { capture: capture.sha256, terminal: terminal.sha256, resource: resourceRead.sha256, }, qualifiedAtMs: now, }); const qualificationPublication = publishOrVerify( qualificationPath, qualification, ); return { state: 'qualified', publication: qualificationPublication.state, sessionId: plan.sessionId, profile: plan.profile, admitted: qualification.counts.admitted, automaticActivation: false, }; } function verifyQualification(root, plan, planRead) { const gateRead = readPrivateJson( filePath(root, plan.files.primaryGate), 64 * 1024, ); const gate = parseLegacyShadowPrimaryGateReceipt(gateRead.value); const qualificationRead = readPrivateJson( filePath(root, plan.files.qualification), 64 * 1024, ); const qualification = parseManualPrimaryCanaryQualification( qualificationRead.value, ); const capture = readPrivateJson(filePath(root, plan.files.capture)); const terminal = readPrivateJson(filePath(root, plan.files.terminal)); const resource = readPrivateJson(filePath(root, plan.files.resource)); if ( qualification.sessionId !== plan.sessionId || qualification.profile !== plan.profile || qualification.planSha256 !== planRead.sha256 || qualification.primaryGateFileSha256 !== gateRead.sha256 || qualification.sourceFileSha256.capture !== capture.sha256 || qualification.sourceFileSha256.terminal !== terminal.sha256 || qualification.sourceFileSha256.resource !== resource.sha256 || qualification.sourceCanonicalSha256.capture !== gate.evidence.captureSha256 || qualification.sourceCanonicalSha256.terminal !== gate.evidence.terminalSha256 || qualification.sourceCanonicalSha256.resource !== gate.evidence.resourceSha256 || qualification.window.startInclusiveMs !== gate.window.startInclusiveMs || qualification.window.endExclusiveMs !== gate.window.endExclusiveMs || qualification.counts.admitted !== gate.counts.admitted || qualification.counts.captured !== gate.counts.captured || qualification.counts.terminalScanned !== gate.counts.terminalScanned || qualification.counts.terminalMatched !== gate.counts.terminalMatched || gate.counts.admitted !== plan.admissionTarget || legacyShadowPrimaryEvidenceSha256(capture.value) !== qualification.sourceCanonicalSha256.capture || legacyShadowPrimaryEvidenceSha256(terminal.value) !== qualification.sourceCanonicalSha256.terminal || legacyShadowPrimaryEvidenceSha256(resource.value) !== qualification.sourceCanonicalSha256.resource || gate.assessment !== 'eligible' ) { throw new ManualPrimaryCanaryError('qualification_drift'); } return { gate, gateRead, qualification, qualificationRead }; } function approve(options, dependencies) { assertRoot(options.root); const { plan, read: planRead } = readPlan(options.root, options.sessionId); const { qualification } = verifyQualification(options.root, plan, planRead); const now = dependencies.clock.now(); const current = currentRollout(options.root, now); if ( current.state === 'enabled' && current.manifest.revision === `manual-primary-${plan.sessionId}` ) { if ( current.manifest.primaryGate.receiptSha256 !== qualification.primaryGateFileSha256 || current.manifest.primaryGate.receiptFile !== plan.files.primaryGate || current.manifest.rollout.origins.manual !== 'primary' || current.manifest.approvedBy !== options.approvedBy || current.manifest.expiresAtMs - current.manifest.approvedAtMs !== options.approvalMs ) { throw new ManualPrimaryCanaryError('active_rollout_drift'); } const selection = { schema: 'qinglong/manual-primary-canary-selection@v1', schemaVersion: 1, sessionId: plan.sessionId, profile: plan.profile, selectedAtMs: current.manifest.approvedAtMs, expiresAtMs: current.manifest.expiresAtMs, manifestSha256: current.read.sha256, priorRollout: plan.currentRollout, }; const publication = publishOrVerify( filePath(options.root, plan.files.selection), selection, ); return { state: 'activation_approved', publication: publication.state, sessionId: plan.sessionId, expiresAtMs: current.manifest.expiresAtMs, requiresRestart: true, }; } assertRolloutExpectation(plan, current); const manifest = createManualPrimaryCanaryEnabledManifest({ plan, qualification, approvedBy: options.approvedBy, approvedAtMs: now, approvalMs: options.approvalMs, }); const manifestBytes = serialized(manifest); if (current.state === 'disabled') { publishOrVerify( filePath(options.root, plan.files.previousRollout), current.read.bytes, ); } replaceRollout( current.target, current.state === 'disabled' ? current.read.sha256 : undefined, manifestBytes, ); const manifestSha256 = manualPrimaryCanarySha256(manifestBytes); const selection = { schema: 'qinglong/manual-primary-canary-selection@v1', schemaVersion: 1, sessionId: plan.sessionId, profile: plan.profile, selectedAtMs: now, expiresAtMs: manifest.expiresAtMs, manifestSha256, priorRollout: plan.currentRollout, }; const selectionPublication = publishOrVerify( filePath(options.root, plan.files.selection), selection, ); return { state: 'activation_approved', publication: selectionPublication.state, sessionId: plan.sessionId, expiresAtMs: manifest.expiresAtMs, requiresRestart: true, }; } function rollback(options, dependencies) { assertRoot(options.root); const { plan } = readPlan(options.root, options.sessionId); const now = dependencies.clock.now(); const target = filePath(options.root, plan.files.rollout); const currentRead = readPrivateJson(target, 64 * 1024); const raw = currentRead.value; const evaluationTime = raw?.enabled === true && Number.isSafeInteger(raw.approvedAtMs) ? raw.approvedAtMs : now; const decision = parseRuntimeRolloutManifest(raw, evaluationTime); const disabled = createManualPrimaryCanaryDisabledManifest(plan.sessionId); const disabledBytes = serialized(disabled); const disabledSha256 = manualPrimaryCanarySha256(disabledBytes); if (decision.manifest.enabled === false) { if (currentRead.sha256 !== disabledSha256) { throw new ManualPrimaryCanaryError('different_disabled_rollout'); } } else if ( decision.manifest.revision !== `manual-primary-${plan.sessionId}` ) { throw new ManualPrimaryCanaryError('rollout_session_mismatch'); } const intentPath = filePath(options.root, plan.files.rollbackIntent); let intent; let intentSha256; if (existsRegular(intentPath)) { const intentRead = readPrivateJson(intentPath, 64 * 1024); intent = intentRead.value; intentSha256 = intentRead.sha256; if ( intent?.schema !== 'qinglong/manual-primary-canary-rollback-intent@v1' || intent.sessionId !== plan.sessionId || intent.profile !== plan.profile || intent.operator !== options.operator || intent.reason !== options.reason || intent.disabledManifestSha256 !== disabledSha256 || (decision.manifest.enabled === true && intent.enabledManifestSha256 !== currentRead.sha256) ) { throw new ManualPrimaryCanaryError('publication_conflict'); } } else { if (decision.manifest.enabled === false) { throw new ManualPrimaryCanaryError('rollback_intent_missing'); } intent = { schema: 'qinglong/manual-primary-canary-rollback-intent@v1', schemaVersion: 1, sessionId: plan.sessionId, profile: plan.profile, createdAtMs: now, operator: options.operator, reason: options.reason, enabledManifestSha256: currentRead.sha256, disabledManifestSha256: disabledSha256, }; intentSha256 = publishNoReplace(intentPath, intent).sha256; } if (decision.manifest.enabled === true) { replaceRollout(target, currentRead.sha256, disabledBytes); } const completedPath = filePath(options.root, plan.files.rollbackComplete); let publication; if (existsRegular(completedPath)) { const completed = readPrivateJson(completedPath, 64 * 1024).value; if ( completed?.schema !== 'qinglong/manual-primary-canary-rollback-complete@v1' || completed.sessionId !== plan.sessionId || completed.profile !== plan.profile || completed.intentSha256 !== intentSha256 || completed.disabledManifestSha256 !== disabledSha256 ) { throw new ManualPrimaryCanaryError('publication_conflict'); } publication = { state: 'existing' }; } else { publication = publishNoReplace(completedPath, { schema: 'qinglong/manual-primary-canary-rollback-complete@v1', schemaVersion: 1, sessionId: plan.sessionId, profile: plan.profile, completedAtMs: now, intentSha256, disabledManifestSha256: disabledSha256, }); } return { state: 'rolled_back', publication: publication.state, sessionId: plan.sessionId, profile: plan.profile, }; } function existsRegular(target) { try { const stat = fs.lstatSync(target); return stat.isFile() && !stat.isSymbolicLink(); } catch (error) { if (error?.code === 'ENOENT') return false; throw error; } } function status(options, dependencies) { assertRoot(options.root); const { plan, read: planRead } = readPlan(options.root, options.sessionId); const present = Object.fromEntries( [ 'capture', 'terminal', 'resource', 'primaryGate', 'qualification', 'selection', 'rollbackIntent', 'rollbackComplete', ].map((name) => [ name, existsRegular(filePath(options.root, plan.files[name])), ]), ); let stage = 'prepared'; if (present.capture) stage = 'captured'; if (present.terminal) stage = 'terminal_observed'; if (present.resource) stage = 'resource_proven'; if (present.primaryGate || present.qualification) { if (!present.primaryGate || !present.qualification) { throw new ManualPrimaryCanaryError('qualification_incomplete'); } verifyQualification(options.root, plan, planRead); stage = 'qualified'; } const rolloutTarget = filePath(options.root, plan.files.rollout); let rolloutMode = 'off'; let approvalExpired = false; if (existsRegular(rolloutTarget)) { const read = readPrivateJson(rolloutTarget, 64 * 1024); const raw = read.value; const now = dependencies.clock.now(); approvalExpired = raw?.enabled === true && Number.isSafeInteger(raw.expiresAtMs) && raw.expiresAtMs <= now; const evaluatedAt = approvalExpired ? raw.approvedAtMs : now; const decision = parseRuntimeRolloutManifest(raw, evaluatedAt); if (decision.manifest.enabled && !approvalExpired) { if (decision.manifest.revision !== `manual-primary-${plan.sessionId}`) { throw new ManualPrimaryCanaryError('rollout_session_mismatch'); } rolloutMode = 'primary_selected'; stage = 'activation_approved'; } else if (approvalExpired) { stage = 'approval_expired'; } } if (present.rollbackComplete) { const disabled = createManualPrimaryCanaryDisabledManifest(plan.sessionId); const read = readPrivateJson(rolloutTarget, 64 * 1024); if (read.sha256 !== manualPrimaryCanarySha256(serialized(disabled))) { throw new ManualPrimaryCanaryError('rollback_not_effective'); } rolloutMode = 'off'; stage = 'rolled_back'; } return { state: stage, sessionId: plan.sessionId, profile: plan.profile, admissionTarget: plan.admissionTarget, rolloutMode, approvalExpired, runtimeActivationObserved: false, artifacts: present, }; } function run(options, overrides = {}) { const dependencies = { clock: overrides.clock ?? { now: () => Date.now() }, spawnSync: overrides.spawnSync, workspaceRoot: overrides.workspaceRoot ?? path.resolve(__dirname, '..'), }; switch (options.mode) { case 'prepare': return prepare(options, dependencies); case 'observe': return observe(options, dependencies); case 'resource': return resource(options, dependencies); case 'qualify': return qualify(options, dependencies); case 'approve': return approve(options, dependencies); case 'rollback': return rollback(options, dependencies); case 'status': return status(options, dependencies); default: throw new ManualPrimaryCanaryError('mode_invalid'); } } function main() { const result = run(parseArguments(process.argv.slice(2))); process.stdout.write(`${JSON.stringify(result)}\n`); } module.exports = { MAX_PRIVATE_JSON_BYTES, ManualPrimaryCanaryError, parseArguments, publishNoReplace, publishOrVerify, readPrivateJson, run, serialized, }; if (require.main === module) { try { main(); } catch (error) { const code = error instanceof ManualPrimaryCanaryError ? error.code : error instanceof Error ? error.name : 'unknown'; process.stderr.write(`${code}\n`); process.exitCode = 1; } }