feat(#61): named leaders — assassination / death / appointment with succession (v0.38.0)
CI / build + unit + e2e (pull_request) Successful in 2m33s
CI / build + unit + e2e (pull_request) Successful in 2m33s
Per-nation named leaders (Nation.leader) and a required TurnResult.leaders
lever ({ changes: [{ target, name, cause }] }). Each change sets the target
nation's leader and applies a deterministic stability dip by cause
(assassination -15, death -3, appointed 0) mirrored to its regions and
re-derived into its stats, plus a narration event (military for an
assassination, political for a death/appointment). An assassination/death
requires the target to already have a leader (a leaderless target is
dropped); an appointment always creates/sets one. Unknown/ambiguous targets
are dropped, never thrown.
- shared/types.ts: optional Nation.leader
- shared/protocol.ts: LeaderCause/LeaderChange/LeaderOps, LEADER_STABILITY_EFFECT,
TurnResult.leaders (required, between nuclear and markers), leader in nationForPrompt
- server/engine.ts: validateLeaderOps, applyLeaderChange, the applyTurnResult
leader block (after nuclear, before markers), isMeaningful, system-prompt
contract + constraint, validateTurnResult + runTurn fallback
- server/stub.ts: leaders always { changes: [] } (e2e unaffected)
- tests: 15 engine.test.ts leader tests + 2 db.test.ts round-trips
- version 0.37.0 -> 0.38.0, CHANGELOG entry
This commit is contained in:
@@ -200,6 +200,28 @@ describe('openDb', () => {
|
||||
db.close();
|
||||
});
|
||||
|
||||
it('(v0.38.0 #61) a legacy row saved before the nation leader field existed loads with it absent (no leader)', () => {
|
||||
const db = openDb(':memory:');
|
||||
// makeState has no nation.leader field — a pre-v0.38 save. The field is
|
||||
// optional and not re-stamped by load, so an absent leader stays absent.
|
||||
db.save(makeState('legacy'));
|
||||
const loaded = db.load('legacy');
|
||||
expect(loaded).not.toBeNull();
|
||||
expect(loaded!.nations.uk.leader).toBeUndefined();
|
||||
db.close();
|
||||
});
|
||||
|
||||
it('(v0.38.0 #61) a set nation leader round-trips through save/load', () => {
|
||||
const db = openDb(':memory:');
|
||||
const s = makeState('ldr');
|
||||
s.nations.uk.leader = { name: 'Admiral Old' };
|
||||
db.save(s);
|
||||
const loaded = db.load('ldr');
|
||||
expect(loaded).not.toBeNull();
|
||||
expect(loaded!.nations.uk.leader).toEqual({ name: 'Admiral Old' });
|
||||
db.close();
|
||||
});
|
||||
|
||||
it('delete removes a game by id and reports absence otherwise', () => {
|
||||
const db = openDb(':memory:');
|
||||
db.save(makeState('a'));
|
||||
|
||||
Reference in New Issue
Block a user