feat(compiler): Z3 SMT-LIB2 verification backend (speckl#21)

- New generator: compiler/src/generators/z3.ts (1,034 lines)
- Translates SpeckDL state → Z3 sort declarations
- Translates invariants → Z3 define-fun returning Bool
- Translates actions → Z3 transition predicates (enabled + step)
- BMC unrolling with --verify-depth=N (default: 10)
- CLI: --target=z3 or --target=all
- ToggleSwitch and TigerBeetleLedger generate valid SMT-LIB2
- KafkaKRaft spec generates valid SMT-LIB2 structure
- Complex forall/set expressions emit 'true' as placeholders (to be improved)
- All 41 existing tests still pass

This unblocks M1.2 (KRaft verification), M3.2 (Show HN), and M4.3 (OAuth verification).
This commit is contained in:
cos Agent 2026-05-09 22:28:39 -07:00 • committed by Scott Scoble
parent 582ef92586
commit 6c6daaf90f
14 changed files with 4787 additions and 49 deletions

View file

@ -7,6 +7,7 @@ import { generateCycloneDX } from './generators/cyclonedx.js';
import { generateSPDX } from './generators/spdx.js';
import { generateTypeScriptStateMachine } from './generators/typescript-state-machine.js';
import { generateWASM } from './generators/wasm.js';
import { generateZ3, parseInvariantsFromSource, parseNextFromSource } from './generators/z3.js';
import fs from 'fs';
import path from 'path';
async function main() {
@ -35,6 +36,19 @@ async function main() {
describe: 'Output directory for compiled artifacts',
type: 'string',
default: './out',
})
.option('target', {
alias: 't',
describe: 'Compilation target',
type: 'string',
choices: ['typescript', 'z3', 'all'],
default: 'typescript',
})
.option('verify-depth', {
alias: 'd',
describe: 'Bounded model checking depth for Z3 verification',
type: 'number',
default: 10,
})
.option('bom-format', {
alias: 'b',
@ -50,6 +64,8 @@ async function main() {
const options = {
outputDir: argv.outputDir,
bomFormat: argv.bomFormat,
target: argv.target,
verifyDepth: argv.verifyDepth,
};
console.log(`Compiling ${file}...`);
// Parse the Speck file
@ -61,23 +77,43 @@ async function main() {
if (!fs.existsSync(options.outputDir)) {
fs.mkdirSync(options.outputDir, { recursive: true });
}
// Always generate provenance (it's the core output)
console.log('\nGenerating provenance graph (PROV-O JSON-LD)...');
generateProvenanceGraph(ast, options.outputDir);
// Generate TypeScript state machine
console.log('\nGenerating TypeScript state machine...');
generateTypeScriptStateMachine(ast, options.outputDir);
// Generate WASM state machine
console.log('\nGenerating WebAssembly (WAT)...');
generateWASM(ast, options.outputDir);
// Generate BOM based on format selection
if (options.bomFormat === 'cdx' || options.bomFormat === 'both') {
console.log('\nGenerating CycloneDX BOM...');
generateCycloneDX(ast, options.outputDir);
// Read raw source for invariant/next parsing that the AST parser doesn't handle yet
const rawSource = fs.readFileSync(file, 'utf-8');
// Always generate provenance (it's the core output) if not z3-only
if (options.target !== 'z3') {
console.log('\nGenerating provenance graph (PROV-O JSON-LD)...');
generateProvenanceGraph(ast, options.outputDir);
}
if (options.bomFormat === 'spdx' || options.bomFormat === 'both') {
console.log('\nGenerating SPDX BOM...');
generateSPDX(ast, options.outputDir);
// Generate Z3 SMT-LIB2 if target is z3 or all
if (options.target === 'z3' || options.target === 'all') {
console.log('\nGenerating Z3 SMT-LIB2...');
// Parse invariants from raw source for Z3 backend
for (const speck of ast.specks) {
const invariants = parseInvariantsFromSource(rawSource, speck.name);
const nextNode = parseNextFromSource(rawSource, speck.name);
// Attach parsed data to the AST for the generator
speck._invariants = invariants;
speck._next = nextNode;
}
const z3Options = { verifyDepth: options.verifyDepth };
generateZ3(ast, options.outputDir, z3Options);
}
// Generate TypeScript state machine if not z3-only
if (options.target !== 'z3') {
console.log('\nGenerating TypeScript state machine...');
generateTypeScriptStateMachine(ast, options.outputDir);
// Generate WASM state machine
console.log('\nGenerating WebAssembly (WAT)...');
generateWASM(ast, options.outputDir);
// Generate BOM based on format selection
if (options.bomFormat === 'cdx' || options.bomFormat === 'both') {
console.log('\nGenerating CycloneDX BOM...');
generateCycloneDX(ast, options.outputDir);
}
if (options.bomFormat === 'spdx' || options.bomFormat === 'both') {
console.log('\nGenerating SPDX BOM...');
generateSPDX(ast, options.outputDir);
}
}
console.log(`\nCompilation complete. Output: ${options.outputDir}/`);
}

View file

@ -1 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}

View file

@ -1 +1 @@
{"version":"2.1.9","results":[[":__tests__/parser.test.ts",{"duration":39.401257999999984,"failed":false}],[":__tests__/e2e-wasm.test.ts",{"duration":108.43775999999997,"failed":false}],[":src/__tests__/compiler.test.ts",{"duration":11.341655000000003,"failed":false}]]}
{"version":"2.1.9","results":[[":__tests__/parser.test.ts",{"duration":49.959937000000025,"failed":false}],[":__tests__/e2e-wasm.test.ts",{"duration":90.40252399999997,"failed":false}],[":src/__tests__/compiler.test.ts",{"duration":11.602408000000025,"failed":false}]]}

File diff suppressed because it is too large Load diff

View file

@ -8,12 +8,15 @@ import { generateCycloneDX } from './generators/cyclonedx.js';
import { generateSPDX } from './generators/spdx.js';
import { generateTypeScriptStateMachine } from './generators/typescript-state-machine.js';
import { generateWASM } from './generators/wasm.js';
import { generateZ3, Z3Options, parseInvariantsFromSource, parseNextFromSource } from './generators/z3.js';
import fs from 'fs';
import path from 'path';
interface CompileOptions {
outputDir: string;
bomFormat: 'cdx' | 'spdx' | 'both';
target: 'typescript' | 'z3' | 'all';
verifyDepth: number;
}
async function main() {
@ -43,6 +46,19 @@ async function main() {
type: 'string',
default: './out',
})
.option('target', {
alias: 't',
describe: 'Compilation target',
type: 'string',
choices: ['typescript', 'z3', 'all'],
default: 'typescript' as const,
})
.option('verify-depth', {
alias: 'd',
describe: 'Bounded model checking depth for Z3 verification',
type: 'number',
default: 10,
})
.option('bom-format', {
alias: 'b',
describe: 'BOM output format',
@ -58,6 +74,8 @@ async function main() {
const options = {
outputDir: argv.outputDir as string,
bomFormat: argv.bomFormat as 'cdx' | 'spdx' | 'both',
target: argv.target as 'typescript' | 'z3' | 'all',
verifyDepth: argv.verifyDepth as number,
};
console.log(`Compiling ${file}...`);
@ -74,27 +92,49 @@ async function main() {
fs.mkdirSync(options.outputDir, { recursive: true });
}
// Always generate provenance (it's the core output)
console.log('\nGenerating provenance graph (PROV-O JSON-LD)...');
generateProvenanceGraph(ast, options.outputDir);
// Generate TypeScript state machine
console.log('\nGenerating TypeScript state machine...');
generateTypeScriptStateMachine(ast, options.outputDir);
// Read raw source for invariant/next parsing that the AST parser doesn't handle yet
const rawSource = fs.readFileSync(file, 'utf-8');
// Generate WASM state machine
console.log('\nGenerating WebAssembly (WAT)...');
generateWASM(ast, options.outputDir);
// Generate BOM based on format selection
if (options.bomFormat === 'cdx' || options.bomFormat === 'both') {
console.log('\nGenerating CycloneDX BOM...');
generateCycloneDX(ast, options.outputDir);
// Always generate provenance (it's the core output) if not z3-only
if (options.target !== 'z3') {
console.log('\nGenerating provenance graph (PROV-O JSON-LD)...');
generateProvenanceGraph(ast, options.outputDir);
}
if (options.bomFormat === 'spdx' || options.bomFormat === 'both') {
console.log('\nGenerating SPDX BOM...');
generateSPDX(ast, options.outputDir);
// Generate Z3 SMT-LIB2 if target is z3 or all
if (options.target === 'z3' || options.target === 'all') {
console.log('\nGenerating Z3 SMT-LIB2...');
// Parse invariants from raw source for Z3 backend
for (const speck of ast.specks) {
const invariants = parseInvariantsFromSource(rawSource, speck.name);
const nextNode = parseNextFromSource(rawSource, speck.name);
// Attach parsed data to the AST for the generator
(speck as any)._invariants = invariants;
(speck as any)._next = nextNode;
}
const z3Options: Z3Options = { verifyDepth: options.verifyDepth };
generateZ3(ast, options.outputDir, z3Options);
}
// Generate TypeScript state machine if not z3-only
if (options.target !== 'z3') {
console.log('\nGenerating TypeScript state machine...');
generateTypeScriptStateMachine(ast, options.outputDir);
// Generate WASM state machine
console.log('\nGenerating WebAssembly (WAT)...');
generateWASM(ast, options.outputDir);
// Generate BOM based on format selection
if (options.bomFormat === 'cdx' || options.bomFormat === 'both') {
console.log('\nGenerating CycloneDX BOM...');
generateCycloneDX(ast, options.outputDir);
}
if (options.bomFormat === 'spdx' || options.bomFormat === 'both') {
console.log('\nGenerating SPDX BOM...');
generateSPDX(ast, options.outputDir);
}
}
console.log(`\nCompilation complete. Output: ${options.outputDir}/`);

View file

@ -12,7 +12,7 @@
"@type": "prov:Generation",
"prov:activity": {
"@type": "prov:Activity",
"prov:startTime": "2026-05-10T05:07:15.423Z"
"prov:startTime": "2026-05-10T05:28:00.665Z"
}
},
"rdfs:label": "RetryHandler",

View file

@ -38,7 +38,7 @@
"name": "Scott Scoble",
"email": "scott@scoble.me"
},
"timestamp": "2026-05-10T05:07:15.425Z"
"timestamp": "2026-05-10T05:28:00.667Z"
},
{
"subject": "speck:RetryHandler",
@ -53,7 +53,7 @@
"name": "Speckl Compiler",
"email": "compiler@speckl.scoble.me"
},
"timestamp": "2026-05-10T05:07:15.425Z"
"timestamp": "2026-05-10T05:28:00.667Z"
},
{
"subject": "speck:RetryHandler",
@ -68,7 +68,7 @@
"name": "Speckl Compiler",
"email": "compiler@speckl.scoble.me"
},
"timestamp": "2026-05-10T05:07:15.425Z"
"timestamp": "2026-05-10T05:28:00.667Z"
}
]
}

View file

@ -13,7 +13,7 @@
"spdxVersion": "3.0.1",
"dataLicense": "CC0-1.0",
"creationInfo": {
"created": "2026-05-10T05:07:15.426Z",
"created": "2026-05-10T05:28:00.668Z",
"createdBy": [
"Organization: Speckl",
"tool: speckl-compile-0.2.0"
@ -27,7 +27,7 @@
"@type": "spdx:Tool",
"name": "speckl-compile"
},
"timestamp": "2026-05-10T05:07:15.427Z",
"timestamp": "2026-05-10T05:28:00.669Z",
"comment": "Review type: manual"
}
]