# CORE-SPEC.md ## Scope This document defines the formal contract of `kron-core`. `kron-core` is a pure, deterministic scheduling engine. It contains no side effects, no I/O, no persistence, and no adapter-specific logic. All adapters (`krond`, `kron-operator`, future integrations) must treat this specification as authoritative for scheduling behavior. --- ## Design Constraints `kron-core` must be: * Pure: no external state access. * Deterministic: identical inputs produce identical outputs. * Stateless: all required state is provided as input. * Time-explicit: no internal clock access. * Side-effect free. --- ## Versioning `kron-core` exposes a semantic version. A change that alters: * window calculation * seed derivation * distribution math * constraint evaluation * determinism guarantees requires a major version increment. --- ## Core Concepts ### Identity A stable string identifying the job: ``` Identity string ``` Must be UTF-8 and non-empty. --- ### Period A period is defined solely by: ``` NominalTime (UTC instant) Timezone (IANA) ``` `kron-core` does not compute cron schedules unless explicitly provided a schedule resolver. --- ## Primary Interfaces ### DecisionRequest The engine consumes a single request object: ``` DecisionRequest { Identity string NominalTime time.Time (UTC) Timezone string WindowMode enum {After, Around} WindowDuration time.Duration Distribution DistributionSpec SeedStrategy SeedSpec Salt string Constraints ConstraintSpec } ``` All times are interpreted in UTC except where constraints require timezone interpretation. --- ### DecisionResult The engine produces: ``` DecisionResult { PeriodID string NominalTime time.Time (UTC) WindowStart time.Time (UTC) WindowEnd time.Time (UTC) ChosenTime time.Time (UTC) SeedHash string Distribution DistributionSpec ConstraintMeta ConstraintMeta } ``` If unschedulable: ``` DecisionResult { ... ChosenTime nil Unschedulable true Reason string } ``` --- ## Determinism Requirements For identical `DecisionRequest` values: * `DecisionResult` must be byte-for-byte identical in: * `ChosenTime` * `SeedHash` * `WindowStart` * `WindowEnd` Determinism must hold across: * Process restarts * Different machines * Different architectures * Supported Go versions within compatibility window Floating point calculations must not introduce nondeterministic rounding across architectures. If floating math is used internally, results must be quantized deterministically before producing `ChosenTime`. --- ## PeriodID ``` PeriodID = NominalTime.UTC().Format(RFC3339) ``` Must not depend on timezone formatting differences. --- ## Window Computation Given: ``` N = NominalTime D = WindowDuration ``` If `WindowMode=After`: ``` WindowStart = N WindowEnd = N + D ``` If `WindowMode=Around`: ``` Half = D / 2 WindowStart = N - Half WindowEnd = N + Half ``` If `D=0`: ``` WindowStart = N WindowEnd = N ChosenTime = N ``` No distribution sampling occurs when `WindowStart == WindowEnd`. --- ## Seed Derivation Seed input string is constructed as: ``` SeedInput = Identity + "\n" + PeriodKey + "\n" + Salt ``` `PeriodKey` depends on seed strategy. ### Seed Strategies #### Stable ``` PeriodKey = PeriodID ``` #### Daily ``` PeriodKey = YYYY-MM-DD in Timezone corresponding to NominalTime ``` #### Weekly ``` PeriodKey = ISOWeek(YYYY-Www) in Timezone corresponding to NominalTime ``` --- ## Seed Hash A cryptographic hash function must be used. The hash function must: * Be fixed for a major version. * Produce identical results across platforms. * Be documented in implementation. Output encoding: ``` SeedHash = lowercase hexadecimal string ``` The full hash output must be used for PRNG seeding. --- ## PRNG Requirements The pseudorandom generator: * Must be deterministic for a given SeedHash. * Must produce reproducible sequences. * Must not depend on runtime-global randomness. Initialization: ``` PRNG(seed = SeedHash bytes) ``` Sequence generation order must be stable and documented. --- ## Distribution Specification ``` DistributionSpec { Name string Params map[string]string } ``` Parameter parsing must be deterministic. Unknown parameters must cause error. --- ## Distribution Contract Given: ``` U = PRNG.NextFloat64() ``` `U` must satisfy: ``` 0 ≤ U < 1 ``` Distributions must transform `U` into an offset within: ``` [0, WindowDuration] ``` or symmetrically around nominal in `Around` mode. The final offset must be clamped to window bounds. --- ## Constraint Specification ``` ConstraintSpec { OnlyClauses []Clause AvoidClauses []Clause } ``` Constraint evaluation must: * Interpret time in specified Timezone. * Be pure. * Not modify state. --- ## Candidate Selection Algorithm 1. Initialize PRNG with SeedHash. 2. For attempt in `0..MaxAttempts-1`: * Generate `U`. * Compute candidate offset via distribution. * Compute candidate time. * If candidate satisfies constraints: * Return candidate. 3. If no candidate accepted: * Return Unschedulable. `MaxAttempts` must be fixed and documented. `MaxAttempts` must be deterministic and independent of runtime conditions. --- ## Constraint Evaluation Rules Given candidate time `T`: * Convert `T` to schedule timezone. * Evaluate `OnlyClauses`: * If present, `T` must satisfy at least one clause set. * Evaluate `AvoidClauses`: * If any clause matches, candidate rejected. Clause types and evaluation logic are defined in SYNTAX.md. Constraint evaluation must not modify `T`. --- ## Error Handling The engine must return explicit errors for: * Invalid timezone * Invalid distribution name * Invalid distribution parameters * Invalid seed strategy * Invalid constraint definitions * Negative window duration Errors must not panic. --- ## Timezone Handling Timezone must be resolved via IANA database. If timezone is invalid: * Return error. All conversions must be deterministic given identical timezone database. Implementations must document supported timezone database source. --- ## Precision Rules * Internal calculations may use nanoseconds. * Final `ChosenTime` must be truncated or rounded in a deterministic manner. * Rounding policy must be stable and documented. ChosenTime must never fall outside window bounds due to rounding. --- ## Unschedulable Semantics If no valid candidate found: ``` DecisionResult.Unschedulable = true DecisionResult.ChosenTime = zero value ``` `SeedHash`, `WindowStart`, `WindowEnd`, and `PeriodID` must still be populated. --- ## Stability Guarantees For a fixed major version: * Seed derivation format must not change. * Hash algorithm must not change. * PRNG algorithm must not change. * Distribution math must not change. * Window computation must not change. Any change affecting output for identical inputs requires major version increment. --- ## Performance Requirements `Decision()` must: * Execute in bounded time. * Be O(1) relative to window duration. * Not allocate unbounded memory. * Not depend on external services. --- ## Prohibited Behaviors `kron-core` must not: * Access system clock. * Perform I/O. * Access filesystem. * Access network. * Read environment variables. * Use global mutable state. * Use non-deterministic randomness. --- ## Conformance A conforming implementation must: * Pass all golden test vectors defined in TEST-VECTORS.md. * Produce identical outputs across supported architectures. * Preserve determinism guarantees. Adapters must not alter or reinterpret `DecisionResult` fields. `kron-core` is the authoritative source of scheduling truth.