Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -366,7 +366,10 @@ jobs:

- name: Refuse missing, extra or mismatched candidates
run: |
tag="${{ github.ref_type == 'tag' && github.ref_name || '' }}"
tag=""
if [[ "$GITHUB_REF" == refs/tags/native-v* ]]; then
tag="$GITHUB_REF_NAME"
fi
if [[ -z "$tag" ]]; then
tag="native-v$(python3 -c 'import tomllib; print(tomllib.load(open("rust/crates/morphir-python-native/Cargo.toml","rb"))["package"]["version"])')"
fi
Expand Down
5 changes: 3 additions & 2 deletions openspec/changes/add-process-mep-extension/design.html

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion openspec/changes/add-process-mep-extension/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,9 @@ This change is being applied. SDK 0.4.0 is published and the separate upstream P
- Final promotion stages 39 assets plus `SHA256SUMS`. Local audit verifies every final checksum, all 11 canonical process archive members, payload hashes, executable modes and all six raw MCK report/recheck pairs. A real four-platform input set is refused for missing Intel evidence. Historical WASM releases `0.4.0` and `0.4.2` remain available with their recorded digests.
- Source-pinned Rust host checks and ten fresh timing samples for small/medium workloads pass on the actual candidate bytes. Raw inputs, reports and toolchain/build identities are retained in the candidate and final host-evidence archive. No general performance claim is made. MoonBit routes remain unsupported at the documented pin with checked limitations.
- SDK `0.4.0` publication and the separate upstream Python JSON MCK profile are complete. The Windows checker build passes with short scoped Cargo storage and explicit parent/submodule Git settings; real source changes are still refused. No corpus change or integrity exception was accepted.
- Main specs are synced. All merges and admin bypass are approved. Python/native/extension release tags require exact maintainer approval once the merged source is concrete. Keep this change active until publication and final verification; archive afterward. Do not treat staged assets as published releases.
- Main specs are synced. All merges and admin bypass are approved. The maintainer approved native `0.1.2`, CLI `0.1.1` and extension `0.5.0` at merge `f2032e3adaf72854a3907dc092e8abb757f08b4a`.
- Native [40758932916](https://github.com/finos/morphir-python/actions/runs/40758932916) published all five wheels and the source archive. Every PyPI file matches its qualified workflow artifact and checksum exactly. Extension [40758936256](https://github.com/finos/morphir-python/actions/runs/40758936256) is qualifying the approved source.
- CLI [40764461472](https://github.com/finos/morphir-python/actions/runs/40764461472) correctly refused publication: the current core `0.1.0` wheel differs from PyPI after documentation-site metadata edits. Direct comparison confirms identical runtime sources and changes only to `METADATA` and `RECORD`. No CLI files were published. Bug `morphir-5hxy.6` prepares core `0.1.1` and CLI `0.1.2`; preserve the failed `python-v0.1.1` tag and the strict byte-identity guard. Corrected publication requires approval for the new tags and source after qualification.
- Extension run `40758936256` passed its platform MEP checks but its native candidate verifier correctly rejected the forwarded extension tag. Bug `morphir-5hxy.7` preserves the verifier and selects the source native tag for extension/manual runs; an actual workflow-shell regression fails before the fix and passes afterward, including rejection of a wrong explicit native tag. Keep extension publication held. Approval for the corrected source is required before retargeting the unpublished extension tag and repeating all gates; published native tags remain unchanged.
- Bug `morphir-5hxy.8` refreshes the stale committed host-evidence fallback exposed by selective PR CI. Fresh qualification from clean commit `6e88b295017d346007409bdd7182e8584c91c622` passes the currently documented released Rust-host recipe, offline round trips and both pinned MoonBit refusal probes. A regression checks the real committed cache against every documented input, preventing a full fresh-host CI run from hiding stale fallback evidence.
- Keep this change active until publication and final verification; archive afterward. Do not treat staged assets as published releases.
2 changes: 1 addition & 1 deletion packages/morphir-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ wheel. No Rust toolchain is required on supported platforms.
To install the CLI and compiler API into an existing Python environment:

```bash
python -m pip install --only-binary=:all: morphir-python==0.1.0
python -m pip install --only-binary=:all: morphir-python==0.1.2
```

Or with uv:
Expand Down
2 changes: 1 addition & 1 deletion packages/morphir-tools/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "morphir-python"
version = "0.1.1"
version = "0.1.2"
description = "CLI tools and extensions for Morphir Python"
readme = "README.md"
license = "Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/morphir-tools/src/morphir_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
Example:
>>> import morphir_tools
>>> morphir_tools.__version__
'0.1.0'
'0.1.2'
"""

__version__ = "0.1.1"
__version__ = "0.1.2"
__all__ = ["__version__"]
2 changes: 1 addition & 1 deletion packages/morphir/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "morphir"
version = "0.1.0"
version = "0.1.1"
description = "Python port of Morphir - functional domain modeling for the enterprise"
readme = "README.md"
license = "Apache-2.0"
Expand Down
4 changes: 2 additions & 2 deletions packages/morphir/src/morphir/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
Example:
>>> import morphir
>>> morphir.__version__
'0.1.0'
'0.1.1'
"""

__version__ = "0.1.0"
__version__ = "0.1.1"
__all__ = ["__version__"]
32 changes: 26 additions & 6 deletions site/evidence/hosts.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@
"state": "succeeded",
"inputs": {
"site/integrations.json": "d83a529d8d4d59c7505892f93cb7e991939e38174892cd0f11f2172c090b3578",
"rust/extension.toml": "6fe92784006cb757c9d6d1e27c1869b2ac5d4ecda4753644d9d8d202b9d7ff5d",
"rust/extension.toml": "31a882701022d95198aad254c4db61659d2b6ec138585a49c673d13a16c80272",
"scripts/docs_hosts.py": "791c2e220217e8931e1c090749987a17e7787fcdbba35443d83b3e234f8b7cc6",
"scripts/extension_bundle.py": "2a2937f2274db14cfee54dd24616045f55592cefe7c99611aa73098fb44cbcd6",
"scripts/extension_bundle.py": "ca03e3d959428dfef41fb0c852eaa3d656f13133f6e4f996db77ea9952126bc3",
"examples/extension.sh": "bbe0a0cf27070b888439f57a9e495eb75506b8fafbafd259b1a8512bcf1af35b",
"examples/model/acme/models.py": "0f57ac6f4ffd2524373ec9ba3df079f23291ce42ca7f7700e4df50fad9d43b50",
"examples/model/acme/rules.py": "cf475c980096c8645550c4c53c5e6343e3a584f2a19cba26c16cf1291ce235c2",
"docs/python-extension.md": "47969c1d2c7de272c6aa275ff0a558b1efc8778556c2796e0108c0a31ff8af4a",
"docs/python-extension.md": "326b9ee7ca856ba88b3ad67accac5fa4657444e0b7968f3eec23287d9db4459c",
"docs/moonbit.md": "574f1e0129975dc10ea68882b48dda07ced36f429b2a30746c6bc724e9f119c2",
"docs/compatibility.md": "3f5ef69142991edf9d30d23dce768d66cf0047f4b325c1f042166a5c2f9c29f8",
"tests/fixtures/python/loans/acme/models.py": "02b453935df7a03fd8e58c88616836d8f09e78868b9c66cae572c18852f6ccf4",
"tests/fixtures/python/loans/acme/rules.py": "6aa4573844f82910c06079ef1af11a56103dc48cbcdc142bfc23c3aa25f6162e"
},
"platform": "macOS-26.6.2-arm64-arm-64bit-Mach-O",
"python": "3.14.7 (main, Sep 1 2026, 14:05:28) [Clang 22.1.3 ]",
"working_tree_dirty": true,
"git_head": "a55985d32c24987b1ae790ea05acd4bc0a39deb1",
"working_tree_dirty": false,
"git_head": "6e88b295017d346007409bdd7182e8584c91c622",
"rust_recipe": {
"recipe": "examples/extension.sh",
"exit_code": 0,
Expand All @@ -39,10 +39,20 @@
"frontend"
],
"multiDocument": true,
"installed_integrity": {
"expected_sha256": "10acafa0f0282c5240e9620a5f2bb21629cc7580b9add528e7b77c7e54db22b5",
"tampered_sha256": "9fd562d8ee2d99ede2e7bd41bb219d755ec23a72813c5cbf81854a8d8b9d1fc3",
"exit_code": 1,
"stdout": "",
"stderr": "Operation ID: op-215cbd72-59bc-4117-880b-f2bff34e2544\nLog: /var/folders/gk/kq2l8mzd0lq64qspbc_6j80m0000gn/T/python-bundle-host-kuoivpf8/home/logs/cli/2026-10-28/20261028T212014.733Z-7424-1d00-18e2ce4909789a80.jsonl\nError: cli::extension_error\n\n \u00d7 Extension error: Failed to verify installed provider 'morphir-python':\n \u2502 digest mismatch for /private/var/folders/gk/kq2l8mzd0lq64qspbc_6j80m0000gn/\n \u2502 T/python-bundle-host-kuoivpf8/home/store/extensions/\n \u2502 sha256/10acafa0f0282c5240e9620a5f2bb21629cc7580b9add528e7b77c7e54db22b5/\n \u2502 morphir-python-binding-0.4.2.wasm: expected\n \u2502 10acafa0f0282c5240e9620a5f2bb21629cc7580b9add528e7b77c7e54db22b5, got\n \u2502 9fd562d8ee2d99ede2e7bd41bb219d755ec23a72813c5cbf81854a8d8b9d1fc3\n\n",
"fresh_project": true
},
"host": {
"morphir": "0.4.0-beta.10",
"sha256": "98635ec74fbdc3c2cef1d4ae184bb1c5ed9e2960575f3d8abb4b97e0e4da363f"
"sha256": "98635ec74fbdc3c2cef1d4ae184bb1c5ed9e2960575f3d8abb4b97e0e4da363f",
"binary_sha256": "e610796e758c4f2b8925228082efd78f9b9d46c45ee22b6e393d9b76b8e807e2"
},
"qualification_script_sha256": "ca03e3d959428dfef41fb0c852eaa3d656f13133f6e4f996db77ea9952126bc3",
"python_api": {
"native_version": "0.1.1",
"compiler_version": "0.4.2"
Expand All @@ -53,13 +63,23 @@
"acme/models.py",
"acme/rules.py"
],
"ir_sha256": "a8211ac125e271a60eea3c3580347ce37c1ec83fb599e15c5954b3a4eed30c6b",
"generated_sha256": {
"acme/models.py": "b1a754879944f2ffdc40873e778d9ebb57adb363e635d730975c02e263f0025f",
"acme/rules.py": "0f9b72e04c0d857d555dcafd76763a07a20cabcb88c8f55fcfb81cc1436183a5"
},
"agrees_with_python_api": true
},
"v4": {
"modules": [
"acme/models.py",
"acme/rules.py"
],
"ir_sha256": "dd41e858e3b0bf769a4884e5722e09029adf6613fc95d4552fa01986e80a315c",
"generated_sha256": {
"acme/models.py": "b1a754879944f2ffdc40873e778d9ebb57adb363e635d730975c02e263f0025f",
"acme/rules.py": "0f9b72e04c0d857d555dcafd76763a07a20cabcb88c8f55fcfb81cc1436183a5"
},
"agrees_with_python_api": true
}
}
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
@pytest.fixture
def sample_version() -> str:
"""Provide the expected version string for tests."""
return "0.1.0"
return "0.1.1"
2 changes: 1 addition & 1 deletion tests/tools/test_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ def test_version_is_defined(self) -> None:

