What changed, and why
On the mission-select briefing you can pick a curated objective or have one composed by AI. The composed one dropped in at the top of the list, pushing the curated pool down and away from the "Compose a fresh objective with AI" button you had just pressed. Your eyes were at the button; the result landed somewhere else.
This moves it to the bottom, right above that button, so the thing you composed appears where you are looking, already selected and ready to begin.
The whole behaviour is one expression. The list is rendered straight from a computed array, so its order is that array's order. The fix reorders one spread; nothing else about compose, selection, or the curated pool moves. A new test pins the placement so it can't quietly regress.
The one-line reorder
options is the array the template walks with v-for to draw the rows. It is just the curated pool, with the freshly composed objective (if any) spliced in. Putting fresh.value first made it lead; putting it last makes it trail. That single position is the entire change to behaviour — the two comments above it and in the template were updated to match.
The template renders options in array order, so the spread order is the display order.
components/MissionSelect.vue · 462 lines
⋯ 87 lines hidden (lines 1–87)
⋯ 276 lines hidden (lines 92–367)
⋯ 89 lines hidden (lines 374–462)
Identity-based selection: stored as the object, compared with ===, auto-set on compose.
components/MissionSelect.vue · 462 lines
⋯ 349 lines hidden (lines 1–349)
⋯ 44 lines hidden (lines 351–394)
⋯ 14 lines hidden (lines 400–413)
⋯ 43 lines hidden (lines 420–462)
A test only the fix can pass
The existing compose tests assert the option count grows by one and that the "freshly composed" badge exists, but neither checks where the row lands — so a top-vs-bottom regression would sail through. This new test closes that gap: it composes, then asserts the last row is the badged, selected one, and that the first row is still curated.
It is discriminating by construction: on the old [fresh, ...curated] ordering the last row is a curated objective with no badge, so the badge assertion fails. Verified by reverting the source line and watching only this test go red. The mock mints a run id for /api/run because compose sends an x-run-id header.
Composes, then checks the fresh row is last, badged, and selected — and the first row is not the fresh one.