{"version":3,"file":"verifier.d.ts","sourceRoot":"","sources":["../../../src/core/reliability/verifier.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAuB,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE5F,MAAM,WAAW,oBAAoB;IACpC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzG,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACtD,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAChE,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,mBAAmB;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACnB;AAqBD;;GAEG;AACH,wBAAsB,MAAM,CAC3B,IAAI,EAAE,gBAAgB,EACtB,QAAQ,EAAE,oBAAoB,EAC9B,OAAO,GAAE,mBAAwB,GAC/B,OAAO,CAAC,kBAAkB,CAAC,CAyG7B","sourcesContent":["/**\n * Verification Engine — deterministic, extensible verification operations.\n *\n * A verifier turns an observation (command exit code, file state, search\n * result, git diff) into a VerificationResult with a pass/fail decision. The\n * decision is computed by Jensen from machine-observable facts — never from\n * model output or model self-review.\n */\n\nimport type { MissionEvidenceType, VerificationResult, VerificationSpec } from \"./types.js\";\n\nexport interface VerificationExecutor {\n\trunCommand(command: string, cwd?: string): Promise<{ exitCode: number; stdout: string; stderr: string }>;\n\tfileExists(path: string, cwd?: string): Promise<boolean>;\n\treadFile(path: string, cwd?: string): Promise<string>;\n\tsearchMatches(pattern: string, cwd?: string): Promise<string[]>;\n\tgitChangedPaths(cwd?: string): Promise<string[]>;\n}\n\nexport interface VerificationOptions {\n\tcriterionId?: string;\n\tcwd?: string;\n\tnow?: () => string;\n}\n\nconst KIND_TO_EVIDENCE_TYPE: Record<VerificationSpec[\"kind\"], MissionEvidenceType> = {\n\tcommand: \"tool_result\",\n\ttest: \"test_result\",\n\tbuild: \"build_result\",\n\tlint: \"verification_result\",\n\ttypecheck: \"verification_result\",\n\tfile_exists: \"file_state\",\n\tfile_absent: \"file_state\",\n\tfile_contains: \"file_state\",\n\tsearch_no_matches: \"search_result\",\n\tgit_diff_scope: \"file_state\",\n};\n\nlet evidenceCounter = 0;\nfunction evidenceId(kind: VerificationSpec[\"kind\"], now: string): string {\n\tevidenceCounter += 1;\n\treturn `ev_${kind}_${now.replace(/\\D/g, \"\")}_${evidenceCounter}`;\n}\n\n/**\n * Execute a single deterministic verification operation.\n */\nexport async function verify(\n\tspec: VerificationSpec,\n\texecutor: VerificationExecutor,\n\toptions: VerificationOptions = {},\n): Promise<VerificationResult> {\n\tconst now = options.now ?? (() => new Date().toISOString());\n\tconst cwd = spec.cwd ?? options.cwd;\n\tconst kind = spec.kind;\n\tconst type = KIND_TO_EVIDENCE_TYPE[kind];\n\tconst criterionIds = options.criterionId ? [options.criterionId] : [];\n\n\tlet passed = false;\n\tlet summary = \"\";\n\tlet detail: string | undefined;\n\tlet data: unknown;\n\n\tswitch (kind) {\n\t\tcase \"command\":\n\t\tcase \"test\":\n\t\tcase \"build\":\n\t\tcase \"lint\":\n\t\tcase \"typecheck\": {\n\t\t\tif (!spec.command) {\n\t\t\t\treturn {\n\t\t\t\t\tpassed: false,\n\t\t\t\t\tkind,\n\t\t\t\t\tevidence: {\n\t\t\t\t\t\tid: evidenceId(kind, now()),\n\t\t\t\t\t\ttype,\n\t\t\t\t\t\tsource: \"runtime\",\n\t\t\t\t\t\tsummary: `missing command for ${kind}`,\n\t\t\t\t\t\tsuccess: false,\n\t\t\t\t\t\tcriterionIds,\n\t\t\t\t\t\ttimestamp: now(),\n\t\t\t\t\t},\n\t\t\t\t\tdetail: `VerificationSpec for ${kind} requires a command`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst result = await executor.runCommand(spec.command, cwd);\n\t\t\tpassed = result.exitCode === 0;\n\t\t\tsummary = `${spec.command} → exit ${result.exitCode}`;\n\t\t\tdetail = result.stdout || result.stderr ? (result.stderr || result.stdout).slice(0, 500) : undefined;\n\t\t\tdata = { command: spec.command, exitCode: result.exitCode };\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"file_exists\": {\n\t\t\tconst exists = await executor.fileExists(spec.path ?? \"\", cwd);\n\t\t\tpassed = exists;\n\t\t\tsummary = `file exists: ${spec.path}`;\n\t\t\tdata = { path: spec.path, exists };\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"file_absent\": {\n\t\t\tconst exists = await executor.fileExists(spec.path ?? \"\", cwd);\n\t\t\tpassed = !exists;\n\t\t\tsummary = `file absent: ${spec.path}`;\n\t\t\tdata = { path: spec.path, exists };\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"file_contains\": {\n\t\t\tconst content = await executor.readFile(spec.path ?? \"\", cwd);\n\t\t\tpassed = spec.pattern ? content.includes(spec.pattern) : false;\n\t\t\tsummary = `file contains pattern: ${spec.path}`;\n\t\t\tdata = { path: spec.path, pattern: spec.pattern };\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"search_no_matches\": {\n\t\t\tconst matches = await executor.searchMatches(spec.pattern ?? \"\", cwd);\n\t\t\tpassed = matches.length === 0;\n\t\t\tsummary = `no stale references for: ${spec.pattern}`;\n\t\t\tdetail = matches.length > 0 ? `matches: ${matches.slice(0, 20).join(\", \")}` : undefined;\n\t\t\tdata = { pattern: spec.pattern, matchCount: matches.length };\n\t\t\tbreak;\n\t\t}\n\n\t\tcase \"git_diff_scope\": {\n\t\t\tconst changed = await executor.gitChangedPaths(cwd);\n\t\t\tconst allowed = spec.allowedPaths ?? [];\n\t\t\tconst outOfScope = changed.filter(\n\t\t\t\t(p) => !allowed.some((a) => p === a || p.startsWith(`${a.replace(/\\/$/, \"\")}/`)),\n\t\t\t);\n\t\t\tpassed = outOfScope.length === 0;\n\t\t\tsummary = `git diff scope: ${changed.length} changed path(s), ${outOfScope.length} out of scope`;\n\t\t\tdetail = outOfScope.length > 0 ? `out of scope: ${outOfScope.join(\", \")}` : undefined;\n\t\t\tdata = { allowedPaths: allowed, changedPaths: changed, outOfScope };\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn {\n\t\tpassed,\n\t\tkind,\n\t\tcriterionId: options.criterionId,\n\t\tevidence: {\n\t\t\tid: evidenceId(kind, now()),\n\t\t\ttype,\n\t\t\tsource: \"runtime\",\n\t\t\tsummary,\n\t\t\tsuccess: passed,\n\t\t\tcriterionIds,\n\t\t\ttimestamp: now(),\n\t\t\tdata,\n\t\t},\n\t\tdetail,\n\t};\n}\n"]}