def test_version_matches_expected(self) -> None:
"""The version should match the expected value."""
assert morphir_tools.__version__ == "0.1.1"
assert morphir_tools.__version__ == "0.1.2"

def test_installed_distribution_name(self) -> None:
"""The tools import belongs to the morphir-python distribution."""
Expand Down
7 changes: 6 additions & 1 deletion tests/unit/test_docs_hosts.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,17 @@

import pytest

from scripts.docs_hosts import INPUTS, input_hashes, verify_evidence
from scripts.docs_hosts import INPUTS, ROOT, input_hashes, verify_evidence

if TYPE_CHECKING:
from pathlib import Path


def test_committed_host_evidence_matches_documented_inputs() -> None:
"""Keep the selective CI fallback usable after documentation changes."""
verify_evidence(json.loads((ROOT / "site/evidence/hosts.json").read_text()))


def test_edited_recipe_invalidates_previously_successful_evidence(
tmp_path: Path,
) -> None:
Expand Down
59 changes: 59 additions & 0 deletions tests/unit/test_release_candidates.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@

import hashlib
import json
import os
import shlex
import shutil
import subprocess
import textwrap
from typing import TYPE_CHECKING

import pytest
Expand Down Expand Up @@ -125,3 +130,57 @@ def test_the_command_writes_a_receipt(tmp_path: Path) -> None:
pytest.skip("fixture names the current native version")
r.main(["native", str(tmp_path), "--tag", f"native-v{version}"])
assert len((tmp_path / "SHA256SUMS").read_text().splitlines()) == 6


