package com.correx.infrastructure.workflow

import com.fasterxml.jackson.annotation.JsonProperty

data class ExecutionPlanModel(
    val goal: String = "",
    val stages: List<PlanStage> = emptyList(),
    val edges: List<PlanEdge> = emptyList(),
)

data class PlanStage(
    val id: String = "",
    val role: String = "",
    val prompt: String = "",
    val produces: String = "",
    val kind: String? = null,
    val needs: List<String> = emptyList(),
    val tools: List<String> = emptyList(),
    // Workspace-relative file paths/globs this stage declares it will write (BACKLOG §B-§2).
    // Drives the plan-derived diff manifest: these are unioned with the static per-stage
    // write globs to form the enforced write-guard manifest. Absent/empty = no plan-derived
    // contribution (the static manifest, if any, still applies). The planner emits this under
    // the JSON key `writes`.
    val writes: List<String> = emptyList(),
    // Declared scope globs this stage's intent is confined to (architecture-conformance,
    // 2026-07-14). The planner emits this under the JSON key `touches`; every concrete path in
    // `writes` must fall within it or the plan is rejected at compile time. Absent/empty = no
    // scope constraint. Set it on narrow stages (a frontend-client stage → ["frontend/**"]) so a
    // stage that quietly widens into the backend is caught before it writes.
    val touches: List<String> = emptyList(),
    // Execution-gate scope (staged-verification §2): none|module|project|tests. Absent = none. The
    // planner emits this under the JSON key `build_expectation`; it resolves at runtime to the
    // project profile's typecheck/build/test command run as a deterministic Gate 4.
    @param:JsonProperty("build_expectation") val buildExpectation: String? = null,
    // Opt-in to the Gate 3 semantic (LLM) reviewer for this stage (staged-verification § Gate 3).
    // The planner emits this under the JSON key `semantic_review`; absent = off.
    @param:JsonProperty("semantic_review") val semanticReview: Boolean = false,
)

data class PlanEdge(
    val from: String = "",
    val to: String = "",
    val condition: PlanCondition = PlanCondition(),
)

data class PlanCondition(
    val type: String = "always_true",
    @param:JsonProperty("artifact_id") val artifactId: String? = null,
    val key: String? = null,
    val field: String? = null,
    val value: String? = null,
    val operator: String? = null,
)
