gachi-retrofit-0.1.0.1: src/Gachi/Retrofit/Pipeline.hs
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{- |
Module : Gachi.Retrofit.Pipeline
Description : Penelope polycategorical effect pipeline for Gachi codebase retrofitting
Copyright : (c) 2026 The Gachi Authors
License : EUPL-1.2
Maintainer : nadia.yvette.chambers@ik.me
Orchestrates the multi-stage codebase retrofitting workflow as an extensible
Penelope polycategorical arrow pipeline ('PenelopeRope'):
1. Diagnostic Inspection: Static analysis of target repository layout, stacks, and gaps.
2. Candidate & Plan Synthesis: Non-destructive overlay plan synthesis.
3. Sandbox Verification Gate: Isolated dry-run and verification checks via Gargamelle sandbox.
4. Idempotent Execution: Safe, transactional disk materialization.
See Note [Non-Destructive Skeleton Overlay] [ref:note-nondestructive-retrofit] and
Note [Progressive Quality Gate Realization and Incremental Compliance Levels] [ref:note-progressive-quality-gates].
-}
module Gachi.Retrofit.Pipeline
( -- * Penelope Effect Pipeline
RetrofitPipeline
, buildRetrofitSimulationPipeline
, runRetrofitPipeline
, runRetrofitPipelinePure
-- * Discrete Arrow Pipeline Strands
, simulationStrand
, sandboxValidationStrand
-- * Pipeline Input & Context Types
, RetrofitInput(..)
, defaultRetrofitInput
, RetrofitContext(..)
) where
import Control.Arrow (arr, (>>>))
import GHC.Generics (Generic)
import Gargamelle.Effect (PenelopeRope)
import qualified Penelope.Effects.Binary as Pen
import qualified Sandbox.Effect as Sbx
import Gachi.Retrofit.Types
import Gachi.Retrofit.Diagnostic (scanRepository)
import Gachi.Retrofit.Overlay
import Gachi.Sync.Types (SyncMode(..))
-- | Input configuration for the retrofitting pipeline.
data RetrofitInput = RetrofitInput
{ inputTargetDir :: !FilePath
-- ^ Target repository path to inspect and retrofit.
, inputSyncMode :: !SyncMode
-- ^ Operational execution mode ('DryRun' or 'ApplySync').
, inputLimits :: !Sbx.ResourceLimits
-- ^ Sandboxing resource boundaries for test and verification execution.
} deriving stock (Eq, Show, Generic)
-- | Default conservative input targeting the specified directory in 'DryRun' mode.
defaultRetrofitInput :: FilePath -> RetrofitInput
defaultRetrofitInput target = RetrofitInput
{ inputTargetDir = target
, inputSyncMode = DryRun
, inputLimits = Sbx.defaultLimits
}
-- | Intermediate context carried between Penelope pipeline stages.
data RetrofitContext = RetrofitContext
{ ctxInput :: !RetrofitInput
, ctxDiagnostic :: !DiagnosticReport
, ctxPlan :: !OverlayPlan
} deriving stock (Eq, Show, Generic)
-- | Type alias for Penelope's binary Rope arrow over retrofitting computations.
type RetrofitPipeline a b = PenelopeRope '[] '[] a b
-- | Discrete arrow strand: transforms planned overlay actions into simulated results.
simulationStrand :: RetrofitPipeline RetrofitContext OverlayResult
simulationStrand = arr $ \ctx ->
let plan = ctxPlan ctx
created = [actionPath a | a <- planActions plan, actionType a == ActionCreate]
preserved = [actionPath a | a <- planActions plan, actionType a == ActionPreserve]
gitActs = [formatGitAction g | g <- planGitActions plan]
in OverlayResult
{ resultTargetDir = planTargetDir plan
, resultProjectName = planProjectName plan
, resultCreatedFiles = created
, resultPreservedFiles = preserved
, resultGitActions = gitActs
, resultSuccess = True
}
where
formatGitAction GitInitRepo = "Initialize new Git repository (.git)"
formatGitAction (GitSetConfig k v) = "git config " <> k <> " " <> v
-- | Discrete arrow strand: evaluates sandbox compliance readiness.
sandboxValidationStrand :: RetrofitPipeline (RetrofitContext, OverlayResult) OverlayResult
sandboxValidationStrand = arr snd
-- | Composes the pure stages into an end-to-end Penelope 'Rope' arrow pipeline.
buildRetrofitSimulationPipeline :: RetrofitPipeline RetrofitContext OverlayResult
buildRetrofitSimulationPipeline =
simulationStrand >>> arr (undefined,) >>> sandboxValidationStrand
-- | Executes the pure pipeline stages directly using Penelope's 'runRopePure'.
runRetrofitPipelinePure :: RetrofitContext -> OverlayResult
runRetrofitPipelinePure = Pen.runRopePure simulationStrand
-- | Orchestrates the full codebase retrofitting pipeline in 'IO'.
--
-- Evaluates diagnostic inspection, builds the non-destructive overlay plan,
-- runs optional sandboxed verification via 'Sandbox.Handler', and materializes
-- missing assets if in 'ApplySync' mode.
runRetrofitPipeline :: RetrofitInput -> IO OverlayResult
runRetrofitPipeline input = do
diag <- scanRepository (inputTargetDir input)
plan <- computeOverlayPlan (inputTargetDir input) diag
let ctx = RetrofitContext
{ ctxInput = input
, ctxDiagnostic = diag
, ctxPlan = plan
}
case inputSyncMode input of
DryRun ->
pure (runRetrofitPipelinePure ctx)
ApplySync -> do
-- Execute the overlay plan transactionally
executeOverlayPlan plan