gachi-plan-0.1.0.0: src/Gachi/Plan/Types.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
-- | Module: Gachi.Plan.Types
-- Description: Core types, models, and data structures for ecosystem plan governance
--
-- This module defines the foundational algebraic data models for the isolated
-- detached Git store architecture (~/src/PLAN.md §1.A, Phase 5, Milestone 5.1).
--
-- = Architectural Context & Invariants
--
-- In accordance with Note [Plan Governance and Rollback Mechanics]
-- [ref:note-plan-governance-rollback], planning files across @~/src/@ are
-- tracked in an isolated detached Git repository without interfering with
-- child repository checkouts. This module formalizes the data models representing
-- the detached store configuration, execution errors, status queries, snapshot
-- ledger metadata, and governed document invariants.
--
-- See also Note [Append-Only Plan Snapshot Invariants] [ref:note-plan-snapshots].
module Gachi.Plan.Types
( -- * Store Configuration
PlanStore(..)
, defaultGovernedFiles
, defaultStoreName
, planGitDirEnvVar
-- * Snapshot Ledger Configuration & Metadata
, SnapshotMeta(..)
, planSnapshotDirEnvVar
, defaultSnapshotDirName
-- * Store Status & Metadata
, PlanStoreStatus(..)
, isPlanStoreClean
-- * Rollback, Diff & Log Models
, RollbackResult(..)
, PlanDiff(..)
, PlanCommit(..)
, CheckpointResult(..)
-- * Failure Conditions
, PlanError(..)
) where
import Data.Text (Text)
import Data.Time (UTCTime)
import GHC.Generics (Generic)
-- | Configuration and runtime handle for a detached Git plan store.
--
-- The detached store separates the repository metadata directory (@--git-dir@)
-- from the working directory root (@--work-tree@). This architecture guarantees
-- that no nested @.git@ directory is created in @~/src/@, completely avoiding
-- collisions with child repository checkouts.
data PlanStore = PlanStore
{ planGitDir :: !FilePath
-- ^ Absolute path to the detached bare Git repository directory
-- (e.g. @/home/nyc/.plan.git@ or @/home/nyc/src/.plan.git@).
, planWorkTree :: !FilePath
-- ^ Absolute path to the governed working tree root directory
-- (e.g. @/home/nyc/src@).
, planGovernedFiles :: ![FilePath]
-- ^ Canonical relative paths of governance documents tracked by the store.
}
deriving stock (Eq, Show, Generic)
-- | Canonical ecosystem planning and governance files tracked by the detached store.
--
-- Per Note [Plan Governance and Rollback Mechanics] [ref:note-plan-governance-rollback],
-- the detached Git store exclusively tracks top-level planning documents and roadmap
-- indexes across @~/src/@.
defaultGovernedFiles :: [FilePath]
defaultGovernedFiles =
[ "PLAN.md"
, "STATE.md"
, "INDEX.md"
, "docs/INDEX.md"
]
-- | Default name of the bare Git store directory relative to the home directory.
defaultStoreName :: FilePath
defaultStoreName = ".plan.git"
-- | Standard environment variable name for overriding the detached Git store path.
planGitDirEnvVar :: String
planGitDirEnvVar = "PLAN_GIT_DIR"
-- | Standard environment variable name for overriding the snapshot ledger directory.
planSnapshotDirEnvVar :: String
planSnapshotDirEnvVar = "PLAN_SNAPSHOT_DIR"
-- | Default snapshot ledger directory relative to workspace root or home directory.
defaultSnapshotDirName :: FilePath
defaultSnapshotDirName = "plans/snapshots"
-- | Metadata record describing an immutable snapshot within the snapshot ledger.
--
-- In accordance with Note [Append-Only Plan Snapshot Invariants] [ref:note-plan-snapshots],
-- each snapshot preserves a byte-for-byte replica of a governed planning document
-- prior to mutation or at an explicit milestone checkpoint.
data SnapshotMeta = SnapshotMeta
{ snapshotId :: !Text
-- ^ Unique snapshot identifier (typically matching the snapshot file name).
, snapshotPath :: !FilePath
-- ^ Absolute filesystem path to the immutable snapshot file.
, snapshotTimestamp :: !UTCTime
-- ^ Timestamp when the snapshot was recorded in UTC.
, snapshotSha256 :: !Text
-- ^ Cryptographic SHA-256 digest of the snapshot file contents.
, snapshotSourceFile :: !FilePath
-- ^ Original governed file name or relative path that was snapshotted (e.g. @"PLAN.md"@).
, snapshotIsCheckpoint :: !Bool
-- ^ Whether this snapshot marks an immutable milestone checkpoint exempt from automated pruning.
}
deriving stock (Eq, Show, Generic)
-- | Observed runtime status, commit metadata, and dirty state of a detached Git plan store.
--
-- Captures the current HEAD commit hash, dirty tracking state of governed files,
-- commit timestamp, and tracked file inventory.
data PlanStoreStatus = PlanStoreStatus
{ statusStorePath :: !FilePath
-- ^ Absolute path to the detached Git store directory.
, statusWorkTree :: !FilePath
-- ^ Absolute path to the governed working tree root directory.
, statusHeadCommit :: !(Maybe Text)
-- ^ Full 40-character SHA-1 commit hash of the current HEAD revision,
-- or 'Nothing' if the repository is newly initialized without commits (unborn HEAD).
, statusIsDirty :: !Bool
-- ^ 'True' if any governed document has unstaged modifications, staged changes,
-- or exists untracked in the worktree.
, statusLastCommitTime :: !(Maybe UTCTime)
-- ^ Timestamp of the most recent commit in UTC, or 'Nothing' if unborn.
, statusDirtyFiles :: ![FilePath]
-- ^ Canonical relative paths of governed files that have uncommitted or untracked changes.
, statusTrackedFiles :: ![FilePath]
-- ^ Canonical relative paths of governed files currently tracked in the Git index.
}
deriving stock (Eq, Show, Generic)
-- | Predicate checking whether a plan store has zero uncommitted or untracked changes.
isPlanStoreClean :: PlanStoreStatus -> Bool
isPlanStoreClean status = not (statusIsDirty status)
-- | Outcome of an atomic rollback operation.
--
-- In accordance with Note [Deterministic Plan Rollback Invariants]
-- [ref:note-plan-rollback-invariants], records the target commit hash, safety pre-mutation
-- snapshots taken prior to modifying disk state, list of restored governed files,
-- and bitwise integrity verification status.
data RollbackResult = RollbackResult
{ rollbackTargetRef :: !Text
-- ^ The target commit hash or git reference to which the store was rolled back.
, rollbackSafetySnapshots :: ![SnapshotMeta]
-- ^ Pre-mutation safety snapshots recorded in the ledger prior to destructive checkout.
, rollbackRestoredFiles :: ![FilePath]
-- ^ Canonical relative paths of governed files successfully restored from the object store.
, rollbackVerified :: !Bool
-- ^ 'True' if restored file contents were verified for byte-level integrity against the git object store.
}
deriving stock (Eq, Show, Generic)
-- | Structured diff report comparing working planning documents against a Git revision.
data PlanDiff = PlanDiff
{ diffTargetRef :: !(Maybe Text)
-- ^ Target git reference compared against ('Nothing' indicates HEAD).
, diffRawContent :: !Text
-- ^ Raw unified diff text output from git diff.
, diffChangedFiles :: ![FilePath]
-- ^ Relative file paths of governed files exhibiting modifications.
, diffAdditions :: !Int
-- ^ Total number of added lines (+).
, diffDeletions :: !Int
-- ^ Total number of deleted lines (-).
}
deriving stock (Eq, Show, Generic)
-- | Historical commit record retrieved from the detached Git plan store.
data PlanCommit = PlanCommit
{ commitHash :: !Text
-- ^ Full 40-character SHA-1 commit hash.
, commitShortHash :: !Text
-- ^ Abbreviated commit hash (7 characters).
, commitAuthor :: !Text
-- ^ Author name and email stanza.
, commitTimestamp :: !UTCTime
-- ^ Commit timestamp in UTC.
, commitSubject :: !Text
-- ^ First line of commit message.
, commitBody :: !Text
-- ^ Commit message explanatory body.
, commitTrailers :: ![(Text, Text)]
-- ^ Parsed RFC 2822 git trailers (e.g. ("Assisted-by", "Antigravity")).
}
deriving stock (Eq, Show, Generic)
-- | Outcome of creating a milestone checkpoint in the plan store.
data CheckpointResult = CheckpointResult
{ checkpointCommitSha :: !Text
-- ^ Commit hash of the created checkpoint in the detached store.
, checkpointSnapshots :: ![SnapshotMeta]
-- ^ Immutable milestone snapshots recorded in the ledger.
, checkpointStagedFiles :: ![FilePath]
-- ^ Governed files staged and committed.
, checkpointMessage :: !Text
-- ^ Final commit message including attribution trailers.
}
deriving stock (Eq, Show, Generic)
-- | Error conditions encountered during detached Git store lifecycle or operations.
data PlanError
= PlanGitError !Text
-- ^ An underlying git command exited with a non-zero exit code.
-- Contains the captured standard error output.
| PlanStoreMissing !FilePath
-- ^ The specified detached Git store directory does not exist or is not a valid bare Git repository.
| PlanWorkTreeMissing !FilePath
-- ^ The specified working tree root directory does not exist.
| PlanIOError !Text
-- ^ A filesystem or I/O failure occurred during store operations.
| PlanInvalidPath !FilePath
-- ^ A provided filesystem path is malformed or invalid.
deriving stock (Eq, Show, Generic)