Skip to content

feat(ir): add IR format 3.0.0 alongside draft IR v4, with migrations and CLI - #32

Merged
DamianReeves merged 3 commits into
mainfrom
chore/add-ir-v3-support
Oct 27, 2026
Merged

DamianReeves merged 3 commits into
mainfrom
chore/add-ir-v3-support

Conversation

@DamianReeves

Copy link
Copy Markdown
Member

Summary

Adds Morphir IR format 3.0.0 as a first-class IR next to draft IR v4, with the OpenSpec change add-ir-v3-support (proposal, HTML design, specs, tasks) in the same PR.

  • morphir.ir.format_version: one permissive reader for every document. Accepts 3, "3", "3.0.0", normalizes to a release, writes canonically, and reports the finos contract codes (missing_format_version, unsupported_format_version_major, unsupported_format_version_minor, and so on). Support table [3.0.0,3.1.0),[4.0.0,4.1.0); formats 1 and 2 and IR 3.1.0 are rejected.
  • morphir.ir.v3: model and JSON codec ported from morphir-elm at bc99af69. All golden fixtures (morphir-elm test fixtures, the morphir-elm reference model, and finos/morphir examples) round-trip to byte-identical JSON.
  • morphir.ir.v4: the existing IR modules moved here; every old morphir.ir.<module> path is a re-export shim, and morphir.ir.__all__ is unchanged. PackageInfo.version is now str | None = None.
  • morphir.ir.v4.codec: draft codec for the finos/morphir v4 JSON profile pinned at efa36060. Constructs the Python v4 model cannot spell in upstream v4 fail with no_v4_spelling rather than lose data.
  • morphir.ir.migrate: v3_to_v4 (always succeeds) and v4_to_v3, which collects every downgrade failure in one pass and allows only the package_version_dropped and opt-in source_location_dropped drops.
  • morphir-tools ir inspect / ir convert (Typer, in morphir-tools only; core morphir stays dependency-free). Conversion writes through a temporary file, so failures leave no output.
  • Docs: package README sections on the two IR versions, the format-version divergence from morphir-elm and the finos contract, the draft v4 status, migrations, and CLI usage; brief root README and AGENTS.md notes.

Testing

  • mise run check: lint, mypy strict, pyright, 1808 unit tests, 23 BDD scenarios all pass.
  • mise run coverage: 98% total.
  • openspec validate add-ir-v3-support --strict passes; all tasks ticked.

Follow-ups (filed as beads)

  • IR formats 1 and 2 (morphir-elm CodecV1)
  • IR 3.1.0 (#28)
  • v4 model realignment with upstream (Native/External bodies, annotations, incomplete definitions) and a v4 spelling for per-input value attributes (the elm reference model hits no_v4_spelling)
  • Re-sync the draft v4 codec when upstream v4 settles; archive the change

DamianReeves and others added 3 commits October 27, 2026 01:15
…draft v4 codec, migrations

Co-authored-by: Cursor <cursoragent@cursor.com>
Make the compatibility shims re-export transitively imported names from their
defining v4 modules so mypy strict accepts them, type v3_to_v4 as always Ok,
document the v3 and draft v4 packages, the format-version divergence, and the
morphir-tools ir CLI, and run the README IR example and IR doctests in tests.

Co-authored-by: Cursor <cursoragent@cursor.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 27, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-27T06:41:10.043414Z 392afc6 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@DamianReeves
DamianReeves merged commit e28fa2f into main Oct 27, 2026
5 checks passed
@DamianReeves
DamianReeves deleted the chore/add-ir-v3-support branch October 27, 2026 06:40

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 392afc6e39

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


def dump_json(value: object) -> str:
"""Serialize JSON compactly with members in insertion order."""
return json.dumps(value, ensure_ascii=False, separators=(",", ":"))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject non-finite numbers before writing interchange JSON

When an IR float contains NaN or infinity, this helper emits bare NaN or Infinity, which are not valid JSON numbers. This can also occur from syntactically valid input such as 1e400, which the shared json.loads call converts to infinity. Consequently, conversion can report success while producing an interchange file that strict JSON readers cannot load. Reject non-finite numbers with a structured diagnostic and disable non-standard numeric output with allow_nan=False.

Useful? React with 👍 / 👎.

Comment on lines +1289 to +1290
access = body.get("access", "Public")
if access not in ACCESS_TAGS:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate the access value before dictionary membership

If a v4 custom type definition contains an array or object as its access value, this membership check raises TypeError because the value is unhashable. Unlike an unknown access string, this malformed input therefore escapes the codec's structured diagnostics and the CLI's DiagnosticError handler, producing a traceback instead of a located error. Check that access is a string before looking it up, as _decode_entry_point already does for its kind.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant