ci: исполнять TS/Python parity на чистом runner (#548)

Issue: #548
User-Visible: no
This commit is contained in:
Sergey Matyunin
2026-09-13 10:49:07 +03:00
parent e85849b86e
commit 76d8017e87
20 changed files with 520 additions and 92 deletions
+11
View File
@@ -324,6 +324,17 @@ export const CHECKS = {
roots: [...BUILD_INPUTS, 'demo/performance/**', ...BROWSER_PROTOCOL, ...REUSE_PROTOCOL, ...WORKFLOW],
reuse: true,
},
geometry_parity: {
// #548: узкий clean-runner guard реальных TS/Python зеркал П1–П4.
// Полный frontend artifact и HA harness ему не нужны; каждый фактический
// вход перечислен здесь и участвует одновременно в selection и reuse key.
entries: ['tests_backend/junction_parity.py', 'src/junction-limits.ts',
'custom_components/houseplan/junction_limits.py', 'scripts/fix-test-build.mjs'],
roots: ['tests_backend/pure_imports.py', 'custom_components/houseplan/wall_segment_model.py',
'test/fixtures/junction-limits-parity.json', 'tsconfig.junction-parity.json', 'tsconfig.json',
'package.json', 'package-lock.json', '.nvmrc', '.python-version', ...REUSE_PROTOCOL, ...WORKFLOW],
reuse: true,
},
backend: {
// pytest tests_backend, unittest scripts/support-relay/tests, ruff/mypy, порог покрытия
entries: ['tests_backend/**/*.py', 'scripts/support-relay/tests/**/*.py', 'scripts/dump-config-schema.py'],
+4
View File
@@ -36,6 +36,7 @@ const JOB_RULES = Object.freeze({
],
golden: [{ exact: 'Golden-кадры против принятых эталонов', count: 1 }],
performance_smoke: [{ exact: 'Перф-смок: бюджет времени кадра', count: 1 }],
geometry_parity: [{ exact: 'Геометрия: TS/Python parity исполнена', count: 1 }],
backend: [{ exact: 'Бэкенд: pytest в Home Assistant', count: 1 }],
});
@@ -66,6 +67,7 @@ export function requiredCheckIds({ request = {}, selection = {} } = {}) {
if (asBool(selection.integration)) ids.push('integration');
if (asBool(request.mutants)) ids.push('mutants');
if (asBool(request.full)) ids.push('smoke', 'golden', 'performance_smoke');
if (asBool(selection.geometry_parity)) ids.push('geometry_parity');
if (asBool(selection.backend)) ids.push('backend');
return ids;
}
@@ -90,6 +92,7 @@ export function buildCiProof({
};
const selection = {
frontend: asBool(changes.frontend),
geometry_parity: asBool(changes.geometry_parity),
backend: asBool(changes.backend),
integration: asBool(changes.integration),
};
@@ -124,6 +127,7 @@ export function buildCiProof({
executedOrReused('golden');
executedOrReused('performance_smoke');
}
if (selection.geometry_parity) executedOrReused('geometry_parity');
if (selection.backend) executedOrReused('backend');
const requiredChecks = requiredCheckIds({ request, selection });
return {
+1
View File
@@ -27,6 +27,7 @@ import { checksAffectedBy } from './check-inputs.mjs';
*/
export const CHECK_OF_OUTPUT = {
frontend: 'frontend',
geometry_parity: 'geometry_parity',
backend: 'backend',
integration: 'integration',
mutants: 'changed_mutants',
+5 -3
View File
@@ -1,6 +1,7 @@
// Ключ переиспользования результата тяжёлой job (issue #208).
//
// Тяжёлые job Validate — smoke, golden, performance_smoke, backend — прогонялись
// Reusable job Validate — smoke, golden, performance_smoke, geometry_parity,
// backend — прогонялись
// на каждый push в dev, включая коммиты в документацию, workflows и процессные
// скрипты, где бандл и оснастка побайтово те же. Ключ здесь отвечает на один
// вопрос: «менялось ли хоть что-то, от чего результат этой job зависит».
@@ -17,8 +18,9 @@
// пишет только успешный прогон с тем же ключом.
//
// Свойство, которое стоит знать: релизный кандидат (бета или стабильный релиз)
// бампает версию — `package.json`/`CARD_VERSION` у браузерных job и
// `custom_components/houseplan/manifest.json` у backend входят в manifest.
// бампает версию — `package.json`/`CARD_VERSION` у браузерных job,
// `package.json` у geometry_parity и `custom_components/houseplan/manifest.json`
// у backend входят в manifest.
// Значит ключ кандидата заведомо новый и полный набор гейтов прогоняется всегда.
// Переиспользование физически не может ослабить релизный гейт.
+13
View File
@@ -3202,6 +3202,19 @@ const MUTANT_DEFINITIONS = [
+ '`${point[0].toFixed(6)},${point[1].toFixed(6)}`;',
}],
},
{
id: 'junction-limit-ts-python-parity-drift',
guard: 'npx tsc -p tsconfig.junction-parity.json && node scripts/fix-test-build.mjs '
+ '&& python3 tests_backend/junction_parity.py --build-dir=test-build/junction-parity',
because: 'the clean-runner parity job must turn red when either production mirror changes '
+ 'one shared rule; otherwise a green run can again mean that no cross-runtime comparison '
+ 'actually happened (#548 AC2)',
patches: [{
file: 'src/junction-limits.ts',
find: 'export const MIN_NODE_DISTANCE_CM = 5;',
replace: 'export const MIN_NODE_DISTANCE_CM = 4; // mutant: drift from Python mirror',
}],
},
{
id: 'junction-limit-branch-dropped',
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '