Repository navigation
NEXUS v0.17.0
NEXUS v0.17 release notes
v0.17.0
Prepared 2026-10-31 (nothing tagged or published: v0.16.0 is the latest release).
v0.17.0 is a minor release that shortens the first app (Tier 1; north-star audits T1.1 and T1.2) and widens the schema types of Command and Event (Tier 1 for the widening, Tier 2 for validate). All changes are additive: omitted arguments, defaulted type parameters, an optional options argument and a new cause field.
Runtime.make()needs no layer. The layer defaults toLayer.empty, so an application with no services yet writesRuntime.make(). (T1.1)Application.define({ name })needs noruntime. The input may omit it. The storedApplicationDefinitionstill hasruntime(filled withLayer.empty), so code that readsapp.definition.runtimeis unchanged. (T1.2)- Transforming schemas for
CommandandEvent.Command.defineandEvent.defineacceptSchema.Schema<A, I>(for exampleSchema.NumberFromString).CommandandEventDefgain a defaulted last type parameter (Encoded = A), so existing references such asEventDef<Tag, P>compile unchanged.Command.invoketakes the encoded input and the handler receives the decoded value.Stateis unchanged. (Tier 1; audit I2 ◐→P, with Valance B3) Event.subscribe(def, { validate: true })(Tier 2; audit I2). Opt-in: each payload is checked against the schema's decoded side (the bus carries decoded values;publishtakes the decoded payload and never decodes), and a failing payload ends the stream with aParseError. The default is unchanged.CommandValidationError.cause. The structuredParseErrornow sits besideissues, which is unchanged.examples/hello: the smallest runnable app, with no Service, Layer or Resource. The README's first app drops itsLayer.emptyargument.- Docs: the shutdown statements in
ARCHITECTURE.md,primitives/capability.mdandprimitives/runtime.mdthat said termination does not wait for effects started withrunorrunForkare corrected: it waits up to the grace, then interrupts them (as since v0.12).
MESH 0.18: the occurrence rename and the context channel
Lands together with MESH 0.18.0 (prepared, not yet published) and Valance Task 19. The peer range gains ^0.18.0; 0.14 to 0.17 stay in it.
- Occurrence, not instance (Tier 2; refinements C-4, Valance K30). MESH 0.18 names one occurrence of a component with a unit
occurrence(Render.occurrences,intent.occurrence) where 0.15 to 0.17 saidinstance.Mesh.UnitOccurrenceandMesh.CommandIntentgain an optionaloccurrence(MESH 0.15 to 0.17 do not give it: readoccurrence ?? instanceto support both); theirinstancestays, marked@deprecated, because it is the only name an older MESH gives and MESH 0.18 keeps it as a non-enumerable alias for one release.Mesh.raise's second parameter is namedoccurrence(a positional rename: no call changes). The adapter passes both through and renames nothing itself. A host that matched the diagnosticruntime-unknown-instancemust matchruntime-unknown-occurrence(MESH retired the old code). - The context channel (Tier 2; refinements C-1, Valance K27). A value many distant components need (a theme, a locale, the current user), declared once in the manifest's
contextand read only by a component that lists it inuses. The host holds the values and the adapter hands them to the runtime beside the snapshot, as it does units:Mesh.render(program, snapshot, units?, context?),Mesh.update(previous, snapshot, units?, context?)(withoutcontext, MESH keeps the previous render's) andMesh.host({ ..., context }), anEffectread each time the host renders. Likeunits, a change of context alone does not render: the host renders when its scope commits. New typeMesh.ContextValues. A program whose manifest has nocontextneeds none of it, and an absent input is not passed, so an older MESH is called exactly as before. - Scorecard: M2 (one term per concept) ◐ → ◐: the unit sense of "instance" is gone from the adapter's names, other collisions remain. C1 (a value reaches a deep component without threading) Fail → Pass and C2 (the channel is explicit and checkable) not applicable → Pass, with MESH 0.18 (the adapter is the pass-through; the check is MESH's). No audit regresses.
- Tests:
tests/mesh-context.test.ts(render, update and host with context; a missing required value is MESH's diagnostic);tests/mesh-units.test.tsreadsoccurrences/occurrenceand checks the deprecated alias passes through. Themesh-sliceintent fixture is re-copied from MESH 0.18, whose intent carries argument names.
Behavior
- Duplicate event tags are refused (audit I2). Each runtime registers an
EventDef's tag at its firstpublishorsubscribe; a second, distinctEventDefwith the same tag dies with aRuntime.Refusal(code: "duplicate-event-tag", a newRefusalCode). This closes the documented_tagcross-delivery hazard, so a subscription only receives its own def's payloads. It refuses only programs that already had that hazard; one def used repeatedly, and distinct tags, are unchanged. In a long-lived runtime, an event re-created on hot reload (a re-evaluated module) is refused: define eachEventDefonce in a module that is not re-evaluated, or restart the runtime on reload. Lands together with Valance Task 25.
Compatibility
- API and behavior: every existing call is unchanged, with one behavior change: a program that registers two distinct
EventDefs under one tag is now refused (see "Behavior"). Beyond that, only omitted arguments, new defaulted type parameters (Encoded, andXonMesh.bind), the optionalsubscribeoptionsargument, the newCommandValidationError.causefield, and the optionalcontextargument and option onMesh.render,Mesh.updateandMesh.hostare newly accepted.occurrenceis added beside the deprecatedinstanceonMesh.UnitOccurrenceandMesh.CommandIntent. - MESH: needs MESH 0.18.0 for
occurrenceandcontext; the peer range still admits^0.14.0to^0.17.0, where everything else works unchanged (withoutcontext, no context argument is passed). RefusalCodegains a member. The StableRuntime.RefusalCodeunion gains"duplicate-event-tag", so an exhaustiveswitchover it (one with aneverdefault) stops compiling until it handles the new code.
Release steps
After MESH 0.18.0 is on npm: revert 538d8e2 (the local packs and pnpm-workspace.yaml overrides), run pnpm install, then pnpm typecheck, pnpm test and pnpm build, then tag v0.17.0.