voice

import "github.com/jbcom/radioactive-ralph/internal/voice"

Package voice renders Ralph’s personality for each variant.

Every user-facing emission from the supervisor — pre-flight questions, startup banners, status lines, attach-stream event renderings, shutdown messages, spend-cap notifications — gets voiced through this package. The same fact emits different copy per variant so the operator experiences the distinct personalities documented in docs/variants/.

M2 ships the skeleton (registry, lookup, fallbacks). M3 fills in the full template libraries for all ten variants. For M2 we include green (the classic) and blue (the observer) as proofs-of-concept.

Design: templates are plain Go string/template-literal pairs rather than text/template. We deliberately don’t use text/template — the interpolation surface is narrow (pr number, repo slug, count, reason, branch, usd) and the control-flow features of text/template are a foot-gun when operators can tweak voice via config.toml later.

Index

func Register

func Register(variant Variant, event Event, template string)

Register adds or replaces a template for one variant + event. Called by the variant package at init time; tests can also use it to override specific templates and inspect the output.

func RegisterFallback

func RegisterFallback(event Event, template string)

RegisterFallback sets the default template used when a variant lacks a specific event template.

func ResetForTesting

func ResetForTesting()

ResetForTesting clears the registry and re-registers the built-in variants. Tests that mutate the registry call this in a t.Cleanup to avoid bleeding state between tests.

func Say

func Say(variant Variant, event Event, f Fields) string

Say returns Ralph’s voiced message for a given variant + event. Falls back to the default template if the variant hasn’t registered one; falls back to a canonical event name if no template exists at all. Never panics.

type Event

Event is the kind-of-emission key. Small, documented set.

type Event string

Canonical events the supervisor voices. Adding new events requires adding templates (or accepting fallbacks) for every variant you care about.

const (
    EventStartup        Event = "startup"
    EventShutdown       Event = "shutdown"
    EventCycleStart     Event = "cycle.start"
    EventCycleEnd       Event = "cycle.end"
    EventSessionSpawn   Event = "session.spawn"
    EventSessionDeath   Event = "session.death"
    EventSessionResume  Event = "session.resume"
    EventTaskClaim      Event = "task.claim"
    EventTaskDone       Event = "task.done"
    EventPRMerge        Event = "pr.merge"
    EventPRMergeFailed  Event = "pr.merge.failed"
    EventReviewApproved Event = "review.approved"
    EventReviewChanges  Event = "review.changes"
    EventSpendCapHit    Event = "spend.cap"
    EventGateRefusal    Event = "gate.refusal"
)

type Fields

Fields are the values substituted into templates. Only the subset relevant to the event is consulted — renderers gracefully tolerate zero values.

type Fields struct {
    Repo     string
    Branch   string
    PRNumber int
    TaskID   string
    Count    int    // severity count, cycle number, etc.
    Reason   string // exit reason, refusal reason, etc.
    USD      string // pre-formatted spend string (e.g. "$42.50")
    Extra    string // catch-all when one more string is needed
}

type Variant

Variant is an identifier matching the variant profile. M3 makes this a proper enum in the variant package; M2 uses lower-case strings.

type Variant string

Canonical variant names. Kept in sync with the variant registry and the operator-facing docs/variants pages.

const (
    VariantGreen        Variant = "green"
    VariantGrey         Variant = "grey"
    VariantRed          Variant = "red"
    VariantBlue         Variant = "blue"
    VariantProfessor    Variant = "professor"
    VariantFixit        Variant = "fixit"
    VariantImmortal     Variant = "immortal"
    VariantSavage       Variant = "savage"
    VariantOldMan       Variant = "old-man"
    VariantWorldBreaker Variant = "world-breaker"
)

Generated by gomarkdoc