Preserve queued Assistant workflow pacing

This commit is contained in:
rcourtman 2026-06-07 15:02:01 +01:00
parent bbd9f9d0e5
commit 5af2d95df4
3 changed files with 62 additions and 6 deletions

View file

@ -394,11 +394,24 @@ func FormatForRemediation(d *ResourceDiscovery) string {
sb.WriteString("\n\n")
}
// Hardware info for special considerations
for _, f := range d.Facts {
if f.Category == FactCategoryHardware {
sb.WriteString(fmt.Sprintf("**Hardware:** %s = %s\n", f.Key, f.Value))
// Other facts needed to diagnose — dependencies (upstreams, brokers, DBs),
// auth/security posture, backing storage, special hardware. Previously only
// hardware surfaced here, so a 502's upstream or a broker's auth never
// reached the fix context. Use the same ranked filter as the chat pack;
// service facts are already shown prominently under Service Control.
var diagnosticFacts []DiscoveryFact
for _, f := range filterImportantFacts(d.Facts) {
if f.Category == FactCategoryService {
continue
}
diagnosticFacts = append(diagnosticFacts, f)
}
if len(diagnosticFacts) > 0 {
sb.WriteString("### Relevant Facts\n")
for _, f := range diagnosticFacts {
sb.WriteString(fmt.Sprintf("- %s: %s\n", f.Key, f.Value))
}
sb.WriteString("\n")
}
return sb.String()

View file

@ -53,7 +53,9 @@ func TestFormattersAndTables(t *testing.T) {
}
remediation := FormatForRemediation(discovery)
if !strings.Contains(remediation, "How to Execute Commands") || !strings.Contains(remediation, "Hardware") {
if !strings.Contains(remediation, "How to Execute Commands") ||
!strings.Contains(remediation, "Relevant Facts") ||
!strings.Contains(remediation, "gpu") {
t.Fatalf("unexpected remediation output: %s", remediation)
}
if FormatForRemediation(nil) != "" {

View file

@ -22,7 +22,10 @@ type contextScenario struct {
name string // service-type cell
userQuestion string // the real question this context must answer
discovery *ResourceDiscovery // a realistic discovered workload
mustContain []string // substrings the context pack must include
mustContain []string // substrings the chat context pack (FormatForAIContext) must include
// substrings the remediation pack (FormatForRemediation, what Patrol/fix
// flows consume) must include; nil skips the remediation check for this cell.
remediationMustContain []string
}
func contextScenarioCorpus() []contextScenario {
@ -117,6 +120,12 @@ func contextScenarioCorpus() []contextScenario {
"postgresql@16-main.service",
"tank/postgres",
},
remediationMustContain: []string{
"postgresql@16-main.service", // service control
"postgresql.conf", // config
"/var/lib/postgresql/16/main", // data directory
"tank/postgres", // storage fact (now surfaced)
},
},
{
name: "frigate Docker (fact-heavy)",
@ -202,6 +211,12 @@ func contextScenarioCorpus() []contextScenario {
"/srv/nginx/conf.d -> /etc/nginx/conf.d (read-only)",
"nginx -s reload",
},
remediationMustContain: []string{
"nginx -s reload", // service control
"default.conf", // config
"/srv/nginx/conf.d", // bind-mount host source
"app:3000", // dependency fact (now surfaced) — the 502 upstream
},
},
{
name: "mosquitto MQTT broker (LXC, auth)",
@ -238,6 +253,11 @@ func contextScenarioCorpus() []contextScenario {
"allow_anonymous false",
"systemctl restart mosquitto",
},
remediationMustContain: []string{
"systemctl restart mosquitto", // service control
"auth.conf", // config
"allow_anonymous false", // security fact (now surfaced) — the connect failure
},
},
}
}
@ -255,3 +275,24 @@ func TestContextScenarioCorpus(t *testing.T) {
})
}
}
// The remediation pack (FormatForRemediation, what Patrol/fix flows consume)
// must carry the same act-on-it context as the chat pack — including the
// dependency, security, and storage facts a fix actually needs (a 502's
// upstream, a broker's auth, a database's backing disk).
func TestRemediationScenarioCorpus(t *testing.T) {
for _, sc := range contextScenarioCorpus() {
if len(sc.remediationMustContain) == 0 {
continue
}
t.Run(sc.name, func(t *testing.T) {
pack := FormatForRemediation(sc.discovery)
for _, want := range sc.remediationMustContain {
if !strings.Contains(pack, want) {
t.Errorf("remediation pack for %q (question: %q) is missing %q —\nthe fix flow could not act without it.\n--- remediation pack ---\n%s",
sc.name, sc.userQuestion, want, pack)
}
}
})
}
}