Skip to content

Releases: peteroettl/Cadence

Release list

Cadence 1.0.0

Choose a tag to compare

@peteroettl peteroettl released this 01 Aug 11:57

Initial public release. Cadence's request scheduling, coalescing, and rate limiting were
extracted and generalized from a production weather app and decoupled from any HTTP client.

Added

  • RequestScheduler actor with three entry points: schedule, debounce, and coordinate.
  • RequestScheduling protocol to allow injecting a pass-through scheduler in tests.
  • RequestCombinable protocol for describing how concurrent requests are keyed, merged, and split.
  • SlidingWindowRateLimiter actor enforcing any number of layered RateLimitRules.
  • RateLimitRule with .perSecond / .perMinute / .perHour / .perDay convenience
    constructors and per-rule .wait / .throw behavior.
  • RateLimiter protocol for custom limiting strategies.
  • RateLimiterStorage with UserDefaultsRateLimiterStorage and InMemoryRateLimiterStorage
    implementations for persisting the rate-limit window across launches.
  • CadenceLogger pluggable diagnostics sink (NoopLogger default, PrintLogger helper).
  • CadenceClock time abstraction (SystemClock default) for deterministic tests.
  • Array.unique() helper for building combine implementations.
  • Full test suite (92% line coverage, verified with mutation analysis), GitHub Actions CI, and
    the Apache 2.0 license.
  • Mutation-testing tooling: muter.conf.yml, the /mutation-review skill, and the read-only
    mutation-survivor-triage agent.
  • Documentation covering Xcode consumption (remote + local packages, multi-target linking) and
    HTTP-client integration with kean/Get.

Security

  • Coalescing tracks each batch's task and parameters under a single AnyHashable(key), so two
    distinct coordination keys whose String(describing:) collide cannot cross-contaminate callers.
  • SlidingWindowRateLimiter and UserDefaultsRateLimiterStorage drop non-finite and future-dated
    persisted timestamps, so a tampered or corrupted backing store cannot permanently jam the limiter.
  • SystemClock.sleep(for:) guards isFinite and clamps magnitude before the Double → UInt64
    conversion, so a non-finite or astronomically large interval cannot trap the process.
  • CI runs with least-privilege permissions: contents: read and digest-pinned container images.