fix: prod-bundle boot, cloud-existence leak, observation gating (final review)

- Wrap main.js body in async main() to eliminate top-level await deadlock in Rollup
- Add npc.lastPlan so clouds persist after hidden arrival/destruction until analytic envelope expires
- Add maxEnvelopeArrival() helper; rewrite playerClouds() to use lastPlan for envelope-gated clouds
- Block markSeen() while player is mid-lane (no observation from hyperspace)
- Pass obsSys=null to playerClouds when player is in a lane (don't exclude visible band from hyperspace)
- Galaxy map clicks now select-only (intel); jumps via Nav buttons / gate diamonds only
- Add preview script, favicon no-op, .playwright-mcp/ and *.png to .gitignore, update README controls text
This commit is contained in:
2026-06-12 15:35:20 +00:00
parent 395c0e851d
commit 051a111855
11 changed files with 116 additions and 78 deletions
+17 -1
View File
@@ -1,5 +1,5 @@
import { describe, it, expect } from 'vitest';
import { cloudFor, excludeVisibleBand, totalMass } from '../src/sim/clouds.js';
import { cloudFor, excludeVisibleBand, totalMass, playerClouds } from '../src/sim/clouds.js';
// Synthetic 3-lane chain: systems 0-1-2-3, each lane 2 days.
function chainGalaxy() {
@@ -88,4 +88,20 @@ describe('clouds', () => {
expect(JSON.stringify(cloudFor(g, doomed, t))).toBe(JSON.stringify(cloudFor(g, intact, t)));
}
});
it('a cloud persists after a hidden early arrival or destruction until the envelope expires', () => {
const g = chainGalaxy();
const lastPlan = chainPlan();
lastPlan.routeLanes = [0, 1, 2];
lastPlan.startSys = 0;
const world = {
t: 4.5, // past a truncated arrival, inside the envelope (max = 6 * 1.15 * 1.6 = 11.04)
galaxy: g,
npcs: [{ id: 0, name: 'Ghost', alive: false, state: 'destroyed', plan: null, lastPlan }],
player: { seenNpcs: new Set([0]) },
};
expect(playerClouds(world, null).length).toBe(1);
world.t = 12; // envelope exhausted: cloud finally gone
expect(playerClouds(world, null)).toEqual([]);
});
});