feat(FEAT-006): add validation and loop state API endpoints

Implemented:
- POST /api/missions/features/:featureId/validate - triggers validation run
- GET /api/missions/features/:featureId/validation-loop - returns loop snapshot
- GET /api/missions/features/:featureId/validation-runs - returns run history with pagination
- GET /api/missions/validation-runs/:runId - returns run detail with assertion results
- POST /api/missions/recover - triggers recovery of active missions
- SSE events for milestone:validation:updated via assertion CRUD and link/unlink

All 4xx/5xx responses use consistent {"error": "message"} format.
Uses existing badRequest, notFound, internalError helpers.

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
gsxdsm
2026-04-11 21:03:15 -07:00
parent bab269dada
commit c4e6c0fd37
6 changed files with 369 additions and 249 deletions

View File

@@ -222,6 +222,10 @@ export function createSSE(
send(`event: mission:event\ndata: ${JSON.stringify(data)}\n\n`);
};
const onMilestoneValidationUpdated = (data: any) => {
send(`event: milestone:validation:updated\ndata: ${JSON.stringify(data)}\n\n`);
};
const onAiSessionUpdated = (data: any) => {
send(`event: ai_session:updated\ndata: ${JSON.stringify(data)}\n\n`);
};
@@ -293,6 +297,7 @@ export function createSSE(
missionStore.off("feature:deleted", onFeatureDeleted);
missionStore.off("feature:linked", onFeatureLinked);
missionStore.off("mission:event", onMissionEvent);
missionStore.off("milestone:validation:updated", onMilestoneValidationUpdated);
}
if (aiSessionStore) {
aiSessionStore.off("ai_session:updated", onAiSessionUpdated);
@@ -332,6 +337,7 @@ export function createSSE(
missionStore.on("feature:deleted", onFeatureDeleted);
missionStore.on("feature:linked", onFeatureLinked);
missionStore.on("mission:event", onMissionEvent);
missionStore.on("milestone:validation:updated", onMilestoneValidationUpdated);
}
if (aiSessionStore) {