Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
095f346
feat: add linkml extension for ers (#3)
meanigfy Feb 16, 2026
57cbfd7
ci: add quality check workflow
twicechild Feb 16, 2026
aef89aa
build: add lint and lint-schema Make targets
twicechild Feb 16, 2026
fe92927
docs: update Make targets overview in README
twicechild Feb 16, 2026
a6eea79
updated the EA diagrams
meanigfy Feb 18, 2026
1149fa0
Merge remote-tracking branch 'MF-origin/develop' into feature/archite…
meanigfy Feb 18, 2026
e324a98
feat: align the ERE schema to the most recent architecture decisions
marco-brandizi Feb 18, 2026
ea2b1f9
update sequence diagrams
meanigfy Feb 18, 2026
4761dd8
feat: regenerate ERE LinkML schema docs and other derived files
marco-brandizi Feb 18, 2026
9dd2180
test: review the Gherkin tests to reflect the V4 ERE Contract
marco-brandizi Feb 18, 2026
7bcea00
Merge pull request #6 from meaningfy-ws/feature/ERS1-103/ci-setup
twicechild Feb 19, 2026
e189915
update L2 diagram
meanigfy Feb 20, 2026
8579ddf
Merge pull request #8 from meaningfy-ws/feature/ERS1-119/ere-model-v4
gkostkowski Feb 20, 2026
4764439
Merge pull request #7 from meaningfy-ws/test/ERS1-120/gherkin-tests-v4
gkostkowski Feb 20, 2026
7f726a9
feat: add similarity score
gkostkowski Feb 20, 2026
9c1fbdb
Disable sync check steps in CI
gkostkowski Feb 20, 2026
012e039
Merge pull request #9 from meaningfy-ws/feature/ERS1-119/similarity-s…
gkostkowski Feb 20, 2026
fe2cf62
Update changelog file
gkostkowski Feb 20, 2026
ab25856
Merge remote-tracking branch 'MF-origin/develop' into feature/archite…
meanigfy Feb 22, 2026
d9f78db
Update architecture README files and sequence diagrams to reflect
meanigfy Feb 22, 2026
3d1fc6d
chore: target Python 3.12+ and configure ruff for syntax enforcement
gkostkowski Feb 23, 2026
393d3de
Fix regex in CI
gkostkowski Feb 23, 2026
92dd99f
Update poetry.lock
gkostkowski Feb 23, 2026
88e8c47
fix(ci): fix sync check for non-deterministic linkml doc output
twicechild Feb 23, 2026
27dee9e
refactor: align core schema with architectural diagrams
meanigfy Feb 23, 2026
79d2d85
chore: update dependencies and drop to Python 3.12
meanigfy Feb 23, 2026
ecb9aeb
docs: regenerate schema documentation for LookupState
meanigfy Feb 23, 2026
67b8e66
docs: clarify README setup and development instructions
meanigfy Feb 23, 2026
890547a
Merge remote-tracking branch 'MF-origin/chore/update-python-version' …
meanigfy Feb 23, 2026
b2264a7
Merge remote-tracking branch 'MF-origin/fix/ERS1-103/ci-sync-check' i…
meanigfy Feb 23, 2026
5f852fb
Merge pull request #12 from meaningfy-ws/feature/ERS1-121
costezki Feb 23, 2026
714509c
fix: explicitly specify erspec package in pyproject.toml for poetry b…
meanigfy Feb 23, 2026
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
112 changes: 112 additions & 0 deletions .github/workflows/code-quality.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: Quality Check

on:
push:
branches: [develop, main]
paths:
- "src/**"
- "resources/schemas/**"
- "pyproject.toml"
- "poetry.lock"
- "Makefile"
- ".github/workflows/code-quality.yaml"
pull_request:
paths:
- "src/**"
- "resources/schemas/**"
- "pyproject.toml"
- "poetry.lock"
- "Makefile"
- ".github/workflows/code-quality.yaml"

jobs:
quality:
name: Lint, Build & Verify
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write

steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Read Python version from pyproject.toml
id: python-version
run: echo "version=$(grep -m1 'python = ' pyproject.toml | grep -oP '\d+\.\d+' | head -1)" >> $GITHUB_OUTPUT

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: ${{ steps.python-version.outputs.version }}

- name: Install Poetry
run: pipx install poetry

- name: Cache Poetry dependencies
uses: actions/cache@v4
with:
path: ~/.cache/pypoetry
key: poetry-${{ runner.os }}-${{ hashFiles('poetry.lock') }}

- name: Install dependencies
run: make install

- name: Lint LinkML schemas
run: poetry run linkml lint --ignore-warnings resources/schemas/

- name: Run ruff linter
run: poetry run ruff check src/

- name: Generate models and docs
run: make -B all

- name: Verify generated code is up to date
id: verify_generated_code
continue-on-error: true
run: |
echo "Checking if generated files match LinkML schemas..."
OUT_OF_SYNC=""

# src/ and JSON schemas are deterministic — use git diff directly
for f in $(git diff --name-only src/ resources/schemas/*json); do
OUT_OF_SYNC="$OUT_OF_SYNC $f"
done

# docs/ uses order-insensitive comparison because linkml generate doc
# produces non-deterministic markdown table row order across runs.
for f in $(git diff --name-only docs/); do
committed=$(git show HEAD:"$f" | sort | sha256sum | awk '{print $1}')
generated=$(sort "$f" | sha256sum | awk '{print $1}')
if [ "$committed" != "$generated" ]; then
OUT_OF_SYNC="$OUT_OF_SYNC $f"
fi
done

if [ -n "$OUT_OF_SYNC" ]; then
echo "status=failed" >> $GITHUB_OUTPUT
echo "Generated code is out of sync!"
{
echo "**Generated code is out of sync with LinkML schemas.**"
echo ""
echo "Please run \`make all\` and commit the updated files:"
echo '```'
git diff --stat $OUT_OF_SYNC
echo '```'
} > sync_report.txt
else
echo "status=passed" >> $GITHUB_OUTPUT
echo "Generated code is up to date" > sync_report.txt
fi

- name: Publish sync check comment
if: always() && github.event_name == 'pull_request'
uses: thollander/actions-comment-pull-request@v3
with:
file-path: sync_report.txt
comment-tag: sync-check

- name: Fail if out of sync
if: steps.verify_generated_code.outputs.status == 'failed'
run: exit 1
13 changes: 12 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,15 @@ __marimo__/
.idea/
.vscode/
.mypy_cache/
.pyre/
.pyre/

# CI/CD artifacts
sync_report.txt
.gitnexus
.serenity/
.pycharm_plugin
.venv
.trueflow
.claude
AGENTS.md
CLAUDE.md
17 changes: 16 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,22 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [unreleased]
...

## [0.2.0-rc.2] - 2026-02-20
### Added
* CI: GitHub Actions quality-check workflow (`.github/workflows/code-quality.yaml`) — LinkML schema linting, `ruff` Python linting, model/docs generation with sync verification, and PR comment posting ([ERS1-103])
* `lint` and `lint-schema` Make targets ([ERS1-103])
* data model: `proposed_cluster_ids` field on `EntityMentionResolutionRequest` — allows the caller to suggest candidate clusters; the ERE has no obligation to honour the proposal ([ERS1-119])
* data model: `similarity_score` field on `ClusterReference` — a 0–1 pairwise score between an entity mention and a cluster representative ([ERS1-119])
* Schema docs: `EREErrorResponse.md`, `EREMessage.md`, `EntityMentionResolutionResponse.md`, `proposed_cluster_ids.md`, `similarity_score.md` ([ERS1-119])

### Changed
* data model: revised semantics of `excluded_cluster_ids` — ERE has no obligation to honour exclusions, and it remains the ultimate resolution authority ([ERS1-119])
* data model: clarified `ere_request_id` — notification responses originating inside the ERE (without a prior request) use the prefix `ereNotification:` ([ERS1-119])
* Removed `FullRebuildRequest` / `FullRebuildResponse` classes from ERE schema and docs ([ERS1-119])
* Renamed `entityType.md` → `EntityType.md` in schema docs ([ERS1-119])
* Gherkin tests updated to reflect the V4 ERE Contract — simplified idempotent-resolution scenarios, added full-rebuild stub, aligned unhappy-path tests ([ERS1-120])
* README updated: added `lint` / `lint-schema` targets to the Makefile overview ([ERS1-103])

## [0.2.0-rc.1] - 2026-02-03
### Added
Expand Down
225 changes: 148 additions & 77 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,79 +1,150 @@
SHELL=/bin/bash -o pipefail

BUILD_PRINT = \e[1;34m
END_BUILD_PRINT = \e[0m

ICON_DONE = [✔]
ICON_ERROR = [x]
ICON_WARNING = [!]
ICON_PROGRESS = [-]

LINKML_MODEL_NAME=ere-service-schema
LINKML_MODEL_VERSION=0.1.0
PYTHON_MODEL_PATH=src/ere/models/core.py

SCHEMAS_DIR=resources/schemas

LINKML_MODEL_PATH=$(SCHEMAS_DIR)/$(LINKML_MODEL_NAME)-v$(LINKML_MODEL_VERSION).yaml
JSON_SCHEMA_PATH=$(SCHEMAS_DIR)/$(LINKML_MODEL_NAME)-v$(LINKML_MODEL_VERSION).json

MODEL_DOCS_DIR=docs/schema
MODEL_DOCS_README=$(MODEL_DOCS_DIR)/README.md

## Setup commands
#

# Note that Python, Poetry and Make are a pre-requisites and we don't deal with them here.
#

install:
@ echo "Installing dependencies using Poetry..."
@ poetry sync


## Build commands
#

all: $(PYTHON_MODEL_PATH) $(JSON_SCHEMA_PATH) $(MODEL_DOCS_README)

generate-models: $(PYTHON_MODEL_PATH) $(JSON_SCHEMA_PATH)
generate-doc: $(MODEL_DOCS_README)

.PHONY: all generate-models generate-doc clean clean-doc clean-models install install-dev check-uv


$(PYTHON_MODEL_PATH): $(LINKML_MODEL_PATH)
@ echo "Generating Python service model..."
@ mkdir -p $(dir $(PYTHON_MODEL_PATH))
@ poetry run linkml generate pydantic $(LINKML_MODEL_PATH) > $(PYTHON_MODEL_PATH)

$(JSON_SCHEMA_PATH): $(LINKML_MODEL_PATH)
@ echo "Generating JSON Schema for the ERE service..."
@ mkdir -p $(dir $(JSON_SCHEMA_PATH))
@ poetry run linkml generate json-schema --indent 2 $(LINKML_MODEL_PATH) > $(JSON_SCHEMA_PATH)



$(MODEL_DOCS_README): $(LINKML_MODEL_PATH)
@ echo "Generating documentation for the ERE service Schema..."
# Changing default index name from index.md to README.md, since the github browser automatically shows the latter name
# when entering the MODEL_DOCS_DIR
@ poetry run linkml generate doc $(LINKML_MODEL_PATH) -d $(MODEL_DOCS_DIR) --index-name README
# TODO: Probably we want PNG instead, but it doesn't work yet (https://github.com/linkml/linkml/issues/3009)
@ poetry run linkml generate plantuml -d $(MODEL_DOCS_DIR) --format svg $(LINKML_MODEL_PATH)

# (Brandizi) I've played with it, but the result isn't great (single-class diagrams in each
# class file)
# @ poetry run linkml generate doc -d $(MODEL_DOCS_DIR) --diagram-type plantuml_class_diagram $(LINKML_MODEL_PATH)


clean-models:
@ echo "Cleaning up generated models..."
@ rm -rf $(PYTHON_MODEL_PATH) $(JSON_SCHEMA_PATH)

clean-doc:
@ echo "Cleaning up generated documentation..."
@ rm -rf $(MODEL_DOCS_DIR)/*.md

clean: clean-doc clean-models
@ echo "All generated files cleaned."
# ─── Formatting ──────────────────────────────────────────────────────────────────

BUILD_PRINT = \e[1;34m
END_PRINT = \e[0m

ICON_DONE = $(BUILD_PRINT)$(END_PRINT) [✔]
ICON_ERROR = $(BUILD_PRINT)$(END_PRINT) [✗]
ICON_PROGRESS = $(BUILD_PRINT)$(END_PRINT) [-]

define log_progress
@printf "$(ICON_PROGRESS) $(BUILD_PRINT)$(1)$(END_PRINT)\n"
endef

define log_done
@printf "$(ICON_DONE) $(BUILD_PRINT)$(1)$(END_PRINT)\n"
endef

# ─── Paths & Naming ─────────────────────────────────────────────────────────────

SCHEMAS_DIR = resources/schemas
SCRIPTS_DIR = resources/scripts
TEMPLATES_DIR = resources/templates
MODELS_DIR = src/erspec/models

# Schema identifiers
ERE_SCHEMA_NAME = ere-service-schema
CORE_SCHEMA_NAME = core-schema
JSON_SCHEMA_NAME = er-schema
SCHEMA_VERSION = 0.1.0

# Source schemas (core is imported by ere, so it is a dependency)
ERE_SCHEMA_PATH = $(SCHEMAS_DIR)/$(ERE_SCHEMA_NAME)-v$(SCHEMA_VERSION).yaml
CORE_SCHEMA_PATH = $(SCHEMAS_DIR)/$(CORE_SCHEMA_NAME)-v$(SCHEMA_VERSION).yaml
ALL_SCHEMA_SOURCES = $(ERE_SCHEMA_PATH) $(CORE_SCHEMA_PATH)

# Generated artefacts
PYTHON_ERE_MODEL = $(MODELS_DIR)/ere.py
PYTHON_CORE_MODEL = $(MODELS_DIR)/core.py
JSON_SCHEMA_PATH = $(SCHEMAS_DIR)/$(JSON_SCHEMA_NAME)-v$(SCHEMA_VERSION).json

MODEL_DOCS_DIR = docs/schema
MODEL_DOCS_README = $(MODEL_DOCS_DIR)/README.md

# ─── Help ────────────────────────────────────────────────────────────────────────

.PHONY: help
help:
@echo ""
@echo "Usage:"
@echo " make <target>"
@echo ""
@echo "Available targets:"
@awk 'BEGIN {FS = ":.*##"; printf ""} \
/^[a-zA-Z0-9_-]+:.*##/ { \
printf " \033[1;34m%-20s\033[0m %s\n", $$1, $$2 \
}' $(MAKEFILE_LIST)

# ─── Setup ───────────────────────────────────────────────────────────────────────
# Note: Python, Poetry and Make are pre-requisites and are not handled here.

.PHONY: install
install: ## Install dependencies using Poetry
$(call log_progress,Installing dependencies using Poetry...)
@poetry sync
$(call log_done,Dependencies installed.)

# ─── Quality ─────────────────────────────────────────────────────────────────────

.PHONY: lint
lint: ## Run ruff linter on source code
$(call log_progress,Running ruff checks...)
@poetry run ruff check src/
$(call log_done,Ruff checks completed.)

.PHONY: lint-schema
lint-schema: ## Run LinkML linter on YAML schemas
$(call log_progress,Linting LinkML schemas...)
@poetry run linkml lint --ignore-warnings $(SCHEMAS_DIR)/
$(call log_done,LinkML schema lint completed.)

# ─── Aggregate targets ──────────────────────────────────────────────────────────

.PHONY: all
all: generate-models generate-doc ## Generate all artefacts (models + docs)
$(call log_done,All artefacts generated.)

.PHONY: generate-models
generate-models: $(PYTHON_ERE_MODEL) $(JSON_SCHEMA_PATH) ## Generate Python models and JSON Schema
$(call log_done,All models generated.)

.PHONY: generate-doc
generate-doc: $(MODEL_DOCS_README) ## Generate schema documentation and diagrams
$(call log_done,Documentation generated.)

# ─── Python Pydantic models (split generation: ere + core) ──────────────────────

$(PYTHON_ERE_MODEL) $(PYTHON_CORE_MODEL) &: $(ALL_SCHEMA_SOURCES)
$(call log_progress,Generating Python models...)
@mkdir -p $(MODELS_DIR)
@poetry run python $(SCRIPTS_DIR)/generate_models.py \
--schema $(ERE_SCHEMA_PATH) \
--output $(PYTHON_ERE_MODEL) \
--template-dir $(TEMPLATES_DIR) \
--schemas-dir $(SCHEMAS_DIR)
@poetry run ruff check --fix $(MODELS_DIR)
$(call log_done,Python models generated.)

# ─── JSON Schema ─────────────────────────────────────────────────────────────────
# The ERE schema imports core, so `linkml generate json-schema` will include both.

$(JSON_SCHEMA_PATH): $(ALL_SCHEMA_SOURCES)
$(call log_progress,Generating JSON Schema...)
@mkdir -p $(dir $(JSON_SCHEMA_PATH))
@poetry run linkml generate json-schema --indent 2 $(ERE_SCHEMA_PATH) > $(JSON_SCHEMA_PATH)
$(call log_done,JSON Schema generated -> $(JSON_SCHEMA_PATH))

# ─── Documentation & PlantUML diagrams ──────────────────────────────────────────

$(MODEL_DOCS_README): $(ALL_SCHEMA_SOURCES)
$(call log_progress,Generating schema documentation...)
@mkdir -p $(MODEL_DOCS_DIR)
# Index is named README.md so GitHub renders it when browsing the directory.
@poetry run linkml generate doc $(ERE_SCHEMA_PATH) \
-d $(MODEL_DOCS_DIR) --index-name README
# TODO: Prefer PNG once upstream is fixed (https://github.com/linkml/linkml/issues/3009)
# TODO: --no-mergeimports doesn't work (https://github.com/linkml/linkml/issues/1296), so, for
# the moment, we include core imported classes in the diagram.
@poetry run linkml generate plantuml \
-d $(MODEL_DOCS_DIR) --format svg $(ERE_SCHEMA_PATH)
$(call log_done,Documentation generated -> $(MODEL_DOCS_DIR))

# ─── Clean ───────────────────────────────────────────────────────────────────────

.PHONY: clean-models
clean-models: ## Remove all generated models
$(call log_progress,Cleaning generated models...)
@rm -f $(PYTHON_ERE_MODEL) $(PYTHON_CORE_MODEL) $(JSON_SCHEMA_PATH)
$(call log_done,Generated models cleaned.)

.PHONY: clean-doc
clean-doc: ## Remove generated docs and diagrams
$(call log_progress,Cleaning generated documentation...)
@rm -rf $(MODEL_DOCS_DIR)/*.md $(MODEL_DOCS_DIR)/*.svg
$(call log_done,Generated documentation cleaned.)

.PHONY: clean
clean: clean-models clean-doc ## Remove all generated files
$(call log_done,All generated files cleaned.)
Loading
Loading