mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-07-09 16:00:59 +00:00
Preserve queued Assistant workflow pacing
This commit is contained in:
parent
bbd9f9d0e5
commit
5af2d95df4
3 changed files with 62 additions and 6 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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) != "" {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue