fix(skill-contract): G-E — страж дрейфа инертен при пустом source.path без содержания

checkContractDrift: external без локального source.path И без поданного
currentContent (== null) → не сторожим (G4 инертен). Это прод-случай зеро-хеша
(Р5 MCP/marketplace): loadRegistry при пустом path не читает content. Прямой
вызов с поданным currentContent — drift сверяется как раньше. TDD: RED→GREEN,
48/48 skill-contract + registry. Дисциплина doubt→drift на реальных источниках
не понижена.

coverage: skill:test-driven-development
This commit is contained in:
Дмитрий
2026-06-08 18:33:05 +03:00
parent 4d257a1c44
commit d1a767867a
2 changed files with 12 additions and 0 deletions
+6
View File
@@ -104,6 +104,12 @@ export function contractHash(content) {
export function checkContractDrift({ contract, currentContent }) {
if (!contract || contract.kind !== 'external')
return { ok: true, drifted: false, reason: 'own/нет внешнего источника — дрейф не сторожится' };
// G-E: нет локального источника (path пуст) И нечего сравнивать (content не прочитан) →
// сторожить нечего, G4 инертен. Это ровно прод-случай зеро-хеша (Р5 MCP/marketplace):
// loadRegistry при пустом path не читает content → currentContent === undefined.
// Прямой вызов с поданным currentContent (тест/иной потребитель) → drift сверяется как обычно.
if (!contract.source?.path && currentContent == null)
return { ok: true, drifted: false, reason: 'external без локального source.path и без содержания — дрейф не сторожится (G4 инертен)' };
const stored = contract.source?.hash;
const actual = contractHash(currentContent);
if (!stored) return { ok: false, drifted: true, reason: 'нет сохранённого отпечатка внешнего скила', fallback: 'soft-reasoning' };
+6
View File
@@ -105,6 +105,12 @@ describe('checkContractDrift (G4)', () => {
const r = checkContractDrift({ contract: { skill: 's', kind: 'external', source: { version: '1' } }, currentContent: 'x' });
expect(r.drifted).toBe(true);
});
it('G-E: external с пустым source.path → дрейф не сторожится (инертен)', () => {
const c = { skill: 'x', kind: 'external', source: { version: '1', hash: '0'.repeat(64), path: '' } };
const r = checkContractDrift({ contract: c, currentContent: undefined });
expect(r.drifted).toBe(false);
expect(r.ok).toBe(true);
});
});
describe('inherent (#1 присущее по природе + гард R4 rationale)', () => {