b739d5adad
Болезни B (роутер в пустоту) + A (наставник не заворачивал) — лечение Р7/Р8 (Подход 1): наставник — единый мозг-рецензент, зовёт classify() как функцию (3 слоя + граф nodes.yaml + карточки — код не тронут, новый вызыватель), судит спеку+план+выбор скилов, заворачивает NO-GO. - validateMentorVerdict + промпты (план/спека): явное decision GO|NO-GO (поглощённый Р7) - plan-skills.mjs: parsePlanSkills (skills-json) + extractPlanGoal (зеркало extractGoal судьи) - mentor-seam: renderSkillContext; onPlanWrite зовёт classifyImpl (fail-safe: сбой → без скил-сверки) - decideMentorObjection: заворот на decision=NO-GO ИЛИ сломанный вердикт; mentor-GO только на чистом GO - formatMentorObjection доносит суть (recommendation + reasoning + plan_points), GO -> пусто - enforce-mentor main: loadRegistry + classify; счётчик L1 decision-aware (Р7/§3.4) - скил-сверка — только план (gate2); спека (gate1) — по сути + decision - включает redesign согласования L1->L2 (Фазы 0-6, способ B: наставник->судья->печать) - регрессия tools-only 3901 passed + 2 skip (база 3877, +24 теста, 0 регрессий) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
23 lines
1.2 KiB
JavaScript
23 lines
1.2 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* mentor-nogo-counter — счётчик подряд идущих NO-GO наставника (L1), зеркало
|
|
* bumpJudgeNoGo. blocked=true → +1; allow → сброс 0. Порог 3 → арбитраж (round-control C-12).
|
|
*/
|
|
import fsDefault from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import { runtimeDir } from './enforce-hook-helpers.mjs';
|
|
|
|
export const MENTOR_ESCALATE_AFTER = 3;
|
|
|
|
export function bumpMentorNoGo({ taskId, sessionId, blocked, fsImpl = fsDefault, dir = runtimeDir() } = {}) {
|
|
// Фаза 4: счётчик на СТЭК (спека+план) одной задачи — ключ task-id (sessionId — fallback
|
|
// backward-compat). Две правки в одной сессии → независимые счётчики.
|
|
const safe = String(taskId || sessionId || 'unknown').replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
const path = join(dir, `mentor-nogo-${safe}.json`);
|
|
let count = 0;
|
|
try { count = (JSON.parse(fsImpl.readFileSync(path, 'utf8')).count) || 0; } catch { count = 0; }
|
|
const next = blocked ? count + 1 : 0;
|
|
try { fsImpl.mkdirSync(dir, { recursive: true }); fsImpl.writeFileSync(path, JSON.stringify({ count: next })); } catch { /* best-effort */ }
|
|
return next;
|
|
}
|