diff --git a/docs/release-control/v6/internal/subsystems/ai-runtime.md b/docs/release-control/v6/internal/subsystems/ai-runtime.md index 251e05671..cfcdb70f3 100644 --- a/docs/release-control/v6/internal/subsystems/ai-runtime.md +++ b/docs/release-control/v6/internal/subsystems/ai-runtime.md @@ -159,6 +159,10 @@ The same runtime boundary now also owns durable action execution auditing. startup, and the write-action tool paths under `internal/ai/tools/` persist append-only action lifecycle and action audit records through that shared store instead of leaving command execution state in memory-only tool helpers. +The patrol-local `memory.ChangeDetector.GetChangesSummary` path now also +delegates to the shared memory recent-change presentation helper, so any +future fallback summary entry point inherits the same heading, resource +prefixing, and change-type labels without re-implementing the markdown shape. Those unified-resource action and export audit records are now also exposed through the enterprise audit read surface so operators can inspect the execution trail without reaching into storage internals. diff --git a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md index f11e2d205..49c0fc3d0 100644 --- a/docs/release-control/v6/internal/subsystems/patrol-intelligence.md +++ b/docs/release-control/v6/internal/subsystems/patrol-intelligence.md @@ -85,6 +85,9 @@ When that detector fallback is used, the Patrol runtime must render recent changes through the shared memory presentation helper so the same heading, resource prefixing, and change labels are reused across the Patrol and AI fallback paths. +`memory.ChangeDetector.GetChangesSummary` now also delegates to that shared +helper, so the detector-owned summary API and the Patrol fallback prompt path +stay aligned on the same markdown shape. Those same Patrol-owned prompt contexts now also surface a canonical resource-graph section from unified-resource relationships, so edge labels, directionality, and provenance stay aligned with the shared graph model diff --git a/internal/ai/memory/changes.go b/internal/ai/memory/changes.go index 4f9afb085..54aa1e26a 100644 --- a/internal/ai/memory/changes.go +++ b/internal/ai/memory/changes.go @@ -333,16 +333,7 @@ func (d *ChangeDetector) GetRecentChanges(limit int, since time.Time) []Change { // GetChangesSummary returns a formatted summary of recent changes for AI context func (d *ChangeDetector) GetChangesSummary(since time.Time, maxChanges int) string { changes := d.GetRecentChanges(maxChanges, since) - if len(changes) == 0 { - return "" - } - - var result string - for _, c := range changes { - ago := time.Since(c.DetectedAt) - result += "- " + c.Description + " (" + formatDuration(ago) + " ago)\n" - } - return result + return FormatRecentChangesContext(changes, false, "##") } // trimChanges removes old changes beyond maxChanges diff --git a/internal/ai/memory/memory_extended_test.go b/internal/ai/memory/memory_extended_test.go index e103c2807..6d663b7c9 100644 --- a/internal/ai/memory/memory_extended_test.go +++ b/internal/ai/memory/memory_extended_test.go @@ -105,8 +105,9 @@ func TestChangeDetector_GetChangesSummary(t *testing.T) { since := time.Now().Add(-1 * time.Hour) summary := d.GetChangesSummary(since, 5) - if summary == "" { - t.Error("Expected non-empty summary") + want := FormatRecentChangesContext(d.GetRecentChanges(5, since), false, "##") + if summary != want { + t.Fatalf("expected shared recent-changes formatter, got %q want %q", summary, want) } }