aureon-os / frontend /src /core /decisionExplainer.ts
GaryLeckey's picture
Deploy Aureon OS (deploy/selfhost stack: nginx edge + fusion API x2 + console + HNC organ + redis + postgres; paper mode) (part 18)
f568a4f verified
Raw History Blame Contribute Delete
9.71 kB
/**
* Decision Explainer Engine
* Traces WHY each HOLD/BUY/SELL decision was made with human-readable reasoning
*/
import { unifiedBus } from './unifiedBus';
export type DecisionAction = 'BUY' | 'SELL' | 'HOLD';
export interface DecisionFactor {
name: string;
value: number;
threshold: number;
passed: boolean;
weight: number;
contribution: string;
}
export interface DecisionExplanation {
id: string;
timestamp: number;
action: DecisionAction;
confidence: number;
factors: DecisionFactor[];
reasoning: string[];
summary: string;
inputFrequency: number;
outputFrequency: number;
prismLevel: number;
waveState: string;
symbol: string;
}
export interface DecisionMetrics {
coherence: number;
lambda: number;
lighthouseL: number;
qgitaTier: number;
qgitaConfidence: number;
prismFrequency: number;
prismLevel: number;
waveState: string;
harmonicLock: boolean;
probabilityFused: number;
sentimentScore: number;
geometricAlignment: number;
}
class DecisionExplainerClass {
private explanations: DecisionExplanation[] = [];
private readonly maxHistory = 100;
private listeners: Set<(explanation: DecisionExplanation) => void> = new Set();
explain(metrics: DecisionMetrics, symbol: string = 'BTCUSDT'): DecisionExplanation {
const factors: DecisionFactor[] = [];
const reasoning: string[] = [];
// Factor 1: Coherence Check
const coherenceThreshold = 0.70;
const coherencePassed = metrics.coherence >= coherenceThreshold;
factors.push({
name: 'Coherence (Ξ“)',
value: metrics.coherence,
threshold: coherenceThreshold,
passed: coherencePassed,
weight: 0.25,
contribution: coherencePassed ? 'SUPPORTS trade' : 'BLOCKS trade'
});
reasoning.push(
coherencePassed
? `βœ“ Coherence ${(metrics.coherence * 100).toFixed(1)}% exceeds ${coherenceThreshold * 100}% threshold`
: `βœ— Coherence ${(metrics.coherence * 100).toFixed(1)}% below ${coherenceThreshold * 100}% threshold`
);
// Factor 2: Lighthouse Signal
const lighthouseThreshold = 0.5;
const lighthousePassed = metrics.lighthouseL >= lighthouseThreshold;
factors.push({
name: 'Lighthouse (L)',
value: metrics.lighthouseL,
threshold: lighthouseThreshold,
passed: lighthousePassed,
weight: 0.20,
contribution: lighthousePassed ? 'SUPPORTS trade' : 'NEUTRAL'
});
reasoning.push(
lighthousePassed
? `βœ“ Lighthouse signal ${metrics.lighthouseL.toFixed(3)} indicates opportunity`
: `β—‹ Lighthouse signal ${metrics.lighthouseL.toFixed(3)} is neutral`
);
// Factor 3: QGITA Tier
const qgitaTierThreshold = 2;
const qgitaPassed = metrics.qgitaTier <= qgitaTierThreshold && metrics.qgitaTier > 0;
factors.push({
name: 'QGITA Tier',
value: metrics.qgitaTier,
threshold: qgitaTierThreshold,
passed: qgitaPassed,
weight: 0.20,
contribution: qgitaPassed ? `Tier ${metrics.qgitaTier} SUPPORTS` : 'LOW confidence'
});
reasoning.push(
qgitaPassed
? `βœ“ QGITA Tier ${metrics.qgitaTier} with ${(metrics.qgitaConfidence * 100).toFixed(0)}% confidence`
: `βœ— QGITA Tier ${metrics.qgitaTier} insufficient (need Tier 1-2)`
);
// Factor 4: Prism Frequency Lock
const prismLockThreshold = 500; // Near 528 Hz love frequency
const prismLocked = metrics.prismFrequency >= prismLockThreshold && metrics.prismLevel >= 4;
factors.push({
name: 'Prism Lock',
value: metrics.prismFrequency,
threshold: prismLockThreshold,
passed: prismLocked,
weight: 0.15,
contribution: prismLocked ? '528Hz ALIGNED' : 'FORMING'
});
reasoning.push(
prismLocked
? `βœ“ Prism at ${metrics.prismFrequency.toFixed(0)}Hz (Level ${metrics.prismLevel}) - 528Hz lock`
: `β—‹ Prism at ${metrics.prismFrequency.toFixed(0)}Hz (Level ${metrics.prismLevel}) - transforming`
);
// Factor 5: 6D Wave State
const bullishStates = ['ACCUMULATION', 'MARKUP', 'BULLISH'];
const bearishStates = ['DISTRIBUTION', 'MARKDOWN', 'BEARISH'];
const isBullish = bullishStates.includes(metrics.waveState.toUpperCase());
const isBearish = bearishStates.includes(metrics.waveState.toUpperCase());
factors.push({
name: '6D Wave State',
value: isBullish ? 1 : isBearish ? -1 : 0,
threshold: 0,
passed: isBullish || isBearish,
weight: 0.10,
contribution: isBullish ? 'BULLISH' : isBearish ? 'BEARISH' : 'NEUTRAL'
});
reasoning.push(
`β—‹ 6D Wave State: ${metrics.waveState} (${isBullish ? 'bullish' : isBearish ? 'bearish' : 'neutral'})`
);
// Factor 6: Harmonic Lock
factors.push({
name: 'Harmonic Lock',
value: metrics.harmonicLock ? 1 : 0,
threshold: 1,
passed: metrics.harmonicLock,
weight: 0.10,
contribution: metrics.harmonicLock ? 'LOCKED' : 'UNLOCKED'
});
reasoning.push(
metrics.harmonicLock
? `βœ“ Harmonic lock ACTIVE - enhanced confidence`
: `β—‹ Harmonic lock inactive`
);
// Calculate weighted decision
let buyScore = 0;
let sellScore = 0;
// Coherence and Lighthouse must pass for any trade
const canTrade = coherencePassed;
if (canTrade) {
// Direction from wave state and sentiment
if (isBullish || metrics.sentimentScore > 0.1) {
buyScore += 0.4;
}
if (isBearish || metrics.sentimentScore < -0.1) {
sellScore += 0.4;
}
// QGITA confidence boost
if (qgitaPassed) {
const boost = metrics.qgitaConfidence * 0.3;
if (metrics.probabilityFused > 0.5) buyScore += boost;
else if (metrics.probabilityFused < 0.5) sellScore += boost;
}
// Prism lock boost
if (prismLocked) {
buyScore += 0.15;
}
// Harmonic lock boost
if (metrics.harmonicLock) {
if (buyScore > sellScore) buyScore += 0.1;
else if (sellScore > buyScore) sellScore += 0.1;
}
}
// Determine action
let action: DecisionAction = 'HOLD';
let confidence = 0;
if (!canTrade) {
action = 'HOLD';
confidence = 1 - metrics.coherence; // High confidence in holding when coherence is low
reasoning.push(`⚠ HOLD: Coherence below threshold - waiting for field alignment`);
} else if (buyScore > sellScore && buyScore > 0.3) {
action = 'BUY';
confidence = Math.min(0.95, buyScore + (metrics.harmonicLock ? 0.1 : 0));
reasoning.push(`β†’ BUY: Score ${(buyScore * 100).toFixed(0)}% > ${(sellScore * 100).toFixed(0)}%`);
} else if (sellScore > buyScore && sellScore > 0.3) {
action = 'SELL';
confidence = Math.min(0.95, sellScore + (metrics.harmonicLock ? 0.1 : 0));
reasoning.push(`β†’ SELL: Score ${(sellScore * 100).toFixed(0)}% > ${(buyScore * 100).toFixed(0)}%`);
} else {
action = 'HOLD';
confidence = 0.5;
reasoning.push(`β†’ HOLD: No clear direction (buy: ${(buyScore * 100).toFixed(0)}%, sell: ${(sellScore * 100).toFixed(0)}%)`);
}
// Build summary
const summary = this.buildSummary(action, confidence, factors);
const explanation: DecisionExplanation = {
id: `decision-${Date.now()}-${crypto.randomUUID()}`,
timestamp: Date.now(),
action,
confidence,
factors,
reasoning,
summary,
inputFrequency: metrics.prismFrequency * 0.8, // Approximate input
outputFrequency: metrics.prismFrequency,
prismLevel: metrics.prismLevel,
waveState: metrics.waveState,
symbol
};
// Store and notify
this.explanations.unshift(explanation);
if (this.explanations.length > this.maxHistory) {
this.explanations.pop();
}
// Publish to bus
unifiedBus.publish({
systemName: 'DecisionExplainer',
timestamp: Date.now(),
ready: true,
coherence: confidence,
confidence,
signal: action === 'BUY' ? 'BUY' : action === 'SELL' ? 'SELL' : 'NEUTRAL',
data: { explanation }
});
// Notify listeners
this.listeners.forEach(listener => listener(explanation));
return explanation;
}
private buildSummary(action: DecisionAction, confidence: number, factors: DecisionFactor[]): string {
const passedFactors = factors.filter(f => f.passed).length;
const totalFactors = factors.length;
if (action === 'BUY') {
return `BUY signal with ${(confidence * 100).toFixed(0)}% confidence. ${passedFactors}/${totalFactors} factors aligned for long entry.`;
} else if (action === 'SELL') {
return `SELL signal with ${(confidence * 100).toFixed(0)}% confidence. ${passedFactors}/${totalFactors} factors aligned for short/exit.`;
} else {
return `HOLD - waiting for better conditions. ${passedFactors}/${totalFactors} factors aligned. Need stronger signal clarity.`;
}
}
getExplanations(): DecisionExplanation[] {
return [...this.explanations];
}
getLatest(): DecisionExplanation | null {
return this.explanations[0] || null;
}
subscribe(listener: (explanation: DecisionExplanation) => void): () => void {
this.listeners.add(listener);
return () => this.listeners.delete(listener);
}
clear(): void {
this.explanations = [];
}
}
export const decisionExplainer = new DecisionExplainerClass();