@pytest.mark.skipif(
os.name == "nt" or shutil.which("bash") is None,
reason="The native-candidates workflow shell runs on Ubuntu",
)
@pytest.mark.parametrize(
("tag", "accepted"),
[
(None, True),
("native-v{native}", True),
("extension/python/v{extension}", True),
("native-v9.9.9", False),
],
)
def test_workflow_verifies_native_candidates_for_each_tag_route(
tmp_path: Path, tag: str | None, accepted: bool
) -> None:
"""Execute the production shell and its strict validator with real ref inputs."""
versions = r.source_versions()
native_set(tmp_path, versions["native"])
workflow = (r.ROOT / ".github/workflows/release.yml").read_text()
step = workflow.split(
" - name: Refuse missing, extra or mismatched candidates\n", 1
)[1]
script = textwrap.dedent(
step.split(" run: |\n", 1)[1].split("\n - name:", 1)[0]
)
ref_name = tag.format(**versions) if tag else "main"
# GitHub expands this expression before handing a step to Bash.
script = script.replace(
"${{ github.ref_type == 'tag' && github.ref_name || '' }}",
ref_name if tag else "",
).replace("dist/candidates", shlex.quote(str(tmp_path)))
result = subprocess.run(
["bash", "-e", "-c", script],
cwd=r.ROOT,
env=os.environ
| {
"GITHUB_REF": f"refs/tags/{ref_name}" if tag else "refs/heads/main",
"GITHUB_REF_NAME": ref_name,
"GITHUB_REF_TYPE": "tag" if tag else "branch",
},
capture_output=True,
text=True,
timeout=30,
check=False,
)
assert (result.returncode == 0) == accepted, result.stderr
receipt = tmp_path / "SHA256SUMS"
if accepted:
assert len(receipt.read_text().splitlines()) == 6
else:
assert not receipt.exists()
4 changes: 2 additions & 2 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading