Reference implementation for the Phoenix Architecture. Work in progress. aicoding.leaflet.pub/
ai coding crazy
at main 65 lines 3.2 kB view raw
1import { readFileSync } from 'node:fs'; 2import { resolve } from 'node:path'; 3import { parseSpec } from '../src/spec-parser.js'; 4import { extractCanonicalNodes } from '../src/canonicalizer.js'; 5 6const ROOT = resolve(import.meta.dirname, '..'); 7 8const specs = [ 9 { name: 'Settlements', path: 'examples/settle-up/spec/settlements.md', docId: 'spec/settlements.md', 10 gold: [ 11 { statement: 'minimum number of payments', type: 'CONSTRAINT' }, 12 { statement: 'same net effect', type: 'REQUIREMENT' }, 13 { statement: 'cycles', type: 'REQUIREMENT' }, 14 { statement: 'all balances are zero', type: 'REQUIREMENT' }, 15 { statement: 'exceeds', type: 'REQUIREMENT' }, 16 { statement: 'settled up', type: 'REQUIREMENT' }, 17 ]}, 18 { name: 'TicTacToe', path: 'examples/tictactoe/spec/game-engine.md', docId: 'spec/game-engine.md', 19 gold: [ 20 { statement: '3x3 grid', type: 'REQUIREMENT' }, 21 { statement: 'already occupied', type: 'REQUIREMENT' }, 22 { statement: 'x always moves first', type: 'INVARIANT' }, 23 { statement: 'win detection', type: 'CONTEXT' }, 24 { statement: 'draw', type: 'REQUIREMENT' }, 25 { statement: 'game must track the current status', type: 'REQUIREMENT' }, 26 ]}, 27 { name: 'Pixel Wars', path: 'examples/pixel-wars/spec/game.md', docId: 'spec/game.md', 28 gold: [ 29 { statement: '20 columns', type: 'CONTEXT' }, 30 { statement: 'cooldown', type: 'CONSTRAINT' }, 31 { statement: 'rejected', type: 'REQUIREMENT' }, 32 { statement: 'broadcast', type: 'REQUIREMENT' }, 33 { statement: '120 seconds', type: 'CONTEXT' }, 34 { statement: 'round-robin', type: 'CONTEXT' }, 35 ]}, 36 { name: 'User Service', path: 'examples/microservices/spec/user-service.md', docId: 'spec/user-service.md', 37 gold: [ 38 { statement: 'system of record', type: 'CONTEXT' }, 39 { statement: 'email addresses must be unique', type: 'REQUIREMENT' }, 40 { statement: 'never store or return plaintext passwords', type: 'INVARIANT' }, 41 { statement: 'soft delete', type: 'REQUIREMENT' }, 42 { statement: '100 characters', type: 'CONSTRAINT' }, 43 { statement: 'locked for 1 hour', type: 'REQUIREMENT' }, 44 { statement: 'parameterized statements', type: 'CONSTRAINT' }, 45 { statement: 'event payloads must never contain passwords', type: 'INVARIANT' }, 46 { statement: '50 results per page', type: 'CONSTRAINT' }, 47 { statement: 'usercreated', type: 'REQUIREMENT' }, 48 ]}, 49]; 50 51for (const spec of specs) { 52 const text = readFileSync(resolve(ROOT, spec.path), 'utf8'); 53 const clauses = parseSpec(text, spec.docId); 54 const nodes = extractCanonicalNodes(clauses); 55 console.log(`\n=== ${spec.name} (${nodes.length} nodes) ===`); 56 for (const g of spec.gold) { 57 const match = nodes.find(n => n.statement.toLowerCase().includes(g.statement.toLowerCase())); 58 if (match) { 59 const ok = match.type === g.type ? 'OK ' : 'MISS'; 60 console.log(`${ok} "${g.statement}" expected=${g.type} got=${match.type} conf=${match.confidence?.toFixed(2)} stmt="${match.statement.substring(0, 80)}"`); 61 } else { 62 console.log(`GONE "${g.statement}"`); 63 } 64 } 65}