From d47e01468e55b365302b1ffaa7e1d5e73a0a95e3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 11 Sep 2026 16:15:18 +0900 Subject: [PATCH 1/7] fix(job-analysis): declare a Python floor its owned dependencies can install services/job-analysis-api/pyproject.toml advertised requires-python >=3.11, but both mandatory owned distributions it pins require >=3.12: packages/hris-kernel (0.4.0) and packages/keyverse-adapter (0.1.0). A 3.11 interpreter therefore cannot install the service's declared dependency closure, while source-tree PYTHONPATH test execution hid the contradiction. Raise the declared floor to >=3.12 and add a metadata regression that reads the owned package pyprojects, asserts the exact internal pins match the canonical package names and versions, and asserts the service Python floor is not below any owned dependency floor. This mirrors the equivalent People API contract so the same class of stale metadata cannot return unnoticed. --- services/job-analysis-api/pyproject.toml | 2 +- .../test_internal_dependency_versions.py | 49 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 services/job-analysis-api/tests/test_internal_dependency_versions.py diff --git a/services/job-analysis-api/pyproject.toml b/services/job-analysis-api/pyproject.toml index 5e27bf477..40fd6d34e 100644 --- a/services/job-analysis-api/pyproject.toml +++ b/services/job-analysis-api/pyproject.toml @@ -7,7 +7,7 @@ name = "orgmetra-job-analysis-api" version = "0.1.0" description = "Governed persistence boundary for Orgmetra job-analysis snapshots." readme = "README.md" -requires-python = ">=3.11" +requires-python = ">=3.12" license = { text = "Apache-2.0" } authors = [{ name = "ContextualWisdomLab" }] dependencies = [ diff --git a/services/job-analysis-api/tests/test_internal_dependency_versions.py b/services/job-analysis-api/tests/test_internal_dependency_versions.py new file mode 100644 index 000000000..8b2499b41 --- /dev/null +++ b/services/job-analysis-api/tests/test_internal_dependency_versions.py @@ -0,0 +1,49 @@ +"""Keep Job Analysis API package metadata aligned with canonical owned packages.""" + +from pathlib import Path +import re +import tomllib + + +_REPOSITORY_ROOT = Path(__file__).resolve().parents[3] + + +def _project_metadata(relative_path: str) -> dict[str, object]: + """Read project metadata without importing or executing package code.""" + pyproject_path = _REPOSITORY_ROOT / relative_path / "pyproject.toml" + with pyproject_path.open("rb") as pyproject_file: + return tomllib.load(pyproject_file)["project"] + + +def _minimum_python_version(project: dict[str, object]) -> tuple[int, int]: + """Return the exact declared lower Python minor for the current simple contract.""" + requires_python = project.get("requires-python") + assert isinstance(requires_python, str) + match = re.fullmatch(r">=(\d+)\.(\d+)", requires_python) + assert match is not None, "requires-python must remain an explicit >=major.minor floor" + return int(match.group(1)), int(match.group(2)) + + +def test_job_analysis_api_internal_dependencies_match_owned_package_versions() -> None: + """Reject stale internal distribution pins hidden by source-tree PYTHONPATH tests.""" + service_project = _project_metadata("services/job-analysis-api") + declared_dependencies = set(service_project["dependencies"]) + + expected_dependencies = set() + for package_path in ("packages/hris-kernel", "packages/keyverse-adapter"): + package_project = _project_metadata(package_path) + expected_dependencies.add( + f"{package_project['name']}=={package_project['version']}" + ) + + assert expected_dependencies <= declared_dependencies + + +def test_job_analysis_api_python_floor_covers_owned_runtime_dependencies() -> None: + """Reject a service Python floor that cannot install its mandatory owned packages.""" + service_project = _project_metadata("services/job-analysis-api") + service_floor = _minimum_python_version(service_project) + + for package_path in ("packages/hris-kernel", "packages/keyverse-adapter"): + package_project = _project_metadata(package_path) + assert _minimum_python_version(package_project) <= service_floor From 361d48bcc15bb8de13df85f5dd08f4aa6b3d1b90 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 11 Sep 2026 17:06:14 +0900 Subject: [PATCH 2/7] test(job-analysis): reject extra internal dependency drift --- .../test_internal_dependency_versions.py | 45 +++++++++++++++---- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/services/job-analysis-api/tests/test_internal_dependency_versions.py b/services/job-analysis-api/tests/test_internal_dependency_versions.py index 8b2499b41..fa6eccfe0 100644 --- a/services/job-analysis-api/tests/test_internal_dependency_versions.py +++ b/services/job-analysis-api/tests/test_internal_dependency_versions.py @@ -4,8 +4,11 @@ import re import tomllib +import pytest + _REPOSITORY_ROOT = Path(__file__).resolve().parents[3] +_OWNED_PACKAGE_PATHS = ("packages/hris-kernel", "packages/keyverse-adapter") def _project_metadata(relative_path: str) -> dict[str, object]: @@ -24,19 +27,45 @@ def _minimum_python_version(project: dict[str, object]) -> tuple[int, int]: return int(match.group(1)), int(match.group(2)) -def test_job_analysis_api_internal_dependencies_match_owned_package_versions() -> None: - """Reject stale internal distribution pins hidden by source-tree PYTHONPATH tests.""" - service_project = _project_metadata("services/job-analysis-api") - declared_dependencies = set(service_project["dependencies"]) - +def _expected_owned_dependencies() -> set[str]: + """Return canonical exact pins for every owned Job Analysis dependency.""" expected_dependencies = set() - for package_path in ("packages/hris-kernel", "packages/keyverse-adapter"): + for package_path in _OWNED_PACKAGE_PATHS: package_project = _project_metadata(package_path) expected_dependencies.add( f"{package_project['name']}=={package_project['version']}" ) + return expected_dependencies + + +def _assert_owned_dependency_pins( + declared_dependencies: list[str], expected_dependencies: set[str] +) -> None: + """Require every expected owned package while preserving the existing contract.""" + assert expected_dependencies <= set(declared_dependencies) + + +def test_owned_dependency_contract_rejects_extra_internal_pin() -> None: + """Reject an unknown or stale internal package that the subset check would miss.""" + expected_dependencies = {"orgmetra-hris-kernel==0.4.0"} + with pytest.raises(AssertionError): + _assert_owned_dependency_pins( + ["orgmetra-hris-kernel==0.4.0", "orgmetra-stale-package==0.1.0"], + expected_dependencies, + ) + + +def test_job_analysis_api_internal_dependencies_match_owned_package_versions() -> None: + """Reject stale internal distribution pins hidden by source-tree PYTHONPATH tests.""" + service_project = _project_metadata("services/job-analysis-api") + declared_dependencies = service_project["dependencies"] + assert isinstance(declared_dependencies, list) + assert all(isinstance(dependency, str) for dependency in declared_dependencies) - assert expected_dependencies <= declared_dependencies + _assert_owned_dependency_pins( + declared_dependencies, + _expected_owned_dependencies(), + ) def test_job_analysis_api_python_floor_covers_owned_runtime_dependencies() -> None: @@ -44,6 +73,6 @@ def test_job_analysis_api_python_floor_covers_owned_runtime_dependencies() -> No service_project = _project_metadata("services/job-analysis-api") service_floor = _minimum_python_version(service_project) - for package_path in ("packages/hris-kernel", "packages/keyverse-adapter"): + for package_path in _OWNED_PACKAGE_PATHS: package_project = _project_metadata(package_path) assert _minimum_python_version(package_project) <= service_floor From 66e2fcb93fea5d7d2624d2cbc8859511a119e6bf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 11 Sep 2026 17:06:37 +0900 Subject: [PATCH 3/7] test(job-analysis): require exact owned dependency set --- .../tests/test_internal_dependency_versions.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/services/job-analysis-api/tests/test_internal_dependency_versions.py b/services/job-analysis-api/tests/test_internal_dependency_versions.py index fa6eccfe0..e98312a1a 100644 --- a/services/job-analysis-api/tests/test_internal_dependency_versions.py +++ b/services/job-analysis-api/tests/test_internal_dependency_versions.py @@ -41,12 +41,17 @@ def _expected_owned_dependencies() -> set[str]: def _assert_owned_dependency_pins( declared_dependencies: list[str], expected_dependencies: set[str] ) -> None: - """Require every expected owned package while preserving the existing contract.""" - assert expected_dependencies <= set(declared_dependencies) + """Require declared internal dependencies to equal the canonical owned pins.""" + declared_owned_dependencies = { + dependency + for dependency in declared_dependencies + if dependency.startswith("orgmetra-") + } + assert declared_owned_dependencies == expected_dependencies def test_owned_dependency_contract_rejects_extra_internal_pin() -> None: - """Reject an unknown or stale internal package that the subset check would miss.""" + """Reject an unknown or stale internal package that a subset check would miss.""" expected_dependencies = {"orgmetra-hris-kernel==0.4.0"} with pytest.raises(AssertionError): _assert_owned_dependency_pins( From b9e1daa73121bf0e6f126c42f8ecda41e8db2e33 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 11 Sep 2026 17:11:25 +0900 Subject: [PATCH 4/7] test(job-analysis): reject normalized internal dependency aliases --- .../tests/test_internal_dependency_versions.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/job-analysis-api/tests/test_internal_dependency_versions.py b/services/job-analysis-api/tests/test_internal_dependency_versions.py index e98312a1a..51d408d2e 100644 --- a/services/job-analysis-api/tests/test_internal_dependency_versions.py +++ b/services/job-analysis-api/tests/test_internal_dependency_versions.py @@ -60,6 +60,16 @@ def test_owned_dependency_contract_rejects_extra_internal_pin() -> None: ) +def test_owned_dependency_contract_rejects_normalized_internal_alias() -> None: + """Reject internal names whose underscore spelling normalizes into Orgmetra.""" + expected_dependencies = {"orgmetra-hris-kernel==0.4.0"} + with pytest.raises(AssertionError): + _assert_owned_dependency_pins( + ["orgmetra-hris-kernel==0.4.0", "orgmetra_stale_package==0.1.0"], + expected_dependencies, + ) + + def test_job_analysis_api_internal_dependencies_match_owned_package_versions() -> None: """Reject stale internal distribution pins hidden by source-tree PYTHONPATH tests.""" service_project = _project_metadata("services/job-analysis-api") From 2934ca96f73187ede10ed0a0fd08c6cd622fd62e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 11 Sep 2026 17:11:54 +0900 Subject: [PATCH 5/7] test(job-analysis): normalize internal distribution names --- .../tests/test_internal_dependency_versions.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/services/job-analysis-api/tests/test_internal_dependency_versions.py b/services/job-analysis-api/tests/test_internal_dependency_versions.py index 51d408d2e..0a268e669 100644 --- a/services/job-analysis-api/tests/test_internal_dependency_versions.py +++ b/services/job-analysis-api/tests/test_internal_dependency_versions.py @@ -9,6 +9,9 @@ _REPOSITORY_ROOT = Path(__file__).resolve().parents[3] _OWNED_PACKAGE_PATHS = ("packages/hris-kernel", "packages/keyverse-adapter") +_DEPENDENCY_NAME_PATTERN = re.compile( + r"^\s*([A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?)(?=\s*(?:\[|@|[<>=!~;]|$))" +) def _project_metadata(relative_path: str) -> dict[str, object]: @@ -27,6 +30,13 @@ def _minimum_python_version(project: dict[str, object]) -> tuple[int, int]: return int(match.group(1)), int(match.group(2)) +def _normalized_dependency_name(dependency: str) -> str: + """Return the standards-normalized distribution name from one dependency string.""" + match = _DEPENDENCY_NAME_PATTERN.match(dependency) + assert match is not None, f"dependency must start with a valid distribution name: {dependency!r}" + return re.sub(r"[-_.]+", "-", match.group(1)).lower() + + def _expected_owned_dependencies() -> set[str]: """Return canonical exact pins for every owned Job Analysis dependency.""" expected_dependencies = set() @@ -45,7 +55,7 @@ def _assert_owned_dependency_pins( declared_owned_dependencies = { dependency for dependency in declared_dependencies - if dependency.startswith("orgmetra-") + if _normalized_dependency_name(dependency).startswith("orgmetra-") } assert declared_owned_dependencies == expected_dependencies From 538de7b45ed497737ec82cdc0f57337196a6cc4c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 11 Sep 2026 17:13:56 +0900 Subject: [PATCH 6/7] test(job-analysis): accept parenthesized dependency specifiers --- .../tests/test_internal_dependency_versions.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/services/job-analysis-api/tests/test_internal_dependency_versions.py b/services/job-analysis-api/tests/test_internal_dependency_versions.py index 0a268e669..691f64d65 100644 --- a/services/job-analysis-api/tests/test_internal_dependency_versions.py +++ b/services/job-analysis-api/tests/test_internal_dependency_versions.py @@ -80,6 +80,14 @@ def test_owned_dependency_contract_rejects_normalized_internal_alias() -> None: ) +def test_owned_dependency_classifier_accepts_parenthesized_third_party_specifier() -> None: + """Preserve valid PEP 508 parenthesized version syntax outside the owned namespace.""" + _assert_owned_dependency_pins( + ["orgmetra-hris-kernel==0.4.0", "requests (>=2.0)"], + {"orgmetra-hris-kernel==0.4.0"}, + ) + + def test_job_analysis_api_internal_dependencies_match_owned_package_versions() -> None: """Reject stale internal distribution pins hidden by source-tree PYTHONPATH tests.""" service_project = _project_metadata("services/job-analysis-api") From 648aca54c30ee7879e85faeeab76609c0a70b1e5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 11 Sep 2026 17:14:15 +0900 Subject: [PATCH 7/7] test(job-analysis): classify dependency names without narrowing PEP 508 --- .../job-analysis-api/tests/test_internal_dependency_versions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/job-analysis-api/tests/test_internal_dependency_versions.py b/services/job-analysis-api/tests/test_internal_dependency_versions.py index 691f64d65..42b83c561 100644 --- a/services/job-analysis-api/tests/test_internal_dependency_versions.py +++ b/services/job-analysis-api/tests/test_internal_dependency_versions.py @@ -10,7 +10,7 @@ _REPOSITORY_ROOT = Path(__file__).resolve().parents[3] _OWNED_PACKAGE_PATHS = ("packages/hris-kernel", "packages/keyverse-adapter") _DEPENDENCY_NAME_PATTERN = re.compile( - r"^\s*([A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?)(?=\s*(?:\[|@|[<>=!~;]|$))" + r"^\s*([A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?)" )