Files
WHOOSH/internal/server/bootstrap.go
Claude Code 3373f7b462
Some checks failed
WHOOSH CI / speclint (push) Has been cancelled
WHOOSH CI / contracts (push) Has been cancelled
Add chorus-entrypoint label to standardized label set
**Problem**: The standardized label set was missing the `chorus-entrypoint`
label, which is present in CHORUS repository and required for triggering
council formation for project kickoffs.

**Changes**:
- Added `chorus-entrypoint` label (#ff6b6b) to `EnsureRequiredLabels()`
  in `internal/gitea/client.go`
- Now creates 9 standard labels (was 8):
  1. bug
  2. bzzz-task
  3. chorus-entrypoint (NEW)
  4. duplicate
  5. enhancement
  6. help wanted
  7. invalid
  8. question
  9. wontfix

**Testing**:
- Rebuilt and deployed WHOOSH with updated label configuration
- Synced labels to all 5 monitored repositories (whoosh-ui,
  SequentialThinkingForCHORUS, TEST, WHOOSH, CHORUS)
- Verified all repositories now have complete 9-label set

**Impact**: All CHORUS ecosystem repositories now have consistent labeling
matching the CHORUS repository standard, enabling proper council formation
triggers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-12 22:06:10 +11:00

123 lines
3.8 KiB
Go

package server
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/rs/zerolog/log"
)
// BootstrapPeer represents a libp2p bootstrap peer for CHORUS agent discovery
type BootstrapPeer struct {
Multiaddr string `json:"multiaddr"` // libp2p multiaddr format: /ip4/{ip}/tcp/{port}/p2p/{peer_id}
PeerID string `json:"peer_id"` // libp2p peer ID
Name string `json:"name"` // Human-readable name
Priority int `json:"priority"` // Priority order (1 = highest)
}
// HandleBootstrapPeers returns list of bootstrap peers for CHORUS agent discovery
// GET /api/bootstrap-peers
//
// This endpoint provides a dynamic list of bootstrap peers that new CHORUS agents
// should connect to when joining the P2P mesh. The list includes:
// 1. HMMM monitor (priority 1) - For traffic observation
// 2. First 3 stable agents (priority 2-4) - For mesh formation
//
// Response format:
// {
// "bootstrap_peers": [
// {
// "multiaddr": "/ip4/172.27.0.6/tcp/9001/p2p/12D3Koo...",
// "peer_id": "12D3Koo...",
// "name": "hmmm-monitor",
// "priority": 1
// }
// ],
// "updated_at": "2025-01-15T10:30:00Z"
// }
func (s *Server) HandleBootstrapPeers(w http.ResponseWriter, r *http.Request) {
log.Info().Msg("📡 Bootstrap peers requested")
var bootstrapPeers []BootstrapPeer
// Get ALL connected agents from discovery - return complete dynamic list
// This allows new agents AND the hmmm-monitor to discover the P2P mesh
agents := s.p2pDiscovery.GetAgents()
log.Debug().Int("total_agents", len(agents)).Msg("Discovered agents for bootstrap list")
// HTTP client for fetching agent health endpoints
client := &http.Client{Timeout: 5 * time.Second}
for priority, agent := range agents {
if agent.Endpoint == "" {
log.Warn().Str("agent", agent.ID).Msg("Agent has no endpoint, skipping")
continue
}
// Query agent health endpoint to get peer_id and multiaddrs
healthURL := fmt.Sprintf("%s/api/health", strings.TrimRight(agent.Endpoint, "/"))
log.Debug().Str("agent", agent.ID).Str("health_url", healthURL).Msg("Fetching agent health")
resp, err := client.Get(healthURL)
if err != nil {
log.Warn().Str("agent", agent.ID).Err(err).Msg("Failed to fetch agent health")
continue
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
log.Warn().Str("agent", agent.ID).Int("status", resp.StatusCode).Msg("Agent health check failed")
continue
}
var health struct {
PeerID string `json:"peer_id"`
Multiaddrs []string `json:"multiaddrs"`
}
if err := json.NewDecoder(resp.Body).Decode(&health); err != nil {
log.Warn().Str("agent", agent.ID).Err(err).Msg("Failed to decode health response")
continue
}
// Add only the first multiaddr per agent to avoid duplicates
// Each agent may have multiple interfaces but we only need one for bootstrap
if len(health.Multiaddrs) > 0 {
bootstrapPeers = append(bootstrapPeers, BootstrapPeer{
Multiaddr: health.Multiaddrs[0],
PeerID: health.PeerID,
Name: agent.ID,
Priority: priority + 1,
})
log.Debug().
Str("agent_id", agent.ID).
Str("peer_id", health.PeerID).
Str("multiaddr", health.Multiaddrs[0]).
Int("priority", priority+1).
Msg("Added agent to bootstrap list")
}
}
response := map[string]interface{}{
"bootstrap_peers": bootstrapPeers,
"updated_at": time.Now(),
"count": len(bootstrapPeers),
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil {
log.Error().Err(err).Msg("Failed to encode bootstrap peers response")
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
log.Info().
Int("peer_count", len(bootstrapPeers)).
Msg("✅ Bootstrap peers list returned")
}