TEST-VECTORS.md

Canonical algorithms for vectors

These test vectors are defined against a fixed, fully specified core algorithm set.

Machine-readable vectors

The executable golden vectors used by kron-core tests live in:

  • core/testdata/vectors/v1.json

  • core/testdata/vectors/v2.json

  • core/testdata/vectors/v3.json

  • core/testdata/vectors/v4.json

  • core/testdata/vectors/v5.json

  • core/testdata/vectors/v6.json

  • core/testdata/vectors/v7.json

Current implementation coverage in that file focuses on implemented MVP behavior:

  • uniform, skewEarly, and skewLate distributions (including skew shape parameter coverage)

  • after, before, and around/center window behavior

  • zero-duration window behavior

  • seed strategies (stable, daily, weekly)

  • constraint handling (hours, dow, between, dom, months, date/dates) and unschedulable outcomes

  • edge cases: timezone period-key boundaries and odd around durations

Seed hash

  • HASH = SHA-256

  • SeedInput = Identity + "\n" + PeriodKey + "\n" + Salt

  • SeedHash = hex(lowercase(SHA-256(SeedInput)))

PRNG

  • PRNG = SplitMix64

  • seed_u64 = uint64_be(SHA-256(SeedInput)[0:8])

  • SplitMix64 step:

x = x + 0x9E3779B97F4A7C15
z = x
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9
z = (z ^ (z >> 27)) * 0x94D049BB133111EB
z = z ^ (z >> 31)
return z
  • NextFloat64():

u = next_uint64()
f = (u >> 11) / 2^53

So 0 f < 1.

Window mapping

Let W = window_end - window_start in whole seconds, where W 0.

  • If W == 0: chosen_time = window_start.

  • Else, for a unit value x in [0,1):

offset_seconds = floor(x * (W + 1))
chosen_time = window_start + offset_seconds seconds

This mapping permits selecting window_end when offset_seconds == W.

Distributions

Let u = NextFloat64().

  • uniform:

    • x = u

  • skewEarly(shape=s) where s > 0:

    • x = u^s

  • skewLate(shape=s) where s > 0:

    • x = 1 - (1 - u)^s

Constraints are evaluated after mapping to a candidate time, using deterministic resampling with the same PRNG stream.

Constraint sampling budget

  • MaxAttempts = 64

  • Attempts consume one NextFloat64() per attempt.

If no candidate satisfies constraints after MaxAttempts, the period is unschedulable.


Notation

  • Times are RFC3339 UTC.

  • PeriodID = NominalTime.UTC().Format(RFC3339).

  • For SeedStrategy=stable, PeriodKey = PeriodID.

  • For SeedStrategy=daily, PeriodKey = YYYY-MM-DD in Timezone corresponding to NominalTime.

  • For SeedStrategy=weekly, PeriodKey = ISO week YYYY-Www in Timezone corresponding to NominalTime.


Core decision vectors

V1 — uniform, after-window, stable seed

Request

  • Identity: prod/db-backup

  • NominalTime: 2026-03-01T00:00:00Z

  • Timezone: UTC

  • WindowMode: after

  • WindowDuration: 3h (W=10800)

  • Distribution: uniform

  • SeedStrategy: stable

  • Salt: backup

  • Constraints: none

Expected

  • PeriodID: 2026-03-01T00:00:00Z

  • WindowStart: 2026-03-01T00:00:00Z

  • WindowEnd: 2026-03-01T03:00:00Z

  • SeedHash: 9c85657760a63b4d925af6088cceb2bb4448380b2e6856b203915a0a51ab5101

  • First u: 0.8462881248863515

  • offset_seconds: 9140

  • ChosenTime: 2026-03-01T02:32:20Z

  • Unschedulable: false


V2 — skewLate, around-window, stable seed

Request

  • Identity: msgs/paris

  • NominalTime: 2026-03-02T09:00:00Z

  • Timezone: Europe/Paris

  • WindowMode: around

  • WindowDuration: 90m (W=5400)

  • Distribution: skewLate(shape=2.5)

  • SeedStrategy: stable

  • Salt: msgs

  • Constraints: none

Expected

  • PeriodID: 2026-03-02T09:00:00Z

  • WindowStart: 2026-03-02T08:15:00Z

  • WindowEnd: 2026-03-02T09:45:00Z

  • SeedHash: 8b95acf566414238f55eb4541a1bc726b80d02fe86a0cd2ad52988a74860b2f5

  • First u: 0.4757178150383121

  • x = 1 - (1-u)^2.5: 0.800972654023368

  • offset_seconds: 4326

  • ChosenTime: 2026-03-02T09:27:06Z

  • Unschedulable: false


V3 — daily seed strategy

Request

  • Identity: daily/test

  • NominalTime: 2026-03-01T00:00:00Z

  • Timezone: UTC

  • WindowMode: after

  • WindowDuration: 1h (W=3600)

  • Distribution: uniform

  • SeedStrategy: daily

  • Salt: empty

  • Constraints: none

