diff --git a/docs/release-control/v6/internal/subsystems/ai-runtime.md b/docs/release-control/v6/internal/subsystems/ai-runtime.md index 83a387de3..5cf2430d0 100644 --- a/docs/release-control/v6/internal/subsystems/ai-runtime.md +++ b/docs/release-control/v6/internal/subsystems/ai-runtime.md @@ -258,9 +258,9 @@ section from unified-resource relationships, so relationship wording and edge provenance stay aligned with the same shared resource model instead of being reconstructed from the drawer or prompt helpers. That relationship section is now rendered by the shared -`internal/unifiedresources.FormatResourceGraphContext` helper, so the service -layer only resolves the canonical resource and does not rebuild the section -format locally. +`internal/unifiedresources.FormatResourceRelationshipContext` helper, so the +service layer only resolves the canonical resource and does not rebuild the +section format locally. The canonical recent-change sentence formatting also lives in `internal/unifiedresources.FormatResourceChangeSummary`, so AI runtime prompt sections and Patrol seed context reuse the same change wording instead of diff --git a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md index 1f5a02d21..ac5d757e6 100644 --- a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md +++ b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md @@ -100,9 +100,9 @@ relationship section from unified-resource relationships, so edge labels, directionality, and provenance stay aligned with the shared relationship model instead of being reconstructed locally. That relationship section is now rendered by the shared -`internal/unifiedresources.FormatResourceGraphContext` helper, so the Patrol -runtime only resolves the canonical relationship context rather than formatting the -relationship section itself. +`internal/unifiedresources.FormatResourceRelationshipContext` helper, so the +Patrol runtime only resolves the canonical relationship context rather than +formatting the relationship section itself. Patrol-owned correlation context now also comes through the shared AI intelligence facade before reaching the detector, so the learned correlation surface is routed through the same canonical AI ownership boundary as recent diff --git a/docs/release-control/v6/internal/subsystems/unified-resources.md b/docs/release-control/v6/internal/subsystems/unified-resources.md index cc85f0265..b0c393a87 100644 --- a/docs/release-control/v6/internal/subsystems/unified-resources.md +++ b/docs/release-control/v6/internal/subsystems/unified-resources.md @@ -144,9 +144,10 @@ from `internal/unifiedresources/relationship_presentation.go`, so the correlatio semantics live with the resource model instead of being duplicated in prompt helpers or drawer-specific markdown. That same resource model now also owns the canonical -`FormatResourceGraphContext` helper, so service-layer callers only resolve the -resource and hand the model the relationship list instead of rebuilding the -relationship section header, ordering, or freshness wording locally. +`FormatResourceRelationshipContext` helper, so service-layer callers only +resolve the resource and hand the model the relationship list instead of +rebuilding the relationship section header, ordering, or freshness wording +locally. The same shared relationship presenter also owns the compact change-timeline relationship summary used by resource change records, so change `from` and `to` values stay aligned with the canonical relationship labels instead of diff --git a/internal/ai/coverage_increase_test.go b/internal/ai/coverage_increase_test.go index 2e5f86a07..cda278955 100644 --- a/internal/ai/coverage_increase_test.go +++ b/internal/ai/coverage_increase_test.go @@ -534,19 +534,19 @@ func TestService_BuildRelationshipContext_UsesCanonicalReadState(t *testing.T) { }) ps.SetCorrelationDetector(corr) - graphContext := s.buildResourceGraphContext(resourceID) - if !strings.Contains(graphContext, "### Resource Graph") { - t.Fatalf("expected canonical relationship context to include graph heading, got %q", graphContext) + relationshipContext := s.buildResourceRelationshipContext(resourceID) + if !strings.Contains(relationshipContext, "### Resource Relationships") { + t.Fatalf("expected canonical relationship context to include relationship heading, got %q", relationshipContext) } - if !strings.Contains(graphContext, "Runs on") { - t.Fatalf("expected canonical relationship context to include relationship label, got %q", graphContext) + if !strings.Contains(relationshipContext, "Runs on") { + t.Fatalf("expected canonical relationship context to include relationship label, got %q", relationshipContext) } - if !strings.Contains(graphContext, "metadata present") { - t.Fatalf("expected canonical relationship context to include shared metadata marker, got %q", graphContext) + if !strings.Contains(relationshipContext, "metadata present") { + t.Fatalf("expected canonical relationship context to include shared metadata marker, got %q", relationshipContext) } resourceCtx := s.buildEnrichedResourceContext(resourceID, "", nil) - if !strings.Contains(resourceCtx, "Resource Graph") { + if !strings.Contains(resourceCtx, "Resource Relationships") { t.Fatalf("expected enriched resource context to include relationship section, got %q", resourceCtx) } if !strings.Contains(resourceCtx, "Runs on") { @@ -566,7 +566,7 @@ func TestService_BuildRelationshipContext_UsesCanonicalReadState(t *testing.T) { } incidentCtx := s.buildIncidentContext(resourceID, "") - if !strings.Contains(incidentCtx, "Resource Graph") { + if !strings.Contains(incidentCtx, "Resource Relationships") { t.Fatalf("expected incident context to include relationship section, got %q", incidentCtx) } if !strings.Contains(incidentCtx, "Runs on") { diff --git a/internal/ai/service.go b/internal/ai/service.go index 9bb127206..1ddc726ee 100644 --- a/internal/ai/service.go +++ b/internal/ai/service.go @@ -4512,8 +4512,8 @@ func (s *Service) buildIncidentContext(resourceID, alertIdentifier string) strin if recentChanges := s.buildRecentResourceChangesContext(resourceID); recentChanges != "" { sections = append(sections, recentChanges) } - if graphContext := s.buildResourceGraphContext(resourceID); graphContext != "" { - sections = append(sections, graphContext) + if relationshipContext := s.buildResourceRelationshipContext(resourceID); relationshipContext != "" { + sections = append(sections, relationshipContext) } } @@ -4614,7 +4614,7 @@ type canonicalResourceGetter interface { Get(id string) (*unifiedresources.Resource, bool) } -func (s *Service) buildResourceGraphContext(resourceID string) string { +func (s *Service) buildResourceRelationshipContext(resourceID string) string { resourceID = strings.TrimSpace(resourceID) if resourceID == "" { return "" @@ -4637,7 +4637,7 @@ func (s *Service) buildResourceGraphContext(resourceID string) string { if !ok || resource == nil { return "" } - return unifiedresources.FormatResourceGraphContext(resource, 3) + return unifiedresources.FormatResourceRelationshipContext(resource, 3) } // truncateString truncates a string to maxLen characters. @@ -4823,8 +4823,8 @@ func (s *Service) buildEnrichedResourceContext(resourceID, _ string, currentMetr } // Get canonical relationship context from unified resources. - if graphContext := s.buildResourceGraphContext(resourceID); graphContext != "" { - sections = append(sections, graphContext) + if relationshipContext := s.buildResourceRelationshipContext(resourceID); relationshipContext != "" { + sections = append(sections, relationshipContext) } // Get shared correlation context for learned related resources. diff --git a/internal/unifiedresources/code_standards_test.go b/internal/unifiedresources/code_standards_test.go index 646c0dd4f..3bd089198 100644 --- a/internal/unifiedresources/code_standards_test.go +++ b/internal/unifiedresources/code_standards_test.go @@ -643,24 +643,24 @@ func TestResourceChangePresentationUsesCanonicalLabels(t *testing.T) { } } -func TestResourceGraphContextUsesCanonicalRelationshipPresentation(t *testing.T) { +func TestResourceRelationshipContextUsesCanonicalRelationshipPresentation(t *testing.T) { data, err := os.ReadFile(filepath.Join("..", "ai", "service.go")) if err != nil { t.Fatalf("failed to read service.go: %v", err) } source := string(data) requiredSnippets := []string{ - "func (s *Service) buildResourceGraphContext(resourceID string) string", - "if graphContext := s.buildResourceGraphContext(resourceID); graphContext != \"\" {", + "func (s *Service) buildResourceRelationshipContext(resourceID string) string", + "if relationshipContext := s.buildResourceRelationshipContext(resourceID); relationshipContext != \"\" {", "Get canonical relationship context from unified resources.", - "unifiedresources.FormatResourceGraphContext(resource, 3)", + "unifiedresources.FormatResourceRelationshipContext(resource, 3)", "unifiedresources.FormatResourceRecentChangesContext(changes, false, \"###\")", "type canonicalResourceGetter interface {", "intel.FormatCorrelationsContext(resourceID)", } for _, snippet := range requiredSnippets { if !strings.Contains(source, snippet) { - t.Fatalf("internal/ai/service.go must pin canonical resource graph presentation snippet %q", snippet) + t.Fatalf("internal/ai/service.go must pin canonical relationship presentation snippet %q", snippet) } } } diff --git a/internal/unifiedresources/relationship_presentation.go b/internal/unifiedresources/relationship_presentation.go index 20e267330..62fe0b497 100644 --- a/internal/unifiedresources/relationship_presentation.go +++ b/internal/unifiedresources/relationship_presentation.go @@ -68,9 +68,9 @@ func DescribeRelationship(rel ResourceRelationship) RelationshipPresentation { return presentation } -// FormatResourceGraphContext returns the canonical AI prompt section for a +// FormatResourceRelationshipContext returns the canonical AI prompt section for a // resource's learned relationships. -func FormatResourceGraphContext(resource *Resource, limit int) string { +func FormatResourceRelationshipContext(resource *Resource, limit int) string { if resource == nil || limit <= 0 || len(resource.Relationships) == 0 { return "" } @@ -112,5 +112,5 @@ func FormatResourceGraphContext(resource *Resource, limit int) string { if len(lines) == 0 { return "" } - return "\n\n### Resource Graph\n" + strings.Join(lines, "\n") + return "\n\n### Resource Relationships\n" + strings.Join(lines, "\n") } diff --git a/internal/unifiedresources/relationship_presentation_test.go b/internal/unifiedresources/relationship_presentation_test.go index 2397e21c2..f88abac7e 100644 --- a/internal/unifiedresources/relationship_presentation_test.go +++ b/internal/unifiedresources/relationship_presentation_test.go @@ -70,7 +70,7 @@ func TestResourceRelationshipSummary(t *testing.T) { } } -func TestFormatResourceGraphContext(t *testing.T) { +func TestFormatResourceRelationshipContext(t *testing.T) { resource := &Resource{ Relationships: []ResourceRelationship{ { @@ -92,21 +92,21 @@ func TestFormatResourceGraphContext(t *testing.T) { }, } - ctx := FormatResourceGraphContext(resource, 1) + ctx := FormatResourceRelationshipContext(resource, 1) if ctx == "" { - t.Fatal("expected graph context") + t.Fatal("expected relationship context") } - if want := "### Resource Graph"; !contains(ctx, want) { - t.Fatalf("expected %q in graph context, got %q", want, ctx) + if want := "### Resource Relationships"; !contains(ctx, want) { + t.Fatalf("expected %q in relationship context, got %q", want, ctx) } if !contains(ctx, "Runs on") { t.Fatalf("expected canonical relationship label, got %q", ctx) } if !contains(ctx, "discoverer docker_adapter") { - t.Fatalf("expected provenance in graph context, got %q", ctx) + t.Fatalf("expected provenance in relationship context, got %q", ctx) } if contains(ctx, "Depends on") { - t.Fatalf("expected graph limit to truncate entries, got %q", ctx) + t.Fatalf("expected relationship limit to truncate entries, got %q", ctx) } }