Add human escalation path with severity levels (gt-1z3z)

Implements structured escalation channel for Gas Town:
- gt escalate command with CRITICAL/HIGH/MEDIUM severity levels
- Mayor startup check for pending escalations
- Escalation beads with tag for audit trail
- Mail routing to overseer with priority mapping
- Documentation in docs/escalation.md

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Steve Yegge
2025-12-30 09:56:20 -08:00
parent ab30b974a4
commit a7831ba11d
4 changed files with 505 additions and 0 deletions

View File

@@ -135,6 +135,11 @@ func runPrime(cmd *cobra.Command, args []string) error {
// Run gt mail check --inject to inject any pending mail
runMailCheckInject(cwd)
// For Mayor, check for pending escalations
if ctx.Role == RoleMayor {
checkPendingEscalations(ctx)
}
// Output startup directive for roles that should announce themselves
// Skip if in autonomous mode (slung work provides its own directive)
if !hasSlungWork {
@@ -1298,3 +1303,90 @@ func ensureBeadsRedirect(ctx RoleContext) {
// Note: We don't print a message here to avoid cluttering prime output
// The redirect is silently restored
}
// checkPendingEscalations queries for open escalation beads and displays them prominently.
// This is called on Mayor startup to surface issues needing human attention.
func checkPendingEscalations(ctx RoleContext) {
// Query for open escalations using bd list with tag filter
cmd := exec.Command("bd", "list", "--status=open", "--tag=escalation", "--json")
cmd.Dir = ctx.WorkDir
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
// Silently skip - escalation check is best-effort
return
}
// Parse JSON output
var escalations []struct {
ID string `json:"id"`
Title string `json:"title"`
Priority int `json:"priority"`
Description string `json:"description"`
Created string `json:"created"`
}
if err := json.Unmarshal(stdout.Bytes(), &escalations); err != nil || len(escalations) == 0 {
// No escalations or parse error
return
}
// Count by severity
critical := 0
high := 0
medium := 0
for _, e := range escalations {
switch e.Priority {
case 0:
critical++
case 1:
high++
default:
medium++
}
}
// Display prominently
fmt.Println()
fmt.Printf("%s\n\n", style.Bold.Render("## 🚨 PENDING ESCALATIONS"))
fmt.Printf("There are %d escalation(s) awaiting human attention:\n\n", len(escalations))
if critical > 0 {
fmt.Printf(" 🔴 CRITICAL: %d\n", critical)
}
if high > 0 {
fmt.Printf(" 🟠 HIGH: %d\n", high)
}
if medium > 0 {
fmt.Printf(" 🟡 MEDIUM: %d\n", medium)
}
fmt.Println()
// Show first few escalations
maxShow := 5
if len(escalations) < maxShow {
maxShow = len(escalations)
}
for i := 0; i < maxShow; i++ {
e := escalations[i]
severity := "MEDIUM"
switch e.Priority {
case 0:
severity = "CRITICAL"
case 1:
severity = "HIGH"
}
fmt.Printf(" • [%s] %s (%s)\n", severity, e.Title, e.ID)
}
if len(escalations) > maxShow {
fmt.Printf(" ... and %d more\n", len(escalations)-maxShow)
}
fmt.Println()
fmt.Println("**Action required:** Review escalations with `bd list --tag=escalation`")
fmt.Println("Close resolved ones with `bd close <id> --reason \"resolution\"`")
fmt.Println()
}