Repository navigation
Release v0.4.0-alpha.5
Pre-releaseAdded
- Releases attach the Windows toolchain for
win-arm64as well aswin-x64: the self-contained host, the F# frontend and backend archives, the candidate, the extension selection and the bundle, with oneSHA256SUMSover both platforms' files, somorphirup-win-arm64.exe setupinstalls from the release. Each Windows toolchain is built once, by the same job as its manager, afterCheckBuildMachine; the separate win-x64 toolchain job is gone. Pull requests build and check thewin-arm64toolchain inmorphirup.ymland keep it downloadable for seven days. deployment.ymlhas adry-runinput for a manual run: it builds every platform, assembles the release assets and checksum files, uploads them as thedry-run-release-assetsartifact, and publishes nothing to NuGet or GitHub releases.- Windows ARM64 (
win-arm64) is a released platform. The release workflow buildsmorphir-win-arm64.exe,morphir-win-arm64-v<version>.tar.gz,morphirup-win-arm64.exeandmorphirup-win-arm64-v<version>.tar.gzon the hostedwindows-11-armrunner, natively, and the morphirup checksum file lists the morphirup ones; the pull request workflowmorphirup.ymlbuilds and checksmorphirupthere too. The names, contents and checks of the other platforms' assets are unchanged. Earlier releases have none of these files (#611). - Experimental Windows release setup with
morphirup: in a project,morphirup setup --yesdownloads the runtime-bundled Morphir host and the independent F# frontend and backend from the exactfinos/morphir-dotnetrelease of the manager's own version (or the exact version.morphir/toolchain.tomlrequests), checks each file's byte count and SHA-256 against the release'sSHA256SUMS, installs the complete folders into the content-addressed store, runs the fixed readiness workflow and selects the completed generation last.morphirup run -- compileandmorphirup run -- generatethen use the installed folders with no network access.setup --dry-runcreates nothing. This is release-checksum delivery, not publisher-authenticated: HTTPS and a matching checksum do not authenticate the publisher, and trust commands are not included. The release transport starts at the exact repository and version tag and follows at most three HTTPS redirects togithub.com,release-assets.githubusercontent.comorobjects.githubusercontent.com. The release attaches the setup bundle for Windows x64 and Windows ARM64.Morphir.Extensions.Installationis a new library package (#608). - Build:
CheckBuildMachine --rid <rid>fails unless the machine's operating system and architecture are the RID's and the .NET SDK runs natively (not x64 under emulation on ARM64), and logs the machine. The CLI release jobs andcli-offering.ymlrun it before they build. - Build:
FlattenReleaseAssetscopies each downloaded platform output into the release assets once, accepting byte-identical duplicates and failing on two different files under one name instead of overwriting; the morphirup checksum jobs use it.WindowsToolchainChecksumswrites oneSHA256SUMSover both Windows toolchain outputs, and writes nothing when a Windows RID's bundle or manager is missing, or an asset its bundle names is missing or differs. scripts/install-windows.ps1and the proto plugin choosewin-arm64on Windows ARM64, where they refused before. The Windows installer now reads the machine's architecture, so an x64 PowerShell under emulation on ARM64 also chooseswin-arm64. Releases before this one have nowin-arm64file, so asking either for an earlier version fails on Windows ARM64.- Experimental configured Python WASM commands:
morphir compile --language pythonandmorphir generate --target pythonuseextensions.python.paththrough the existing MEP model adapters and owned WASM sessions. Includes a pinned Python 0.6.0 walkthrough; Windows x64 retains its named runtime refusal (#610). - Experimental WASM host-kit reports adopt the pinned parent report schema, computed ordered verdict reasons, per-profile guest-kit citations and eight named refusals. All 22 fixed policy controls are checked independently; the runner retains observation recomputation and exact report rebuilding. Citation-bearing runs fail closed with an explicit unavailable-checker result until the actual generic-kit report checker is integrated. This does not qualify a host, guest, artifact or platform (#564).
- Internal current-family standalone and embedded claim reader, retaining supplied JSON beside existing MEP values and an understood-member projection, with recursive metadata checks, critical paths and host comparators reused from Toolchain. Claims 27/27 and affected SharedReaders 19/19 pass on Windows, repeated after pinned formatting. Public codecs, full corpus conformance, probes and installation lifecycle remain unfinished (#558).
- Internal extension-family reader increment with pinned, offline hash-checked schemas and case data from parent
0439c4c0. The focused Windows SharedReaders suite passes 19/19, including six parent release/schema cases and two I-JSON refusal cases with valid parse controls. Full claim/package semantics, state codecs, inventory, probes and command lifecycle remain unfinished; the 137 identity and 66 package cases have not all been executed (#558). - Extension installer security corrections: descriptor-bound single-file publication, interprocess run-directory ownership coordination, directory/owner identity checks, and gzip metadata/padding budgets with cancellation below the tar reader. Windows regression evidence is 131 passed with three Unix-only cases ignored. Independent security/interop re-review of
b6936ba5found no concrete remaining finding under the approved cooperating Home boundary; Unix runs and AOT remain pending. Recorded the approved selection, command, provenance and explicit developer-consent decisions; inherited default stagedautogrants no automatic install consent. Shared readers use parent source0439c4c0; portable pin/overlay formats remain parent toolchain work (#558). - Extension installation library foundations: portable distribution identifiers over the existing domain types, RID/descriptor/index mappings and exact implemented MEP eligibility within the supported 0.2 line. Includes an Expecto suite and C# probe; CLI installation and Native AOT qualification remain unfinished (#558).
- Extension installation I/O: a single-file content-addressed store that hashes while copying, rehashes reuse and refuses corrupt objects without replacement; ZIP and tar-gzip inspection with the recorded path, type and resource limits; and exclusive ownership and stale cleanup of .NET run directories. Windows tests and the C# JIT probe cover these APIs. Package formats, extraction, inventory, activation and CLI installation are unfinished; Unix filesystem runs and Native AOT qualification remain pending (#558).
morphir mck <args>runs the separately installed Morphir Compatibility Kit,morphir-mck <args>, a development tool from finos/morphir, in every entry point (morphir, the managedmorphir,dotnet-morphir). The arguments, working directory, environment and standard streams are passed on unchanged, and the exit code is the tool's.MORPHIR_MCKnames the tool's absolute path; otherwise only absolutePATHfolders are searched, never the current directory, and on Windows onlymorphir-mck.exeis a candidate. With no tool, the CLI writes a diagnostic to stderr and exits with 127. On Windows, killingmorphiralso stops the tool and its children (a kill-on-close job object); on Linux and macOS, SIGTERM or SIGHUP stops the tool's tree.mckis the only command routed to another executable, and the CLI includes no kit of its own (#589)morphir extension list --jsonanddotnet-morphir extension list --jsonsay which offering is running and what it needs from the machine:deployment(native-aot,self-contained,framework-dependentordotnet-tool), set at build time by the named release profile and never inferred from how the process runs;execution(native-aotorjit);platform(the runtime identifier, left out for the portable tool package); andprerequisites(runtime,sdkwith itsphase, andnative). A build that no named profile produced, such asdotnet run, a test host or the legacymorphir-<rid>single-file assets, leaves outdeployment,platformandprerequisites. Each extension entry gainsdeployments,prerequisitesand, when it is not available, areason. Thehostmember keeps its meaning as the command name (#558)- The built-in F# frontend is listed as
morphir-dotnet.fsharp, available in the self-contained and framework-dependentmorphirand indotnet-morphir. The Native AOTmorphirlists it as not available, with the reason; the registry andcompiletake the claim from the same declaration (#558) Morphir.Toolchain: the recipe binding checks of the toolset recipe page, as pure functions over a recipe, the authenticated targets and their bytes.RecipeBindings.checkruns every host row (atool-releaseoffering's v1 release descriptor is authenticated, not revoked, served with its length and digest and readable, and lists each bound artifact for its platform with matchingtool-artifactmetadata) and every provider row (the extension release descriptor is bound, served, readable and names the provider's identity; each artifact or package is bound and listed with the delivery's runtime, digest and platform; and the claims name the capability kind, MEP version, language or target and model tuple), each with the row's code and path. It reads tool release metadata v1 release descriptors (ToolReleaseDocument), extension release descriptors at2.0.0-draft.2(ExtensionReleaseDocument) and capability claim sets at0.1.0-draft.2(ClaimSetDocument), and nothing earlier.ToolResolver.resolveselects a tool release by the v1 channel, CLI compatibility and platform rules. No command uses them, nothing is downloaded, and none of it has had a security review (#558)morphirup setup --dry-run: the same request assetup --plan, with the same plan,planSha256, result, refusals and exit codes, and nothing created, changed or removed.--planis unchanged; both may be given; neither permits--yes. Every latermorphirupcommand that creates, updates, repairs or removes persistent state will have--dry-runon its own planning and validation path (#558)Morphir.Toolchain:Comparator.allMet, which says whether an installed version meets a list of comparators by the Rustsemverand npm rule (a prerelease matches only when a comparator names its own major, minor and patch with a prerelease; an empty list is always met), andDiscovery.requestInwithDiscovery.PathCase, which compares names without case on Windows, andDiscovery.within. The suite also runs the contract'snfc,setup-platforms,prerequisite-versionsandversionbinding cases and its Windows discovery case (#558)Morphir.Toolchain: the verification part of a TUF client for the tool release metadata v1 profile, as pure functions over supplied bytes and one trusted start time: strict readers for root, timestamp, snapshot and targets metadata, Ed25519 threshold verification with BouncyCastle, root rotation with both thresholds and a retry after 32 roots, timestamp, snapshot and targets checks with rollback, link and expiry, and typed failures mapped to the stable codes. A refresh returns aRefreshResultwhose every outcome (Refreshed,NothingNewfor a timestamp at the trusted version,RootRotationPausedandFailed) carries the newest trust state accepted, so a root accepted before a failure is kept. No exception leaves the client: a defect is aFailedwithTufFailure.Internal. A trust anchor carries its purpose, and aProductionanchor must be the repository identity the caller names; every root accepted later meets the same rules. Text insidesignedthat is not NFC, a member differing from a known member only in letter case, a prereleasespec_versionand an integer above 2^53 - 1 are refused. It does no I/O and no command uses it. It has not had a security review and must not be used to authenticate a production release until it has. Where the profile is silent it takes the stricter reading, marked provisional (#558)morphir generate --extensionand the configuration key[codegen.<target>].extensionselect a MEP backend extension (a command name, a path, or a.dll, as forcompile --extension), for examplemorphir-fsharp-backend. The option wins over the key; without either, the built-in backend runs as before. Every entry point has the option. The generate report names the extension by its own id and addsbackendTransport(mep) andbackendVersion. Failures have the codesextension.unavailable,extension.protocol_error,extension.timeout,extension.tuple_unavailable,extension.not_admitted,extension.unsafe_artifactandinvalid-extension. An extension cannot be selected by an installed extension id yetMepGenerationBackendinMorphir.Tooling: anIGenerationBackendover a MEP guest'smorphir.backend.generateModel. It sends the model's JSON IR (IR4.0.0or3.0.0) only within the limits that the session agreed (MepBackendOptions.OfferLimits), accepts at most 10,000 artifacts in one result, and checks every returned artifact path before publication, including Windows-equivalent names, reserved device names and file/directory conflicts.MepBackendOptions.Environmentsets the guest's whole environment. A guest that gives the id of a built-in backend is refusedMepGuestProcessinMorphir.Compilation.Mep: the guest-process lifecycle (start, initialize, describe, request with a deadline, shutdown or kill of the process tree) thatMepFrontendandMepGenerationBackendshare.MepGuestOptions.Environment, and an additiveMepFrontend.ConnectAsyncoverload, set the guest's whole environmentMorphir.CodeGeneration.FSharp, for C# callers: the public unionFSharpFormatting(Applied,Off,Unavailable, withWireValue), whichTranspiler.formattingnow records;FSharpGeneration.TryGetFormatting(tree, out formatting)andFSharpGeneration.WithRequiredSemantics(context, semantics); andGenerationOptions.WithOptimizeandWithFormat. The project now sets nullable metadata, warnings as errors, and the trim and AOT propertiesmorphir generate --target fsharp --option format=false: the F# backend optionformat(Boolean,trueby default, besideoptimize) turns Fantomas formatting off. The files are the generator's own text, with LF line endings only and exactly one final LF, the same bytes on every operating system, under JIT and Native AOT, and in every culture. The external backendmorphir-fsharp-backendaccepts the same option through thegenerateModeloptions.GenerationOptions.FormatandTranspiler.formattingcarry it inMorphir.CodeGeneration.FSharp- The generate report member
formatting:applied,offorunavailable, written for a built-in backend only: an external backend (backendTransportmep) has noformattingmember, even withformat=false, because a MEP generate result does not say whether the guest formatted.compile --targetwrites the same member in itsgenerationreport member. Under the default, a host that cannot run the formatter (the Native AOTmorphir) writes a warning on stderr fromgenerateand fromcompile --target, never on stdout or in the JSON output; its bytes are unchanged
Changed
- Build: the repository builds with the .NET 11 SDK (
11.0.100) and C# 15.morphir,dotnet-morphir,morphirup, the F# extension tools and the tests targetnet11.0, so the framework-dependentmorphiranddotnet-morphirneedMicrosoft.NETCore.App11.x, and installingdotnet-morphirneeds a .NET SDK 11.0.100 or later. The library packages targetnet11.0andnet10.0, so .NET 10 applications can still use them. .NET 8 and .NET 9 reached the end of support on 2026-11-10, so .NET 10 is the lowest target. The MSBuild tasks and Myriad plugins inMorphir.MyriadandMorphir.Myriad.SystemTextJsonstay onnet10.0, so the .NET 10 SDK can load them. Their MSBuild reference packages return to the 18.0 line, because 18.1 and later have nonet10.0assets.Microsoft.Extensions.*andSystem.Text.Jsonmove to 11.0.0, which also supportsnet10.0. The target frameworks are set in one place,Directory.Build.props - Build: the Native AOT publish of
morphirtreats IL3050 as an error. The F# formatter (Emit.formatCore, Fantomas) is[RequiresDynamicCode]and is called only behindRuntimeFeature.IsDynamicCodeSupported, so if that guard goes, ILC refuses the publish instead of putting Fantomas (about 20 MB) into an image that cannot run it - Release process: finos/morphir now builds, qualifies and publishes the official Morphir CLI from a pinned commit of this repository. The deployment workflow here publishes the library packages and the F# extension tools, and builds and publishes the CLI (the
morphir-<rid>executables, themorphirup-<rid>assets and theMorphir.Toolpackage) only when the repository variableMORPHIR_DOTNET_CLI_PUBLICATIONisenabled, as a rollback. The reusable workflowcli-offering.ymlbuilds one of the four offerings for one platform at a given commit withPackRelease, starts the produced executable (or the installeddotnet-morphir) with--version, and uploads the file, its launch metadata and its SHA-256.PublishToolis nowPublishCliToolplusPublishExtensionTools, andPublishToolandPublishAllpublish what they did. Seedocs/contributing/cli-build-interface.md(#589) - In the Native AOT
morphir, the hint ofcompile.frontend_unavailablefor F# now names the offerings that have a built-in F# frontend and the process deliverymorphir-fsharp-frontend(#558) Morphir.Toolchainandmorphirupfollow the finos/morphir toolchain contract at9e1f853b7(the draft finos/morphir#1147), re-pinned from1451c081f. The same input now gets another code or path:- a MEP version (
protocolVersion, an offering'sprotocolVersions) that is not a version in canonical SemVer spelling, such as0.1,v0.2.0or one past the version bound, isinvalid_valueinstead ofunsupported_case. A SemVer version off the 0.2 line, such as0.1.0, staysunsupported_case; - a recipe provider with
deliverybuilt-inisinconsistent_documentinstead ofunsupported_case; - in a receipt, a workflow check without
workflowand aprobedclaim check withoutprobeSourceareinvalid_documentinstead ofinconsistent_document, and a component whosereadinessisworkflow-qualifiedisinconsistent_documentinstead ofunsupported_case; - in a result, a plan without
planSha256isinvalid_documentinstead ofinconsistent_document, and a host component whose source names another artifact is refused atsource.targetinstead ofsource
- a MEP version (
- Documents that were read before are now refused with
inconsistent_document: a built-in withprotocolVersionormodelTuplein a recipe, lock or receipt, at that member; an offering that lists a MEP version or a WASM ABI twice, at the repetition; a plan whose host source isrecipe-digestor whose provider source isrepository-target, at itssource; and a diagnostic withdocumentorpathbut not both, at the one present morphirupresults: anunsupported-artifactdiagnostic fromsetup --plannames the request member it concerns withdocumentrequestandpath, such astoolset.providers[1], and arepository_mismatchdiagnostic names the recipe member (setup --plan) or lock member (doctor) that names another repository. A recipe, lock or request that0.4.0-alpha.4accepted and that is now refused turns aplannedorsucceededresult (exit 0) into afailedone (exit 1); for example, a recipe that lists a MEP version twice in one offering. Exit code 2 (the command was not run) and exit code 3 (an internal error) mean what they did, and the plan digest of any input both read is unchanged. The version bound (256 characters, 15 digits per numeric identifier) is the contract's rule and no longer provisionalMorphir.ToolchainAPI, for F# callers:DiagnosticDetail.UnsupportedArtifactandDiagnosticDetail.TrustFailurehave a last fieldconcerns: DocumentMember option;BindingFailure.RepositoryMismatchcarries the document whose member its path names;Diagnostics.ofTargetRefusaltakes that document; andRecipeTargets.checkLockedGenerationtakes the generation's recipe as a functionunit -> Result<Recipe, TargetRefusal>, asked for only for the host release row (a refusal it returns is the check's, and an exception it throws isinvalid_documentatrecipe.target), and refuses a generation whose recipe target the trust state does not list withtarget_not_authenticatedatrecipe.target, before reading the recipe (#558)morphir generate --inputnow loads the project configuration (from--project,--configor discovery) to read[codegen.<target>].extensionwhen--extensionis absent. With--projector--config, a configuration that fails to load fails the command with exit code 2. With neither, a discovered configuration that does not load is a warning on stderr and the built-in backend runs, as beforecompile --extension, from the shared guest-process lifecycle: a user cancellation (Ctrl+C) while the guest initializes is now a cancelled compile (exit code 130) instead ofextension.unavailable, and a guest that honors$/cancelRequestat the deadline now givesextension.timeoutinstead ofextension.protocol_errorcompile --targetdoes not run a backend extension: it runs the built-in backend of the target, as before. When the project configuration sets[codegen.<target>].extensionfor that target, it now prints a note on stderr saying soGenerationOptions(Morphir.CodeGeneration.FSharp) has the new fieldFormat, so a record expression that sets every field needs it, and C# that calls its two-argument constructor must pass both;{ GenerationOptions.Default with Optimize = ... }andGenerationOptions.Default.WithOptimize(...)keep working
Fixed
-
morphirup setup: asetup.readiness_failedrefusal now includes the host's own diagnostic code and message; a completed attempt removes its staging folders under Home, on success and on refusal;run -- generate --target csharp --output fsharpkeeps the built-in C# backend, because installed F# providers are chosen from the--targetand--languagevalues only; and on Windows, dry run and apply refuse before creating Home when an installed host or provider executable path would reach 260 characters, naming Home, the executable and the 259-character limit (#616). -
WASM execution now refuses Windows x64 with
win_x64_trap_unsupportedbefore loading the engine or a module. Other CLI capabilities remain available; the CET/Spectre-preserving fix is tracked in #609. The diagnostic signal-trap override is removed. -
Corrected Darwin ARM64 variadic mode placement for installer
open/openat, preserving no-follow/exclusive flags and descriptor identity. Hosted macOS failures at4c908047are the regression evidence. Focused Windows Store 15/15 and RunCopies 5/5 pass, with three Unix-only tests ignored; exact-head macOS/Linux verification remains pending (#593). -
Configuration: a member of
[frontend]that is not a table (for example[frontend]note = "x") is no longer refused as an invalid language table. Only an object-valued member is a[frontend.<language>]table withproject_fileandextension; any other member stays unconstrained, as the upstream schema leaves it -
compile --extension: a frontend guest that never answerscompileModelnow fails withextension.timeoutat the deadline, and a guest that does not answershutdownor takeexitwithin the deadline (for example one whose handler blocks its read loop) has its process tree stopped. Before, the host could wait indefinitely in both cases. The same holds forgenerate --extension, so a timed-out request ends within about two deadlines -
A frontend or backend guest that fails to start or initialize no longer leaves its stderr reader or process handle behind
-
compile: for a language id with a dot,[frontend."acme.lang"].extensionandproject_fileare now read from that quoted table; before, the id was split at the dot, so the keys were looked up under[frontend.acme.lang]and the quoted table was ignored. A project file key that is not read for lack of a language is now named with the quotes too
Security
- Morphir.Live: centrally pin the transitive
Microsoft.AspNetCore.WebUtilitiesdependency to 9.0.23 for CVE-2026-114149 / GHSA-x33c-w48q-qrgc, replacing the affected 9.0.19 selected through Fun.Blazor. compile --extension,generate --extensionand theextensionconfiguration keys refuse a guest that reports an extension id that starts withmorphir., which is reserved for the built-in frontends and backends, including built-ins that do not ship yet (extension.unavailable). Before,generaterefused only the id of a registered built-in backend, andcompilechecked no id.org.finos.morphir.*ids are not reserved.Morphir.Mep.ReservedExtensionIdsandExtensionId.ReservedForBuiltInshold the rulecompile --extension,generate --extensionand theextensionconfiguration keys: a command name without a directory (for examplemorphir-fsharp-backend) is now searched only in the absolutePATHdirectories, and the resolved absolute path starts. Before, process start also looked in the directory ofmorphirand in the current directory first (CreateProcess on Windows, and .NET on Unix), so a checkout could plant a binary of that name and have it run. A.dllextension'sdotnethost is resolved the same way whenDOTNET_HOST_PATHis not set. A name that is not onPATHnow fails withextension.unavailablebefore any process starts.MepFrontendExtensionConnector.ResolvethrowsFileNotFoundExceptionfor such a name instead of returning it unchanged