Preuve · code, extrait

telemetry.go

Dépôt apteva/server · commit b1d72aa5f0326d40536b7cdd280733edeb9a285b · plateforme Apteva, serveur, clone du 13 septembre 2026

Extrait tel qu'à ce commit : lignes 589–649, sur 1 386 (numérotation d'origine, 30 lignes de contexte autour de chaque citation) · fichier intégral sur GitHub (dépôt public)

Lignes citées par l'audit : 619

61 lignes reproduites · ← retour à l'audit · catalogue des preuves

589		return
590	}
591
592	if err := s.store.InsertTelemetry(events); err != nil {
593		http.Error(w, "insert failed: "+err.Error(), http.StatusInternalServerError)
594		return
595	}
596	// React to directive changes — update DB so dashboard sees it immediately
597	for _, ev := range events {
598		if ev.Type == "directive.evolved" && ev.AgentID > 0 {
599			var data struct {
600				New string `json:"new"`
601			}
602			if json.Unmarshal(ev.Data, &data) == nil && data.New != "" {
603				if _, err := s.store.db.Exec("UPDATE agents SET directive=? WHERE id=?", data.New, ev.AgentID); err == nil {
604					// Do not make Core's telemetry ingestion wait on re-entrant
605					// per-thread HTTP updates. Persistence is complete; each thread's
606					// next delivery also performs the same drift check defensively.
607					go s.refreshChannelChatConversationDirectives(ev.AgentID)
608				}
609			}
610		}
611	}
612
613	// No broadcast here — /telemetry/live handles real-time broadcast.
614	// This endpoint is for DB persistence only.
615
616	writeJSON(w, map[string]int{"inserted": len(events)})
617}
618
619const storedToolResultPreviewBytes = 1000
620
621// sanitizeStoredToolResultTelemetry is a defensive server-side bound. New
622// cores already send a preview plus exact size metadata, but this also keeps
623// inline results from older cores from persisting an unbounded payload.
624func sanitizeStoredToolResultTelemetry(events []TelemetryEvent) {
625	for i := range events {
626		if events[i].Type != "tool.result" || len(events[i].Data) == 0 {
627			continue
628		}
629		var data map[string]any
630		if json.Unmarshal(events[i].Data, &data) != nil {
631			continue
632		}
633		result, ok := data["result"].(string)
634		if !ok {
635			continue
636		}
637		alreadyTruncated, _ := data["result_truncated"].(bool)
638		if len(result) > storedToolResultPreviewBytes && !(alreadyTruncated && len(result) <= storedToolResultPreviewBytes+3) {
639			end := storedToolResultPreviewBytes
640			for end > 0 && !utf8.ValidString(result[:end]) {
641				end--
642			}
643			result = result[:end] + "..."
644			data["result"] = result
645			alreadyTruncated = true
646		}
647		data["result_preview_bytes"] = len(result)
648		data["result_truncated"] = alreadyTruncated
649		if raw, err := json.Marshal(data); err == nil {