# Scrum review — c4_replay — opus (opencode/claude-opus-4-7)

**Latency:** 18708ms · **Tokens:** 6 in / 926 out · **Date:** 2026-05-02

---

SEVERITY: WARN
WHERE:    internal/replay/replay.go:67
WHAT:     RecordedRunID derived from RFC3339Nano timestamp can collide for back-to-back runs and is not unique per call.
WHY:      sha256(recordedAt)[:12] depends only on wall-clock time at nanosecond precision; two replays in the same nanosecond (or with monotonic clock quirks) produce identical run IDs, breaking the audit invariant.

SEVERITY: WARN
WHERE:    internal/replay/replay.go:90
WHAT:     Escalation reason prepend logic only fires when validation already passed, but is appended to whatever Reasons existed from the failing local call — message ordering implies the failure happened before recovery but the "recovered" note may sit alongside stale local-fail reasons.
WHY:      The code does `append([]string{"recovered..."}, validation.Reasons...)` after re-running ValidateResponse, which returns fresh Reasons (likely empty on Pass), so the note is fine — but if escalation Pass returns reasons (e.g., short response warning), the prefix conflates pass+warn states confusingly.

SEVERITY: INFO
WHERE:    internal/replay/retrieval.go:215
WHAT:     `trim` slices bytes of a UTF-8 string, can split a multi-byte rune and produce invalid UTF-8 in ContentPreview/ModelResponse log.
WHY:      `s[:n]` on a string with multi-byte characters at boundary n produces a malformed tail; replay corpora often contain non-ASCII (em dash, arrows used in this very repo's logs).

SEVERITY: INFO
WHERE:    internal/replay/replay.go:138
WHAT:     `persist.ReplayResult.ModelResponse = trim(...)` mutates a copy, but the comment says "log is truncated"; in-memory result returned to caller retains the full response — confirm this matches TS.
WHY:      Struct embedding copies by value here so the mutation is local to `persist`; behavior is correct but worth a one-line comment to prevent a future "fix".

SEVERITY: INFO
WHERE:    internal/replay/types.go:96
WHAT:     `DefaultLocalModel = "qwen3.5:latest"` and `qwen3.5:397b` in inferProvider — the `.5` form is unusual; verify the gateway accepts this exact tag.
WHY:      Smoke test asserts the literal string in stdout, so a typo would be caught at runtime, but the model name looks suspect compared to standard qwen2.5/qwen3 naming.

VERDICT: ship-with-fixes — run-id collision risk is the only real concern; rest is polish.
