Add scout constellation mode for APK venue persona packs.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Cluster 3+ scout_report hits on the same SSID within 10 minutes; server infers airport/campus/retail venue class and pushes persona spread_policy. Emberwake weather-map merges active scout biomes. Includes agent, server API, and Vitest coverage.
This commit is contained in:
@@ -54,6 +54,7 @@ export interface AccessDepthServerPolicy {
|
||||
lotl_onion_tiers?: string[];
|
||||
mining_tier_order?: string[];
|
||||
mining_skip_tiers?: string[];
|
||||
graft_enabled?: boolean;
|
||||
triple_onion?: {
|
||||
recon_tiers?: string[];
|
||||
deploy_lanes?: string[];
|
||||
@@ -521,6 +522,8 @@ export function buildAccessDepthModel(
|
||||
export function parseAccessDepthServerPolicy(config: {
|
||||
server?: {
|
||||
lotl_onion_tiers?: string[];
|
||||
ai_control_enabled?: boolean;
|
||||
fleet_roles_enabled?: boolean;
|
||||
triple_onion_policy?: {
|
||||
recon_tiers?: string[];
|
||||
deploy_lanes?: string[];
|
||||
@@ -528,9 +531,12 @@ export function parseAccessDepthServerPolicy(config: {
|
||||
};
|
||||
}): AccessDepthServerPolicy {
|
||||
const server = config.server;
|
||||
const graftEnabled =
|
||||
server?.ai_control_enabled === true && server?.fleet_roles_enabled === true;
|
||||
return {
|
||||
lotl_onion_tiers: server?.lotl_onion_tiers,
|
||||
mining_tier_order: [...DEFAULT_MINING_TIER_ORDER],
|
||||
graft_enabled: graftEnabled,
|
||||
triple_onion: server?.triple_onion_policy
|
||||
? {
|
||||
recon_tiers: server.triple_onion_policy.recon_tiers,
|
||||
|
||||
29
server/web/src/help/scoutBiomeWeather.test.ts
Normal file
29
server/web/src/help/scoutBiomeWeather.test.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { PAGE_WEATHER } from './pageWeather';
|
||||
import { dominantScoutVenue, mergeScoutBiomeWeather } from './scoutBiomeWeather';
|
||||
|
||||
describe('scoutBiomeWeather', () => {
|
||||
it('picks dominant venue by agent weight', () => {
|
||||
const venue = dominantScoutVenue({
|
||||
constellations: [
|
||||
{ ssid: 'a', venue_class: 'campus', agent_ids: ['1', '2', '3'] },
|
||||
{ ssid: 'b', venue_class: 'airport', agent_ids: ['4', '5', '6', '7'] },
|
||||
],
|
||||
});
|
||||
expect(venue).toBe('airport');
|
||||
});
|
||||
|
||||
it('boosts emberwake pulse for retail scout biome', () => {
|
||||
const base = PAGE_WEATHER['/emberwake'];
|
||||
const merged = mergeScoutBiomeWeather(base, {
|
||||
constellations: [{ ssid: 'Target-Guest', venue_class: 'retail', agent_ids: ['a', 'b', 'c'] }],
|
||||
});
|
||||
expect(merged.pulse).toBeGreaterThan(base.pulse);
|
||||
expect(merged.energyPulse).toBe(true);
|
||||
});
|
||||
|
||||
it('returns base weather when no constellations', () => {
|
||||
const base = PAGE_WEATHER['/dashboard'];
|
||||
expect(mergeScoutBiomeWeather(base, null)).toEqual(base);
|
||||
});
|
||||
});
|
||||
56
server/web/src/help/scoutBiomeWeather.ts
Normal file
56
server/web/src/help/scoutBiomeWeather.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
/** Scout constellation venue → ambient weather biome overlay. */
|
||||
|
||||
import type { PageWeatherConfig } from './pageWeather';
|
||||
|
||||
export interface ScoutConstellationBiome {
|
||||
ssid: string;
|
||||
venue_class: string;
|
||||
persona_pack?: string;
|
||||
agent_ids?: string[];
|
||||
hits?: number;
|
||||
}
|
||||
|
||||
export interface ScoutConstellationSnapshot {
|
||||
constellations?: ScoutConstellationBiome[];
|
||||
}
|
||||
|
||||
const VENUE_BIOME: Record<string, Partial<PageWeatherConfig>> = {
|
||||
airport: { pulse: 1.35, linkStrength: 0.92, density: 0.95, palette: 'campaign' },
|
||||
campus: { pulse: 1.1, linkStrength: 0.82, density: 0.88, palette: 'default' },
|
||||
retail: { pulse: 1.75, speed: 0.62, linkStrength: 0.88, palette: 'campaign', energyPulse: true },
|
||||
unknown: { pulse: 0.95, linkStrength: 0.7, density: 0.8 },
|
||||
};
|
||||
|
||||
/** Pick the dominant venue class from active scout constellations. */
|
||||
export function dominantScoutVenue(snapshot: ScoutConstellationSnapshot | null | undefined): string | null {
|
||||
const list = snapshot?.constellations ?? [];
|
||||
if (!list.length) return null;
|
||||
const rank: Record<string, number> = { airport: 4, retail: 3, campus: 2, unknown: 1 };
|
||||
let best = list[0].venue_class || 'unknown';
|
||||
let bestScore = (list[0].agent_ids?.length ?? 1) * (rank[best] ?? 1);
|
||||
for (let i = 1; i < list.length; i++) {
|
||||
const venue = list[i].venue_class || 'unknown';
|
||||
const score = (list[i].agent_ids?.length ?? 1) * (rank[venue] ?? 1);
|
||||
if (score > bestScore) {
|
||||
best = venue;
|
||||
bestScore = score;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/** Merge fleet scout biome hints into route weather (Emberwake / dashboard). */
|
||||
export function mergeScoutBiomeWeather(
|
||||
base: PageWeatherConfig,
|
||||
snapshot: ScoutConstellationSnapshot | null | undefined,
|
||||
): PageWeatherConfig {
|
||||
const venue = dominantScoutVenue(snapshot);
|
||||
if (!venue) return base;
|
||||
const overlay = VENUE_BIOME[venue] ?? VENUE_BIOME.unknown;
|
||||
return {
|
||||
...base,
|
||||
...overlay,
|
||||
intensity: Math.min(1, (base.intensity + (overlay.intensity ?? base.intensity)) / 2 + 0.08),
|
||||
energyPulse: overlay.energyPulse ?? base.energyPulse,
|
||||
};
|
||||
}
|
||||
@@ -156,6 +156,10 @@ export const UI_HELP: Record<string, string> = {
|
||||
md_preflight:
|
||||
'Wallet, control URL, and worker name must pass validation before Equip & Strike unlocks. Spread Kit export is skipped automatically when your loadout ships a single-platform or fusion deliverable instead.',
|
||||
|
||||
subnet_immune_autopsy:
|
||||
'Auto-built when a /24 hits five spread failures: last LOTL attempts, WSUS mimic, persona, erasure fallback, atlas gossip whispers, cause-of-death, and BGP vaccination lane from the spread router.',
|
||||
pt_subnet_autopsy:
|
||||
'Immune autopsy for spread-target /24 prefixes paused by subnet_spread_pause — shows vaccination route hints beside Path Tracer spread routes.',
|
||||
ew_overview:
|
||||
'Spread desk after you forge: tag install links with ?c=, export lure kits, and read campaign funnels. Forge agents on Mission Deck (fast) or Forge (full control).',
|
||||
ew_campaign_setup:
|
||||
|
||||
@@ -90,6 +90,7 @@ export const WS_LATEST_MESSAGE_TYPES = new Set([
|
||||
'notes_typing',
|
||||
'emberwake_notes_updated',
|
||||
'emberwake_war_room',
|
||||
'scout_constellations',
|
||||
'agent_online',
|
||||
'agent_offline',
|
||||
'new_share',
|
||||
|
||||
Reference in New Issue
Block a user