# v0.4.8 (17 July 2026) {#v048-17-july-2026}

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

**Async, Typed Errors, and Resilience**

The Path family gains a typed-error async carrier and a single resilience vocabulary.

- [VResultPath](../effect/path_vresult.md): A first-class railway for `VTask<Either<E, A>>` (async work that can fail with a typed domain error), speaking the family vocabulary (`map`/`via`/`then`, `mapError`/`recover`/`recoverWith`/`bimap`) with no `EitherT` bridges. Structured-concurrency combinators (`firstSuccess`, `allSucceed`/`allSucceedAccumulating`, `withTimeout`, `bracketOutcome`) keep typed failures in the value channel; defects stay on the `VTask` channel ([#606](https://github.com/higher-kinded-j/higher-kinded-j/issues/606))
- [Path-native resilience](../resilience/ch_intro.md): `withRetry`/`withTimeout`/`withCircuitBreaker`/`withBulkhead` now form one `with*` vocabulary across the family: instance-chained on the lazy carriers (`IOPath`, `VTaskPath`, `VResultPath`), static (step-as-`Supplier`) on the eager `EitherPath`. Railway-aware: a business `Left` is a value (never retried, never trips the breaker), while typed overloads opt selected transient errors into retry and land timeouts/rejections as `Left`s ([#607](https://github.com/higher-kinded-j/higher-kinded-j/issues/607))

**Validation and Error Accumulation**

A non-empty error channel, an inclusive-or, and open-arity validated assembly.

- [NonEmptyList](../monads/nonemptylist_monad.md): A list that encodes "at least one element" in the type, so `head`/`last`/`reduce` are total. The canonical companion to `Validated` (mirroring Cats' `NonEmptyList`/`ValidatedNel`): `Path.validNel`/`invalidNel` and `Validated.validNel`/`invalidNel` bake in its semigroup, dropping the manual `Semigroups.list()` argument. Full `Kind`/`Functor`/`Monad`/`Traverse` support, an `assertThatNonEmptyList` assertion, and Jackson support in `hkj-spring`. Purely additive ([#549](https://github.com/higher-kinded-j/higher-kinded-j/issues/549))
- [EitherOrBoth](../monads/either_or_both_monad.md): The inclusive-or (`Ior`/`These`) for a success that also carries non-fatal warnings: sealed over `Left`/`Right`/`Both`, right-biased, with total `Maybe`-returning accessors. Accumulating `flatMap`, a `Kind`/`Kind2` with `Bifunctor`, an [EitherOrBothPath](../effect/path_either_or_both.md) railway, plus `hkj-spring` Jackson support and a warnings-in-header return handler. Purely additive ([#551](https://github.com/higher-kinded-j/higher-kinded-j/issues/551), [#583](https://github.com/higher-kinded-j/higher-kinded-j/pull/583))
- [Open-arity accumulating assembly](../monads/validated_assembly.md): `Validated.fields()`/`accumulate()` assemble a record from N validated fields (any arity to 16) with every error collected in declaration order, no `Semigroup` argument, and no `Kind` ceremony. Errors are located `FieldError`s with composable paths; one shape across three carriers: `Validated` (strict), `ValidationPath` (railway), and `EitherOrBoth` (tolerant) ([#581](https://github.com/higher-kinded-j/higher-kinded-j/issues/581))
- [@GenerateAssembly](../monads/validated_assembly.md): The codegen layer for the above: annotate a record and get a same-package `UserAssembly.fields().name(v)…assemble()` companion with one order-enforcing method per component; a component typed as another annotated record accepts its sub-companion's result directly ([#586](https://github.com/higher-kinded-j/higher-kinded-j/issues/586))
- [Assembly arity ceiling](../monads/validated_assembly.md): the shared `accumulate()`/`fields()` ladder, and the `@GenerateMapping`/`@GenerateMerge` `parse` built on it, locate up to **16 components**; the ladder generates its own `Tuple13..16` so the For-comprehension arity stays independent at 12 ([#626](https://github.com/higher-kinded-j/higher-kinded-j/issues/626))
- [PathOps first-success NonEmptyList overloads](../effect/advanced_topics.md): The five race/first-success combinators gain total `NonEmptyList` overloads beside the throwing `List` ones, so a statically-known competitor set needs no empty guard ([#579](https://github.com/higher-kinded-j/higher-kinded-j/issues/579), [#585](https://github.com/higher-kinded-j/higher-kinded-j/pull/585))

**Record Mapping and Typed-Error Codegen**

Three annotation processors for the record↔DTO boundary.

- [@GenerateMapping](../mapping/ch_intro.md): Annotate `interface UserMapping extends MappingSpec<User, UserDto>` and the processor generates a total `build` plus an accumulating `parse` returning `Validated<NonEmptyList<FieldError>, User>`. `@MapField` renames, nesting, `List`/`Optional`/`Map` container lifting (map values lift like list elements, keys are identity), derived wire fields (a `Getter`-returning `default` method fills a wire-only component on `build`), sealed-interface dispatch, and truthful emission tiers (`asIso` / `asLens` / accumulating `parse`). Every tier is law-checked against the published `hkj-test` harness ([#600](https://github.com/higher-kinded-j/higher-kinded-j/issues/600))
- [@GenerateMerge](../mapping/ch_intro.md): The forward-only assembler: annotate an interface whose one method declares `DashboardDto assemble(User, Account, Settings)` and the processor fills each target component from the same-named source (identity or through a `ValidatedPrism` leaf). Ambiguous or unfilled components are what/why/fix compile errors; no inverse is generated ([#613](https://github.com/higher-kinded-j/higher-kinded-j/issues/613))
- [@GenerateErrorEnvelope](../mapping/merge_envelopes.md#generating-error-envelopes-generateerrorenvelope): Each variant of a sealed error hierarchy declares only its domain fields plus one `ErrorEnvelope<C>` component, and the processor generates the `<Name>s` companion: per-variant factories, a typed context builder, and an `editContext` wither. Context is records-as-schema (`context.orderId()`, not `map.get(...)`); timestamps read from a `TimeSource` for deterministic tests ([#610](https://github.com/higher-kinded-j/higher-kinded-j/issues/610))

**Optics**

- [ValidatedPrism](../optics/validated_prism.md): The smart-constructor optic for parse-don't-validate boundaries: `parse` returns `Validated<NonEmptyList<FieldError>, A>` (every failure located), `build` is total. Nested composition short-circuits while siblings accumulate; both round-trip laws ship as `ValidatedPrismLaws` in `hkj-test`. Purely additive ([#597](https://github.com/higher-kinded-j/higher-kinded-j/issues/597))
- [Published optic-law harness](../tooling/test_assertions.md): `hkj-test` gains `org.higherkindedj.optics.laws` (`IsoLaws`, `LensLaws`, `PrismLaws`, `AffineLaws`, `TraversalLaws`), so users can law-test hand-written optics; failures name the violated law with the offending values. Purely additive ([#596](https://github.com/higher-kinded-j/higher-kinded-j/issues/596))
- [Optic-path labelling](../optics/multi_edit.md): `@GenerateFocus` companions emit the component name as a path segment, and every path type surfaces `segments()`/`pathString()` (`"customer.address.zip"`), so `Edit.parseIfPresent` locates parse failures automatically. Purely additive ([#592](https://github.com/higher-kinded-j/higher-kinded-j/issues/592))
- [Edits](../optics/multi_edit.md): Sparse, accumulating multi-edit over optics: `Edits.combine` folds pure edits into one `Update<S>`; `Edits.accumulate` adds the validated REST-`PATCH` shape, reporting every bad field at once and applying the writes only if all validated. `…IfPresent` treats `null` as absent. Purely additive ([#582](https://github.com/higher-kinded-j/higher-kinded-j/issues/582))
- [Update\<S\> and Monoids.update()](../functional/semigroup_and_monoid.md): A named, composable update (`UnaryOperator<S>` with `identity`/`andThen`) and its monoid (the `Endo` monoid), the keystone under `Edits`. Purely additive ([#591](https://github.com/higher-kinded-j/higher-kinded-j/issues/591))

**Tooling, Build, and Internals**

- [TimeSource](../monads/io_monad.md): `java.time.Clock` lifted into the effect world (`system()`/`of(clock)`/`fixed(instant)`, lazy `now()` / `nowAsync()`), deterministic in tests; deliberately not named `Clock`. `hkj-test` gains a `SteppableClock` so time-dependent code is exercised by moving the clock, not sleeping ([#609](https://github.com/higher-kinded-j/higher-kinded-j/issues/609))
- Processor diagnostics: what / why / fix. Annotation-processor errors now follow a shared three-part format (what is wrong, why, the exact fix), adopted across the `@GenerateFocus`/`@GenerateLenses`/`@ImportOptics` error paths and the standard for every future processor ([#601](https://github.com/higher-kinded-j/higher-kinded-j/issues/601))
- Codegen on-ramp: `-parameters` wired by both build plugins. The Gradle and Maven plugins now add `-parameters` automatically, completing the one-line codegen setup ([#602](https://github.com/higher-kinded-j/higher-kinded-j/issues/602))
- Annotation-processor hygiene: Every processor now reports `SourceVersion.latestSupported()` (no warnings on newer JDKs) and threads originating elements through the `Filer` for correct incremental processing; generated output is byte-identical ([#588](https://github.com/higher-kinded-j/higher-kinded-j/issues/588))
- `hkj-spring` deserialisers resolve generic element types: The `Either`/`Validated`/`NonEmptyList` deserialisers now implement Jackson 3.x contextual resolution, so nested custom types round-trip instead of yielding `LinkedHashMap` and a `ClassCastException` ([#578](https://github.com/higher-kinded-j/higher-kinded-j/pull/578))
- Worked-example hardening: The `example.order` and `example.market` showcases were reviewed to demonstrate current HKJ functionality with `hkj-test` throughout. Example- and documentation-only; no library API change

---

**Previous:** [v0.4.9](v0_4_9.md)
**Next:** [v0.4.7](v0_4_7.md)
