fix(beads): use hq- prefix for group/channel beads (town-level entities)

Groups and channels are town-level entities that span rigs, so they
should use the hq- prefix rather than gt- (rig-level).

Changes:
- GroupBeadID: gt-group- → hq-group-
- ChannelBeadID: gt-channel- → hq-channel-
- Add --force flag to bypass prefix validation (town beads may have
  mixed prefixes from test runs)
- Update tests and documentation

Also adds docs/beads-native-messaging.md documenting:
- New bead types (gt:group, gt:queue, gt:channel)
- CLI commands (gt mail group, gt mail channel)
- Address resolution logic
- Usage examples

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
gastown/crew/max
2026-01-14 22:19:00 -08:00
committed by Steve Yegge
parent e30e46a87a
commit cbbf566f06
4 changed files with 239 additions and 10 deletions

View File

@@ -127,15 +127,15 @@ func ParseChannelFields(description string) *ChannelFields {
return fields
}
// ChannelBeadID returns the channel bead ID for a given channel name.
// Format: hq-channel-<name> for town-level channels (default).
// Town-level channels are stored in the shared beads database.
// ChannelBeadID returns the bead ID for a channel name.
// Format: hq-channel-<name> (town-level, channels span rigs)
func ChannelBeadID(name string) string {
return "hq-channel-" + name
}
// CreateChannelBead creates a channel bead for pub/sub messaging.
// The ID format is: hq-channel-<name> (e.g., hq-channel-alerts) for town-level.
// The ID format is: hq-channel-<name> (e.g., hq-channel-alerts)
// Channels are town-level entities (hq- prefix) because they span rigs.
// The created_by field is populated from BD_ACTOR env var for provenance tracking.
func (b *Beads) CreateChannelBead(name string, subscribers []string, createdBy string) (*Issue, error) {
id := ChannelBeadID(name)
@@ -156,6 +156,7 @@ func (b *Beads) CreateChannelBead(name string, subscribers []string, createdBy s
"--description=" + description,
"--type=task", // Channels use task type with gt:channel label
"--labels=gt:channel",
"--force", // Override prefix check (town beads may have mixed prefixes)
}
// Default actor from BD_ACTOR env var for provenance tracking

View File

@@ -97,13 +97,14 @@ func ParseGroupFields(description string) *GroupFields {
}
// GroupBeadID returns the bead ID for a group name.
// Format: gt-group-<name>
// Format: hq-group-<name> (town-level, groups span rigs)
func GroupBeadID(name string) string {
return "gt-group-" + name
return "hq-group-" + name
}
// CreateGroupBead creates a group bead for mail distribution.
// The ID format is: gt-group-<name> (e.g., gt-group-ops-team)
// The ID format is: hq-group-<name> (e.g., hq-group-ops-team)
// Groups are town-level entities (hq- prefix) because they span rigs.
// The created_by field is populated from BD_ACTOR env var for provenance tracking.
func (b *Beads) CreateGroupBead(name string, members []string, createdBy string) (*Issue, error) {
id := GroupBeadID(name)
@@ -123,6 +124,7 @@ func (b *Beads) CreateGroupBead(name string, members []string, createdBy string)
"--description=" + description,
"--type=task", // Groups use task type with gt:group label
"--labels=gt:group",
"--force", // Override prefix check (town beads may have mixed prefixes)
}
// Default actor from BD_ACTOR env var for provenance tracking

View File

@@ -163,9 +163,9 @@ func TestGroupBeadID(t *testing.T) {
name string
want string
}{
{"ops-team", "gt-group-ops-team"},
{"all", "gt-group-all"},
{"crew-leads", "gt-group-crew-leads"},
{"ops-team", "hq-group-ops-team"},
{"all", "hq-group-all"},
{"crew-leads", "hq-group-crew-leads"},
}
for _, tt := range tests {