Files
brain/tools/criterion-green.mjs
T

62 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env node
/**
* criterion-green (Машина 5 Пакет 5, Блок 3, 5.6) — по-критерийный производитель GREEN.
*
* Для этой цели заменяет «весь-прогон-разом» enforce-verify-record: эмитит подписанный
* подписантом GREEN ТОЛЬКО при настоящем зелёном прогоне конкретного критерия. Два условия
* настоящего green (оба обязательны):
* - testPassed: тест изменённого шага реально прошёл;
* - mutationKilled (P18): сломали изменённый код — тест ОБЯЗАН покраснеть; выжил зелёным →
* тест ничего не проверяет → НЕ green.
* Иначе green:false с причиной (mutation-survived / test-not-passed / no-signer-key) — fail-CLOSE.
*
* Подпись — над аутентифицирующей тройкой {criterion_id, code_fingerprint, occurrence} (floor-signer,
* домен M5_GREEN). green/coverage_of_changed — поля записи; подлинность даёт подпись (Δ5),
* свежесть — отпечаток (Δ2). Чистый модуль: факты прогона (testPassed/mutationKilled/отпечаток/
* покрытие) и ключ подписанта инъектируются; никакого fs/исполнения тестов здесь (это — живая
* обёртка под активацией владельца). code_fingerprint считается отдельно через codeFingerprint.
*/
import { createHash } from 'node:crypto';
import { canonicalJson } from './receipt-sign.mjs';
import { signGreen } from './floor-signer.mjs';
/**
* Δ2: отпечаток «по делу» = sha256 канонизированной карты {путь: содержимое} изменённых
* файлов шага + тест-файлов, которые их прогоняли. Граф импортов НЕ считаем (кросс-язык —
* дорого/хрупко; надёжность даёт мутация P18). Правка любого из этих файлов после прогона →
* другой отпечаток → green аннулируется fingerprintFresh. Детерминирован (canonicalJson сортит
* ключи — порядок файлов не влияет).
*/
export function codeFingerprint(fileContents = {}) {
return createHash('sha256').update(canonicalJson(fileContents)).digest('hex');
}
/**
* Произвести по-критерийный GREEN. Настоящий green ⇔ testPassed && mutationKilled && есть ключ.
* @returns настоящий green: {criterion_id, code_fingerprint, occurrence, sig, green:true, coverage_of_changed}
* иначе: {criterion_id, green:false, code_fingerprint, coverage_of_changed, occurrence, reason}
*/
export function produceGreen({
criterion_id,
occurrence,
code_fingerprint,
coverage_of_changed = null,
testPassed = false,
mutationKilled = false,
signerKey,
} = {}) {
if (testPassed !== true) {
return { criterion_id, green: false, code_fingerprint, coverage_of_changed, occurrence, reason: 'test-not-passed' };
}
if (mutationKilled !== true) {
// P18: тест прошёл, но мутация выжила — тест не проверяет изменённый код → не green.
return { criterion_id, green: false, code_fingerprint, coverage_of_changed, occurrence, reason: 'mutation-survived' };
}
const receipt = signGreen({ criterion_id, code_fingerprint, occurrence }, signerKey);
if (!receipt) {
// Нет ключа подписанта → подлинный green произвести нельзя (fail-CLOSE).
return { criterion_id, green: false, code_fingerprint, coverage_of_changed, occurrence, reason: 'no-signer-key' };
}
return { ...receipt, green: true, coverage_of_changed };
}