package api import ( "encoding/json" "crypto-miner-server/internal/epidemiology" "crypto-miner-server/internal/miningsurgery" ) func (h *WSHub) miningSurgeryTracker() *miningsurgery.Tracker { if h == nil { return nil } return h.miningSurgery } // WireDefaultMiningSurgeryReporter connects self-surgery telemetry to Seer + oath ledger. func (h *WSHub) WireDefaultMiningSurgeryReporter() { if h == nil { return } tr := h.miningSurgeryTracker() if tr == nil { return } tr.SetReporter(miningsurgery.Reporter{ OnSeer: func(ev miningsurgery.SeerEvent) { h.broadcastSeerEvent(epidemiology.SeerEvent{ Kind: ev.Kind, AgentID: ev.AgentID, Payload: ev.Payload, Timestamp: ev.Timestamp, }) if h.db != nil { _, _ = h.db.InsertSeerEvent(ev.Kind, ev.AgentID, ev.Payload) } }, OnOath: func(agentID, actor, actionType, strain, whyHash, outcome string, payload map[string]interface{}) { if h.db == nil { return } _, _ = h.db.InsertOathLedger(actor, actionType, agentID, strain, whyHash, outcome, payload) }, }) } func (h *WSHub) observeMiningSelfSurgeryFromStats(agentID string, stats epidemiology.StatsInput) { if h == nil || agentID == "" { return } if !h.serverPolicySnapshot().AIControlEnabled { return } tr := h.miningSurgeryTracker() if tr == nil { return } idlePct := h.defaultIdleThresholdPct() if state := epidemiology.DetectInterruption(agentID, stats); state != nil { plan := miningsurgery.ComposeFromInterrupt(*state, idlePct) tr.QueuePlan(plan) return } if miningsurgery.DetectLowHashrate(stats, miningsurgery.DefaultLowHashrateHPS) { hr := stats.MiningHashrate if hr <= 0 { hr = stats.Hashrate15m } plan := miningsurgery.ComposeFromLowHashrate(agentID, stats.ActiveMethod, hr, idlePct) tr.QueuePlan(plan) } } func (h *WSHub) defaultIdleThresholdPct() int { return 20 } func (h *WSHub) attachMiningSelfSurgery(resp map[string]interface{}, agentID string) { tr := h.miningSurgeryTracker() if tr == nil { return } plan, ok := tr.ConsumePlan(agentID) if !ok { return } resp["mining_self_surgery"] = plan } func (h *WSHub) handleSelfSurgeryReport(agentID string, payload json.RawMessage) { tr := h.miningSurgeryTracker() if tr == nil { return } var report struct { Outcome string `json:"outcome"` Results []map[string]interface{} `json:"results"` } if json.Unmarshal(payload, &report) != nil { report.Outcome = "applied" } if report.Outcome == "" { report.Outcome = "applied" } tr.RecordOutcome(agentID, report.Outcome, report.Results) }