Diff
1diff --git a/internal/availability/availability.go b/internal/availability/availability.go
2index a3013be35d4127bf78cbd86cbff7b00744a8389b..4d231532767e317441f5d379612dde7976e06175 100644
3--- a/internal/availability/availability.go
4+++ b/internal/availability/availability.go
5@@ -26,18 +26,6 @@ type Service struct {
6 Detail string
7 }
8
9-func (s Service) String() string {
10- state := "down"
11- if s.Up {
12- state = "up"
13- }
14- line := fmt.Sprintf("%s %s %s", s.Name, state, s.URL)
15- if s.Detail != "" {
16- line += " (" + s.Detail + ")"
17- }
18- return line
19-}
20-
21 // CheckAllAsync probes every configured service concurrently and invokes fn
22 // once per service, in completion order. Each probe keeps its bounded timeout
23 // and names the affected URL on failure, so one slow or dead service does not
24diff --git a/internal/game/orchestrator.go b/internal/game/orchestrator.go
25index ea075a4be0d7501f54430b17911513fc096b0406..5eb41d43afde5c94c885343ba780f2acd33cb018 100644
26--- a/internal/game/orchestrator.go
27+++ b/internal/game/orchestrator.go
28@@ -55,19 +55,16 @@ type PersonaView struct {
29 // ErrNotInLocation is returned when a turn is finished outside any location.
30 var ErrNotInLocation = errors.New("game: not in a location")
31
32-// TurnResult reports what happened in one turn. Transcript is the raw Japanese
33-// line (for LLM prompts only, never shown); the display romaji comes from Judge
34-// when it succeeds, and there is no romaji when it fails. A non-nil Err means no
35-// NPC reply was produced, so nothing was recorded to history. JudgeErr and
36-// SpeakErr are recoverable: they do not prevent recording and are surfaced
37+// TurnResult reports what happened in one turn. The display romaji comes from
38+// Judge when it succeeds, and there is no romaji when it fails. A non-nil Err
39+// means no NPC reply was produced, so nothing was recorded to history. JudgeErr
40+// and SpeakErr are recoverable: they do not prevent recording and are surfaced
41 // separately.
42 type TurnResult struct {
43- Transcript string
44- Judge llm.JudgeResult
45- JudgeErr error
46- NPC llm.NPCReply
47- SpeakErr error
48- Err error
49+ Judge llm.JudgeResult
50+ JudgeErr error
51+ SpeakErr error
52+ Err error
53 }
54
55 // Orchestrator runs the turn flow over the adapter interfaces, keeping all game
56@@ -119,7 +116,6 @@ func (o *Orchestrator) Finish(ctx context.Context) TurnResult {
57 res.Err = err
58 return res
59 }
60- res.Transcript = raw
61
62 view := o.personas[loc]
63 prior := toLLMTurns(o.state.History(loc))
64@@ -149,21 +145,15 @@ func (o *Orchestrator) Finish(ctx context.Context) TurnResult {
65
66 res.Judge, res.JudgeErr = judgeRes, judgeErr
67 if npcErr != nil {
68- res.NPC, res.Err = npcRes, npcErr
69+ res.Err = npcErr
70 return res
71 }
72- res.NPC = npcRes
73-
74- var playerRomaji string
75- if judgeErr == nil {
76- playerRomaji = judgeRes.Romaji
77- }
78
79 if err := o.speechOut.Speak(ctx, npcRes.Kana); err != nil {
80 res.SpeakErr = err
81 }
82
83- o.state.RecordTurn(loc, raw, playerRomaji, Reply{Romaji: npcRes.Romaji, English: npcRes.English})
84+ o.state.RecordTurn(loc, raw, Reply{Romaji: npcRes.Romaji, English: npcRes.English})
85 return res
86 }
87
88diff --git a/internal/game/state.go b/internal/game/state.go
89index 47c92e78919ee8bc7ddab3f356f35d03161e6f87..80aa9a5b2b1afc50776857230b28987d4021f66e 100644
90--- a/internal/game/state.go
91+++ b/internal/game/state.go
92@@ -52,12 +52,11 @@ type Reply struct {
93 }
94
95 // Turn is one exchange in a location's history: the player's spoken line and
96-// the NPC reply to it. PlayerRaw is the original transcript (for LLM prompts);
97-// PlayerRomaji is the romaji form shown to the player, sourced from the judge.
98+// the NPC reply to it. PlayerRaw is the original transcript, kept for LLM
99+// prompts only.
100 type Turn struct {
101- PlayerRaw string
102- PlayerRomaji string
103- NPC Reply
104+ PlayerRaw string
105+ NPC Reply
106 }
107
108 // State is the pure, in-memory free-roam game state: where the player stands,
109@@ -122,16 +121,6 @@ func (s *State) LocationAt(p Position) string {
110 return ""
111 }
112
113-// LocationDef looks up a location definition by id.
114-func (s *State) LocationDef(id string) (LocationDef, bool) {
115- for _, loc := range s.m.Locations {
116- if loc.ID == id {
117- return loc, true
118- }
119- }
120- return LocationDef{}, false
121-}
122-
123 // History returns a copy of the conversation history recorded at location id.
124 func (s *State) History(id string) []Turn {
125 src := s.history[id]
126@@ -142,12 +131,11 @@ func (s *State) History(id string) []Turn {
127
128 // RecordTurn appends one exchange to location id's history. A recorded reply
129 // always starts with both text fields hidden.
130-func (s *State) RecordTurn(id string, playerRaw, playerRomaji string, npc Reply) {
131+func (s *State) RecordTurn(id string, playerRaw string, npc Reply) {
132 npc.Reveal = Hidden
133 s.history[id] = append(s.history[id], Turn{
134- PlayerRaw: playerRaw,
135- PlayerRomaji: playerRomaji,
136- NPC: npc,
137+ PlayerRaw: playerRaw,
138+ NPC: npc,
139 })
140 }
141
142diff --git a/internal/stt/recorder.go b/internal/stt/recorder.go
143index c8fafd963a796027f43a619c733b7d6ae4c7fd92..dfc2588dd93d3dfbf769180bffce967b4bff979b 100644
144--- a/internal/stt/recorder.go
145+++ b/internal/stt/recorder.go
146@@ -103,9 +103,6 @@ func (rec *Recording) Stop() (string, error) {
147 return rec.resultPath, rec.resultErr
148 }
149
150-// Done closes once the recording has ended and its process has been reaped.
151-func (rec *Recording) Done() <-chan struct{} { return rec.doneCh }
152-
153 func (rec *Recording) watchdog(ctx context.Context) {
154 var timerC <-chan time.Time
155 if rec.maxRecord > 0 {
156diff --git a/internal/tts/player.go b/internal/tts/player.go
157index 54eb85cd2b51c1001615245763e16f8b0d080e3c..d603e58dd1adce103497bdf359f7222e6c5c03f9 100644
158--- a/internal/tts/player.go
159+++ b/internal/tts/player.go
160@@ -50,17 +50,6 @@ func (p *Player) Play(wav []byte, onDone func()) error {
161 return nil
162 }
163
164-// Stop interrupts an in-flight playback. It is safe to call when idle.
165-func (p *Player) Stop() {
166- p.mu.Lock()
167- cancel := p.stopCur
168- p.stopCur = nil
169- p.mu.Unlock()
170- if cancel != nil {
171- cancel()
172- }
173-}
174-
175 func (p *Player) play(ctx context.Context, spec *WAVSpec, onDone func()) {
176 data := make([]byte, len(spec.Data))
177 copy(data, spec.Data)