Files
qinglong/scripts/ql3-local-alpha-reconciliation-decision-fixture.cjs

634 lines
19 KiB
JavaScript

#!/usr/bin/env node
'use strict';
const fs = require('node:fs');
const path = require('node:path');
const DOMAINS = Object.freeze([
'schema_lineage',
'automation',
'secret_and_config',
'run_history',
'plugin_package',
'ai_and_tool',
'identity_policy_audit',
'unknown',
]);
const DATABASES = Object.freeze(['legacy', 'target']);
const FACT_KINDS = Object.freeze(['schema_object', 'table']);
const MAX_JSON_BYTES = 4 * 1024 * 1024;
const DIGEST = /^[0-9a-f]{64}$/u;
const UUID_V4 =
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
const UUID_V7 =
/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
function fail(message) {
throw new Error(message);
}
function canonicalFile(filePath, maximumBytes, label) {
const resolved = path.resolve(filePath);
const stat = fs.lstatSync(resolved);
if (
!stat.isFile() ||
stat.isSymbolicLink() ||
stat.size < 2 ||
stat.size > maximumBytes ||
fs.realpathSync(resolved) !== resolved
) {
fail(`${label} must be one bounded canonical regular file`);
}
return resolved;
}
function readJson(filePath, label) {
const resolved = canonicalFile(filePath, MAX_JSON_BYTES, label);
try {
return JSON.parse(fs.readFileSync(resolved, 'utf8'));
} catch {
return fail(`${label} must contain valid JSON`);
}
}
function writeExclusive(filePath, records) {
const resolved = path.resolve(filePath);
const parent = path.dirname(resolved);
if (
fs.existsSync(resolved) ||
!fs.lstatSync(parent).isDirectory() ||
fs.realpathSync(parent) !== parent
) {
fail('fixture output must be a new file below one canonical directory');
}
const descriptor = fs.openSync(
resolved,
fs.constants.O_WRONLY | fs.constants.O_CREAT | fs.constants.O_EXCL,
0o600,
);
try {
fs.writeFileSync(
descriptor,
`${records.map((record) => JSON.stringify(record)).join('\n')}\n`,
);
fs.fsyncSync(descriptor);
} finally {
fs.closeSync(descriptor);
}
return resolved;
}
function fixtureRoot(value) {
const resolved = path.resolve(value || '');
if (
!path.isAbsolute(value || '') ||
!fs.lstatSync(resolved).isDirectory() ||
fs.realpathSync(resolved) !== resolved
) {
fail('reconciliation root must be one canonical directory');
}
return resolved;
}
function validateSummary(root, status) {
const summary = readJson(
path.join(root, 'summary.json'),
'reconciliation summary',
);
if (
summary?.schemaVersion !== 1 ||
summary?.schema !==
'qinglong/local-alpha-reconciliation-rehearsal-summary@v1' ||
summary?.status !== status ||
(summary?.profile !== 'edge' && summary?.profile !== 'standalone')
) {
fail(`reconciliation summary is not in ${status} state`);
}
return summary;
}
function validateFact(fact, expected) {
if (
fact?.schemaVersion !== 1 ||
fact?.schema !== 'qinglong3-local-reconciliation-diagnostic-fact' ||
fact?.database !== expected.database ||
fact?.domain !== expected.domain ||
fact?.factKind !== expected.factKind ||
!Number.isSafeInteger(fact.ordinal) ||
fact.ordinal < 1 ||
!DIGEST.test(fact.factDigest || '') ||
!['informational', 'required', 'blocked'].includes(fact.decisionRequirement)
) {
fail('diagnostic fact is incompatible with the fixture contract');
}
}
function diagnosticFacts(root, summary) {
const facts = [];
let pageCount = 0;
for (const database of DATABASES) {
for (const domain of DOMAINS) {
for (const factKind of FACT_KINDS) {
let pageNumber = 0;
let expectedOffset = 0;
while (true) {
const page = readJson(
path.join(
root,
'diagnostics',
`${database}-${domain}-${factKind}-${pageNumber}.json`,
),
'diagnostic page',
);
if (
page?.schemaVersion !== 1 ||
page?.schema !== 'qinglong3-local-reconciliation-diagnostic-page' ||
page?.state !== 'reconciliation_review_prepared' ||
page?.reviewId !== summary.review.reviewId ||
page?.planDigest !== summary.plan.planDigest ||
page?.preparationDigest !== summary.review.preparationDigest ||
page?.database !== database ||
page?.domain !== domain ||
page?.factKind !== factKind ||
page?.offset !== expectedOffset ||
page?.limit !== 64 ||
!Array.isArray(page.records) ||
page.recordCount !== page.records.length ||
!DIGEST.test(page.pageDigest || '')
) {
fail('diagnostic page is detached or malformed');
}
for (const fact of page.records) {
validateFact(fact, { database, domain, factKind });
facts.push(fact);
}
pageCount += 1;
if (page.complete === true && page.nextOffset === null) break;
if (
page.complete !== false ||
!Number.isSafeInteger(page.nextOffset) ||
page.nextOffset <= expectedOffset
) {
fail('diagnostic pagination is invalid');
}
expectedOffset = page.nextOffset;
pageNumber += 1;
}
}
}
}
if (
pageCount !== summary.review.diagnosticPages ||
facts.length !== summary.review.diagnosticRecords
) {
fail('diagnostic inventory differs from the reconciliation summary');
}
return facts;
}
function readNdjson(filePath, maximumBytes, label) {
const resolved = canonicalFile(filePath, maximumBytes, label);
try {
return fs
.readFileSync(resolved, 'utf8')
.trimEnd()
.split('\n')
.map((line) => JSON.parse(line));
} catch {
return fail(`${label} must be canonical NDJSON`);
}
}
function reviewFixture(root, output) {
const summary = validateSummary(root, 'operator_decision_required');
if (
!UUID_V4.test(summary.review?.reviewId || '') ||
!DIGEST.test(summary.plan?.planDigest || '') ||
!DIGEST.test(summary.review?.preparationDigest || '')
) {
fail('review fixture identity is invalid');
}
const facts = diagnosticFacts(root, summary);
let adoptedAutomationTables = 0;
const decisions = [];
for (const fact of facts) {
if (fact.decisionRequirement === 'informational') continue;
const automationTable =
fact.database === 'legacy' &&
fact.domain === 'automation' &&
fact.factKind === 'table' &&
fact.tableName === 'Crontabs' &&
fact.decisionRequirement === 'required';
if (automationTable) adoptedAutomationTables += 1;
const blocked = fact.decisionRequirement === 'blocked';
const legacy = fact.database === 'legacy';
const legacyRunHistory = legacy && fact.domain === 'run_history';
decisions.push({
schemaVersion: 1,
kind: 'qinglong3-local-reconciliation-review-decision',
database: fact.database,
domain: fact.domain,
factKind: fact.factKind,
ordinal: fact.ordinal,
factDigest: fact.factDigest,
disposition: automationTable
? 'adopt_legacy'
: blocked || legacyRunHistory
? 'manual_external'
: legacy
? 'exclude_legacy'
: 'retain_target',
reason: automationTable
? 'prefer_legacy'
: blocked || legacyRunHistory
? 'external_recovery_required'
: legacy
? 'legacy_excluded'
: 'preserve_target',
});
}
if (adoptedAutomationTables !== 1 || decisions.length < 1) {
fail('fixture requires exactly one reviewable Legacy Crontabs table');
}
const records = [
{
schemaVersion: 1,
kind: 'qinglong3-local-reconciliation-review-decision-header',
diagnosticsContractVersion: 1,
reviewId: summary.review.reviewId,
profile: summary.profile,
planDigest: summary.plan.planDigest,
preparationDigest: summary.review.preparationDigest,
},
...decisions,
];
const filePath = writeExclusive(output, records);
return Object.freeze({
mode: 'review',
filePath,
decisionCount: decisions.length,
adoptedAutomationTables,
});
}
function completionReviewFixture(root, output) {
const summary = validateSummary(root, 'operator_decision_required');
if (
!UUID_V4.test(summary.review?.reviewId || '') ||
!DIGEST.test(summary.plan?.planDigest || '') ||
!DIGEST.test(summary.review?.preparationDigest || '')
) {
fail('completion review fixture identity is invalid');
}
const facts = diagnosticFacts(root, summary);
let adoptedAutomationTables = 0;
let legacyRunHistoryFacts = 0;
let targetRunHistoryFacts = 0;
let secretConfigFacts = 0;
const decisions = [];
for (const fact of facts) {
if (fact.decisionRequirement === 'informational') continue;
const externallyRecoverableSecretConfig =
fact.decisionRequirement === 'blocked' &&
fact.domain === 'secret_and_config' &&
fact.reason === 'secret_custody_required';
if (
fact.decisionRequirement === 'blocked' &&
!externallyRecoverableSecretConfig
) {
fail('completion review fixture refuses blocked diagnostic facts');
}
const automationTable =
fact.database === 'legacy' &&
fact.domain === 'automation' &&
fact.factKind === 'table' &&
fact.tableName === 'Crontabs' &&
fact.decisionRequirement === 'required';
const runHistory = fact.domain === 'run_history';
const secretConfig = fact.domain === 'secret_and_config';
if (automationTable) adoptedAutomationTables += 1;
if (runHistory && fact.database === 'legacy') legacyRunHistoryFacts += 1;
if (runHistory && fact.database === 'target') targetRunHistoryFacts += 1;
if (secretConfig) secretConfigFacts += 1;
const legacy = fact.database === 'legacy';
decisions.push({
schemaVersion: 1,
kind: 'qinglong3-local-reconciliation-review-decision',
database: fact.database,
domain: fact.domain,
factKind: fact.factKind,
ordinal: fact.ordinal,
factDigest: fact.factDigest,
disposition: automationTable
? 'adopt_legacy'
: secretConfig
? 'manual_external'
: runHistory && legacy
? 'retain_both'
: legacy
? 'exclude_legacy'
: 'retain_target',
reason: automationTable
? 'prefer_legacy'
: secretConfig
? 'external_recovery_required'
: runHistory && legacy
? 'preserve_both'
: legacy
? 'legacy_excluded'
: 'preserve_target',
});
}
if (
adoptedAutomationTables !== 1 ||
legacyRunHistoryFacts < 1 ||
targetRunHistoryFacts < 1 ||
secretConfigFacts < 1
) {
fail(
'completion fixture requires Automation, Secret/Config, and dual Run History authority',
);
}
const records = [
{
schemaVersion: 1,
kind: 'qinglong3-local-reconciliation-review-decision-header',
diagnosticsContractVersion: 1,
reviewId: summary.review.reviewId,
profile: summary.profile,
planDigest: summary.plan.planDigest,
preparationDigest: summary.review.preparationDigest,
},
...decisions,
];
const filePath = writeExclusive(output, records);
return Object.freeze({
mode: 'completion-review',
filePath,
decisionCount: decisions.length,
adoptedAutomationTables,
legacyRunHistoryFacts,
targetRunHistoryFacts,
secretConfigFacts,
});
}
function automationFixture(root, output) {
const summary = validateSummary(root, 'automation_decision_required');
const automation = summary.automation;
const decision = summary.decision;
if (
!UUID_V4.test(automation?.automationId || '') ||
!UUID_V7.test(decision?.decisionId || '') ||
!DIGEST.test(automation?.automationPlanDigest || '') ||
automation.rowCount !== 1 ||
automation.eligibleCount !== 1 ||
automation.conflictCount !== 0
) {
fail('fixture requires one conflict-free eligible Automation row');
}
const directory = path.join(root, 'automation', automation.automationId);
const receipt = readJson(
path.join(directory, 'receipt.json'),
'Automation plan receipt',
);
if (
receipt?.schemaVersion !== 1 ||
receipt?.schema !==
'qinglong3-local-reconciliation-automation-plan-receipt' ||
receipt?.automationId !== automation.automationId ||
receipt?.automationPlanDigest !== automation.automationPlanDigest ||
receipt?.rowCount !== 1 ||
receipt?.eligibleCount !== 1 ||
receipt?.manualCount !== 0 ||
receipt?.conflictCount !== 0 ||
!DIGEST.test(receipt.legacyInventoryDigest || '')
) {
fail('Automation plan receipt is not fixture-eligible');
}
const planPath = canonicalFile(
path.join(directory, 'plan.ndjson'),
8 * 1024 * 1024,
'Automation row plan',
);
let records;
try {
records = fs
.readFileSync(planPath, 'utf8')
.trimEnd()
.split('\n')
.map((line) => JSON.parse(line));
} catch {
return fail('Automation row plan must be canonical NDJSON');
}
const rows = records.filter(
(record) =>
record?.kind === 'qinglong3-local-reconciliation-automation-plan-row',
);
if (
rows.length !== 1 ||
rows[0].schemaVersion !== 1 ||
rows[0].requirement !== 'review_adopt' ||
rows[0].target?.state !== 'absent' ||
!Number.isSafeInteger(rows[0].rowOrdinal) ||
rows[0].rowOrdinal < 1 ||
!DIGEST.test(rows[0].sourceDigest || '')
) {
fail('Automation row plan contains a non-lossless or conflicting row');
}
const outputRecords = [
{
schemaVersion: 1,
kind: 'qinglong3-legacy-crontab-decision-review-file-header',
decisionId: decision.decisionId,
profile: summary.profile,
planDigest: automation.automationPlanDigest,
inventoryDigest: receipt.legacyInventoryDigest,
},
{
schemaVersion: 1,
kind: 'qinglong3-legacy-crontab-decision-review-file-row',
decision: {
rowOrdinal: rows[0].rowOrdinal,
sourceDigest: rows[0].sourceDigest,
disposition: 'adopt',
reason: 'reviewed_lossless',
},
},
];
const filePath = writeExclusive(output, outputRecords);
return Object.freeze({
mode: 'automation',
filePath,
decisionCount: 1,
automationPlanDigest: automation.automationPlanDigest,
});
}
function secretConfigFixture(root, output) {
const summary = validateSummary(root, 'secret_config_decision_required');
const secretConfig = summary.secretConfig;
const decision = summary.secretConfigDecision;
if (
!UUID_V4.test(secretConfig?.secretConfigId || '') ||
!UUID_V7.test(decision?.decisionId || '') ||
!DIGEST.test(secretConfig?.secretConfigPlanDigest || '') ||
!DIGEST.test(decision?.preparationDigest || '') ||
!Number.isSafeInteger(secretConfig?.eligibleBindingCount) ||
!Number.isSafeInteger(secretConfig?.eligiblePreservationCount) ||
secretConfig.eligibleBindingCount + secretConfig.eligiblePreservationCount <
1 ||
secretConfig.targetConflictCount !== 0 ||
secretConfig.unadaptedLegacyConfigCount !== 0
) {
fail('fixture requires one ready conflict-free Secret/Config plan');
}
const directory = path.join(
root,
'secret-config',
secretConfig.secretConfigId,
);
const receipt = readJson(
path.join(directory, 'receipt.json'),
'Secret/Config plan receipt',
);
if (
receipt?.schemaVersion !== 1 ||
receipt?.schema !==
'qinglong3-local-reconciliation-secret-config-plan-receipt' ||
receipt?.state !== 'reconciliation_secret_config_planned' ||
receipt?.secretConfigId !== secretConfig.secretConfigId ||
receipt?.secretConfigPlanDigest !== secretConfig.secretConfigPlanDigest ||
receipt?.outcome !== 'ready' ||
receipt?.eligibleBindingCount !== secretConfig.eligibleBindingCount ||
receipt?.eligiblePreservationCount !==
secretConfig.eligiblePreservationCount ||
receipt?.targetConflictCount !== 0 ||
receipt?.unadaptedLegacyConfigCount !== 0
) {
fail('Secret/Config plan receipt is not fixture-eligible');
}
const records = readNdjson(
path.join(directory, 'plan.ndjson'),
8 * 1024 * 1024,
'Secret/Config row plan',
);
const candidates = records.filter(
(record) =>
record?.kind ===
'qinglong3-local-reconciliation-secret-config-plan-candidate',
);
if (
candidates.length !==
secretConfig.eligibleBindingCount + secretConfig.eligiblePreservationCount
) {
fail('Secret/Config row plan candidate count is incompatible');
}
const decisions = candidates.map((candidate) => {
if (
candidate?.schemaVersion !== 1 ||
!Number.isSafeInteger(candidate.candidateOrdinal) ||
candidate.candidateOrdinal < 1 ||
!DIGEST.test(candidate.candidateDigest || '') ||
!['review_apply_binding', 'review_preserve_disabled'].includes(
candidate.requirement,
) ||
candidate.target?.state !== 'absent'
) {
fail('Secret/Config row plan contains a conflicting candidate');
}
const active = candidate.requirement === 'review_apply_binding';
return {
schemaVersion: 1,
kind: 'qinglong3-local-reconciliation-secret-config-decision',
candidateOrdinal: candidate.candidateOrdinal,
candidateDigest: candidate.candidateDigest,
disposition: active ? 'apply_active_binding' : 'preserve_disabled',
reason: active
? 'reviewed_active_binding'
: 'reviewed_disabled_preservation',
};
});
const outputRecords = [
{
schemaVersion: 1,
kind: 'qinglong3-local-reconciliation-secret-config-decision-header',
decisionContractVersion: 1,
decisionId: decision.decisionId,
profile: summary.profile,
secretConfigPlanDigest: secretConfig.secretConfigPlanDigest,
preparationDigest: decision.preparationDigest,
},
...decisions,
];
const filePath = writeExclusive(output, outputRecords);
return Object.freeze({
mode: 'secret-config',
filePath,
decisionCount: decisions.length,
secretConfigPlanDigest: secretConfig.secretConfigPlanDigest,
});
}
function parseArguments(argv) {
const values = {};
for (const argument of argv) {
const match = /^--([a-z-]+)=(.+)$/u.exec(argument);
if (!match || Object.hasOwn(values, match[1]))
fail('arguments are invalid');
values[match[1]] = match[2];
}
if (
!['review', 'completion-review', 'automation', 'secret-config'].includes(
values.mode,
) ||
JSON.stringify(Object.keys(values).sort()) !==
JSON.stringify(['mode', 'output', 'reconciliation-root'])
) {
fail('fixture arguments are invalid');
}
return Object.freeze({
mode: values.mode,
reconciliationRoot: fixtureRoot(values['reconciliation-root']),
output: path.resolve(values.output),
});
}
function runCli(argv) {
const options = parseArguments(argv);
const fixtures = {
review: reviewFixture,
'completion-review': completionReviewFixture,
automation: automationFixture,
'secret-config': secretConfigFixture,
};
const report = fixtures[options.mode](
options.reconciliationRoot,
options.output,
);
process.stdout.write(`${JSON.stringify(report)}\n`);
return report;
}
if (require.main === module) {
try {
runCli(process.argv.slice(2));
} catch (error) {
process.stderr.write(
`${error instanceof Error ? error.message : 'decision fixture failed'}\n`,
);
process.exitCode = 1;
}
}
module.exports = Object.freeze({
automationFixture,
completionReviewFixture,
diagnosticFacts,
parseArguments,
reviewFixture,
runCli,
secretConfigFixture,
});