feat: Telegram fleet alerts, forge sigil scramble, UI polish, agent ops

- Calibrate: per-event Telegram/SMTP toggles, test notification, chat ID help
- Notify on agent connect/reconnect, offline/hashrate/rejection, forge complete
- Sigil scramble post-forge uniquification and Dispense Reveal ceremony
- Full system check, desktop push, BITS/host-binary persistence, Path Tracer
- Dashboard/Crucible visual polish, haptics, sacred geometry, mobile nav
- README documents alerts, sigil scramble, and pack-usb workflow
- USB bundle repacked via pack-usb.bat (AetherForge.exe + synced agent source)
This commit is contained in:
AetherForge
2026-06-03 20:32:59 -07:00
parent 03937edba7
commit d52479c9a6
139 changed files with 10611 additions and 369 deletions

View File

@@ -0,0 +1,63 @@
import { describe, expect, it } from 'vitest';
import {
generateSampleSeries,
validateChartSeries,
resolveChartSeries,
chartSeriesDelta,
chartSeriesPeak,
SAMPLE_CONTRIBUTION_BARS,
SAMPLE_FLEET_PREVIEW,
} from './chartSampleData';
describe('chartSampleData', () => {
const kinds = ['hashrate', 'accept', 'cpu', 'mem', 'gpu'] as const;
it.each(kinds)('generateSampleSeries(%s) validates', (kind) => {
const series = generateSampleSeries(kind, 48);
expect(series).toHaveLength(48);
const v = validateChartSeries(series);
expect(v.ok, v.errors.join('; ')).toBe(true);
expect(chartSeriesPeak(series)).toBeGreaterThan(0);
});
it('hashrate sample trends upward (mining ramp)', () => {
const series = generateSampleSeries('hashrate', 48);
expect(series[series.length - 1].value).toBeGreaterThan(series[0].value);
const delta = chartSeriesDelta(series);
expect(delta).not.toBeNull();
expect(delta!).toBeGreaterThan(0);
});
it('accept sample stays in realistic pool band', () => {
const series = generateSampleSeries('accept', 48);
for (const p of series) {
expect(p.value).toBeGreaterThanOrEqual(90);
expect(p.value).toBeLessThanOrEqual(100);
}
});
it('resolveChartSeries uses sample when live is empty', () => {
const { data, mode } = resolveChartSeries([], 'hashrate');
expect(mode).toBe('sample');
expect(data.length).toBe(48);
expect(validateChartSeries(data).ok).toBe(true);
});
it('resolveChartSeries prefers live when enough points', () => {
const live = generateSampleSeries('cpu', 20).map((p, i) => ({
...p,
value: 40 + i * 0.5,
}));
const { data, mode } = resolveChartSeries(live, 'cpu');
expect(mode).toBe('live');
expect(data.length).toBe(20);
});
it('preview constants are internally consistent', () => {
const totalPct = SAMPLE_CONTRIBUTION_BARS.reduce((s, b) => s + b.pct, 0);
expect(totalPct).toBeGreaterThan(98);
expect(totalPct).toBeLessThan(102);
expect(SAMPLE_FLEET_PREVIEW.hashrate).toBeGreaterThan(50_000);
expect(SAMPLE_FLEET_PREVIEW.xmrPerDay).toBeGreaterThan(0);
});
});