Fixes#28263.
## Why
When a thread starts with `/goal`, the goal extension can update SQLite
goal state before the thread has any user-turn rollout items.
`thread/list` and `thread/search` rely on persisted listing metadata, so
a goal-first live thread could be absent from app-server listings after
restart even though the goal itself existed.
This regressed when goal handling moved out of core: the core path wrote
the goal update through the live thread rollout path, while the
extension-backed app-server path only updated goal state and emitted the
live notification.
## What
- Add `GoalSetOutcome::thread_goal_updated_item()` so the goal extension
owns the canonical `ThreadGoalUpdated` rollout item shape.
- Expose a narrow `CodexThread::append_rollout_items()` helper that
appends through the live thread and keeps derived SQLite metadata in
sync.
- When app-server sets a goal on an active live thread, persist the goal
update through that live-thread path.
- Add an app-server regression test that starts a live thread with
`thread/goal/set` and verifies it appears in state-DB-only
`thread/list`.
## Verification
- `env -u CODEX_SQLITE_HOME just test -p codex-app-server
goal_first_live_thread_appears_in_state_db_thread_list`