fix(v0.3.1): storyline beats manifesto L1+ (only L0 alive emergencies override)
Found in live logs after the previous commit deployed: storyline: step 1/11: orient_self → explore.wander advisor-trigger: firing because wedged (planned=survive.acquire-food, ...) Manifesto was still picking survive.acquire-food (L1 food) over the storyline's orient_self → explore.wander. That's the wrong precedence — storyline expresses a *concrete operational subgoal* and L1+ manifesto needs are just "you'd benefit from food" priorities, not emergencies. New dispatch precedence in curriculumReflex: 1. manifesto L0 (alive emergencies: lava, low-HP+hostile, food=0) 2. storyline (concrete narrative subgoal — beats L1+ manifesto) 3. manifesto L1+ (fallback when storyline has no concrete suggestion) 4. curriculum plan (legacy fallback) This way the bot starts following the narrative arc even while manifesto's L1 food is technically unsatisfied — orient_self runs to completion before pursuing food explicitly. Storyline already handles food as step 5 (first_food), so we're not skipping it. Tests: 378 green (+2 priority-ordering tests): - L0 manifesto emergency: upstream reflex (defend/modes) catches before curriculum dispatch - storyline beats manifesto when both have suggestions: well-fed bot with logs → craft.planks (storyline crafting_basics), not gather.logs (manifesto L2) - updated "manifesto fallback" test to require disableStoryline=true Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+58
-1
@@ -242,9 +242,10 @@ test("curriculum dispatches suggested skill by id", () => {
|
||||
assert.ok(typeof dispatches[0].opts.onComplete === "function");
|
||||
});
|
||||
|
||||
test("manifesto: hungry bot with no food drives survive.acquire-food (overrides curriculum plan)", () => {
|
||||
test("manifesto: hungry bot with no food drives survive.acquire-food (manifesto fallback when storyline disabled)", () => {
|
||||
const { ctx, dispatches } = makeCtx({
|
||||
disableManifesto: false,
|
||||
disableStoryline: true,
|
||||
snapshot: {
|
||||
connected: true,
|
||||
health: 20,
|
||||
@@ -264,6 +265,62 @@ test("manifesto: hungry bot with no food drives survive.acquire-food (overrides
|
||||
assert.equal(ctx.activeNeed?.need?.id, "food");
|
||||
});
|
||||
|
||||
test("L0 manifesto emergency: defend/modes layer catches the threat BEFORE curriculum", () => {
|
||||
// HP=4 + creeper@3m fires `modes` (self_preservation) or defendReflex
|
||||
// before curriculum even runs — which is the right outcome: alive
|
||||
// emergencies don't reach the storyline/manifesto branch at all.
|
||||
const { ctx, dispatches } = makeCtx({
|
||||
disableManifesto: false,
|
||||
disableStoryline: false,
|
||||
bot: { entities: { z1: { name: "creeper", height: 1.7, position: { x: 3, y: 64, z: 0, distanceTo: () => 3 } } }, entity: { position: { x: 0, y: 64, z: 0 } } },
|
||||
snapshot: {
|
||||
connected: true,
|
||||
health: 4,
|
||||
food: 12,
|
||||
hasFood: false,
|
||||
inventory: { oak_log: 10 },
|
||||
equipment: {},
|
||||
nearbyBlocks: { logs: 4 },
|
||||
hazards: { footBlock: "grass_block", belowBlock: "dirt", headBlock: "air" },
|
||||
closestHostile: { name: "creeper", distance: 3 },
|
||||
threats: [{ name: "creeper", distance: 3, position: { x: 3, y: 64, z: 0 } }],
|
||||
isDay: true,
|
||||
curriculum: { plan: { skillId: "gather.logs" } },
|
||||
},
|
||||
});
|
||||
const out = runTick(ctx);
|
||||
assert.notEqual(out?.kind, "curriculum-skill", "an upstream reflex caught the emergency before curriculum");
|
||||
});
|
||||
|
||||
test("storyline beats manifesto L1+ when both have suggestions", () => {
|
||||
// Snapshot: well-fed (food=20 + 8 bread → manifesto L1 satisfied, L2
|
||||
// tools_wood unmet) AND storyline orient_self complete (HP=20, blocks
|
||||
// visible). Storyline should drive a wood-tier crafting step, not
|
||||
// manifesto's gather.logs (which would also be valid but less concrete).
|
||||
const { ctx, dispatches } = makeCtx({
|
||||
disableManifesto: false,
|
||||
disableStoryline: false,
|
||||
snapshot: {
|
||||
connected: true,
|
||||
health: 20,
|
||||
food: 20,
|
||||
hasFood: true,
|
||||
inventory: { bread: 8, oak_log: 10 }, // logs done, no planks
|
||||
equipment: {},
|
||||
nearbyBlocks: { logs: 3 },
|
||||
hazards: { footBlock: "grass_block", belowBlock: "dirt", headBlock: "air" },
|
||||
isDay: true,
|
||||
_sessionMs: 60_000,
|
||||
curriculum: { plan: { skillId: "explore.far" } },
|
||||
},
|
||||
});
|
||||
const out = runTick(ctx);
|
||||
assert.equal(out.reflex, "curriculum");
|
||||
// Storyline step crafting_basics suggests craft.planks (10 logs, no planks yet).
|
||||
assert.equal(dispatches[0].label, "craft.planks");
|
||||
assert.equal(ctx.storyStep?.step?.id, "crafting_basics");
|
||||
});
|
||||
|
||||
test("manifesto: well-fed bot with all wood tools defers to curriculum plan", () => {
|
||||
const { ctx, dispatches } = makeCtx({
|
||||
disableManifesto: false,
|
||||
|
||||
Reference in New Issue
Block a user