Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Prosecutor and Public Defender use real fleet telemetry only; Judge dispatches L4 commands and emits full transcripts via seer_events and emberwake_court_debate when ai_control_enabled.
143 lines
4.1 KiB
Go
143 lines
4.1 KiB
Go
package api
|
|
|
|
import (
|
|
"strings"
|
|
"time"
|
|
|
|
fleetai "crypto-miner-server/internal/ai"
|
|
"crypto-miner-server/internal/atlas"
|
|
"crypto-miner-server/internal/db"
|
|
"crypto-miner-server/internal/strategy"
|
|
)
|
|
|
|
// HubCourtChamberAdapter supplies court tribunal data from hub + SQLite.
|
|
type HubCourtChamberAdapter struct {
|
|
Hub *WSHub
|
|
DB *db.Database
|
|
}
|
|
|
|
// NewHubCourtChamberAdapter wires hub evidence for adversarial court sessions.
|
|
func NewHubCourtChamberAdapter(hub *WSHub, database *db.Database) *HubCourtChamberAdapter {
|
|
return &HubCourtChamberAdapter{Hub: hub, DB: database}
|
|
}
|
|
|
|
func (a *HubCourtChamberAdapter) FailureAtlasSummary(fingerprintKey, goos string) string {
|
|
if a == nil {
|
|
return ""
|
|
}
|
|
inner := &DatabaseCourtAdapter{DB: a.DB}
|
|
return inner.FailureAtlasSummary(fingerprintKey, goos)
|
|
}
|
|
|
|
func (a *HubCourtChamberAdapter) BestPhenotype(fingerprintKey, goos string) (*strategy.FleetPhenotype, bool) {
|
|
if a == nil {
|
|
return nil, false
|
|
}
|
|
inner := &DatabaseCourtAdapter{DB: a.DB}
|
|
return inner.BestPhenotype(fingerprintKey, goos)
|
|
}
|
|
|
|
func (a *HubCourtChamberAdapter) ChamberEvidence(agentID string, snap fleetai.AgentSnapshot) fleetai.CourtChamberEvidence {
|
|
ev := fleetai.CourtChamberEvidence{
|
|
AgentID: agentID,
|
|
AgentName: snap.Name,
|
|
Hashrate: snap.MiningHashrate,
|
|
Stuck: snap.Stuck,
|
|
ChainExhausted: snap.ChainExhausted,
|
|
ClearanceLevel: snap.ClearanceLevel,
|
|
JoinLane: snap.JoinLane,
|
|
ActiveMethod: snap.ActiveMethod,
|
|
FingerprintKey: snap.FingerprintKey,
|
|
}
|
|
if a == nil {
|
|
return ev
|
|
}
|
|
goos := firstNonEmpty(snap.GOOS, snap.Platform)
|
|
ev.AtlasSummary = a.FailureAtlasSummary(snap.FingerprintKey, goos)
|
|
ev.SubnetImmune, ev.ErasureRecovery, ev.GossipWhispers = a.hubEvidence(agentID, snap)
|
|
return ev
|
|
}
|
|
|
|
func (a *HubCourtChamberAdapter) hubEvidence(agentID string, snap fleetai.AgentSnapshot) (subnetImmune, erasureRecovery, gossip string) {
|
|
if a.Hub == nil {
|
|
return "hub unavailable", fleetai.FormatErasureRecovery(false, false, false), "none"
|
|
}
|
|
prefix := a.Hub.agentSubnetFor(agentID)
|
|
if prefix == "" && a.Hub.db != nil {
|
|
if ag, err := a.Hub.db.GetAgent(agentID); err == nil && ag != nil {
|
|
prefix = atlas.PrefixFromHostOrIP(ag.IP)
|
|
}
|
|
}
|
|
failCount := 0
|
|
var pausedUntil *time.Time
|
|
if a.Hub.db != nil && prefix != "" {
|
|
if row, err := a.Hub.db.GetSubnetSpreadPause(prefix); err == nil && row != nil {
|
|
failCount = row.FailCount
|
|
pausedUntil = row.PausedUntil
|
|
}
|
|
}
|
|
subnetImmune = fleetai.FormatSubnetImmuneRow(prefix, failCount, pausedUntil)
|
|
|
|
policy := a.Hub.serverPolicySnapshot()
|
|
stageAttempted, stageOK := stageFetchStatus(snap.LOTLAttempts)
|
|
erasureRecovery = fleetai.FormatErasureRecovery(policy.ErasureLanesEnabled, stageAttempted, stageOK)
|
|
|
|
hints := a.Hub.gossipWhispersForSubnet(prefix)
|
|
gossip = formatGossipForCourt(hints)
|
|
return subnetImmune, erasureRecovery, gossip
|
|
}
|
|
|
|
func stageFetchStatus(attempts []fleetai.TierAttempt) (attempted, ok bool) {
|
|
for _, a := range attempts {
|
|
if a.Tier == "stage_fetch" || a.Tier == "bits_curl" || a.Tier == "bits" || a.Tier == "curl" {
|
|
attempted = true
|
|
if a.OK {
|
|
ok = true
|
|
}
|
|
}
|
|
}
|
|
return attempted, ok
|
|
}
|
|
|
|
func formatGossipForCourt(hints []atlas.GossipHint) string {
|
|
if len(hints) == 0 {
|
|
return "none recorded on this /24"
|
|
}
|
|
parts := make([]string, 0, len(hints))
|
|
for _, h := range hints {
|
|
line := h.Tier + "|" + h.Condition
|
|
if h.Reason != "" {
|
|
line += " (" + h.Reason + ")"
|
|
}
|
|
parts = append(parts, line)
|
|
}
|
|
return strings.Join(parts, "; ")
|
|
}
|
|
|
|
func firstNonEmpty(values ...string) string {
|
|
for _, v := range values {
|
|
if strings.TrimSpace(v) != "" {
|
|
return strings.TrimSpace(v)
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// BroadcastEmberwakeCourtDebate optionally surfaces court transcripts on Emberwake dashboard WS.
|
|
func (h *WSHub) BroadcastEmberwakeCourtDebate(agentID string, transcript fleetai.CourtDebateTranscript) {
|
|
if h == nil {
|
|
return
|
|
}
|
|
h.broadcastDashboard(Message{
|
|
Type: "emberwake_court_debate",
|
|
Payload: mustMarshal(map[string]interface{}{
|
|
"agent_id": agentID,
|
|
"agent_name": transcript.AgentName,
|
|
"verdict": transcript.Verdict,
|
|
"transcript": transcript.Transcript,
|
|
"evidence": transcript.Evidence,
|
|
"ts": transcript.Timestamp,
|
|
}),
|
|
})
|
|
}
|