diff --git a/tools/arbitration-card.mjs b/tools/arbitration-card.mjs index b55aa83..654a235 100644 --- a/tools/arbitration-card.mjs +++ b/tools/arbitration-card.mjs @@ -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: 'Ты вписываешь своё — оно становится обязательным для контроллера.' }, ], diff --git a/tools/arbitration-card.test.mjs b/tools/arbitration-card.test.mjs index ba4b7f3..24bc98f 100644 --- a/tools/arbitration-card.test.mjs +++ b/tools/arbitration-card.test.mjs @@ -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); + }); });