# v0.4.5 (22 May 2026) {#v045-22-may-2026}

[v0.4.5 on GitHub](https://github.com/higher-kinded-j/higher-kinded-j/releases/tag/v0.4.5)

**A Uniform `Instances` Facade for Type-Class Lookup**

This release introduces `Instances`, a single static entry point for obtaining any built-in type-class instance, replacing the three inconsistent legacy idioms (a static `INSTANCE` field, a generic `instance()` method, or an argument-taking constructor) with one predictable shape discovered by capability through IDE autocomplete. The whole codebase (tests, runnable examples, and the book) is migrated to the one idiom.

- [Obtaining Instances](../functional/instances_facade.md): New `org.higherkindedj.hkt.instances` package with the `Instances` facade and the `Witnesses` typed-token helper. `Instances.monad/applicative/functor(token)` are total (every canonical instance is at least a `Monad`); a single token yields all three by Java subtyping. Phantom-typed witnesses (`Either`, `Reader`, `Context`, `State`) still infer their type parameter from the assignment target, matching `EitherMonad.<L>instance()` behaviour. The facade is a thin static re-export of the existing accessors (not Spring-wired, not `PathRegistry`/`ServiceLoader`-backed) so compile-time safety is preserved and no built-in instance can be missing at runtime ([#522](https://github.com/higher-kinded-j/higher-kinded-j/issues/522))
- [Partial capability lookups](../functional/instances_facade.md): `Instances.monadError`, `monadZero` and `alternative` for canonical instances that implement the richer capability (e.g. `Maybe`, `Optional`, `Try`, `Either`, `List`, `Stream`). The error type `E` of `monadError` is inferred from the assignment target; asking for a capability the instance does not have fails fast with a `ClassCastException`, exactly as calling a non-existent method would
- [Argument-carrying re-exports](../functional/instances_facade.md): `Instances.validated(Semigroup)`, `writer(Monoid)`, `eitherT(outer)`, `maybeT(outer)`, `optionalT(outer)`, `readerT(outer)`, `stateT(outer)` and `writerT(outer, Monoid)`. The structurally-required dependency is now a compiler-enforced, self-documenting method parameter instead of something discovered by reading a constructor
- One-idiom migration: The `Instances` facade is adopted across ~196 test files, 66 runnable examples, and 71 book pages so the documentation and examples teach a single way to obtain an instance. The `MonadReader`/`MonadState` MTL capability classes and `Traverse`/`Selective`/`Foldable` remain a separate surface, intentionally out of scope for this facade and tracked separately
- Reference material: New [glossary](../glossary.md) entry, a Type-Class Instances section in the [cheat sheet](../cheatsheet.md), and a `InstancesFacadeExample` runnable example
- [Bifunctor law verification](../functional/bifunctor.md): The reusable Bifunctor law harness (`LawTestPattern`/`TypeClassTestPattern`) now verifies the first-map (`first(f, fab) == bimap(f, id, fab)`) and second-map (`second(g, fab) == bimap(id, g, fab)`) consistency laws alongside the existing identity and composition laws, so every canonical instance (`Either`, `Tuple`, `Const`, `Validated`, `Writer`) is checked against all four laws; explicit named consistency tests added for `Either` (Left/Right) and `Tuple` ([#461](https://github.com/higher-kinded-j/higher-kinded-j/issues/461))
- [Collection-path fold family](../functional/foldable_and_traverse.md): `ListPath` and `StreamPath` gain the monoid-style `fold(identity, op)` and the `Foldable`-style `foldMap(Monoid, fn)`, plus `foldRight` on `StreamPath`, matching the existing `VStreamPath`/`VStreamContext` fold surface so the same reduction reads identically across every sequence-like path and stays inside the path chain. Documented in the [cheat sheet](../cheatsheet.md) and the Foldable chapter, with `CollectionPathsExample` updated to fold without unwrapping ([#462](https://github.com/higher-kinded-j/higher-kinded-j/issues/462))
- [Effect Path `toString()` standardisation](../effect/effect_path_overview.md): A shared `PathToString` helper gives every Effect Path type one debugging-friendly, greppable `toString()` convention: the round-parenthesis wrapper form `TypeName(inner)`, a uniform angle-bracketed sentinel vocabulary (`<deferred>`, `<stream>`, `<empty>`, `<pending>`, `<failed>`), and bounded rendering for collection-backed paths (`ListPath`, `NonDetPath`, `WriterPath` logs) with an explicit `…(+k more)` marker so a large backing collection never produces an unbounded log line. `IdPath` is now null-safe and `LazyPath` never forces its computation when rendered; all changed path classes hold at 100% line/branch coverage ([#530](https://github.com/higher-kinded-j/higher-kinded-j/issues/530))

**Expanded `hkj-checker` Compile-Time Diagnostics**

This release grows the `hkj-checker` javac plugin from a single Path-type-mismatch check into a catalogue of twelve compile-time checks, adds per-check severity configuration, and consolidates the relevant OpenRewrite recipes into compile-time feedback. Several further candidate checks were investigated and deliberately not shipped (kept as passing characterisation tests that document why) because the targeted error is unreachable on modern javac, already caught by the compiler, or only detectable via a rot-prone heuristic; the strict no-false-positives policy is preserved throughout.

- [Compile-Time Checks](../tooling/compile_checks.md): Eleven new checks join `path-type-mismatch`: `effect-composition`, `transformer-missing-monad`, `free-switch-exhaustive`, `discarded-effect`, `state-t-mapt-arity`, `error-type-mismatch`, `kind-value-narrow`, `witness-arity`, `via-non-path`, `map-nests-effect`, and `migration-nudge`. Each is a companion to a real javac error or the sole signal for an otherwise-silent mistake (a discarded lazy effect, a silently-erased error type, a nested effect); the sole-signal heuristics default to a warning
- [Per-check severity](../tooling/compile_checks.md): The plugin-argument grammar adds `severity:<id>=error|warn` alongside the global `severity=` and `disable=<id>`, so the warn-default checks can be promoted per project. Unknown ids and unparseable values are ignored so a typo never breaks the build
- Recipe consolidation: `migration-nudge` folds the `ConvertRawFreeToFreePath` and `DetectInjectBoilerplate` OpenRewrite diagnoses into advisory compile-time nudges; `free-switch-exhaustive` and `witness-arity` do the same for the Free-switch and `WitnessArity` recipes
- Documentation: `tooling/compile_checks.md` is now the authoritative checker catalogue (every check, its default severity, and the configuration grammar); the effect/transformers/optics *Common Compiler Errors* chapters were corrected where they described errors modern javac no longer emits and cross-linked to the catalogue

**Hardened `hkj-openrewrite` Recipes**

This release audits and hardens the `hkj-openrewrite` migration recipes: correctness fixes, broader detection, type-safe matching, new 0.5.0 deprecation recipes, and a near-quadrupled test suite (9 → 34 tests).

- Arity bounds: `AddArityBoundsToTypeParameters` now emits `TypeArity.Binary` for `Kind2`, `Bifunctor` and `Profunctor` (previously always `Unary`, which generated incorrect bounds), detects witness use across fields, local variables, the class hierarchy, nested generics and wildcard bounds (not just method signatures), and no longer emits malformed output (`<Fextends  …>`); the existing-bound intersection case is also fixed
- Type-safe detection: `ConvertRawFreeToFreePath` and `DetectInjectBoilerplate` use a type-attributed `MethodMatcher` instead of rendered-string matching (a user type named `Free`, fully-qualified calls, or static imports no longer mis-fire or get missed); `AddHandleErrorCase` now also handles switch *expressions* with whole-word case matching; the three detect-only recipes emit OpenRewrite search-result markers instead of rewriting source with TODO comments
- 0.5.0 deprecation migration: New `MigrateDeprecationsTo0_5_0` recipe group renames `StateTKind.narrowK` → `narrow` and `KindValidator.narrowWithPattern` → `narrowHolder`

**Library and Build Refinements**

This release also marks one wildcard-witness escape hatch for removal, makes the Java 25 toolchain self-provisioning, and lands the module-internal foundation for batched optic data access.

- `StateTKind.narrowK` deprecation: `StateTKind.narrowK` accepts a wildcard-witness `Kind<?, A>`, bypassing the HKT witness type safety enforced everywhere else in the library; it has no callers and the type-safe `narrow(Kind)` already covers the use case. It is now `@Deprecated(forRemoval = true)` for removal in 0.5.0, with the `MigrateDeprecationsTo0_5_0` OpenRewrite recipe automating the `narrowK` → `narrow` rename ([#455](https://github.com/higher-kinded-j/higher-kinded-j/issues/455))
- Java 25 toolchain auto-provisioning: `settings.gradle.kts` applies the `foojay-resolver-convention` plugin so Gradle downloads and provisions a matching Java 25 JDK automatically when the build machine does not already have one, removing a manual setup step for new contributors
- Request-batching substrate: New module-internal `org.higherkindedj.optics.fetch` package: a free-applicative-style `Fetch<K, V, A>` (`Done`/`Blocked`) and `FetchApplicative` that plug into the optic `modifyF` seam so a traversal whose focused values are loaded from a backend coalesces those N loads into one batched call (the classic N+1), with a transport- and datastore-neutral `BatchLoader` contract and round-based `runCached`/`runAsync` runners carrying a per-run request cache. The package is intentionally not exported; it is the foundation for later data-access capabilities and carries no public API yet ([#539](https://github.com/higher-kinded-j/higher-kinded-j/issues/539))

---

**Previous:** [v0.4.6](v0_4_6.md)
**Next:** [v0.4.4](v0_4_4.md)
