Files
qinglong/packages/ql3-local-owner-cli/test/reconciliationCapturePrepare.test.cjs
T

2447 lines
77 KiB
JavaScript

const assert = require('node:assert/strict');
const crypto = require('node:crypto');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');
const { spawnSync } = require('node:child_process');
const { DatabaseSync } = require('node:sqlite');
const { test } = require('node:test');
const {
commitLocalReconciliationCapture,
commitLocalReconciliationPlan,
commitLocalReconciliationReview,
prepareLocalReconciliationCapture,
prepareLocalReconciliationPlan,
prepareLocalReconciliationReview,
verifyLocalReconciliationCapture,
verifyLocalReconciliationPlan,
verifyLocalReconciliationReview,
writeLocalReconciliationReviewDiagnostics,
} = require('../dist/deployment/localDeployment.js');
const {
normalizeLocalReconciliationCaptureManifest,
} = require('../dist/deployment/reconciliation/bundle.js');
const {
createLocalDataDirectoryApplicationCommit,
} = require('@qinglong/local-sqlite/data-directory-application-commit');
const {
advanceLocalCutoverInstanceHead,
claimLocalCutoverInstance,
readLocalCutoverInstanceHead,
} = require('../dist/deployment/cutover/instanceLineage.js');
const {
readTargetDataReconciliationEvidenceForPaths,
} = require('../dist/deployment/cutover/targetDataEvidence.js');
const {
targetRunJournalRecord,
targetStopPhasePath,
targetStopSequence,
} = require('../dist/deployment/cutover/target-run/targetRunJournal.js');
const {
targetStoppedEvidence,
} = require('../dist/deployment/cutover/targetStopRecordEvidence.js');
function digest(value) {
return crypto
.createHash('sha256')
.update(JSON.stringify(value), 'utf8')
.digest('hex');
}
function rootAcknowledgement() {
return typeof process.getuid === 'function' && process.getuid() === 0;
}
const CAPTURE_ASSET_NAMES = Object.freeze({
'target-main': 'target.sqlite',
'target-wal': 'target.sqlite-wal',
'target-shm': 'target.sqlite-shm',
'target-journal': 'target.sqlite-journal',
'legacy-main': 'legacy.sqlite',
'legacy-wal': 'legacy.sqlite-wal',
'legacy-shm': 'legacy.sqlite-shm',
'legacy-journal': 'legacy.sqlite-journal',
'recovery-main': 'recovery.sqlite',
});
function removeFixtureRoot(root) {
if (!fs.existsSync(root)) return;
const unlock = (candidate) => {
const stat = fs.lstatSync(candidate);
if (stat.isDirectory() && !stat.isSymbolicLink()) {
fs.chmodSync(candidate, 0o700);
for (const name of fs.readdirSync(candidate)) {
unlock(path.join(candidate, name));
}
} else if (!stat.isSymbolicLink()) {
fs.chmodSync(candidate, 0o600);
}
};
unlock(root);
fs.rmSync(root, { recursive: true, force: true });
}
function fixture(
t,
{
reconciliationRequired = true,
stoppedAuthority = 'docker',
profile = 'edge',
createDefaultSidecars = true,
initializeDatabases,
mutateTarget,
} = {},
) {
const root = fs.realpathSync(
fs.mkdtempSync(path.join(os.tmpdir(), 'ql3-reconciliation-capture-')),
);
fs.chmodSync(root, 0o700);
t.after(() => removeFixtureRoot(root));
const deploymentRoot = path.join(root, 'runtime');
const serviceRoot = path.join(deploymentRoot, 'service');
const cutoverId = 'capture-cutover-1';
const journal = path.join(serviceRoot, 'cutovers', cutoverId);
const instanceRoot = path.join(serviceRoot, 'cutover-instances');
const captureRoot = path.join(root, 'capture-root');
for (const directory of [
deploymentRoot,
serviceRoot,
path.dirname(journal),
journal,
instanceRoot,
captureRoot,
]) {
if (!fs.existsSync(directory)) fs.mkdirSync(directory, { mode: 0o700 });
}
const legacySourcePath = path.join(root, 'database.sqlite');
const targetDatabasePath = path.join(root, 'database.ql3.sqlite');
const recoveryPath = path.join(root, 'database.recovery.sqlite');
const manifestPath = path.join(root, 'adoption-manifest.json');
const activationPath = path.join(root, 'activation.json');
const applicationConfigPath = path.join(
deploymentRoot,
'local-application.json',
);
if (initializeDatabases === undefined) {
fs.writeFileSync(legacySourcePath, 'legacy-source\n', { mode: 0o600 });
fs.writeFileSync(targetDatabasePath, 'target-initial\n', { mode: 0o600 });
fs.writeFileSync(recoveryPath, 'legacy-source\n', { mode: 0o600 });
} else {
initializeDatabases({
legacySourcePath,
recoveryPath,
targetDatabasePath,
});
}
const manifestPayload = {
schemaVersion: 1,
kind: 'qinglong3-local-sqlite-adoption-manifest-fixture',
};
const manifestDigest = digest(manifestPayload);
fs.writeFileSync(
manifestPath,
`${JSON.stringify({ ...manifestPayload, manifestDigest })}\n`,
{ mode: 0o600 },
);
const targetStat = fs.statSync(targetDatabasePath, { bigint: true });
const activationPayload = {
schemaVersion: 1,
kind: 'qinglong3-local-sqlite-activation',
state: 'prepared',
profile,
createdAtMs: 1_000,
adoptionManifestDigest: manifestDigest,
planDigest: '2'.repeat(64),
sourcePathDigest: crypto
.createHash('sha256')
.update(legacySourcePath, 'utf8')
.digest('hex'),
sourceSha256: crypto
.createHash('sha256')
.update(fs.readFileSync(legacySourcePath))
.digest('hex'),
recoverySha256: crypto
.createHash('sha256')
.update(fs.readFileSync(recoveryPath))
.digest('hex'),
targetSha256: crypto
.createHash('sha256')
.update(fs.readFileSync(targetDatabasePath))
.digest('hex'),
targetPathDigest: crypto
.createHash('sha256')
.update(targetDatabasePath, 'utf8')
.digest('hex'),
targetDevice: targetStat.dev.toString(),
targetInode: targetStat.ino.toString(),
};
const activationDigest = digest(activationPayload);
fs.writeFileSync(
activationPath,
`${JSON.stringify({ ...activationPayload, activationDigest })}\n`,
{ mode: 0o600 },
);
let mutationEvidence = Object.freeze({});
if (reconciliationRequired) {
mutationEvidence =
mutateTarget?.({ root, targetDatabasePath }) ?? Object.freeze({});
if (mutateTarget === undefined) {
fs.writeFileSync(targetDatabasePath, 'target-mutated\n', {
mode: 0o600,
});
}
if (createDefaultSidecars) {
fs.writeFileSync(`${targetDatabasePath}-wal`, 'target-wal-facts\n', {
mode: 0o600,
});
fs.writeFileSync(
`${legacySourcePath}-journal`,
'legacy-journal-state\n',
{
mode: 0o600,
},
);
}
}
const commitmentPayload = {
schemaVersion: 1,
kind: 'qinglong3-local-legacy-silence-commitment',
state: 'legacy_stopped',
cutoverId,
profile,
instanceId: 'edge-router-1',
activationDigest,
requestedAtMs: 1_100,
observedAtMs: 1_200,
previousRecordDigest: '1'.repeat(64),
controller: {
kind: 'docker',
endpointDigest: '2'.repeat(64),
legacyContainerId: '3'.repeat(64),
legacyContainerIdentityDigest: '4'.repeat(64),
legacySourceBindingDigest: '5'.repeat(64),
},
};
const commitmentDigest = digest(commitmentPayload);
const commitmentPath = path.join(journal, '0002-legacy-stopped.json');
fs.writeFileSync(
commitmentPath,
`${JSON.stringify({ ...commitmentPayload, commitmentDigest })}\n`,
{ mode: 0o600 },
);
const dataCommit = createLocalDataDirectoryApplicationCommit({
mutationId: '00000000-0000-4000-8000-000000000301',
projectId: 'project-edge-router-1',
profile,
sourceStageManifestDigest: '6'.repeat(64),
transformationDigest: '7'.repeat(64),
modelDigest: '8'.repeat(64),
publicationDigest: '9'.repeat(64),
receiptDigest: 'a'.repeat(64),
committedAtMs: 1_300,
receipt: {
secretCount: 0,
environmentSecretCount: 0,
sshSecretCount: 0,
},
});
const dataCommitPath = path.join(root, 'legacy-data-commit.json');
fs.writeFileSync(dataCommitPath, `${JSON.stringify(dataCommit)}\n`, {
mode: 0o600,
});
const application = {
schema: 'qinglong/local-application-process@v4',
instanceId: 'edge-router-1',
profile,
storage: {
mode: 'adopted',
sourcePath: legacySourcePath,
targetPath: targetDatabasePath,
recoveryPath,
manifestPath,
activationPath,
expectedActivationDigest: activationDigest,
},
runtime: {
receiptRoot: path.join(deploymentRoot, 'receipts'),
artifactRoot: path.join(deploymentRoot, 'artifacts'),
secretKeyringPath: path.join(deploymentRoot, 'local-secret-keyring.json'),
},
pluginPackages: {
stagingRoot: path.join(deploymentRoot, 'plugin-staging'),
activationRoot: path.join(deploymentRoot, 'plugin-activation'),
recoverySource: { mode: 'disabled' },
pageSize: 4,
maxPages: 4,
taskPublicationPageSize: 4,
taskPublicationMaxPages: 4,
},
ai: { deployment: 'excluded' },
cutover: {
cutoverId,
commitmentPath,
expectedCommitmentDigest: commitmentDigest,
},
legacyDataApplication: {
commitPath: dataCommitPath,
expectedCommitDigest: dataCommit.commitDigest,
expectedReceiptDigest: dataCommit.receiptDigest,
},
};
const applicationContents = `${JSON.stringify(application, null, 2)}\n`;
fs.writeFileSync(applicationConfigPath, applicationContents, { mode: 0o600 });
const adoptedBundlePayload = {
schemaVersion: 1,
kind: 'qinglong3-local-adopted-deployment-bundle',
state: 'prepared',
bundleId: '00000000-0000-4000-8000-000000000d88',
preparedAtMs: 1_400,
profile,
instanceId: 'edge-router-1',
cutoverId,
serviceKind: 'compose',
deploymentRootDigest: crypto
.createHash('sha256')
.update(deploymentRoot, 'utf8')
.digest('hex'),
sourcePathDigest: crypto
.createHash('sha256')
.update(legacySourcePath, 'utf8')
.digest('hex'),
applicationConfigDigest: crypto
.createHash('sha256')
.update(applicationContents, 'utf8')
.digest('hex'),
serviceDescriptorDigest: 'b'.repeat(64),
composeSelectionDigest: 'c'.repeat(64),
activationDigest,
commitmentDigest,
legacyDataApplicationCommitDigest: dataCommit.commitDigest,
legacyDataApplicationReceiptDigest: dataCommit.receiptDigest,
manifestDigest,
sourceSha256: activationPayload.sourceSha256,
recoverySha256: activationPayload.recoverySha256,
targetIdentityDigest: 'd'.repeat(64),
};
fs.writeFileSync(
path.join(serviceRoot, 'adopted-bundle.json'),
`${JSON.stringify({
...adoptedBundlePayload,
bundleDigest: digest(adoptedBundlePayload),
})}\n`,
{ mode: 0o600 },
);
const identity = {
options: { deploymentRoot },
request: {
cutoverId,
profile,
instanceId: 'edge-router-1',
expectedActivationDigest: activationDigest,
requestedAtMs: 2_000,
},
};
const uid = typeof process.getuid === 'function' ? process.getuid() : 0;
claimLocalCutoverInstance(identity, uid, '3'.repeat(64));
advanceLocalCutoverInstanceHead(
identity,
uid,
'legacy_stopped',
0,
'4'.repeat(64),
);
advanceLocalCutoverInstanceHead(
identity,
uid,
'target_active',
1,
'5'.repeat(64),
);
const reconciliation = readTargetDataReconciliationEvidenceForPaths(
{
profile,
activationPath,
legacySourcePath,
targetDatabasePath,
expectedActivationDigest: activationDigest,
},
uid,
);
const runCommand = {
request: {
cutoverId,
profile,
instanceId: 'edge-router-1',
expectedActivationDigest: activationDigest,
generation: 1,
requestedAtMs: 3_000,
},
};
let stoppedRecord;
if (stoppedAuthority === 'docker') {
stoppedRecord = targetRunJournalRecord(
runCommand,
targetStopSequence(1, 'outcome'),
'target_stopped',
'6'.repeat(64),
targetStoppedEvidence(
{
activeRecordDigest: '5'.repeat(64),
targetContainerIdentityDigest:
mutationEvidence.targetContainerIdentityDigest ?? '7'.repeat(64),
targetApplicationBindingDigest: '8'.repeat(64),
startupReceiptDigest: '9'.repeat(64),
},
reconciliation,
),
);
fs.writeFileSync(
targetStopPhasePath(journal, 1, 'outcome'),
`${JSON.stringify(stoppedRecord)}\n`,
{ mode: 0o600 },
);
} else {
const evidence = {
managerOutcomeDigest: '6'.repeat(64),
managerObservationDigest: '7'.repeat(64),
applicationConfigDigest: '8'.repeat(64),
activationDigest,
commitmentDigest: '9'.repeat(64),
targetDataIdentityDigest: 'a'.repeat(64),
startupReceiptDigest: 'b'.repeat(64),
shutdownReceiptDigest: 'c'.repeat(64),
processIdentityDigest: 'd'.repeat(64),
manualReason: null,
};
const payload = {
schema: 'qinglong3-local-service-manager-cutover-record',
schemaVersion: 1,
actionId: '00000000-0000-4000-8000-000000000201',
action: 'stop',
state: 'target_stopped',
cutoverId,
profile,
instanceId: 'edge-router-1',
activationDigest,
generation: 1,
previousRecordDigest: '5'.repeat(64),
intentDigest: 'e'.repeat(64),
requestedAtMs: 2_500,
completedAtMs: 3_000,
evidence,
};
stoppedRecord = { ...payload, recordDigest: digest(payload) };
fs.writeFileSync(
path.join(journal, 'service-manager-g01-stopped.json'),
`${JSON.stringify(stoppedRecord)}\n`,
{ mode: 0o600 },
);
}
const stoppedHead = advanceLocalCutoverInstanceHead(
identity,
uid,
'target_stopped',
1,
stoppedRecord.recordDigest,
);
const command = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.capture.prepare',
options: {
deploymentRoot,
captureRoot,
allowRootService: rootAcknowledgement(),
},
request: {
captureId: '00000000-0000-4000-8000-000000000101',
stoppedAuthority,
profile,
instanceId: 'edge-router-1',
cutoverId,
generation: 1,
applicationConfigPath,
activationPath,
legacySourcePath,
targetDatabasePath,
recoveryPath,
expectedActivationDigest: activationDigest,
expectedHeadDigest: stoppedHead.headDigest,
expectedStoppedRecordDigest: stoppedRecord.recordDigest,
preparedAtMs: 4_000,
},
};
return {
command,
activation: Object.freeze({ ...activationPayload, activationDigest }),
deploymentRoot,
captureRoot,
identity,
stoppedHead,
uid,
legacySourcePath,
targetDatabasePath,
recoveryPath,
};
}
test('capture prepare establishes one replayable reconciliation fence', (t) => {
const state = fixture(t);
const prepared = prepareLocalReconciliationCapture(state.command);
assert.equal(prepared.status, 'prepared');
assert.equal(prepared.state, 'reconciliation_capture_prepared');
assert.equal(
fs.existsSync(
path.join(
state.captureRoot,
state.command.request.captureId,
'intent.json',
),
),
true,
);
const head = readLocalCutoverInstanceHead(
state.deploymentRoot,
state.command.request.instanceId,
state.uid,
);
assert.equal(head.state, 'reconciliation_capture_prepared');
assert.equal(head.sourceRecordDigest, prepared.preparationDigest);
const replay = prepareLocalReconciliationCapture(state.command);
assert.equal(replay.status, 'existing');
assert.equal(replay.instanceHeadDigest, prepared.instanceHeadDigest);
assert.throws(
() =>
advanceLocalCutoverInstanceHead(
state.identity,
state.uid,
'rollback_prepared',
1,
'a'.repeat(64),
),
/transition is invalid/,
);
const conflicting = structuredClone(state.command);
conflicting.request.captureId = '00000000-0000-4000-8000-000000000102';
assert.throws(
() => prepareLocalReconciliationCapture(conflicting),
/another capture owns/,
);
});
test('capture prepare rejects rollback-candidate stopped data', (t) => {
const state = fixture(t, { reconciliationRequired: false });
assert.throws(
() => prepareLocalReconciliationCapture(state.command),
/reconciliation-required evidence/,
);
const head = readLocalCutoverInstanceHead(
state.deploymentRoot,
state.command.request.instanceId,
state.uid,
);
assert.equal(head.headDigest, state.stoppedHead.headDigest);
assert.equal(
fs.existsSync(
path.join(
state.captureRoot,
state.command.request.captureId,
'intent.json',
),
),
false,
);
});
test('service-manager stopped authority uses the same capture fence', (t) => {
const state = fixture(t, { stoppedAuthority: 'service-manager' });
const prepared = prepareLocalReconciliationCapture(state.command);
assert.equal(prepared.status, 'prepared');
assert.equal(prepared.state, 'reconciliation_capture_prepared');
const replay = prepareLocalReconciliationCapture(state.command);
assert.equal(replay.status, 'existing');
assert.equal(replay.preparationDigest, prepared.preparationDigest);
});
test('capture prepare CLI consumes a private command and emits no paths', (t) => {
const state = fixture(t);
const commandPath = path.join(state.deploymentRoot, 'capture-command.json');
fs.writeFileSync(commandPath, `${JSON.stringify(state.command)}\n`, {
mode: 0o600,
});
const result = spawnSync(
process.execPath,
[
path.join(__dirname, '../dist/deployment/localDeploymentCli.js'),
'reconciliation-capture-prepare',
'--command-file',
commandPath,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
const output = JSON.parse(result.stdout);
assert.equal(output.state, 'reconciliation_capture_prepared');
assert.equal(output.captureId, state.command.request.captureId);
assert.equal(result.stdout.includes(state.captureRoot), false);
assert.equal(
result.stdout.includes(state.command.request.targetDatabasePath),
false,
);
assert.equal(result.stderr, '');
});
function preparedCapture(t, options) {
const state = fixture(t, options);
const prepared = prepareLocalReconciliationCapture(state.command);
const commitCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.capture.commit',
options: state.command.options,
request: {
captureId: state.command.request.captureId,
expectedPreparationDigest: prepared.preparationDigest,
committedAtMs: 5_000,
},
};
return { ...state, prepared, commitCommand };
}
function planningDatabaseInitializer({ unknownTargetTable = false } = {}) {
return ({ legacySourcePath, recoveryPath, targetDatabasePath }) => {
const legacy = new DatabaseSync(legacySourcePath);
legacy.exec(`
CREATE TABLE "Crontabs" (id INTEGER PRIMARY KEY, schedule TEXT NOT NULL);
CREATE TABLE "Envs" (id INTEGER PRIMARY KEY, name TEXT NOT NULL, value TEXT NOT NULL);
INSERT INTO "Crontabs" (id, schedule) VALUES (1, '0 0 * * *');
INSERT INTO "Envs" (id, name, value) VALUES (1, 'TOKEN', 'private-value');
`);
legacy.close();
fs.chmodSync(legacySourcePath, 0o600);
fs.copyFileSync(legacySourcePath, recoveryPath);
fs.chmodSync(recoveryPath, 0o600);
const target = new DatabaseSync(targetDatabasePath);
target.exec(`
CREATE TABLE "QingLong3SchemaCapabilities" (id INTEGER PRIMARY KEY);
CREATE TABLE "QingLong3TaskDefinitions" (id INTEGER PRIMARY KEY);
CREATE TABLE "Runs" (id INTEGER PRIMARY KEY);
${
unknownTargetTable
? 'CREATE TABLE "UnreviewedFacts" (id INTEGER PRIMARY KEY); INSERT INTO "UnreviewedFacts" (id) VALUES (1);'
: ''
}
`);
target.close();
fs.chmodSync(targetDatabasePath, 0o600);
};
}
function mutatePlanningTarget({ targetDatabasePath }) {
const target = new DatabaseSync(targetDatabasePath);
target.exec('INSERT INTO "QingLong3TaskDefinitions" (id) VALUES (1)');
target.close();
return Object.freeze({});
}
function preparedPlan(t, options = {}) {
const state = preparedCapture(t, {
createDefaultSidecars: options.createDefaultSidecars ?? false,
initializeDatabases:
options.initializeDatabases ?? planningDatabaseInitializer(options),
mutateTarget: options.mutateTarget ?? mutatePlanningTarget,
profile: options.profile ?? 'edge',
});
const captured = commitLocalReconciliationCapture(state.commitCommand);
const planRoot = path.join(path.dirname(state.captureRoot), 'plan-root');
fs.mkdirSync(planRoot, { mode: 0o700 });
const prepareCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.plan.prepare',
options: {
deploymentRoot: state.deploymentRoot,
captureRoot: state.captureRoot,
planRoot,
allowRootService: rootAcknowledgement(),
},
request: {
planId: options.planId ?? '00000000-0000-4000-8000-000000000201',
captureId: state.command.request.captureId,
expectedBundleDigest: captured.bundleDigest,
expectedHeadDigest: captured.instanceHeadDigest,
legacyTimezone: options.legacyTimezone ?? null,
preparedAtMs: 6_000,
},
};
const planPrepared = prepareLocalReconciliationPlan(prepareCommand);
const planCommitCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.plan.commit',
options: prepareCommand.options,
request: {
planId: prepareCommand.request.planId,
expectedPreparationDigest: planPrepared.preparationDigest,
committedAtMs: 7_000,
},
};
return {
...state,
captureCommand: state.command,
captured,
planRoot,
prepareCommand,
planPrepared,
planCommitCommand,
};
}
function preparedReview(t, options = {}) {
const state = preparedPlan(t, options);
const planned = commitLocalReconciliationPlan(state.planCommitCommand);
const root = path.dirname(state.captureRoot);
const reviewRoot = path.join(
root,
`review-root-${options.reviewSuffix ?? '1'}`,
);
const diagnosticRoot = path.join(
root,
`diagnostic-root-${options.reviewSuffix ?? '1'}`,
);
fs.mkdirSync(reviewRoot, { mode: 0o700 });
fs.mkdirSync(diagnosticRoot, { mode: 0o700 });
const reviewCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.review.prepare',
options: {
deploymentRoot: state.deploymentRoot,
captureRoot: state.captureRoot,
planRoot: state.planRoot,
reviewRoot,
allowRootService: rootAcknowledgement(),
},
request: {
reviewId: options.reviewId ?? '00000000-0000-4000-8000-000000000301',
planId: state.prepareCommand.request.planId,
expectedPlanDigest: planned.planDigest,
expectedHeadDigest: planned.instanceHeadDigest,
preparedAtMs: 8_000,
},
};
return {
...state,
planned,
reviewRoot,
diagnosticRoot,
reviewCommand,
};
}
function diagnosticCommand(
state,
prepared,
{
database = 'legacy',
domain = 'automation',
factKind = 'table',
offset = 0,
limit = 64,
outputName = 'diagnostic-page.json',
} = {},
) {
return {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.review.diagnostics',
options: state.reviewCommand.options,
request: {
reviewId: state.reviewCommand.request.reviewId,
expectedPreparationDigest: prepared.preparationDigest,
database,
domain,
factKind,
offset,
limit,
outputPath: path.join(state.diagnosticRoot, outputName),
},
};
}
function writeReviewDecisionFile(state, prepared, fileName = 'review.ndjson') {
const decisions = [];
const domains = [
'schema_lineage',
'automation',
'secret_and_config',
'run_history',
'plugin_package',
'ai_and_tool',
'identity_policy_audit',
'unknown',
];
for (const database of ['legacy', 'target']) {
for (const domain of domains) {
for (const factKind of ['schema_object', 'table']) {
let offset = 0;
let pageNumber = 0;
while (true) {
const command = diagnosticCommand(state, prepared, {
database,
domain,
factKind,
offset,
outputName: `decision-${database}-${domain}-${factKind}-${pageNumber}.json`,
});
const result = writeLocalReconciliationReviewDiagnostics(command);
const page = JSON.parse(
fs.readFileSync(command.request.outputPath, 'utf8'),
);
for (const fact of page.records) {
if (fact.decisionRequirement === 'informational') continue;
const blocked = fact.decisionRequirement === 'blocked';
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: blocked ? 'manual_external' : 'retain_target',
reason: blocked
? 'external_recovery_required'
: 'preserve_target',
});
}
if (result.complete) break;
offset = result.nextOffset;
pageNumber += 1;
}
}
}
}
const records = [
{
schemaVersion: 1,
kind: 'qinglong3-local-reconciliation-review-decision-header',
diagnosticsContractVersion: 1,
reviewId: state.reviewCommand.request.reviewId,
profile: state.command.request.profile,
planDigest: state.planned.planDigest,
preparationDigest: prepared.preparationDigest,
},
...decisions,
];
const filePath = path.join(state.diagnosticRoot, fileName);
fs.writeFileSync(
filePath,
`${records.map((record) => JSON.stringify(record)).join('\n')}\n`,
{ mode: 0o600 },
);
return { filePath, records, decisions };
}
function reviewCommitFixture(t, options = {}) {
const state = preparedReview(t, options);
const prepared = prepareLocalReconciliationReview(state.reviewCommand);
const reviewFile = writeReviewDecisionFile(state, prepared);
const ownerPepperKeyringDirectory = path.join(
state.deploymentRoot,
'review-owner-peppers',
);
fs.mkdirSync(ownerPepperKeyringDirectory, { mode: 0o700 });
const credentialFilePath = path.join(
state.deploymentRoot,
'review-credential.json',
);
fs.writeFileSync(credentialFilePath, '{}\n', { mode: 0o600 });
const issuerKeyringPath = path.join(
state.deploymentRoot,
'review-issuer.keyring',
);
const committedAtMs = Date.now();
const command = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.review.commit',
options: {
...state.reviewCommand.options,
targetDatabasePath: state.targetDatabasePath,
ownerPepperKeyringDirectory,
credentialFilePath,
issuerKeyringPath,
},
request: {
reviewId: state.reviewCommand.request.reviewId,
expectedPreparationDigest: prepared.preparationDigest,
expectedHeadDigest: prepared.instanceHeadDigest,
decisionFilePath: reviewFile.filePath,
committedAtMs,
authorizationLifetimeMs: 30 * 60 * 1_000,
},
};
let authentications = 0;
let confirmations = 0;
const dependencies = {
now: () => committedAtMs,
async openAuthenticationDatabase() {
return { async close() {} };
},
async authenticate(_database, authenticateOptions) {
authentications += 1;
assert.equal(
authenticateOptions.authenticationNamespace,
'local_reconciliation_review',
);
return {
principal: {
subject: { type: 'user', id: 'review-owner' },
authenticationId: 'local_reconciliation_review:test',
authenticatedAtMs: committedAtMs,
expiresAtMs: committedAtMs + 60_000,
assurance: 'local_console',
},
databaseFence: {
credentialId: 'review-owner',
credentialVersion: 1,
pepperKeyId: 'review-owner-v1',
pepperVersion: 1,
},
async confirm() {
confirmations += 1;
},
};
},
};
return {
...state,
prepared,
reviewFile,
command,
dependencies,
issuerKeyringPath,
authenticationCount: () => authentications,
confirmationCount: () => confirmations,
};
}
function dockerReadSealedSqlite(assetsDirectory, mode) {
const source =
mode === 'main_only_immutable'
? 'file:/bundle/target.sqlite?immutable=1'
: '/bundle/target.sqlite';
const script = `
const crypto = require('node:crypto');
const fs = require('node:fs');
const { DatabaseSync } = require('node:sqlite');
const files = fs.readdirSync('/bundle').sort();
const snapshot = () => Object.fromEntries(files.map((name) => [name, crypto.createHash('sha256').update(fs.readFileSync('/bundle/' + name)).digest('hex')]));
const before = snapshot();
const client = new DatabaseSync(${JSON.stringify(
source,
)}, { allowExtension: false, defensive: true, readOnly: true, timeout: 0 });
client.enableDefensive(true);
client.exec('PRAGMA trusted_schema = OFF; PRAGMA query_only = ON; PRAGMA temp_store = MEMORY; PRAGMA mmap_size = 0; PRAGMA cache_size = -2048');
const row = client.prepare('SELECT COUNT(*) AS count FROM "QingLong3TaskDefinitions"').get();
client.close();
const after = snapshot();
process.stdout.write(JSON.stringify({ count: row.count, unchanged: JSON.stringify(before) === JSON.stringify(after) }));
`;
const result = spawnSync(
'docker',
[
'run',
'--rm',
'--mount',
`type=bind,source=${assetsDirectory},target=/bundle,readonly`,
'node:24-bookworm-slim',
'node',
'-e',
script,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
return JSON.parse(result.stdout);
}
function capturePath(state, name) {
return path.join(state.captureRoot, state.command.request.captureId, name);
}
function captureAssetPath(state, logicalName) {
return capturePath(state, `assets/${CAPTURE_ASSET_NAMES[logicalName]}`);
}
function captureAssetStagePath(state, logicalName) {
return capturePath(
state,
`assets/.${CAPTURE_ASSET_NAMES[logicalName]}.ql3-capture-stage`,
);
}
test('commit captures main, sidecars and recovery then verifies without sources', (t) => {
const state = preparedCapture(t);
fs.writeFileSync(`${state.targetDatabasePath}.unrelated`, 'ignored\n', {
mode: 0o600,
});
const committed = commitLocalReconciliationCapture(state.commitCommand);
assert.equal(committed.status, 'prepared');
assert.equal(committed.state, 'reconciliation_captured');
assert.equal(committed.assetCount, 5);
const manifest = JSON.parse(
fs.readFileSync(capturePath(state, 'manifest.json'), 'utf8'),
);
assert.equal(manifest.schemaVersion, 2);
assert.equal(manifest.legacyBaselineSha256, state.activation.sourceSha256);
assert.equal(manifest.targetBaselineSha256, state.activation.targetSha256);
assert.deepEqual(
manifest.assets.map((asset) => asset.logicalName),
[
'target-main',
'target-wal',
'legacy-main',
'legacy-journal',
'recovery-main',
],
);
const manifestText = fs.readFileSync(
capturePath(state, 'manifest.json'),
'utf8',
);
assert.equal(manifestText.includes(state.captureRoot), false);
assert.equal(manifestText.includes(state.targetDatabasePath), false);
assert.equal(manifestText.includes(state.legacySourcePath), false);
assert.equal(
fs.readFileSync(captureAssetPath(state, 'target-main'), 'utf8'),
'target-mutated\n',
);
assert.equal(
fs.readFileSync(captureAssetPath(state, 'target-wal'), 'utf8'),
'target-wal-facts\n',
);
assert.equal(fs.statSync(capturePath(state, 'assets')).mode & 0o777, 0o500);
for (const asset of manifest.assets) {
assert.equal(
fs.statSync(captureAssetPath(state, asset.logicalName)).mode & 0o777,
0o400,
);
}
const head = readLocalCutoverInstanceHead(
state.deploymentRoot,
state.command.request.instanceId,
state.uid,
);
assert.equal(head.state, 'reconciliation_captured');
assert.equal(head.sourceRecordDigest, committed.bundleDigest);
const verifyCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.capture.verify',
options: state.command.options,
request: {
captureId: state.command.request.captureId,
expectedBundleDigest: committed.bundleDigest,
},
};
assert.equal(
verifyLocalReconciliationCapture(verifyCommand).status,
'verified',
);
fs.unlinkSync(state.targetDatabasePath);
fs.unlinkSync(state.legacySourcePath);
fs.unlinkSync(state.recoveryPath);
assert.equal(
verifyLocalReconciliationCapture(verifyCommand).bundleDigest,
committed.bundleDigest,
);
assert.equal(
commitLocalReconciliationCapture(state.commitCommand).status,
'existing',
);
const driftedCommit = structuredClone(state.commitCommand);
driftedCommit.request.committedAtMs += 1;
assert.throws(
() => commitLocalReconciliationCapture(driftedCommit),
/instance head binding/,
);
});
test('commit resumes after an asset publication crash without replacement', (t) => {
const state = preparedCapture(t);
let failed = false;
assert.throws(
() =>
commitLocalReconciliationCapture(state.commitCommand, {
afterAssetPublished(logicalName) {
if (!failed && logicalName === 'target-main') {
failed = true;
throw new Error('asset crash');
}
},
}),
/asset crash/,
);
const targetAsset = captureAssetPath(state, 'target-main');
const before = fs.statSync(targetAsset, { bigint: true });
assert.equal(fs.existsSync(capturePath(state, 'manifest.json')), false);
const committed = commitLocalReconciliationCapture(state.commitCommand);
const after = fs.statSync(targetAsset, { bigint: true });
assert.equal(after.ino, before.ino);
assert.equal(committed.status, 'prepared');
});
test('commit resumes after manifest and receipt crash windows', (t) => {
const manifestState = preparedCapture(t);
assert.throws(
() =>
commitLocalReconciliationCapture(manifestState.commitCommand, {
afterManifestPublished() {
throw new Error('manifest crash');
},
}),
/manifest crash/,
);
assert.equal(
fs.existsSync(capturePath(manifestState, 'manifest.json')),
true,
);
assert.equal(
fs.existsSync(capturePath(manifestState, 'receipt.json')),
false,
);
fs.unlinkSync(manifestState.targetDatabasePath);
fs.unlinkSync(manifestState.legacySourcePath);
fs.unlinkSync(manifestState.recoveryPath);
assert.equal(
commitLocalReconciliationCapture(manifestState.commitCommand).state,
'reconciliation_captured',
);
const receiptState = preparedCapture(t, {
stoppedAuthority: 'service-manager',
});
assert.throws(
() =>
commitLocalReconciliationCapture(receiptState.commitCommand, {
afterReceiptPublished() {
throw new Error('receipt crash');
},
}),
/receipt crash/,
);
const preparedHead = readLocalCutoverInstanceHead(
receiptState.deploymentRoot,
receiptState.command.request.instanceId,
receiptState.uid,
);
assert.equal(preparedHead.state, 'reconciliation_capture_prepared');
fs.unlinkSync(receiptState.targetDatabasePath);
fs.unlinkSync(receiptState.legacySourcePath);
fs.unlinkSync(receiptState.recoveryPath);
const resumed = commitLocalReconciliationCapture(receiptState.commitCommand);
assert.equal(resumed.status, 'prepared');
assert.equal(resumed.state, 'reconciliation_captured');
});
test('commit converges a partially sealed terminal bundle without sources', (t) => {
const state = preparedCapture(t);
let failed = false;
assert.throws(
() =>
commitLocalReconciliationCapture(state.commitCommand, {
afterAssetSealed(logicalName) {
if (!failed && logicalName === 'target-main') {
failed = true;
throw new Error('seal crash');
}
},
}),
/seal crash/,
);
assert.equal(fs.existsSync(capturePath(state, 'receipt.json')), true);
assert.equal(
fs.statSync(captureAssetPath(state, 'target-main')).mode & 0o777,
0o400,
);
assert.equal(
fs.statSync(captureAssetPath(state, 'target-wal')).mode & 0o777,
0o600,
);
assert.equal(fs.statSync(capturePath(state, 'assets')).mode & 0o777, 0o700);
fs.unlinkSync(state.targetDatabasePath);
fs.unlinkSync(state.legacySourcePath);
fs.unlinkSync(state.recoveryPath);
const resumed = commitLocalReconciliationCapture(state.commitCommand);
assert.equal(resumed.state, 'reconciliation_captured');
assert.equal(fs.statSync(capturePath(state, 'assets')).mode & 0o777, 0o500);
const manifest = JSON.parse(
fs.readFileSync(capturePath(state, 'manifest.json'), 'utf8'),
);
for (const asset of manifest.assets) {
assert.equal(
fs.statSync(captureAssetPath(state, asset.logicalName)).mode & 0o777,
0o400,
);
}
});
test('hard-link publication replay removes only the exact retained stage', (t) => {
const state = preparedCapture(t);
const cleanupError = Object.assign(new Error('stage cleanup unavailable'), {
code: 'EIO',
});
assert.throws(
() =>
commitLocalReconciliationCapture(state.commitCommand, {
stableCopy: {
unlink() {
throw cleanupError;
},
},
}),
/capture asset cannot be published/,
);
const target = captureAssetPath(state, 'target-main');
const stage = captureAssetStagePath(state, 'target-main');
const targetBefore = fs.statSync(target, { bigint: true });
const stageBefore = fs.statSync(stage, { bigint: true });
assert.equal(targetBefore.ino, stageBefore.ino);
assert.equal(targetBefore.nlink, 2n);
const committed = commitLocalReconciliationCapture(state.commitCommand);
assert.equal(committed.state, 'reconciliation_captured');
assert.equal(fs.existsSync(stage), false);
assert.equal(fs.statSync(target, { bigint: true }).ino, targetBefore.ino);
});
test('ENOSPC cleans a new stage and exact replay completes', (t) => {
const state = preparedCapture(t);
const noSpace = Object.assign(new Error('no space'), { code: 'ENOSPC' });
assert.throws(
() =>
commitLocalReconciliationCapture(state.commitCommand, {
stableCopy: {
write() {
throw noSpace;
},
},
}),
/capture asset cannot be published/,
);
const assetsRoot = capturePath(state, 'assets');
assert.deepEqual(fs.readdirSync(assetsRoot), []);
const head = readLocalCutoverInstanceHead(
state.deploymentRoot,
state.command.request.instanceId,
state.uid,
);
assert.equal(head.state, 'reconciliation_capture_prepared');
assert.equal(
commitLocalReconciliationCapture(state.commitCommand).state,
'reconciliation_captured',
);
});
test('a cleanup-resistant partial stage resumes only from its exact prefix', (t) => {
const state = preparedCapture(t);
let writes = 0;
assert.throws(
() =>
commitLocalReconciliationCapture(state.commitCommand, {
stableCopy: {
write(descriptor, buffer, offset, length, position) {
writes += 1;
if (writes === 1) {
return fs.writeSync(
descriptor,
buffer,
offset,
Math.min(4, length),
position,
);
}
throw Object.assign(new Error('no space'), { code: 'ENOSPC' });
},
unlink() {
throw Object.assign(new Error('cleanup unavailable'), {
code: 'EIO',
});
},
},
}),
/capture asset cannot be published/,
);
const stage = captureAssetStagePath(state, 'target-main');
assert.equal(fs.statSync(stage).size, 4);
assert.equal(
fs
.readFileSync(stage)
.equals(fs.readFileSync(state.targetDatabasePath).subarray(0, 4)),
true,
);
assert.equal(
commitLocalReconciliationCapture(state.commitCommand).state,
'reconciliation_captured',
);
assert.equal(fs.existsSync(stage), false);
});
test('sidecar set drift prevents manifest publication and remains replayable', (t) => {
const state = preparedCapture(t);
let changed = false;
const unexpectedSidecar = `${state.targetDatabasePath}-shm`;
assert.throws(
() =>
commitLocalReconciliationCapture(state.commitCommand, {
afterAssetPublished() {
if (!changed) {
changed = true;
fs.writeFileSync(unexpectedSidecar, 'late-sidecar\n', {
mode: 0o600,
});
}
},
}),
/sidecar set changed/,
);
assert.equal(fs.existsSync(capturePath(state, 'manifest.json')), false);
fs.unlinkSync(unexpectedSidecar);
assert.equal(
commitLocalReconciliationCapture(state.commitCommand).state,
'reconciliation_captured',
);
});
test('terminal verify rejects asset drift and CLI output remains content-free', (t) => {
const state = preparedCapture(t);
const committed = commitLocalReconciliationCapture(state.commitCommand);
const verifyCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.capture.verify',
options: state.command.options,
request: {
captureId: state.command.request.captureId,
expectedBundleDigest: committed.bundleDigest,
},
};
const verifyPath = path.join(state.deploymentRoot, 'verify-command.json');
fs.writeFileSync(verifyPath, `${JSON.stringify(verifyCommand)}\n`, {
mode: 0o600,
});
const result = spawnSync(
process.execPath,
[
path.join(__dirname, '../dist/deployment/localDeploymentCli.js'),
'reconciliation-capture-verify',
'--command-file',
verifyPath,
],
{ encoding: 'utf8' },
);
assert.equal(result.status, 0, result.stderr);
assert.equal(result.stdout.includes(state.captureRoot), false);
assert.equal(result.stdout.includes(state.targetDatabasePath), false);
const targetAsset = captureAssetPath(state, 'target-main');
fs.chmodSync(targetAsset, 0o600);
fs.writeFileSync(targetAsset, 'drift\n');
fs.chmodSync(targetAsset, 0o400);
assert.throws(
() => verifyLocalReconciliationCapture(verifyCommand),
/asset drifted/,
);
});
test('capture manifest schema v1 is rejected instead of silently upgraded', (t) => {
const state = preparedCapture(t);
commitLocalReconciliationCapture(state.commitCommand);
const manifest = JSON.parse(
fs.readFileSync(capturePath(state, 'manifest.json'), 'utf8'),
);
manifest.schemaVersion = 1;
assert.throws(
() => normalizeLocalReconciliationCaptureManifest(manifest),
/reconciliation capture manifest (?:drifted|schemaVersion must be 2)/,
);
});
test('plan reads sealed main-only SQLite with fixed budgets and verifies without opening', (t) => {
const state = preparedPlan(t);
const beforeAssets = fs
.readdirSync(capturePath(state, 'assets'))
.map((name) => ({
name,
bytes: fs.readFileSync(capturePath(state, `assets/${name}`)),
stat: fs.statSync(capturePath(state, `assets/${name}`), { bigint: true }),
}));
const opens = [];
const committed = commitLocalReconciliationPlan(state.planCommitCommand, {
beforeDatabaseOpen(kind, mode, cacheKiB) {
opens.push({ kind, mode, cacheKiB });
},
});
assert.equal(committed.status, 'prepared');
assert.equal(committed.state, 'reconciliation_planned');
assert.deepEqual(opens, [
{ kind: 'legacy', mode: 'main_only_immutable', cacheKiB: 2048 },
{ kind: 'target', mode: 'main_only_immutable', cacheKiB: 2048 },
]);
const planPath = path.join(
state.planRoot,
state.prepareCommand.request.planId,
'plan.json',
);
const planText = fs.readFileSync(planPath, 'utf8');
const plan = JSON.parse(planText);
assert.equal(Buffer.byteLength(planText, 'utf8') <= 64 * 1024, true);
assert.deepEqual(
plan.domains.map((domain) => domain.domain),
[
'schema_lineage',
'automation',
'secret_and_config',
'run_history',
'plugin_package',
'ai_and_tool',
'identity_policy_audit',
'unknown',
],
);
assert.equal(plan.domains.length, 8);
assert.equal(plan.outcome, 'manual_required');
assert.equal(planText.includes('private-value'), false);
assert.equal(planText.includes(state.captureRoot), false);
assert.equal(planText.includes(state.legacySourcePath), false);
assert.equal(planText.includes('Crontabs'), false);
const head = readLocalCutoverInstanceHead(
state.deploymentRoot,
state.command.request.instanceId,
state.uid,
);
assert.equal(head.state, 'reconciliation_planned');
assert.equal(head.sourceRecordDigest, committed.planDigest);
const verifyCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.plan.verify',
options: state.prepareCommand.options,
request: {
planId: state.prepareCommand.request.planId,
expectedPlanDigest: committed.planDigest,
},
};
let verifyOpens = 0;
assert.equal(
verifyLocalReconciliationPlan(verifyCommand, {
beforeDatabaseOpen() {
verifyOpens += 1;
},
}).status,
'verified',
);
assert.equal(verifyOpens, 0);
for (const before of beforeAssets) {
const assetPath = capturePath(state, `assets/${before.name}`);
const after = fs.statSync(assetPath, { bigint: true });
assert.equal(fs.readFileSync(assetPath).equals(before.bytes), true);
for (const key of [
'dev',
'ino',
'uid',
'gid',
'mode',
'nlink',
'size',
'mtimeNs',
'ctimeNs',
]) {
assert.equal(after[key], before.stat[key]);
}
}
});
test('plan reads a sealed WAL and SHM snapshot without changing either asset', (t) => {
let target;
const initializeDatabases = (paths) => {
planningDatabaseInitializer()(paths);
target = new DatabaseSync(paths.targetDatabasePath);
target.exec('PRAGMA journal_mode = WAL; PRAGMA wal_autocheckpoint = 0');
};
const mutateTarget = ({ targetDatabasePath }) => {
target.exec('INSERT INTO "QingLong3TaskDefinitions" (id) VALUES (1)');
fs.chmodSync(`${targetDatabasePath}-wal`, 0o600);
fs.chmodSync(`${targetDatabasePath}-shm`, 0o600);
return Object.freeze({});
};
t.after(() => {
try {
target?.close();
} catch {
// The fixture cleanup may already have invalidated the source handle.
}
});
const state = preparedPlan(t, {
initializeDatabases,
mutateTarget,
planId: '00000000-0000-4000-8000-000000000205',
});
const targetWal = captureAssetPath(state, 'target-wal');
const targetShm = captureAssetPath(state, 'target-shm');
const before = [targetWal, targetShm].map((assetPath) => ({
assetPath,
bytes: fs.readFileSync(assetPath),
stat: fs.statSync(assetPath, { bigint: true }),
}));
const opens = [];
commitLocalReconciliationPlan(state.planCommitCommand, {
beforeDatabaseOpen(kind, mode, cacheKiB) {
opens.push({ kind, mode, cacheKiB });
},
});
assert.deepEqual(opens, [
{ kind: 'legacy', mode: 'main_only_immutable', cacheKiB: 2048 },
{ kind: 'target', mode: 'wal_shm_readonly', cacheKiB: 2048 },
]);
for (const item of before) {
const after = fs.statSync(item.assetPath, { bigint: true });
assert.equal(fs.readFileSync(item.assetPath).equals(item.bytes), true);
assert.equal(after.mtimeNs, item.stat.mtimeNs);
assert.equal(after.ctimeNs, item.stat.ctimeNs);
assert.equal(after.mode, item.stat.mode);
}
});
test('standalone planning fixes each SQLite cache at 8 MiB', (t) => {
const state = preparedPlan(t, {
profile: 'standalone',
planId: '00000000-0000-4000-8000-000000000206',
});
const opens = [];
commitLocalReconciliationPlan(state.planCommitCommand, {
beforeDatabaseOpen(kind, mode, cacheKiB) {
opens.push({ kind, mode, cacheKiB });
},
});
assert.deepEqual(opens, [
{ kind: 'legacy', mode: 'main_only_immutable', cacheKiB: 8192 },
{ kind: 'target', mode: 'main_only_immutable', cacheKiB: 8192 },
]);
});
test('plan commit converges plan, receipt and head crash windows exactly', (t) => {
const planState = preparedPlan(t, {
planId: '00000000-0000-4000-8000-000000000211',
});
assert.throws(
() =>
commitLocalReconciliationPlan(planState.planCommitCommand, {
afterPlanPublished() {
throw new Error('plan crash');
},
}),
/plan crash/,
);
let replayOpens = 0;
const resumedPlan = commitLocalReconciliationPlan(
planState.planCommitCommand,
{
beforeDatabaseOpen() {
replayOpens += 1;
},
},
);
assert.equal(resumedPlan.status, 'prepared');
assert.equal(replayOpens, 0);
const receiptState = preparedPlan(t, {
planId: '00000000-0000-4000-8000-000000000212',
});
assert.throws(
() =>
commitLocalReconciliationPlan(receiptState.planCommitCommand, {
afterReceiptPublished() {
throw new Error('receipt crash');
},
}),
/receipt crash/,
);
replayOpens = 0;
assert.equal(
commitLocalReconciliationPlan(receiptState.planCommitCommand, {
beforeDatabaseOpen() {
replayOpens += 1;
},
}).status,
'prepared',
);
assert.equal(replayOpens, 0);
const headState = preparedPlan(t, {
planId: '00000000-0000-4000-8000-000000000213',
});
assert.throws(
() =>
commitLocalReconciliationPlan(headState.planCommitCommand, {
afterHeadAdvanced() {
throw new Error('head response loss');
},
}),
/head response loss/,
);
assert.equal(
commitLocalReconciliationPlan(headState.planCommitCommand).status,
'existing',
);
});
test('hot journal and unpaired sidecars become manual without SQLite open', (t) => {
const state = preparedPlan(t, {
createDefaultSidecars: true,
planId: '00000000-0000-4000-8000-000000000221',
});
let opens = 0;
const committed = commitLocalReconciliationPlan(state.planCommitCommand, {
beforeDatabaseOpen() {
opens += 1;
},
});
assert.equal(opens, 0);
assert.equal(committed.outcome, 'manual_required');
const plan = JSON.parse(
fs.readFileSync(
path.join(
state.planRoot,
state.prepareCommand.request.planId,
'plan.json',
),
'utf8',
),
);
assert.deepEqual(
plan.databases.map((database) => ({
kind: database.kind,
topology: database.topology,
opened: database.opened,
})),
[
{ kind: 'legacy', topology: 'manual_required', opened: false },
{ kind: 'target', topology: 'manual_required', opened: false },
],
);
assert.equal(
plan.domains.every((domain) => domain.disposition === 'manual_required'),
true,
);
});
test('unknown target schema is summarized only by digest and requires manual review', (t) => {
const state = preparedPlan(t, {
unknownTargetTable: true,
planId: '00000000-0000-4000-8000-000000000231',
});
commitLocalReconciliationPlan(state.planCommitCommand);
const planText = fs.readFileSync(
path.join(state.planRoot, state.prepareCommand.request.planId, 'plan.json'),
'utf8',
);
const plan = JSON.parse(planText);
const unknown = plan.domains.find((domain) => domain.domain === 'unknown');
assert.equal(unknown.targetTables, 1);
assert.equal(unknown.rowCountsComplete, false);
assert.equal(unknown.disposition, 'manual_required');
assert.equal(plan.outcome, 'manual_required');
assert.equal(planText.includes('UnreviewedFacts'), false);
});
test('one plan fence blocks a second plan and all rollback transitions', (t) => {
const state = preparedPlan(t, {
planId: '00000000-0000-4000-8000-000000000241',
});
const competing = structuredClone(state.prepareCommand);
competing.request.planId = '00000000-0000-4000-8000-000000000242';
assert.throws(
() => prepareLocalReconciliationPlan(competing),
/compare-and-swap/,
);
assert.throws(
() =>
advanceLocalCutoverInstanceHead(
state.identity,
state.uid,
'rollback_prepared',
1,
'f'.repeat(64),
),
/transition is invalid/,
);
assert.throws(
() =>
advanceLocalCutoverInstanceHead(
state.identity,
state.uid,
'target_active',
2,
'e'.repeat(64),
),
/transition is invalid/,
);
});
test('plan prepare recovers head response loss and CLI verify stays content-free', (t) => {
const capture = preparedCapture(t, {
createDefaultSidecars: false,
initializeDatabases: planningDatabaseInitializer(),
mutateTarget: mutatePlanningTarget,
});
const captured = commitLocalReconciliationCapture(capture.commitCommand);
const planRoot = path.join(path.dirname(capture.captureRoot), 'plan-root');
fs.mkdirSync(planRoot, { mode: 0o700 });
const prepareCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.plan.prepare',
options: {
deploymentRoot: capture.deploymentRoot,
captureRoot: capture.captureRoot,
planRoot,
allowRootService: rootAcknowledgement(),
},
request: {
planId: '00000000-0000-4000-8000-000000000251',
captureId: capture.command.request.captureId,
expectedBundleDigest: captured.bundleDigest,
expectedHeadDigest: captured.instanceHeadDigest,
legacyTimezone: null,
preparedAtMs: 6_000,
},
};
assert.throws(
() =>
prepareLocalReconciliationPlan(prepareCommand, {
afterHeadPrepared() {
throw new Error('prepare response loss');
},
}),
/prepare response loss/,
);
const prepared = prepareLocalReconciliationPlan(prepareCommand);
assert.equal(prepared.status, 'prepared');
const committed = commitLocalReconciliationPlan({
schemaVersion: 1,
operation: 'local.deployment.reconciliation.plan.commit',
options: prepareCommand.options,
request: {
planId: prepareCommand.request.planId,
expectedPreparationDigest: prepared.preparationDigest,
committedAtMs: 7_000,
},
});
const verifyCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.plan.verify',
options: prepareCommand.options,
request: {
planId: prepareCommand.request.planId,
expectedPlanDigest: committed.planDigest,
},
};
const commandPath = path.join(capture.deploymentRoot, 'plan-verify.json');
fs.writeFileSync(commandPath, `${JSON.stringify(verifyCommand)}\n`, {
mode: 0o600,
});
const cli = spawnSync(
process.execPath,
[
path.join(__dirname, '../dist/deployment/localDeploymentCli.js'),
'reconciliation-plan-verify',
'--command-file',
commandPath,
],
{ encoding: 'utf8' },
);
assert.equal(cli.status, 0, cli.stderr);
assert.equal(JSON.parse(cli.stdout).status, 'verified');
assert.equal(cli.stdout.includes(capture.captureRoot), false);
assert.equal(cli.stdout.includes(planRoot), false);
assert.equal(cli.stdout.includes(capture.targetDatabasePath), false);
const overlapping = structuredClone(prepareCommand);
overlapping.request.planId = '00000000-0000-4000-8000-000000000252';
overlapping.options.planRoot = capture.captureRoot;
assert.throws(
() => prepareLocalReconciliationPlan(overlapping),
/must not overlap/,
);
});
test('review prepare establishes one replayable fence and blocks rollback', (t) => {
const state = preparedReview(t, {
planId: '00000000-0000-4000-8000-000000000301',
reviewId: '00000000-0000-4000-8000-000000000311',
});
assert.throws(
() =>
prepareLocalReconciliationReview(state.reviewCommand, {
afterHeadPrepared() {
throw new Error('review prepare response loss');
},
}),
/review prepare response loss/,
);
const prepared = prepareLocalReconciliationReview(state.reviewCommand);
assert.equal(prepared.status, 'prepared');
assert.equal(prepared.state, 'reconciliation_review_prepared');
const replay = prepareLocalReconciliationReview(state.reviewCommand);
assert.equal(replay.status, 'existing');
assert.equal(replay.preparationDigest, prepared.preparationDigest);
assert.equal(replay.instanceHeadDigest, prepared.instanceHeadDigest);
const head = readLocalCutoverInstanceHead(
state.deploymentRoot,
state.command.request.instanceId,
state.uid,
);
assert.equal(head.state, 'reconciliation_review_prepared');
assert.equal(head.sourceRecordDigest, prepared.preparationDigest);
const competing = structuredClone(state.reviewCommand);
competing.request.reviewId = '00000000-0000-4000-8000-000000000312';
competing.options.reviewRoot = path.join(
path.dirname(state.reviewRoot),
'review-root-competing',
);
fs.mkdirSync(competing.options.reviewRoot, { mode: 0o700 });
assert.throws(
() => prepareLocalReconciliationReview(competing),
/compare-and-swap/,
);
assert.throws(
() =>
advanceLocalCutoverInstanceHead(
state.identity,
state.uid,
'rollback_prepared',
1,
'f'.repeat(64),
),
/transition is invalid/,
);
assert.throws(
() =>
advanceLocalCutoverInstanceHead(
state.identity,
state.uid,
'target_active',
2,
'e'.repeat(64),
),
/transition is invalid/,
);
});
test('review diagnostics publish one private exact page without changing assets', (t) => {
const state = preparedReview(t, {
planId: '00000000-0000-4000-8000-000000000321',
reviewId: '00000000-0000-4000-8000-000000000322',
});
const prepared = prepareLocalReconciliationReview(state.reviewCommand);
const assets = fs.readdirSync(capturePath(state, 'assets')).map((name) => ({
name,
bytes: fs.readFileSync(capturePath(state, `assets/${name}`)),
stat: fs.statSync(capturePath(state, `assets/${name}`), { bigint: true }),
}));
const command = diagnosticCommand(state, prepared);
const opens = [];
const result = writeLocalReconciliationReviewDiagnostics(command, {
beforeDatabaseOpen(kind, mode, cacheKiB) {
opens.push({ kind, mode, cacheKiB });
},
});
assert.deepEqual(opens, [
{ kind: 'legacy', mode: 'main_only_immutable', cacheKiB: 2048 },
]);
assert.equal(result.status, 'prepared');
assert.equal(result.recordCount, 1);
assert.equal(result.complete, true);
assert.equal(result.nextOffset, null);
assert.equal(
JSON.stringify(result).includes(command.request.outputPath),
false,
);
assert.equal(JSON.stringify(result).includes('Crontabs'), false);
const pageText = fs.readFileSync(command.request.outputPath, 'utf8');
const page = JSON.parse(pageText);
assert.equal(page.records[0].name, 'Crontabs');
assert.equal(page.records[0].rowCount, '1');
assert.equal(page.records[0].decisionRequirement, 'required');
assert.equal(pageText.includes('0 0 * * *'), false);
assert.equal(pageText.includes('private-value'), false);
assert.equal(fs.statSync(command.request.outputPath).mode & 0o777, 0o600);
assert.equal(
writeLocalReconciliationReviewDiagnostics(command).status,
'existing',
);
for (const before of assets) {
const assetPath = capturePath(state, `assets/${before.name}`);
const after = fs.statSync(assetPath, { bigint: true });
assert.equal(fs.readFileSync(assetPath).equals(before.bytes), true);
assert.equal(after.mtimeNs, before.stat.mtimeNs);
assert.equal(after.ctimeNs, before.stat.ctimeNs);
assert.equal(after.mode, before.stat.mode);
}
});
test('review diagnostics keep secret and unknown facts blocked and row-free', (t) => {
const state = preparedReview(t, {
unknownTargetTable: true,
planId: '00000000-0000-4000-8000-000000000331',
reviewId: '00000000-0000-4000-8000-000000000332',
});
const prepared = prepareLocalReconciliationReview(state.reviewCommand);
const secretCommand = diagnosticCommand(state, prepared, {
domain: 'secret_and_config',
outputName: 'secret.json',
});
writeLocalReconciliationReviewDiagnostics(secretCommand);
const secretText = fs.readFileSync(secretCommand.request.outputPath, 'utf8');
const secret = JSON.parse(secretText);
assert.equal(secret.records[0].name, 'Envs');
assert.equal(secret.records[0].decisionRequirement, 'blocked');
assert.equal(secret.records[0].reason, 'secret_custody_required');
assert.equal(secretText.includes('TOKEN'), false);
assert.equal(secretText.includes('private-value'), false);
const unknownCommand = diagnosticCommand(state, prepared, {
database: 'target',
domain: 'unknown',
outputName: 'unknown.json',
});
writeLocalReconciliationReviewDiagnostics(unknownCommand);
const unknown = JSON.parse(
fs.readFileSync(unknownCommand.request.outputPath, 'utf8'),
);
assert.equal(unknown.records[0].name, 'UnreviewedFacts');
assert.equal(unknown.records[0].rowCount, null);
assert.equal(unknown.records[0].decisionRequirement, 'blocked');
assert.equal(unknown.records[0].reason, 'unknown_schema');
const overlapping = structuredClone(unknownCommand);
overlapping.request.outputPath = path.join(state.reviewRoot, 'leak.json');
assert.throws(
() => writeLocalReconciliationReviewDiagnostics(overlapping),
/outside authority roots/,
);
});
test('review diagnostics page at sixty-four and CLI output stays content-free', (t) => {
const initializeDatabases = (paths) => {
planningDatabaseInitializer()(paths);
const target = new DatabaseSync(paths.targetDatabasePath);
for (let index = 0; index < 70; index += 1) {
target.exec(
`CREATE TABLE "QingLong3TaskDefinitionExtra${String(index).padStart(
2,
'0',
)}" (id INTEGER PRIMARY KEY)`,
);
}
target.close();
fs.chmodSync(paths.targetDatabasePath, 0o600);
};
const state = preparedReview(t, {
initializeDatabases,
planId: '00000000-0000-4000-8000-000000000341',
reviewId: '00000000-0000-4000-8000-000000000342',
});
const prepared = prepareLocalReconciliationReview(state.reviewCommand);
const firstCommand = diagnosticCommand(state, prepared, {
database: 'target',
domain: 'automation',
factKind: 'schema_object',
outputName: 'page-1.json',
});
const first = writeLocalReconciliationReviewDiagnostics(firstCommand);
assert.equal(first.recordCount, 64);
assert.equal(first.complete, false);
assert.equal(first.nextOffset, 64);
const secondCommand = diagnosticCommand(state, prepared, {
database: 'target',
domain: 'automation',
factKind: 'schema_object',
offset: first.nextOffset,
outputName: 'page-2.json',
});
const second = writeLocalReconciliationReviewDiagnostics(secondCommand);
assert.equal(second.recordCount, 7);
assert.equal(second.complete, true);
assert.equal(second.nextOffset, null);
const cliCommand = diagnosticCommand(state, prepared, {
database: 'target',
domain: 'automation',
factKind: 'table',
limit: 1,
outputName: 'cli-page.json',
});
const commandPath = path.join(state.deploymentRoot, 'review-diagnostic.json');
fs.writeFileSync(commandPath, `${JSON.stringify(cliCommand)}\n`, {
mode: 0o600,
});
const cli = spawnSync(
process.execPath,
[
path.join(__dirname, '../dist/deployment/localDeploymentCli.js'),
'reconciliation-review-diagnostics',
'--command-file',
commandPath,
],
{ encoding: 'utf8' },
);
assert.equal(cli.status, 0, cli.stderr);
const output = JSON.parse(cli.stdout);
assert.equal(output.recordCount, 1);
assert.equal(cli.stdout.includes(state.reviewRoot), false);
assert.equal(cli.stdout.includes(state.diagnosticRoot), false);
assert.equal(cli.stdout.includes('QingLong3TaskDefinitions'), false);
assert.equal(cli.stderr, '');
});
test('review commit signs the exact decision stream, seals terminal evidence and verifies read-only', async (t) => {
const state = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000351',
reviewId: '00000000-0000-4000-8000-000000000352',
});
const targetBefore = fs.statSync(state.targetDatabasePath, { bigint: true });
const targetBytes = fs.readFileSync(state.targetDatabasePath);
const committed = await commitLocalReconciliationReview(
state.command,
state.dependencies,
);
assert.equal(committed.status, 'prepared');
assert.equal(committed.state, 'reconciliation_reviewed');
assert.equal(committed.decisionCount, state.reviewFile.decisions.length);
assert.equal(state.authenticationCount(), 1);
assert.equal(state.confirmationCount(), 3);
const reviewDirectory = path.join(
state.reviewRoot,
state.reviewCommand.request.reviewId,
);
assert.deepEqual(fs.readdirSync(reviewDirectory).sort(), [
'authorization.ndjson',
'intent.json',
'receipt.json',
'review.json',
'staging',
]);
assert.equal(fs.statSync(reviewDirectory).mode & 0o777, 0o500);
assert.equal(
fs.statSync(path.join(reviewDirectory, 'staging')).mode & 0o777,
0o500,
);
for (const fileName of [
'authorization.ndjson',
'intent.json',
'receipt.json',
'review.json',
]) {
assert.equal(
fs.statSync(path.join(reviewDirectory, fileName)).mode & 0o777,
0o400,
);
}
const authorizationText = fs.readFileSync(
path.join(reviewDirectory, 'authorization.ndjson'),
'utf8',
);
assert.equal(authorizationText.includes('Crontabs'), false);
assert.equal(authorizationText.includes('private-value'), false);
assert.equal(authorizationText.includes('0 0 * * *'), false);
const head = readLocalCutoverInstanceHead(
state.deploymentRoot,
state.captureCommand.request.instanceId,
state.uid,
);
assert.equal(head.state, 'reconciliation_reviewed');
assert.equal(head.sourceRecordDigest, committed.reviewDigest);
const verifyCommand = {
schemaVersion: 1,
operation: 'local.deployment.reconciliation.review.verify',
options: {
...state.reviewCommand.options,
issuerKeyringPath: state.issuerKeyringPath,
},
request: {
reviewId: state.reviewCommand.request.reviewId,
expectedReviewDigest: committed.reviewDigest,
},
};
const verified = await verifyLocalReconciliationReview(verifyCommand);
assert.equal(verified.status, 'verified');
assert.equal(verified.reviewDigest, committed.reviewDigest);
const targetAfter = fs.statSync(state.targetDatabasePath, { bigint: true });
assert.equal(
fs.readFileSync(state.targetDatabasePath).equals(targetBytes),
true,
);
assert.equal(targetAfter.mtimeNs, targetBefore.mtimeNs);
assert.equal(targetAfter.ctimeNs, targetBefore.ctimeNs);
const commandPath = path.join(state.deploymentRoot, 'review-verify.json');
fs.writeFileSync(commandPath, `${JSON.stringify(verifyCommand)}\n`, {
mode: 0o600,
});
const cli = spawnSync(
process.execPath,
[
path.join(__dirname, '../dist/deployment/localDeploymentCli.js'),
'reconciliation-review-verify',
'--command-file',
commandPath,
],
{ encoding: 'utf8' },
);
assert.equal(cli.status, 0, cli.stderr);
assert.equal(JSON.parse(cli.stdout).status, 'verified');
assert.equal(cli.stdout.includes(state.reviewRoot), false);
assert.equal(cli.stdout.includes('review-owner'), false);
assert.equal(cli.stdout.includes('Crontabs'), false);
});
test('review commit rejects missing and policy-invalid decisions before terminal publication', async (t) => {
const missing = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000361',
reviewId: '00000000-0000-4000-8000-000000000362',
reviewSuffix: 'missing',
});
const missingRecords = missing.reviewFile.records.slice(0, -1);
fs.writeFileSync(
missing.reviewFile.filePath,
`${missingRecords.map((record) => JSON.stringify(record)).join('\n')}\n`,
{ mode: 0o600 },
);
await assert.rejects(
commitLocalReconciliationReview(missing.command, missing.dependencies),
/omitted a canonical fact/,
);
assert.equal(
fs.existsSync(
path.join(
missing.reviewRoot,
missing.reviewCommand.request.reviewId,
'authorization.ndjson',
),
),
false,
);
const blocked = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000363',
reviewId: '00000000-0000-4000-8000-000000000364',
reviewSuffix: 'blocked',
});
const blockedRecord = blocked.reviewFile.records.find(
(record) =>
record.kind === 'qinglong3-local-reconciliation-review-decision' &&
[
'secret_and_config',
'run_history',
'identity_policy_audit',
'unknown',
].includes(record.domain),
);
blockedRecord.disposition = 'adopt_legacy';
blockedRecord.reason = 'prefer_legacy';
fs.writeFileSync(
blocked.reviewFile.filePath,
`${blocked.reviewFile.records
.map((record) => JSON.stringify(record))
.join('\n')}\n`,
{ mode: 0o600 },
);
await assert.rejects(
commitLocalReconciliationReview(blocked.command, blocked.dependencies),
/not allowed for canonical fact/,
);
});
test('review commit rejects weak principals, oversized Edge streams and decision-file drift around signing', async (t) => {
const weak = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000365',
reviewId: '00000000-0000-4000-8000-000000000366',
reviewSuffix: 'weak',
});
await assert.rejects(
commitLocalReconciliationReview(weak.command, {
...weak.dependencies,
async authenticate() {
return {
principal: {
subject: { type: 'user', id: 'weak-user' },
authenticationId: 'local_reconciliation_review:weak',
authenticatedAtMs: weak.command.request.committedAtMs,
expiresAtMs: weak.command.request.committedAtMs + 60_000,
assurance: 'single_factor',
},
databaseFence: {},
async confirm() {},
};
},
}),
/recent strongly authenticated User/,
);
const oversized = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000367',
reviewId: '00000000-0000-4000-8000-000000000368',
reviewSuffix: 'oversized',
});
fs.truncateSync(oversized.reviewFile.filePath, 8 * 1024 * 1024 + 1);
await assert.rejects(
commitLocalReconciliationReview(oversized.command, oversized.dependencies),
/identity or size is invalid/,
);
const drift = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000369',
reviewId: '00000000-0000-4000-8000-00000000036a',
reviewSuffix: 'drift',
});
let confirmations = 0;
await assert.rejects(
commitLocalReconciliationReview(drift.command, {
...drift.dependencies,
async authenticate() {
return {
principal: {
subject: { type: 'user', id: 'review-owner' },
authenticationId: 'local_reconciliation_review:drift',
authenticatedAtMs: drift.command.request.committedAtMs,
expiresAtMs: drift.command.request.committedAtMs + 60_000,
assurance: 'hardware',
},
databaseFence: {},
async confirm() {
confirmations += 1;
if (confirmations === 3) {
fs.appendFileSync(drift.reviewFile.filePath, '{}\n');
}
},
};
},
}),
/identity changed after reading/,
);
});
test('review commit resumes authorization, receipt, seal and head response-loss windows without re-authentication', async (t) => {
const authorizationState = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000371',
reviewId: '00000000-0000-4000-8000-000000000372',
reviewSuffix: 'authorization-crash',
});
await assert.rejects(
commitLocalReconciliationReview(authorizationState.command, {
...authorizationState.dependencies,
afterAuthorizationPublished() {
throw new Error('authorization crash');
},
}),
/authorization crash/,
);
const authorizationDirectory = path.join(
authorizationState.reviewRoot,
authorizationState.reviewCommand.request.reviewId,
);
fs.linkSync(
path.join(authorizationDirectory, 'authorization.ndjson'),
path.join(authorizationDirectory, 'staging', 'authorization.ndjson.stage'),
);
const authorizationReplay = await commitLocalReconciliationReview(
authorizationState.command,
{
...authorizationState.dependencies,
async authenticate() {
throw new Error('must not re-authenticate signed response-loss replay');
},
},
);
assert.equal(authorizationReplay.state, 'reconciliation_reviewed');
const receiptState = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000373',
reviewId: '00000000-0000-4000-8000-000000000374',
reviewSuffix: 'receipt-crash',
});
await assert.rejects(
commitLocalReconciliationReview(receiptState.command, {
...receiptState.dependencies,
afterReceiptPublished() {
throw new Error('receipt crash');
},
}),
/receipt crash/,
);
const receiptReplay = await commitLocalReconciliationReview(
receiptState.command,
receiptState.dependencies,
);
assert.equal(receiptReplay.state, 'reconciliation_reviewed');
const sealState = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000375',
reviewId: '00000000-0000-4000-8000-000000000376',
reviewSuffix: 'seal-crash',
});
await assert.rejects(
commitLocalReconciliationReview(sealState.command, {
...sealState.dependencies,
afterTerminalSealed() {
throw new Error('seal crash');
},
}),
/seal crash/,
);
assert.equal(
fs.statSync(
path.join(sealState.reviewRoot, sealState.reviewCommand.request.reviewId),
).mode & 0o777,
0o500,
);
const sealReplay = await commitLocalReconciliationReview(
sealState.command,
sealState.dependencies,
);
assert.equal(sealReplay.state, 'reconciliation_reviewed');
const headState = reviewCommitFixture(t, {
planId: '00000000-0000-4000-8000-000000000377',
reviewId: '00000000-0000-4000-8000-000000000378',
reviewSuffix: 'head-crash',
});
await assert.rejects(
commitLocalReconciliationReview(headState.command, {
...headState.dependencies,
afterHeadAdvanced() {
throw new Error('head response loss');
},
}),
/head response loss/,
);
const headReplay = await commitLocalReconciliationReview(
headState.command,
headState.dependencies,
);
assert.equal(headReplay.status, 'existing');
});
test(
'real stopped Docker target produces an independently verified bundle',
{ skip: process.env.QL3_RECONCILIATION_DOCKER_GATE !== '1' },
(t) => {
const containerName = `ql3-reconciliation-${process.pid}-${Date.now()}`;
t.after(() => {
spawnSync('docker', ['rm', '--force', containerName], {
encoding: 'utf8',
});
});
const state = preparedCapture(t, {
createDefaultSidecars: false,
initializeDatabases: planningDatabaseInitializer(),
mutateTarget({ root }) {
const created = spawnSync(
'docker',
[
'create',
'--name',
containerName,
'--mount',
`type=bind,source=${root},target=/capture-fixture`,
'node:24-bookworm-slim',
'node',
'-e',
"const { DatabaseSync } = require('node:sqlite'); const db = new DatabaseSync('/capture-fixture/database.ql3.sqlite'); db.exec('INSERT INTO \\\"QingLong3TaskDefinitions\\\" (id) VALUES (1)'); db.close()",
],
{ encoding: 'utf8' },
);
assert.equal(created.status, 0, created.stderr);
const containerId = created.stdout.trim();
assert.match(containerId, /^[0-9a-f]{64}$/);
const started = spawnSync(
'docker',
['start', '--attach', containerName],
{
encoding: 'utf8',
},
);
assert.equal(started.status, 0, started.stderr);
const inspected = spawnSync(
'docker',
[
'inspect',
'--format',
'{{.State.Running}} {{.State.Status}}',
containerName,
],
{ encoding: 'utf8' },
);
assert.equal(inspected.status, 0, inspected.stderr);
assert.equal(inspected.stdout.trim(), 'false exited');
return Object.freeze({
targetContainerIdentityDigest: crypto
.createHash('sha256')
.update(containerId, 'utf8')
.digest('hex'),
});
},
});
const committed = commitLocalReconciliationCapture(state.commitCommand);
assert.deepEqual(
dockerReadSealedSqlite(
capturePath(state, 'assets'),
'main_only_immutable',
),
{ count: 1, unchanged: true },
);
const verified = verifyLocalReconciliationCapture({
schemaVersion: 1,
operation: 'local.deployment.reconciliation.capture.verify',
options: state.command.options,
request: {
captureId: state.command.request.captureId,
expectedBundleDigest: committed.bundleDigest,
},
});
assert.equal(verified.status, 'verified');
assert.equal(verified.bundleDigest, committed.bundleDigest);
},
);
test(
'real Docker reads sealed WAL and SHM without changing the bundle',
{ skip: process.env.QL3_RECONCILIATION_DOCKER_GATE !== '1' },
(t) => {
let target;
const state = preparedCapture(t, {
createDefaultSidecars: false,
initializeDatabases(paths) {
planningDatabaseInitializer()(paths);
target = new DatabaseSync(paths.targetDatabasePath);
target.exec('PRAGMA journal_mode = WAL; PRAGMA wal_autocheckpoint = 0');
},
mutateTarget({ targetDatabasePath }) {
target.exec('INSERT INTO "QingLong3TaskDefinitions" (id) VALUES (1)');
fs.chmodSync(`${targetDatabasePath}-wal`, 0o600);
fs.chmodSync(`${targetDatabasePath}-shm`, 0o600);
return Object.freeze({});
},
});
t.after(() => {
try {
target?.close();
} catch {
// The fixture cleanup may already have invalidated the source handle.
}
});
commitLocalReconciliationCapture(state.commitCommand);
assert.deepEqual(
dockerReadSealedSqlite(capturePath(state, 'assets'), 'wal_shm_readonly'),
{ count: 1, unchanged: true },
);
},
);