fix(handoff): normalize identity in sendHandoffMail (#780)
The handoff mail bead was created with un-normalized assignee (e.g., gastown/crew/holden) but mailbox queries use normalized identity (gastown/holden), causing self-mail to be invisible to the inbox. Export addressToIdentity as AddressToIdentity and call it in sendHandoffMail() to normalize the agent identity before storing, matching the normalization performed in Router.sendToSingle(). Fix handoff mail delivery (hq-snp8)
This commit is contained in:
@@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/steveyegge/gastown/internal/config"
|
"github.com/steveyegge/gastown/internal/config"
|
||||||
"github.com/steveyegge/gastown/internal/constants"
|
"github.com/steveyegge/gastown/internal/constants"
|
||||||
"github.com/steveyegge/gastown/internal/events"
|
"github.com/steveyegge/gastown/internal/events"
|
||||||
|
"github.com/steveyegge/gastown/internal/mail"
|
||||||
"github.com/steveyegge/gastown/internal/session"
|
"github.com/steveyegge/gastown/internal/session"
|
||||||
"github.com/steveyegge/gastown/internal/style"
|
"github.com/steveyegge/gastown/internal/style"
|
||||||
"github.com/steveyegge/gastown/internal/tmux"
|
"github.com/steveyegge/gastown/internal/tmux"
|
||||||
@@ -577,6 +578,9 @@ func sendHandoffMail(subject, message string) (string, error) {
|
|||||||
return "", fmt.Errorf("detecting agent identity: %w", err)
|
return "", fmt.Errorf("detecting agent identity: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Normalize identity to match mailbox query format
|
||||||
|
agentID = mail.AddressToIdentity(agentID)
|
||||||
|
|
||||||
// Detect town root for beads location
|
// Detect town root for beads location
|
||||||
townRoot := detectTownRootFromCwd()
|
townRoot := detectTownRootFromCwd()
|
||||||
if townRoot == "" {
|
if townRoot == "" {
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ func NewMailboxBeads(identity, workDir string) *Mailbox {
|
|||||||
func NewMailboxFromAddress(address, workDir string) *Mailbox {
|
func NewMailboxFromAddress(address, workDir string) *Mailbox {
|
||||||
beadsDir := beads.ResolveBeadsDir(workDir)
|
beadsDir := beads.ResolveBeadsDir(workDir)
|
||||||
return &Mailbox{
|
return &Mailbox{
|
||||||
identity: addressToIdentity(address),
|
identity: AddressToIdentity(address),
|
||||||
workDir: workDir,
|
workDir: workDir,
|
||||||
beadsDir: beadsDir,
|
beadsDir: beadsDir,
|
||||||
legacy: false,
|
legacy: false,
|
||||||
@@ -66,7 +66,7 @@ func NewMailboxFromAddress(address, workDir string) *Mailbox {
|
|||||||
// NewMailboxWithBeadsDir creates a mailbox with an explicit beads directory.
|
// NewMailboxWithBeadsDir creates a mailbox with an explicit beads directory.
|
||||||
func NewMailboxWithBeadsDir(address, workDir, beadsDir string) *Mailbox {
|
func NewMailboxWithBeadsDir(address, workDir, beadsDir string) *Mailbox {
|
||||||
return &Mailbox{
|
return &Mailbox{
|
||||||
identity: addressToIdentity(address),
|
identity: AddressToIdentity(address),
|
||||||
workDir: workDir,
|
workDir: workDir,
|
||||||
beadsDir: beadsDir,
|
beadsDir: beadsDir,
|
||||||
legacy: false,
|
legacy: false,
|
||||||
|
|||||||
@@ -569,7 +569,7 @@ func (r *Router) sendToGroup(msg *Message) error {
|
|||||||
// sendToSingle sends a message to a single recipient.
|
// sendToSingle sends a message to a single recipient.
|
||||||
func (r *Router) sendToSingle(msg *Message) error {
|
func (r *Router) sendToSingle(msg *Message) error {
|
||||||
// Convert addresses to beads identities
|
// Convert addresses to beads identities
|
||||||
toIdentity := addressToIdentity(msg.To)
|
toIdentity := AddressToIdentity(msg.To)
|
||||||
|
|
||||||
// Build labels for from/thread/reply-to/cc
|
// Build labels for from/thread/reply-to/cc
|
||||||
var labels []string
|
var labels []string
|
||||||
@@ -582,7 +582,7 @@ func (r *Router) sendToSingle(msg *Message) error {
|
|||||||
}
|
}
|
||||||
// Add CC labels (one per recipient)
|
// Add CC labels (one per recipient)
|
||||||
for _, cc := range msg.CC {
|
for _, cc := range msg.CC {
|
||||||
ccIdentity := addressToIdentity(cc)
|
ccIdentity := AddressToIdentity(cc)
|
||||||
labels = append(labels, "cc:"+ccIdentity)
|
labels = append(labels, "cc:"+ccIdentity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -692,7 +692,7 @@ func (r *Router) sendToQueue(msg *Message) error {
|
|||||||
labels = append(labels, "reply-to:"+msg.ReplyTo)
|
labels = append(labels, "reply-to:"+msg.ReplyTo)
|
||||||
}
|
}
|
||||||
for _, cc := range msg.CC {
|
for _, cc := range msg.CC {
|
||||||
ccIdentity := addressToIdentity(cc)
|
ccIdentity := AddressToIdentity(cc)
|
||||||
labels = append(labels, "cc:"+ccIdentity)
|
labels = append(labels, "cc:"+ccIdentity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -763,7 +763,7 @@ func (r *Router) sendToAnnounce(msg *Message) error {
|
|||||||
labels = append(labels, "reply-to:"+msg.ReplyTo)
|
labels = append(labels, "reply-to:"+msg.ReplyTo)
|
||||||
}
|
}
|
||||||
for _, cc := range msg.CC {
|
for _, cc := range msg.CC {
|
||||||
ccIdentity := addressToIdentity(cc)
|
ccIdentity := AddressToIdentity(cc)
|
||||||
labels = append(labels, "cc:"+ccIdentity)
|
labels = append(labels, "cc:"+ccIdentity)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -836,7 +836,7 @@ func (r *Router) sendToChannel(msg *Message) error {
|
|||||||
labels = append(labels, "reply-to:"+msg.ReplyTo)
|
labels = append(labels, "reply-to:"+msg.ReplyTo)
|
||||||
}
|
}
|
||||||
for _, cc := range msg.CC {
|
for _, cc := range msg.CC {
|
||||||
ccIdentity := addressToIdentity(cc)
|
ccIdentity := AddressToIdentity(cc)
|
||||||
labels = append(labels, "cc:"+ccIdentity)
|
labels = append(labels, "cc:"+ccIdentity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -488,7 +488,7 @@ func ParseMessageType(s string) MessageType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// addressToIdentity converts a GGT address to a beads identity.
|
// AddressToIdentity converts a GGT address to a beads identity.
|
||||||
//
|
//
|
||||||
// Liberal normalization: accepts multiple address formats and normalizes
|
// Liberal normalization: accepts multiple address formats and normalizes
|
||||||
// to canonical form (Postel's Law - be liberal in what you accept).
|
// to canonical form (Postel's Law - be liberal in what you accept).
|
||||||
@@ -504,7 +504,7 @@ func ParseMessageType(s string) MessageType {
|
|||||||
// - "gastown/Toast" → "gastown/Toast" (already canonical)
|
// - "gastown/Toast" → "gastown/Toast" (already canonical)
|
||||||
// - "gastown/refinery" → "gastown/refinery"
|
// - "gastown/refinery" → "gastown/refinery"
|
||||||
// - "gastown/" → "gastown" (rig broadcast)
|
// - "gastown/" → "gastown" (rig broadcast)
|
||||||
func addressToIdentity(address string) string {
|
func AddressToIdentity(address string) string {
|
||||||
// Overseer (human operator) - no trailing slash, distinct from agents
|
// Overseer (human operator) - no trailing slash, distinct from agents
|
||||||
if address == "overseer" {
|
if address == "overseer" {
|
||||||
return "overseer"
|
return "overseer"
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ func TestAddressToIdentity(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.address, func(t *testing.T) {
|
t.Run(tt.address, func(t *testing.T) {
|
||||||
got := addressToIdentity(tt.address)
|
got := AddressToIdentity(tt.address)
|
||||||
if got != tt.expected {
|
if got != tt.expected {
|
||||||
t.Errorf("addressToIdentity(%q) = %q, want %q", tt.address, got, tt.expected)
|
t.Errorf("AddressToIdentity(%q) = %q, want %q", tt.address, got, tt.expected)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user