/*
Resolve the systemId a mission belongs to — shared by evidence.sync and evidence.fetch so the derivation can never diverge between the R2 upload prefix and its download reader.
- Do not open or validate the mission — resolution is a read-only lookup, never a lifecycle check.
- mission.yaml wins over the currentMission scan: the manifest records the system at open and survives close/archive, while system-state.currentMission clears at close — a closed mission (the evidence.sync call site after ship) can only resolve through the manifest.
- RFC-1324: initial — replaces the duplicated `split("-m")[0]` derivation that cut `e2e-valid-minimal-m000001` at the mid-slug "-m" to `e2e-valid`.
- RFC-1324: cold-run defect: evidence.sync/fetch resolveSystemId split on bare '-m' — e2e-valid-minimal-m000001 resolved to e2e-valid, SYSTEM_MISMATCH blocked post-close deploy; shared resolveSystemIdForMission reads mission.yaml first
*/
import { discoverSystems, readSystemState } from "../sternsystem/registry-io.ts";
import { readMissionManifest } from "../mission/mission-io.ts";
import type { WorkspaceIO } from "@warpgogol/werkstatt-shared/kernel/workspace-io";
export async function resolveSystemIdForMission(
workspaceRoot: string,
missionId: string,
io: WorkspaceIO,
): Promise {
try {
const manifest = await readMissionManifest(workspaceRoot, missionId, io);
if (manifest.systemId) return manifest.systemId;
} catch {
// Manifest absent or unreadable — fall through to scan/derivation.
}
const { systems } = await discoverSystems(workspaceRoot);
for (const sys of systems) {
try {
const state = await readSystemState(workspaceRoot, sys.id);
if (state.currentMission === missionId) return sys.id;
} catch {
// State not available for this system — skip
}
}
// Last resort: strip the canonical -mNNNNNN mission suffix. Never split on
// a bare "-m" — system slugs like `e2e-valid-minimal` contain it mid-word.
const m = /^(.*)-m\d{6}$/.exec(missionId);
return m ? m[1] : missionId;
}