feat: round-memory arbitration-card sealAction owner-seal SP3-c1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-06-17 03:36:15 +03:00
parent 6a9d3e2466
commit ce58f37d8f
2 changed files with 24 additions and 3 deletions
+10 -3
View File
@@ -9,15 +9,22 @@ export const ARBITRATION_OPTIONS = ['hold', 'accept', 'own'];
const verbatim = (s) => (typeof s === 'string' ? s : '');
export function buildArbitrationCard({ side, level, round, objectionVerbatim, controllerPositionVerbatim } = {}) {
export function buildArbitrationCard({ side, level, round, objectionVerbatim, controllerPositionVerbatim, sealAction = null } = {}) {
const who = side === 'judge' ? 'судьи' : 'наставника';
// SP3-c: sealAction = `owner-seal:<хеш тела>` (тот же, что считает sealTurnProd: спека →
// judgedHashOf(sealableArtifact), план → planId(steps)). Несём его в карточку + в честный
// hold-текст, чтобы владельцу было ОТКУДА взять точную escape-строку (ownerseal-wiring-bug).
const seal = typeof sealAction === 'string' && sealAction ? sealAction : null;
const holdText = seal
? `Опечатать версию контроллера как есть — подпиши escape-опцией: FLOOR-ESCAPE: ${seal} (замечание ${who} перевешено владельцем).`
: `Ворота пропустят версию контроллера — замечание ${who} отведено тобой (escape-грант).`;
return {
side, level, round,
side, level, round, sealAction: seal,
title: `Арбитраж (${level}): тупик спора с ${side === 'judge' ? 'судьёй' : 'наставником'} после ${round} кругов`,
objection: verbatim(objectionVerbatim),
position: verbatim(controllerPositionVerbatim),
options: [
{ key: 'hold', label: 'Держусь позиции контроллера', whatChanges: `Ворота пропустят версию контроллера — замечание ${who} отведено тобой (escape-грант).` },
{ key: 'hold', label: 'Держусь позиции контроллера', whatChanges: holdText },
{ key: 'accept', label: 'Согласиться с замечанием', whatChanges: `Контроллер переделает по замечанию ${who}; счётчик круга сбрасывается.` },
{ key: 'own', label: 'Своё решение', whatChanges: 'Ты вписываешь своё — оно становится обязательным для контроллера.' },
],
+14
View File
@@ -36,4 +36,18 @@ describe('buildArbitrationCard', () => {
expect(c.objection).toBe('');
expect(c.position).toBe('');
});
it('SP3-c: sealAction передан → card.sealAction + hold-текст несёт точную escape-строку', () => {
const c = buildArbitrationCard({ ...base, sealAction: 'owner-seal:abc123' });
expect(c.sealAction).toBe('owner-seal:abc123');
const hold = c.options.find((o) => o.key === 'hold');
expect(hold.whatChanges).toContain('FLOOR-ESCAPE: owner-seal:abc123');
});
it('SP3-c: sealAction не передан → null, прежний hold-текст, форма цела', () => {
const c = buildArbitrationCard(base);
expect(c.sealAction).toBe(null);
const hold = c.options.find((o) => o.key === 'hold');
expect(hold.whatChanges).not.toContain('FLOOR-ESCAPE');
expect(typeof hold.whatChanges).toBe('string');
expect(hold.whatChanges.length).toBeGreaterThan(0);
});
});