Expected

  • PeriodID: 2026-03-01T00:00:00Z

  • PeriodKey: 2026-03-01

  • WindowStart: 2026-03-01T00:00:00Z

  • WindowEnd: 2026-03-01T01:00:00Z

  • SeedHash: 3a1cbafc74e05e46dc6a4eff53a9d71da286eda9585a70c5c19bd43c52763161

  • First u: 0.3528233669308106

  • offset_seconds: 1270

  • ChosenTime: 2026-03-01T00:21:10Z

  • Unschedulable: false


V4 — zero window duration (no sampling)

Request

  • Identity: exact/nojitter

  • NominalTime: 2026-01-01T00:00:00Z

  • Timezone: UTC

  • WindowMode: after

  • WindowDuration: 0s (W=0)

  • Distribution: uniform

  • SeedStrategy: stable

  • Salt: empty

  • Constraints: none

Expected

  • PeriodID: 2026-01-01T00:00:00Z

  • WindowStart: 2026-01-01T00:00:00Z

  • WindowEnd: 2026-01-01T00:00:00Z

  • SeedHash: 8b0e1ef5c9c9886e07842b8f00c04697f5257c68188a33de362a414012b4eb84

  • ChosenTime: 2026-01-01T00:00:00Z

  • Unschedulable: false


V5 — constraints cause unschedulable (sampling budget exceeded)

Constraint model

  • Only: between=18:58-19:00 in UTC (inclusive bounds)

  • Equivalent allowed offset range (relative to window start): 3500..3600 seconds inclusive

  • MaxAttempts = 64

Request

  • Identity: home/lights

  • NominalTime: 2026-03-01T18:00:00Z

  • Timezone: UTC

  • WindowMode: after

  • WindowDuration: 1h (W=3600)

  • Distribution: uniform

  • SeedStrategy: stable

  • Salt: lights

  • Constraints: Only(between=18:58-19:00)

Expected

  • PeriodID: 2026-03-01T18:00:00Z

  • WindowStart: 2026-03-01T18:00:00Z

  • WindowEnd: 2026-03-01T19:00:00Z

  • SeedHash: d61bedd4e238549ebdb9d45993ea58904aa8042c4691967c720b0f2006416345

  • ChosenTime: empty

  • Unschedulable: true

  • Reason: no candidate accepted within MaxAttempts


V6 — calendar constraints (dom, months, date/dates) in zero-window cases

v6.json adds deterministic zero-window vectors to validate day/month/date-range constraint behavior.

Coverage in this vector set:

  • schedulable candidate with combined Only(dom, months, dates)

  • unschedulable candidate with Avoid(dom)

  • unschedulable candidate with Avoid(months)

  • unschedulable candidate with Avoid(dates range)


V7 — skew-shape parameter determinism

v7.json adds deterministic vectors for skewLate with explicit shape values.

Coverage in this vector set:

  • explicit shape=1.5

  • explicit shape=2.5

  • stable output differences from shape changes under fixed period/window/seed strategy


Adapter outcome vectors

These vectors combine a core decision with policy evaluation at a specific now.

A1 — missed with deadline=0s

Decision

Use V1 decision.

  • ChosenTime: 2026-03-01T02:32:20Z

Policy

  • deadline = 0s

  • concurrency = forbid

  • suspend = false

Input

  • now = 2026-03-01T02:32:21Z

  • active_execution = false

  • state: period not handled yet

Expected outcome

  • Terminal outcome: missed

  • No execution started

  • Period marked handled as missed


A2 — executed within deadline

Decision

Use V1 decision.

  • ChosenTime: 2026-03-01T02:32:20Z

Policy

  • deadline = 10m

  • concurrency = forbid

  • suspend = false

Input

  • now = 2026-03-01T02:40:00Z

  • active_execution = false

  • state: period not handled yet

Expected outcome

  • Terminal outcome: executed

  • Execution started once

  • Period marked handled as executed


A3 — skipped due to forbid concurrency

Decision

Use V3 decision.

  • ChosenTime: 2026-03-01T00:21:10Z

Policy

  • deadline = 30m

  • concurrency = forbid

  • suspend = false

Input

  • now = 2026-03-01T00:25:00Z

  • active_execution = true

Expected outcome

  • Terminal outcome: skipped

  • No new execution started

  • Period marked handled as skipped


A4 — idempotency prevents duplicate execution

Decision

Use V1 decision.

Policy

  • deadline = 10m

  • concurrency = allow

  • suspend = false

Input

  • now = 2026-03-01T02:35:00Z

  • active_execution = false

  • state: LastHandledPeriodID == 2026-03-01T00:00:00Z with outcome=executed

Expected outcome

  • No execution started

  • Period remains handled

  • Adapter reports job_exists / already handled behavior