You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
81 lines
2.6 KiB
81 lines
2.6 KiB
/**
|
|
* Tests for SEMA_HOLDS_BY_INTENT and resolveHoldsByIntent.
|
|
*
|
|
* The map encodes the book Cap. 24 §6.2 lookup: for a given (family,
|
|
* intent), what is the canonical perceptual hold + lifecycle policy?
|
|
*/
|
|
|
|
import { describe, expect, it } from 'vitest';
|
|
import { SEMA_HOLDS_BY_INTENT, resolveHoldsByIntent } from './holds';
|
|
|
|
describe('SEMA_HOLDS_BY_INTENT', () => {
|
|
it('covers all 8 canonical families', () => {
|
|
const families = Object.keys(SEMA_HOLDS_BY_INTENT);
|
|
expect(families).toEqual(
|
|
expect.arrayContaining([
|
|
'contact',
|
|
'commit',
|
|
'signal',
|
|
'handle',
|
|
'emerge',
|
|
'shift',
|
|
'sustain',
|
|
'delegate'
|
|
])
|
|
);
|
|
expect(families).toHaveLength(8);
|
|
});
|
|
|
|
it('every family has a _default policy', () => {
|
|
for (const [family, entry] of Object.entries(SEMA_HOLDS_BY_INTENT)) {
|
|
expect(entry._default, `${family}._default`).toBeDefined();
|
|
expect(entry._default.hold, `${family}._default.hold`).toBeDefined();
|
|
expect(entry._default.persistence, `${family}._default.persistence`).toBeDefined();
|
|
}
|
|
});
|
|
|
|
it('signal + risk = untilFix per book §6.2', () => {
|
|
const policy = resolveHoldsByIntent('signal', 'risk');
|
|
expect(policy?.persistence).toBe('untilFix');
|
|
});
|
|
|
|
it('signal + threat = untilAction per book §6.2', () => {
|
|
const policy = resolveHoldsByIntent('signal', 'threat');
|
|
expect(policy?.persistence).toBe('untilAction');
|
|
});
|
|
|
|
it('signal + neutral = transient per book §6.2', () => {
|
|
const policy = resolveHoldsByIntent('signal', 'neutral');
|
|
expect(policy?.persistence).toBe('transient');
|
|
});
|
|
|
|
it('sustain = stateBound regardless of intent', () => {
|
|
expect(resolveHoldsByIntent('sustain')?.persistence).toBe('stateBound');
|
|
expect(resolveHoldsByIntent('sustain', 'neutral')?.persistence).toBe('stateBound');
|
|
});
|
|
});
|
|
|
|
describe('resolveHoldsByIntent', () => {
|
|
it('falls back to _default when intent is undefined', () => {
|
|
const policy = resolveHoldsByIntent('commit');
|
|
expect(policy).toEqual(SEMA_HOLDS_BY_INTENT.commit._default);
|
|
});
|
|
|
|
it('falls back to _default when intent has no per-intent entry', () => {
|
|
// commit only declares per-intent for `fulfill`. Other intents
|
|
// resolve to `_default`.
|
|
const policy = resolveHoldsByIntent('commit', 'affirm');
|
|
expect(policy).toEqual(SEMA_HOLDS_BY_INTENT.commit._default);
|
|
});
|
|
|
|
it('returns the per-intent override when present', () => {
|
|
const policy = resolveHoldsByIntent('commit', 'fulfill');
|
|
expect(policy).toEqual(SEMA_HOLDS_BY_INTENT.commit.fulfill);
|
|
});
|
|
|
|
it('returns undefined for an unknown family', () => {
|
|
const policy = resolveHoldsByIntent(undefined);
|
|
expect(policy).toBeUndefined();
|
|
});
|
|
});
|