From 56d34fa72e88e43977ffb8064dd1fa6248640be6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 07:57:45 -0700 Subject: [PATCH 01/43] test(semantic-job-evidence): define package coverage gate --- .../pyproject.toml | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/pyproject.toml diff --git a/packages/semantic-job-evidence-adapter/pyproject.toml b/packages/semantic-job-evidence-adapter/pyproject.toml new file mode 100644 index 000000000..952e799b5 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/pyproject.toml @@ -0,0 +1,24 @@ +[build-system] +requires = ["setuptools>=69"] +build-backend = "setuptools.build_meta" + +[project] +name = "orgmetra-semantic-job-evidence-adapter" +version = "0.1.0" +description = "Fail-closed Semantic Data Portal ontology evidence boundary for Orgmetra job analysis." +requires-python = ">=3.12" + +[project.optional-dependencies] +test = ["pytest>=8.3", "pytest-cov>=5.0"] + +[tool.setuptools.packages.find] +where = ["src"] + +[tool.pytest.ini_options] +testpaths = ["tests"] +addopts = [ + "--cov=orgmetra_semantic_job_evidence_adapter", + "--cov-branch", + "--cov-report=term-missing", + "--cov-fail-under=100", +] From 804f0f99b608202eeefe637b28b2ecded04e143a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 07:57:51 -0700 Subject: [PATCH 02/43] test(semantic-job-evidence): expose missing governed envelope --- .../src/orgmetra_semantic_job_evidence_adapter/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/__init__.py diff --git a/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/__init__.py b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/__init__.py new file mode 100644 index 000000000..6ab7f307e --- /dev/null +++ b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/__init__.py @@ -0,0 +1,5 @@ +"""Public contract for governed Semantic Data Portal job-analysis evidence.""" + +from .envelope import SemanticJobEvidenceEnvelope + +__all__ = ["SemanticJobEvidenceEnvelope"] From eac4afeaebda59dca4cf5f2b5c798705edebcfd1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 07:58:17 -0700 Subject: [PATCH 03/43] test(semantic-job-evidence): define fail-closed evidence contract --- .../tests/test_envelope.py | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/tests/test_envelope.py diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py new file mode 100644 index 000000000..938ed3909 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -0,0 +1,159 @@ +from dataclasses import replace +from datetime import datetime, timezone +from hashlib import sha256 +from uuid import uuid1, uuid4 + +import pytest + +from orgmetra_semantic_job_evidence_adapter import SemanticJobEvidenceEnvelope + + +SDP_REVISION = "e48aa13c4af7a4875d4b53e6a60b50405c265a2f" +DIGEST_A = "a" * 64 +DIGEST_B = "b" * 64 +DIGEST_C = "c" * 64 + + +def values() -> dict[str, object]: + return { + "tenant_record_id": str(uuid4()), + "job_analysis_reference": f"job_analysis:{uuid4()}", + "ontology_request_reference": f"ontology_request:{uuid4()}", + "requesting_actor_reference": "actor:hr-analyst", + "reviewing_actor_reference": "actor:job-analysis-reviewer", + "resolution_use_code": "job_analysis_source_evidence", + "query_term_digest": DIGEST_A, + "response_evidence_digest": DIGEST_B, + "source_catalog_digest": DIGEST_C, + "semantic_data_portal_revision": SDP_REVISION, + "api_operation": "POST /ontology/resolve", + "evidence_version": 1, + "recorded_at": datetime(2026, 8, 22, 14, 50, 12, 123456, tzinfo=timezone.utc), + } + + +def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: + packet = SemanticJobEvidenceEnvelope(**values()) + document = packet.canonical_document() + + assert document["source_system"] == "semantic-data-portal" + assert document["source_trust_state"] == "external_source_evidence" + assert document["review_state"] == "requires_human_review" + assert document["decision_authority_state"] == "not_authorized_for_job_or_employment_decision" + assert document["recorded_at"] == "2026-08-22T14:50:12.123456Z" + assert "query_term" not in document + assert "response" not in document + assert "person" not in document + assert packet.evidence_digest() == sha256(packet.canonical_json().encode("utf-8")).hexdigest() + assert packet.canonical_json() == SemanticJobEvidenceEnvelope(**values()).canonical_json() if False else packet.canonical_json() + assert repr(packet) == "SemanticJobEvidenceEnvelope()" + + +@pytest.mark.parametrize( + ("field_name", "bad_value"), + [ + ("tenant_record_id", "00000000-0000-0000-0000-000000000000"), + ("tenant_record_id", "not-a-uuid"), + ("job_analysis_reference", f"job_analysis:{uuid1()}"), + ("job_analysis_reference", f"person:{uuid4()}"), + ("ontology_request_reference", f"ontology_request:{uuid1()}"), + ("ontology_request_reference", "ontology_request:not-a-uuid"), + ("requesting_actor_reference", "staff:analyst"), + ("reviewing_actor_reference", "actor:has space"), + ("query_term_digest", "A" * 64), + ("response_evidence_digest", "b" * 63), + ("source_catalog_digest", "not-a-digest"), + ("semantic_data_portal_revision", "0" * 40), + ("api_operation", "POST /search/semantic"), + ("resolution_use_code", "automated_job_decision"), + ("evidence_version", 0), + ("evidence_version", 1_000_001), + ("evidence_version", True), + ("recorded_at", datetime(2026, 8, 22, 14, 50, 12)), + ], +) +def test_rejects_invalid_governance_evidence(field_name: str, bad_value: object) -> None: + candidate = values() + candidate[field_name] = bad_value + with pytest.raises(ValueError): + SemanticJobEvidenceEnvelope(**candidate) + + +def test_rejects_same_requester_and_reviewer() -> None: + candidate = values() + candidate["reviewing_actor_reference"] = candidate["requesting_actor_reference"] + with pytest.raises(ValueError, match="must differ"): + SemanticJobEvidenceEnvelope(**candidate) + + +class ForgedText(str): + def __eq__(self, other: object) -> bool: + return True + + def __ne__(self, other: object) -> bool: + return False + + def __hash__(self) -> int: + return hash("job_analysis_source_evidence") + + +class ForgedInt(int): + def __le__(self, other: object) -> bool: + return True + + def __ge__(self, other: object) -> bool: + return True + + def __lt__(self, other: object) -> bool: + return False + + def __gt__(self, other: object) -> bool: + return False + + +class ForgedDateTime(datetime): + pass + + +def test_rejects_runtime_subclasses_before_governance_comparison() -> None: + for field_name, bad_value in ( + ("resolution_use_code", ForgedText("automated_job_decision")), + ("api_operation", ForgedText("POST /search/semantic")), + ("evidence_version", ForgedInt(999999999)), + ("recorded_at", ForgedDateTime(2026, 8, 22, tzinfo=timezone.utc)), + ): + candidate = values() + candidate[field_name] = bad_value + with pytest.raises(ValueError): + SemanticJobEvidenceEnvelope(**candidate) + + +def test_rejects_post_construction_rewrite() -> None: + packet = SemanticJobEvidenceEnvelope(**values()) + object.__setattr__(packet, "response_evidence_digest", "d" * 64) + with pytest.raises(ValueError, match="changed after construction"): + packet.canonical_json() + + +def test_replace_cannot_reseal_changed_evidence() -> None: + packet = SemanticJobEvidenceEnvelope(**values()) + with pytest.raises(ValueError, match="changed after construction"): + replace(packet, response_evidence_digest="d" * 64, _creation_seal=None) + + +def test_rejects_caller_supplied_seal_and_marker_rewrite() -> None: + candidate = values() + candidate["_creation_seal"] = "0" * 64 + with pytest.raises(ValueError, match="changed after construction"): + SemanticJobEvidenceEnvelope(**candidate) + + packet = SemanticJobEvidenceEnvelope(**values()) + object.__setattr__(packet, "_issuance_marker", object()) + with pytest.raises(ValueError, match="changed after construction"): + packet.canonical_document() + + +def test_runtime_type_is_final() -> None: + with pytest.raises(TypeError, match="final"): + class DerivedEnvelope(SemanticJobEvidenceEnvelope): + pass From c01d47cb1551ad1090d4fb9db3a8f7cd6423ae3c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 07:59:29 -0700 Subject: [PATCH 04/43] test(semantic-job-evidence): add exact-head RED quality lane --- .../semantic-job-evidence-adapter-quality.yml | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 .github/workflows/semantic-job-evidence-adapter-quality.yml diff --git a/.github/workflows/semantic-job-evidence-adapter-quality.yml b/.github/workflows/semantic-job-evidence-adapter-quality.yml new file mode 100644 index 000000000..a2f51e1f9 --- /dev/null +++ b/.github/workflows/semantic-job-evidence-adapter-quality.yml @@ -0,0 +1,56 @@ +name: Semantic Job Evidence Adapter Quality + +on: + pull_request: + branches: + - bootstrap + - develop + - main + paths: + - "packages/semantic-job-evidence-adapter/**" + - ".github/requirements/foundation-test.txt" + - ".github/workflows/semantic-job-evidence-adapter-quality.yml" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: semantic-job-evidence-adapter-quality-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + unit: + name: Semantic source evidence contract and 100% coverage + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Checkout exact candidate + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + - name: Prove exact candidate checkout + env: + ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.14" + check-latest: false + - name: Install reviewed test toolchain + run: | + python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt + python -m pip check + - name: Compile adapter boundary + run: python -m compileall -q packages/semantic-job-evidence-adapter/src packages/semantic-job-evidence-adapter/tests + - name: Test governed semantic source evidence with exact statement and branch coverage + env: + PYTHONPATH: packages/semantic-job-evidence-adapter/src + COVERAGE_FILE: /tmp/orgmetra-semantic-job-evidence-adapter.coverage + run: python -m pytest -c packages/semantic-job-evidence-adapter/pyproject.toml packages/semantic-job-evidence-adapter/tests + - name: Require clean checkout + run: | + git diff --exit-code + test -z "$(git status --porcelain)" From 46913b985a8f5db7db62f35d20a7c8c77c002504 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:00:37 -0700 Subject: [PATCH 05/43] feat(semantic-job-evidence): implement governed ontology evidence envelope --- .../envelope.py | 208 ++++++++++++++++++ 1 file changed, 208 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py diff --git a/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py new file mode 100644 index 000000000..adf90c5a8 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py @@ -0,0 +1,208 @@ +"""Governed, value-minimized Semantic Data Portal ontology evidence for job analysis.""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from datetime import datetime, timezone +from hashlib import sha256 +import hmac +import json +import re +import secrets +from typing import ClassVar +from uuid import UUID + + +_SEMANTIC_DATA_PORTAL_REVISION = "e48aa13c4af7a4875d4b53e6a60b50405c265a2f" +_PROCESS_SEAL_KEY = secrets.token_bytes(32) +_NEW_ISSUANCE_MARKER = object() +_USED_ISSUANCE_MARKER = object() +_DIGEST_PATTERN = re.compile(r"[0-9a-f]{64}") +_ACTOR_PATTERN = re.compile(r"actor:[A-Za-z0-9._~-]{1,128}") +_ALLOWED_RESOLUTION_USES = frozenset({"job_analysis_source_evidence"}) + + +def _require_text(value: object, field_name: str) -> str: + """Return exact built-in non-empty text before caller-defined behavior can run.""" + if type(value) is not str or not value: + raise ValueError(f"{field_name} must be exact non-empty text") + return value + + +def _validate_operational_uuid(value: object, field_name: str) -> str: + """Require one canonical non-sentinel operational UUID string.""" + text = _require_text(value, field_name) + try: + parsed = UUID(text) + except (ValueError, AttributeError, TypeError) as error: + raise ValueError(f"{field_name} must be a canonical operational UUID") from error + if str(parsed) != text or parsed.int in (0, (1 << 128) - 1): + raise ValueError(f"{field_name} must be a canonical non-sentinel operational UUID") + return text + + +def _validate_reference(value: object, field_name: str, namespace: str) -> str: + """Require a bounded namespaced reference with a canonical UUIDv4 suffix.""" + text = _require_text(value, field_name) + prefix = f"{namespace}:" + if len(text) > 180 or not text.startswith(prefix): + raise ValueError(f"{field_name} must be a bounded {namespace}: UUIDv4 reference") + suffix = text[len(prefix) :] + try: + parsed = UUID(suffix) + except (ValueError, AttributeError, TypeError) as error: + raise ValueError(f"{field_name} must end in a canonical UUIDv4") from error + if str(parsed) != suffix or parsed.version != 4: + raise ValueError(f"{field_name} must end in a canonical UUIDv4") + return text + + +def _validate_actor_reference(value: object, field_name: str) -> str: + """Require bounded opaque actor correlation without treating syntax as authentication.""" + text = _require_text(value, field_name) + if _ACTOR_PATTERN.fullmatch(text) is None: + raise ValueError(f"{field_name} must be a bounded actor: reference") + return text + + +def _validate_digest(value: object, field_name: str) -> str: + """Require one lowercase SHA-256 evidence digest.""" + text = _require_text(value, field_name) + if _DIGEST_PATTERN.fullmatch(text) is None: + raise ValueError(f"{field_name} must be a lowercase SHA-256 digest") + return text + + +def _validate_recorded_at(value: object) -> datetime: + """Require exact built-in UTC system-recorded time for immutable evidence.""" + if type(value) is not datetime or value.tzinfo is not timezone.utc: + raise ValueError("recorded_at must be an exact built-in UTC datetime") + return value + + +def _canonical_timestamp(value: datetime) -> str: + """Render an already-governed UTC timestamp in deterministic RFC 3339 form.""" + return value.isoformat().replace("+00:00", "Z") + + +def _seal(payload_json: str) -> str: + """Bind one in-process issuance to its exact creation-time canonical payload.""" + return hmac.new(_PROCESS_SEAL_KEY, payload_json.encode("utf-8"), "sha256").hexdigest() + + +@dataclass(frozen=True, slots=True, repr=False) +class SemanticJobEvidenceEnvelope: + """Bind ontology source provenance without granting Job or employment decision authority.""" + + tenant_record_id: str + job_analysis_reference: str + ontology_request_reference: str + requesting_actor_reference: str + reviewing_actor_reference: str + resolution_use_code: str + query_term_digest: str + response_evidence_digest: str + source_catalog_digest: str + semantic_data_portal_revision: str + api_operation: str + evidence_version: int + recorded_at: datetime + _creation_seal: str | None = field(default=None, repr=False, compare=False) + _issuance_marker: object = field(default=_NEW_ISSUANCE_MARKER, repr=False, compare=False) + + SOURCE_SYSTEM: ClassVar[str] = "semantic-data-portal" + SOURCE_TRUST_STATE: ClassVar[str] = "external_source_evidence" + REVIEW_STATE: ClassVar[str] = "requires_human_review" + DECISION_AUTHORITY_STATE: ClassVar[str] = "not_authorized_for_job_or_employment_decision" + + def __init_subclass__(cls, **kwargs: object) -> None: + """Keep the trust-bearing runtime type final.""" + raise TypeError("SemanticJobEvidenceEnvelope is final") + + def __post_init__(self) -> None: + """Validate the reviewed boundary and seal its exact creation-time evidence.""" + if self._issuance_marker is not _NEW_ISSUANCE_MARKER: + raise ValueError("semantic job evidence changed after construction") + if self._creation_seal is not None: + raise ValueError("semantic job evidence changed after construction") + self._validate_fields() + object.__setattr__(self, "_creation_seal", _seal(self._canonical_payload_json())) + object.__setattr__(self, "_issuance_marker", _USED_ISSUANCE_MARKER) + + def _validate_fields(self) -> None: + """Fail closed on scope, source provenance, actor separation, and reviewed state.""" + _validate_operational_uuid(self.tenant_record_id, "tenant_record_id") + _validate_reference(self.job_analysis_reference, "job_analysis_reference", "job_analysis") + _validate_reference(self.ontology_request_reference, "ontology_request_reference", "ontology_request") + requester = _validate_actor_reference(self.requesting_actor_reference, "requesting_actor_reference") + reviewer = _validate_actor_reference(self.reviewing_actor_reference, "reviewing_actor_reference") + if requester == reviewer: + raise ValueError("reviewing_actor_reference must differ from requesting_actor_reference") + resolution_use = _require_text(self.resolution_use_code, "resolution_use_code") + if resolution_use not in _ALLOWED_RESOLUTION_USES: + raise ValueError("resolution_use_code is not an approved source-evidence use") + _validate_digest(self.query_term_digest, "query_term_digest") + _validate_digest(self.response_evidence_digest, "response_evidence_digest") + _validate_digest(self.source_catalog_digest, "source_catalog_digest") + revision = _require_text(self.semantic_data_portal_revision, "semantic_data_portal_revision") + if revision != _SEMANTIC_DATA_PORTAL_REVISION: + raise ValueError("semantic_data_portal_revision must match the reviewed dependency revision") + operation = _require_text(self.api_operation, "api_operation") + if operation != "POST /ontology/resolve": + raise ValueError("api_operation must use the reviewed ontology-resolution contract") + if type(self.evidence_version) is not int or not 1 <= self.evidence_version <= 1_000_000: + raise ValueError("evidence_version must be an exact positive bounded integer") + _validate_recorded_at(self.recorded_at) + + def _payload(self) -> dict[str, object]: + """Return value-minimized canonical evidence without raw ontology or HR content.""" + return { + "api_operation": self.api_operation, + "decision_authority_state": self.DECISION_AUTHORITY_STATE, + "evidence_version": self.evidence_version, + "job_analysis_reference": self.job_analysis_reference, + "ontology_request_reference": self.ontology_request_reference, + "query_term_digest": self.query_term_digest, + "recorded_at": _canonical_timestamp(self.recorded_at), + "requesting_actor_reference": self.requesting_actor_reference, + "resolution_use_code": self.resolution_use_code, + "response_evidence_digest": self.response_evidence_digest, + "review_state": self.REVIEW_STATE, + "reviewing_actor_reference": self.reviewing_actor_reference, + "semantic_data_portal_revision": self.semantic_data_portal_revision, + "source_catalog_digest": self.source_catalog_digest, + "source_system": self.SOURCE_SYSTEM, + "source_trust_state": self.SOURCE_TRUST_STATE, + "tenant_record_id": self.tenant_record_id, + } + + def _canonical_payload_json(self) -> str: + """Serialize the live evidence deterministically without consulting its creation seal.""" + return json.dumps(self._payload(), sort_keys=True, separators=(",", ":"), ensure_ascii=True) + + def _assert_integrity(self) -> None: + """Reject post-construction rewriting before canonical evidence can leave this boundary.""" + self._validate_fields() + if self._issuance_marker is not _USED_ISSUANCE_MARKER: + raise ValueError("semantic job evidence changed after construction") + seal = self._creation_seal + if type(seal) is not str or not hmac.compare_digest(seal, _seal(self._canonical_payload_json())): + raise ValueError("semantic job evidence changed after construction") + + def canonical_document(self) -> dict[str, object]: + """Return a fresh canonical document only while issuance evidence remains intact.""" + self._assert_integrity() + return self._payload() + + def canonical_json(self) -> str: + """Return deterministic canonical JSON for immutable audit/outbox correlation.""" + self._assert_integrity() + return self._canonical_payload_json() + + def evidence_digest(self) -> str: + """Return SHA-256 of the exact canonical evidence bytes.""" + return sha256(self.canonical_json().encode("utf-8")).hexdigest() + + def __repr__(self) -> str: + """Avoid leaking tenant, actors, Job-analysis scope, or source correlation into logs.""" + return "SemanticJobEvidenceEnvelope()" From ef37f71e2ebd351086f984ffba7940acb13d4c79 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:01:27 -0700 Subject: [PATCH 06/43] test(semantic-job-evidence): strengthen adversarial evidence coverage --- .../tests/test_envelope.py | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py index 938ed3909..b5c78e35f 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_envelope.py +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -1,6 +1,7 @@ from dataclasses import replace from datetime import datetime, timezone from hashlib import sha256 +import json from uuid import uuid1, uuid4 import pytest @@ -15,6 +16,7 @@ def values() -> dict[str, object]: + """Return one valid value-minimized ontology source-evidence fixture.""" return { "tenant_record_id": str(uuid4()), "job_analysis_reference": f"job_analysis:{uuid4()}", @@ -33,6 +35,7 @@ def values() -> dict[str, object]: def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: + """Canonical evidence contains governance/provenance only and has stable bytes.""" packet = SemanticJobEvidenceEnvelope(**values()) document = packet.canonical_document() @@ -44,8 +47,9 @@ def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: assert "query_term" not in document assert "response" not in document assert "person" not in document - assert packet.evidence_digest() == sha256(packet.canonical_json().encode("utf-8")).hexdigest() - assert packet.canonical_json() == SemanticJobEvidenceEnvelope(**values()).canonical_json() if False else packet.canonical_json() + expected_json = json.dumps(document, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + assert packet.canonical_json() == expected_json + assert packet.evidence_digest() == sha256(expected_json.encode("utf-8")).hexdigest() assert repr(packet) == "SemanticJobEvidenceEnvelope()" @@ -54,8 +58,10 @@ def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: [ ("tenant_record_id", "00000000-0000-0000-0000-000000000000"), ("tenant_record_id", "not-a-uuid"), + ("tenant_record_id", str(uuid4()).upper()), ("job_analysis_reference", f"job_analysis:{uuid1()}"), ("job_analysis_reference", f"person:{uuid4()}"), + ("job_analysis_reference", "job_analysis:" + "a" * 181), ("ontology_request_reference", f"ontology_request:{uuid1()}"), ("ontology_request_reference", "ontology_request:not-a-uuid"), ("requesting_actor_reference", "staff:analyst"), @@ -65,6 +71,7 @@ def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: ("source_catalog_digest", "not-a-digest"), ("semantic_data_portal_revision", "0" * 40), ("api_operation", "POST /search/semantic"), + ("api_operation", ""), ("resolution_use_code", "automated_job_decision"), ("evidence_version", 0), ("evidence_version", 1_000_001), @@ -73,6 +80,7 @@ def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: ], ) def test_rejects_invalid_governance_evidence(field_name: str, bad_value: object) -> None: + """Malformed, unsafe, or unreviewed evidence fails closed at construction.""" candidate = values() candidate[field_name] = bad_value with pytest.raises(ValueError): @@ -80,6 +88,7 @@ def test_rejects_invalid_governance_evidence(field_name: str, bad_value: object) def test_rejects_same_requester_and_reviewer() -> None: + """One actor cannot self-review ontology evidence for Job Analysis.""" candidate = values() candidate["reviewing_actor_reference"] = candidate["requesting_actor_reference"] with pytest.raises(ValueError, match="must differ"): @@ -87,35 +96,47 @@ def test_rejects_same_requester_and_reviewer() -> None: class ForgedText(str): + """Simulate caller text that lies during reviewed equality/hash operations.""" + def __eq__(self, other: object) -> bool: + """Pretend every comparison is equal.""" return True def __ne__(self, other: object) -> bool: + """Pretend every comparison is not unequal.""" return False def __hash__(self) -> int: + """Pretend to hash like an approved use code.""" return hash("job_analysis_source_evidence") class ForgedInt(int): + """Simulate caller numeric evidence that lies during bounds checks.""" + def __le__(self, other: object) -> bool: + """Forge less-than-or-equal comparisons.""" return True def __ge__(self, other: object) -> bool: + """Forge greater-than-or-equal comparisons.""" return True def __lt__(self, other: object) -> bool: + """Forge strict less-than comparisons.""" return False def __gt__(self, other: object) -> bool: + """Forge strict greater-than comparisons.""" return False class ForgedDateTime(datetime): - pass + """Represent caller-executable temporal behavior at the trust boundary.""" def test_rejects_runtime_subclasses_before_governance_comparison() -> None: + """Caller-defined primitives cannot forge reviewed state or canonical evidence.""" for field_name, bad_value in ( ("resolution_use_code", ForgedText("automated_job_decision")), ("api_operation", ForgedText("POST /search/semantic")), @@ -129,6 +150,7 @@ def test_rejects_runtime_subclasses_before_governance_comparison() -> None: def test_rejects_post_construction_rewrite() -> None: + """Valid-looking field replacement cannot rewrite already-issued evidence.""" packet = SemanticJobEvidenceEnvelope(**values()) object.__setattr__(packet, "response_evidence_digest", "d" * 64) with pytest.raises(ValueError, match="changed after construction"): @@ -136,12 +158,14 @@ def test_rejects_post_construction_rewrite() -> None: def test_replace_cannot_reseal_changed_evidence() -> None: + """Dataclass replacement cannot reset the issuance seal and create new authority.""" packet = SemanticJobEvidenceEnvelope(**values()) with pytest.raises(ValueError, match="changed after construction"): replace(packet, response_evidence_digest="d" * 64, _creation_seal=None) def test_rejects_caller_supplied_seal_and_marker_rewrite() -> None: + """Private seal and issuance marker fields remain fail-closed under hostile access.""" candidate = values() candidate["_creation_seal"] = "0" * 64 with pytest.raises(ValueError, match="changed after construction"): @@ -153,7 +177,16 @@ def test_rejects_caller_supplied_seal_and_marker_rewrite() -> None: packet.canonical_document() +def test_rejects_creation_seal_rewrite_even_when_payload_is_unchanged() -> None: + """The authoritative in-process seal cannot be replaced independently.""" + packet = SemanticJobEvidenceEnvelope(**values()) + object.__setattr__(packet, "_creation_seal", object()) + with pytest.raises(ValueError, match="changed after construction"): + packet.canonical_json() + + def test_runtime_type_is_final() -> None: + """Subclasses cannot override derived trust state on the governed envelope.""" with pytest.raises(TypeError, match="final"): class DerivedEnvelope(SemanticJobEvidenceEnvelope): - pass + """Attempt to extend the final evidence boundary.""" From d763a587bbdcf6a4326c876202a5ddfd0359a09d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:01:53 -0700 Subject: [PATCH 07/43] docs(semantic-job-evidence): document governed adapter contract --- .../semantic-job-evidence-adapter/README.md | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/README.md diff --git a/packages/semantic-job-evidence-adapter/README.md b/packages/semantic-job-evidence-adapter/README.md new file mode 100644 index 000000000..2bdab80a2 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/README.md @@ -0,0 +1,34 @@ +# Orgmetra Semantic Job Evidence Adapter + +This package is the Orgmetra-owned trust boundary for ontology-resolution evidence imported from the read-only Semantic Data Portal dependency. + +## What it does + +`SemanticJobEvidenceEnvelope` binds one ontology-resolution result to: + +- one Orgmetra tenant and one opaque Job Analysis reference; +- one opaque ontology-request reference; +- distinct requesting and human-reviewing actors; +- the approved non-decision use `job_analysis_source_evidence`; +- SHA-256 digests of the submitted term evidence, returned response evidence, and reviewed source-catalog state; +- the reviewed Semantic Data Portal revision `e48aa13c4af7a4875d4b53e6a60b50405c265a2f`; +- the reviewed `POST /ontology/resolve` operation; +- an evidence version and exact UTC system-recorded timestamp. + +The canonical document always declares the imported material to be `external_source_evidence`, `requires_human_review`, and `not_authorized_for_job_or_employment_decision`. + +## What it deliberately does not do + +The envelope does not carry the raw ontology query term, raw response, candidate/worker PII, credentials, scores, or a Job/employment decision. A syntactically valid actor reference is correlation evidence, not proof of identity. The host must resolve actors and tenant/Job Analysis scope through Orgmetra's authoritative boundaries before source evidence is accepted into a reviewed Job Analysis snapshot. + +Orgmetra does not read Semantic Data Portal application tables. The foreign service remains independently deployable and is consumed only through its published API contract. A changed provider revision or API operation fails closed until reviewed and explicitly updated here. + +## Evidence integrity + +Trust-bearing text, integers, and timestamps must be exact built-in runtime types before equality, membership, bounds, UUID parsing, or serialization. Packet-owned references use canonical UUIDv4 suffixes; the tenant ID follows Orgmetra's canonical non-sentinel operational UUID contract. The envelope is final and detects post-construction payload/seal rewriting before canonical evidence leaves the boundary. + +## Testing + +The dedicated quality lane runs the package tests with exact 100% owned production statement and branch coverage and requires a clean checkout. Adversarial regressions cover malformed references/digests, self-review, runtime-subclass forgery, invalid dependency revision/API use, and post-issuance evidence rewriting. + +See `docs/traceability/semantic-job-evidence.md`, `docs/adr/semantic-job-source-evidence.md`, and `docs/doctoring/semantic-job-evidence-references.md` for the governed rationale and evidence map. From 4bcae2a4ca14be81ad7ef95c0d417dc175e37194 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:01:59 -0700 Subject: [PATCH 08/43] docs(semantic-job-evidence): record active-pr change history --- packages/semantic-job-evidence-adapter/CHANGELOG.md | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/CHANGELOG.md diff --git a/packages/semantic-job-evidence-adapter/CHANGELOG.md b/packages/semantic-job-evidence-adapter/CHANGELOG.md new file mode 100644 index 000000000..7ff11bb22 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog + +## 0.1.0 — active PR + +- Add a value-minimized, human-review-required Semantic Data Portal ontology evidence envelope for Job Analysis. +- Pin the reviewed read-only dependency revision and `POST /ontology/resolve` API operation. +- Bind tenant, Job Analysis scope, accountable actors, source/query/response digests, evidence version, and UTC system-recorded time without copying raw ontology or HR content. +- Fail closed on malformed governance evidence, self-review, caller-defined primitive subclasses, dependency-contract drift, post-construction mutation, seal reset, and runtime type extension. +- Add an exact-head quality workflow with exact 100% owned production statement and branch coverage plus clean-checkout enforcement. From f285a47be4cb5b263904a469712097a8cad194e3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:02:17 -0700 Subject: [PATCH 09/43] docs(semantic-job-evidence): record source-evidence architecture decision --- docs/adr/semantic-job-source-evidence.md | 41 ++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 docs/adr/semantic-job-source-evidence.md diff --git a/docs/adr/semantic-job-source-evidence.md b/docs/adr/semantic-job-source-evidence.md new file mode 100644 index 000000000..8bdec9616 --- /dev/null +++ b/docs/adr/semantic-job-source-evidence.md @@ -0,0 +1,41 @@ +# ADR — Govern Semantic Data Portal source evidence at the Orgmetra Job Analysis boundary + +## Status + +Active PR. This document does not describe protected-main truth until the owning PR merges. + +## Context + +Orgmetra's protected Job Analysis model already distinguishes authoritative human-reviewed evidence from draft/model-derived material, while protected traceability still lists Semantic Data Portal integration as planned. Semantic Data Portal is a separately owned CWL product and publishes ontology-resolution APIs. Direct table access or copying its implementation into Orgmetra would violate the dedicated-writer and modular-service boundary. + +Ontology resolution can improve Task/FJA/KSAO evidence discovery, but a semantic match is not itself an authoritative Job-analysis conclusion and must not become an autonomous employment decision. Orgmetra therefore needs a local governance artifact that records exactly what external contract and evidence version were reviewed without storing the raw ontology query/response in the audit correlation object. + +## Decision + +Orgmetra owns a final, immutable `SemanticJobEvidenceEnvelope` that binds: + +1. tenant and Job Analysis scope; +2. an opaque Orgmetra ontology-request reference; +3. distinct requesting and human-reviewing actor references; +4. the closed use `job_analysis_source_evidence`; +5. SHA-256 digests for query-term evidence, response evidence, and source-catalog state; +6. the reviewed Semantic Data Portal revision `e48aa13c4af7a4875d4b53e6a60b50405c265a2f` and `POST /ontology/resolve` operation; +7. evidence version and exact UTC system-recorded time. + +The canonical evidence always records `external_source_evidence`, `requires_human_review`, and `not_authorized_for_job_or_employment_decision`. + +Semantic Data Portal remains read-only to this Orgmetra lane. No foreign application table is queried. Provider revision/API drift fails closed until explicitly reviewed. Raw ontology content, PII, credentials, scores, and decisions stay outside this value-minimized envelope. + +Trust-bearing runtime primitives are accepted only as exact built-in types before caller-overridable equality, hashing, comparison, parsing, or serialization can run. Creation-time evidence is sealed in process and is revalidated before canonical export so valid-looking post-construction rewrites fail closed. + +## Consequences + +- Buyers can trace a Job Analysis source claim to an exact external contract revision and evidence digests without treating that source as authoritative by syntax alone. +- Human review remains explicit and separable from source retrieval. +- A future Semantic Data Portal contract change requires an Orgmetra review/update rather than silently changing evidence semantics. +- This slice does not implement network transport, foreign retries, foreign authorization, raw ontology storage, Job Analysis approval, or employment decisions. +- The approach is compatible with W3C provenance principles: source entities and activities remain externally owned while Orgmetra records bounded provenance needed for its own evidence chain. + +## Verification + +The package quality lane requires exact-current-head tests, exact 100% owned production statement and branch coverage, adversarial runtime-integrity regressions, and a clean checkout. Repository-level Foundation/SAST/Security/Recovery evidence remains separately required by live merge governance. From cb2c6a54a41921fbe2c992a6aaeec93f1c78199b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:02:37 -0700 Subject: [PATCH 10/43] docs(semantic-job-evidence): add executable traceability --- docs/traceability/semantic-job-evidence.md | 25 ++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 docs/traceability/semantic-job-evidence.md diff --git a/docs/traceability/semantic-job-evidence.md b/docs/traceability/semantic-job-evidence.md new file mode 100644 index 000000000..96d4d7890 --- /dev/null +++ b/docs/traceability/semantic-job-evidence.md @@ -0,0 +1,25 @@ +# Semantic Job Evidence Traceability + +## Maturity + +`active_pr`. Protected `develop` still lists Semantic Data Portal / ontology integration as planned. This document records only the executable scope of the owning PR and must not be read as protected-main truth until merge. + +| Requirement | Executable evidence | Boundary | +|---|---|---| +| Consume only a published foreign contract | reviewed Semantic Data Portal revision `e48aa13c4af7a4875d4b53e6a60b50405c265a2f`; exact `POST /ontology/resolve` operation | read-only dependency; no foreign table access | +| Bind source evidence to Orgmetra scope | canonical tenant, `job_analysis:` and `ontology_request:` references | Orgmetra-owned evidence envelope | +| Require accountable human review | distinct `actor:` requester and reviewer; canonical state `requires_human_review` | syntax is correlation only; host identity/scope resolution remains authoritative | +| Prevent semantic evidence from becoming a decision | canonical state `not_authorized_for_job_or_employment_decision` | source evidence cannot authorize Job/employment action | +| Minimize HR/audit exposure | query term, response and source catalog represented only by SHA-256 digests | no raw query/response, PII, credential, score, or decision in canonical evidence | +| Preserve exact source provenance | foreign revision, API operation, source-system/trust-state, evidence version, UTC recorded time | provider drift fails closed | +| Prevent runtime evidence forgery | exact built-in primitives, UUID/reference/digest validation, final runtime type | adversarial subclass regressions | +| Prevent post-issuance rewrite | creation-time HMAC seal plus issuance marker, live-field revalidation before canonical export | mutation/replace/seal-reset regressions | +| Maintain exact owned production coverage | dedicated `Semantic Job Evidence Adapter Quality` workflow | 100% statement and branch coverage required | + +## Test mapping + +`packages/semantic-job-evidence-adapter/tests/test_envelope.py` verifies canonical value minimization, reviewed trust states, tenant/reference validity, requester/reviewer separation, source revision/API binding, bounded evidence versions, exact UTC recorded time, hostile runtime subclasses, post-construction mutation, dataclass replacement/seal reset, marker/seal tampering, redacted repr, and final runtime type. + +## Non-claims + +This active PR does not prove the truth of Semantic Data Portal content, does not authenticate actor syntax, does not implement the network client, does not directly approve a Job Analysis, and does not authorize a hiring or other employment decision. Those authorities remain with their owning Orgmetra and dedicated-writer boundaries. From b9436d28490c8be8019aaae8048a15d1ac3c3113 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:02:48 -0700 Subject: [PATCH 11/43] docs(semantic-job-evidence): record primary provenance references --- .../semantic-job-evidence-references.md | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 docs/doctoring/semantic-job-evidence-references.md diff --git a/docs/doctoring/semantic-job-evidence-references.md b/docs/doctoring/semantic-job-evidence-references.md new file mode 100644 index 000000000..38744ef2b --- /dev/null +++ b/docs/doctoring/semantic-job-evidence-references.md @@ -0,0 +1,20 @@ +# Semantic Job Evidence — primary references + +## Scope + +These references support the active-PR decision to keep foreign ontology output as provenance-bearing source evidence that requires human review, rather than copying a dedicated-writer service or treating semantic resolution as authoritative Job/employment decision evidence. + +## References (APA 7) + +ContextualWisdomLab. (2026). *Semantic Data Portal* (Revision e48aa13c4af7a4875d4b53e6a60b50405c265a2f) [Computer software]. GitHub. https://github.com/ContextualWisdomLab/semantic-data-portal/tree/e48aa13c4af7a4875d4b53e6a60b50405c265a2f + +Lebo, T., Sahoo, S., & McGuinness, D. (Eds.). (2013). *PROV-O: The PROV ontology* (W3C Recommendation). World Wide Web Consortium. https://www.w3.org/TR/prov-o/ + +Tabassi, E. (2023). *Artificial intelligence risk management framework (AI RMF 1.0)* (NIST AI 100-1). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.100-1 + +## Evidence notes + +- The pinned Semantic Data Portal README publishes `POST /ontology/resolve` as an ontology/terminology API. That is the exact foreign operation recorded by this Orgmetra adapter; the dependency remains read-only. +- W3C PROV-O is a W3C Recommendation for interoperable provenance representation across heterogeneous systems. The Orgmetra envelope uses a small application-specific provenance record rather than claiming PROV-O serialization compliance. +- NIST AI RMF 1.0 remains the published final framework while NIST develops revisions/profiles. Its risk-management framing supports keeping model/semantic outputs governed and reviewable. This package does not claim AI RMF conformity or certification. +- No psychometric/statistical estimator is implemented in this slice, so no research-only statistical claim is introduced and no foreign psychometric kernel is duplicated. From c706301eec2a3d1679ebd1fde23b4c0c2d300437 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:03:13 -0700 Subject: [PATCH 12/43] test(semantic-job-evidence): enforce owned docstring completeness --- .../tests/test_docstrings.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/tests/test_docstrings.py diff --git a/packages/semantic-job-evidence-adapter/tests/test_docstrings.py b/packages/semantic-job-evidence-adapter/tests/test_docstrings.py new file mode 100644 index 000000000..5eeea7cae --- /dev/null +++ b/packages/semantic-job-evidence-adapter/tests/test_docstrings.py @@ -0,0 +1,31 @@ +"""Executable documentation-completeness contract for semantic source evidence.""" + +from __future__ import annotations + +import ast +from pathlib import Path + + +PACKAGE_ROOT = Path(__file__).resolve().parents[1] +SOURCE_ROOT = PACKAGE_ROOT / "src" / "orgmetra_semantic_job_evidence_adapter" +TEST_ROOT = PACKAGE_ROOT / "tests" + + +def _python_files() -> tuple[Path, ...]: + """Return every owned Python source/test file in deterministic order.""" + return tuple(sorted((*SOURCE_ROOT.glob("*.py"), *TEST_ROOT.glob("*.py")))) + + +def test_owned_python_modules_and_callables_are_documented() -> None: + """Require beginner-readable docstrings on every owned module, class, and callable.""" + missing: list[str] = [] + for path in _python_files(): + tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path)) + if ast.get_docstring(tree, clean=False) is None: + missing.append(f"{path.relative_to(PACKAGE_ROOT)}:") + for node in ast.walk(tree): + if not isinstance(node, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)): + continue + if ast.get_docstring(node, clean=False) is None: + missing.append(f"{path.relative_to(PACKAGE_ROOT)}:{node.lineno}:{node.name}") + assert not missing, "Missing owned Python docstrings: " + ", ".join(missing) From 8f99a73ef6d16cbcf1b1948848dab6575f7fb0c7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:03:42 -0700 Subject: [PATCH 13/43] test(semantic-job-evidence): document adversarial regression suite --- packages/semantic-job-evidence-adapter/tests/test_envelope.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py index b5c78e35f..3e672915c 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_envelope.py +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -1,3 +1,5 @@ +"""Adversarial contract tests for governed Semantic Data Portal source evidence.""" + from dataclasses import replace from datetime import datetime, timezone from hashlib import sha256 From c7b79e7c241770d98c061e334bfcf7acc7c5b258 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:05:07 -0700 Subject: [PATCH 14/43] test(semantic-job-evidence): expose packet-owned seal rewrite bypass --- .../tests/test_creation_seal_integrity.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py diff --git a/packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py b/packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py new file mode 100644 index 000000000..599cda8c9 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py @@ -0,0 +1,18 @@ +"""Regression for authoritative creation evidence living outside packet-writable slots.""" + +import pytest + +import orgmetra_semantic_job_evidence_adapter.envelope as envelope_module +from orgmetra_semantic_job_evidence_adapter import SemanticJobEvidenceEnvelope +from test_envelope import values + + +def test_recomputed_packet_owned_seal_cannot_authorize_rewritten_evidence() -> None: + """Rewriting payload plus its packet-owned seal must still fail closed.""" + packet = SemanticJobEvidenceEnvelope(**values()) + object.__setattr__(packet, "response_evidence_digest", "d" * 64) + forged_seal = envelope_module._seal(packet._canonical_payload_json()) + object.__setattr__(packet, "_creation_seal", forged_seal) + + with pytest.raises(ValueError, match="changed after construction"): + packet.canonical_json() From 7b1e33ad1f637fd2a24e7e9d9e9b2f22e66f7718 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:06:31 -0700 Subject: [PATCH 15/43] fix(semantic-job-evidence): externalize authoritative creation seal --- .../envelope.py | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py index adf90c5a8..ced6e2337 100644 --- a/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py +++ b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py @@ -9,8 +9,10 @@ import json import re import secrets +from threading import RLock from typing import ClassVar from uuid import UUID +from weakref import finalize _SEMANTIC_DATA_PORTAL_REVISION = "e48aa13c4af7a4875d4b53e6a60b50405c265a2f" @@ -20,6 +22,28 @@ _DIGEST_PATTERN = re.compile(r"[0-9a-f]{64}") _ACTOR_PATTERN = re.compile(r"actor:[A-Za-z0-9._~-]{1,128}") _ALLOWED_RESOLUTION_USES = frozenset({"job_analysis_source_evidence"}) +_CREATION_SEALS: dict[int, str] = {} +_CREATION_SEALS_LOCK = RLock() + + +def _discard_creation_seal(envelope_id: int) -> None: + """Discard the process-local authoritative seal when its envelope is collected.""" + with _CREATION_SEALS_LOCK: + _CREATION_SEALS.pop(envelope_id, None) + + +def _register_creation_seal(envelope: object, seal: str) -> None: + """Bind one live envelope identity to creation evidence outside writable slots.""" + envelope_id = id(envelope) + with _CREATION_SEALS_LOCK: + _CREATION_SEALS[envelope_id] = seal + finalize(envelope, _discard_creation_seal, envelope_id) + + +def _authoritative_creation_seal(envelope: object) -> str | None: + """Return process-local creation evidence without trusting packet-owned state.""" + with _CREATION_SEALS_LOCK: + return _CREATION_SEALS.get(id(envelope)) def _require_text(value: object, field_name: str) -> str: @@ -90,7 +114,7 @@ def _seal(payload_json: str) -> str: return hmac.new(_PROCESS_SEAL_KEY, payload_json.encode("utf-8"), "sha256").hexdigest() -@dataclass(frozen=True, slots=True, repr=False) +@dataclass(frozen=True, slots=True, repr=False, weakref_slot=True) class SemanticJobEvidenceEnvelope: """Bind ontology source provenance without granting Job or employment decision authority.""" @@ -126,8 +150,10 @@ def __post_init__(self) -> None: if self._creation_seal is not None: raise ValueError("semantic job evidence changed after construction") self._validate_fields() - object.__setattr__(self, "_creation_seal", _seal(self._canonical_payload_json())) + seal = _seal(self._canonical_payload_json()) + object.__setattr__(self, "_creation_seal", seal) object.__setattr__(self, "_issuance_marker", _USED_ISSUANCE_MARKER) + _register_creation_seal(self, seal) def _validate_fields(self) -> None: """Fail closed on scope, source provenance, actor separation, and reviewed state.""" @@ -185,8 +211,15 @@ def _assert_integrity(self) -> None: self._validate_fields() if self._issuance_marker is not _USED_ISSUANCE_MARKER: raise ValueError("semantic job evidence changed after construction") - seal = self._creation_seal - if type(seal) is not str or not hmac.compare_digest(seal, _seal(self._canonical_payload_json())): + packet_seal = self._creation_seal + authoritative_seal = _authoritative_creation_seal(self) + live_seal = _seal(self._canonical_payload_json()) + if ( + type(packet_seal) is not str + or type(authoritative_seal) is not str + or not hmac.compare_digest(packet_seal, authoritative_seal) + or not hmac.compare_digest(live_seal, authoritative_seal) + ): raise ValueError("semantic job evidence changed after construction") def canonical_document(self) -> dict[str, object]: From b28101ee3b71d7a467cbb1ee699d001608f75261 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:07:17 -0700 Subject: [PATCH 16/43] docs(semantic-job-evidence): record external creation-seal repair --- packages/semantic-job-evidence-adapter/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/semantic-job-evidence-adapter/CHANGELOG.md b/packages/semantic-job-evidence-adapter/CHANGELOG.md index 7ff11bb22..7c08a9b86 100644 --- a/packages/semantic-job-evidence-adapter/CHANGELOG.md +++ b/packages/semantic-job-evidence-adapter/CHANGELOG.md @@ -6,4 +6,5 @@ - Pin the reviewed read-only dependency revision and `POST /ontology/resolve` API operation. - Bind tenant, Job Analysis scope, accountable actors, source/query/response digests, evidence version, and UTC system-recorded time without copying raw ontology or HR content. - Fail closed on malformed governance evidence, self-review, caller-defined primitive subclasses, dependency-contract drift, post-construction mutation, seal reset, and runtime type extension. +- Repair the post-issuance integrity path so rewriting a payload together with a recomputed packet-owned seal still fails: the authoritative creation seal is held in a process-local, lock-protected issuance registry outside envelope-writable slots. - Add an exact-head quality workflow with exact 100% owned production statement and branch coverage plus clean-checkout enforcement. From df4a0731dcd0b5d8b918fa3713e618048fb44088 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:07:40 -0700 Subject: [PATCH 17/43] docs(semantic-job-evidence): align ADR with authoritative seal registry --- docs/adr/semantic-job-source-evidence.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/adr/semantic-job-source-evidence.md b/docs/adr/semantic-job-source-evidence.md index 8bdec9616..253fbbc0a 100644 --- a/docs/adr/semantic-job-source-evidence.md +++ b/docs/adr/semantic-job-source-evidence.md @@ -26,7 +26,7 @@ The canonical evidence always records `external_source_evidence`, `requires_huma Semantic Data Portal remains read-only to this Orgmetra lane. No foreign application table is queried. Provider revision/API drift fails closed until explicitly reviewed. Raw ontology content, PII, credentials, scores, and decisions stay outside this value-minimized envelope. -Trust-bearing runtime primitives are accepted only as exact built-in types before caller-overridable equality, hashing, comparison, parsing, or serialization can run. Creation-time evidence is sealed in process and is revalidated before canonical export so valid-looking post-construction rewrites fail closed. +Trust-bearing runtime primitives are accepted only as exact built-in types before caller-overridable equality, hashing, comparison, parsing, or serialization can run. Creation-time evidence is sealed in process and its authoritative seal is held in a lock-protected issuance registry outside envelope-writable slots. Canonical export revalidates live fields against that external seal, so changing the payload together with a recomputed packet-owned seal still fails closed. ## Consequences From dd0097d52c8fbead81cfd0ad373809199c3fa6db Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:08:05 -0700 Subject: [PATCH 18/43] docs(semantic-job-evidence): trace external issuance-seal regression --- docs/traceability/semantic-job-evidence.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/traceability/semantic-job-evidence.md b/docs/traceability/semantic-job-evidence.md index 96d4d7890..87b03ea56 100644 --- a/docs/traceability/semantic-job-evidence.md +++ b/docs/traceability/semantic-job-evidence.md @@ -13,13 +13,15 @@ | Minimize HR/audit exposure | query term, response and source catalog represented only by SHA-256 digests | no raw query/response, PII, credential, score, or decision in canonical evidence | | Preserve exact source provenance | foreign revision, API operation, source-system/trust-state, evidence version, UTC recorded time | provider drift fails closed | | Prevent runtime evidence forgery | exact built-in primitives, UUID/reference/digest validation, final runtime type | adversarial subclass regressions | -| Prevent post-issuance rewrite | creation-time HMAC seal plus issuance marker, live-field revalidation before canonical export | mutation/replace/seal-reset regressions | +| Prevent post-issuance rewrite | packet consistency seal plus lock-protected process-local authoritative issuance seal, live-field revalidation before canonical export | payload-only, seal-only, payload+recomputed-seal, replace, and marker-tamper regressions | | Maintain exact owned production coverage | dedicated `Semantic Job Evidence Adapter Quality` workflow | 100% statement and branch coverage required | ## Test mapping `packages/semantic-job-evidence-adapter/tests/test_envelope.py` verifies canonical value minimization, reviewed trust states, tenant/reference validity, requester/reviewer separation, source revision/API binding, bounded evidence versions, exact UTC recorded time, hostile runtime subclasses, post-construction mutation, dataclass replacement/seal reset, marker/seal tampering, redacted repr, and final runtime type. +`packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py` proves that rewriting a valid trust-bearing field together with a freshly recomputed packet-owned HMAC cannot authorize changed evidence because the authoritative creation seal is stored outside envelope-writable slots. + ## Non-claims This active PR does not prove the truth of Semantic Data Portal content, does not authenticate actor syntax, does not implement the network client, does not directly approve a Job Analysis, and does not authorize a hiring or other employment decision. Those authorities remain with their owning Orgmetra and dedicated-writer boundaries. From ce7c31acac293aa6ef1c726b39a99f39960e05c8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:08:26 -0700 Subject: [PATCH 19/43] docs(semantic-job-evidence): explain authoritative seal boundary --- packages/semantic-job-evidence-adapter/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/README.md b/packages/semantic-job-evidence-adapter/README.md index 2bdab80a2..d2974396d 100644 --- a/packages/semantic-job-evidence-adapter/README.md +++ b/packages/semantic-job-evidence-adapter/README.md @@ -25,10 +25,10 @@ Orgmetra does not read Semantic Data Portal application tables. The foreign serv ## Evidence integrity -Trust-bearing text, integers, and timestamps must be exact built-in runtime types before equality, membership, bounds, UUID parsing, or serialization. Packet-owned references use canonical UUIDv4 suffixes; the tenant ID follows Orgmetra's canonical non-sentinel operational UUID contract. The envelope is final and detects post-construction payload/seal rewriting before canonical evidence leaves the boundary. +Trust-bearing text, integers, and timestamps must be exact built-in runtime types before equality, membership, bounds, UUID parsing, or serialization. Packet-owned references use canonical UUIDv4 suffixes; the tenant ID follows Orgmetra's canonical non-sentinel operational UUID contract. The envelope is final and detects post-construction rewriting before canonical evidence leaves the boundary. Its packet-owned HMAC is only a consistency value: the authoritative creation seal is held in a lock-protected process-local issuance registry outside envelope-writable slots, so rewriting both payload and packet seal still fails closed. ## Testing -The dedicated quality lane runs the package tests with exact 100% owned production statement and branch coverage and requires a clean checkout. Adversarial regressions cover malformed references/digests, self-review, runtime-subclass forgery, invalid dependency revision/API use, and post-issuance evidence rewriting. +The dedicated quality lane runs the package tests with exact 100% owned production statement and branch coverage and requires a clean checkout. Adversarial regressions cover malformed references/digests, self-review, runtime-subclass forgery, invalid dependency revision/API use, payload-only mutation, packet-seal mutation, payload plus recomputed-seal forgery, replacement/seal reset, and runtime-type extension. See `docs/traceability/semantic-job-evidence.md`, `docs/adr/semantic-job-source-evidence.md`, and `docs/doctoring/semantic-job-evidence-references.md` for the governed rationale and evidence map. From 505054aeebe4383ecf4d83424735259a944c0181 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 08:09:22 -0700 Subject: [PATCH 20/43] test(semantic-job-evidence): remove unused derived-class binding --- packages/semantic-job-evidence-adapter/tests/test_envelope.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py index 3e672915c..c627cca59 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_envelope.py +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -190,5 +190,4 @@ def test_rejects_creation_seal_rewrite_even_when_payload_is_unchanged() -> None: def test_runtime_type_is_final() -> None: """Subclasses cannot override derived trust state on the governed envelope.""" with pytest.raises(TypeError, match="final"): - class DerivedEnvelope(SemanticJobEvidenceEnvelope): - """Attempt to extend the final evidence boundary.""" + type("DerivedEnvelope", (SemanticJobEvidenceEnvelope,), {}) From 011c5685d8e2df7f409ed3a3f05ee2793283693d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 12:10:54 -0700 Subject: [PATCH 21/43] test(semantic-evidence): require installed-wheel quality execution --- .../tests/test_artifact_execution.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/tests/test_artifact_execution.py diff --git a/packages/semantic-job-evidence-adapter/tests/test_artifact_execution.py b/packages/semantic-job-evidence-adapter/tests/test_artifact_execution.py new file mode 100644 index 000000000..2fc021517 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/tests/test_artifact_execution.py @@ -0,0 +1,28 @@ +"""Regression contract for exact installed-wheel quality execution.""" + +from pathlib import Path + + +_REPOSITORY_ROOT = Path(__file__).resolve().parents[3] +_WORKFLOW_PATH = _REPOSITORY_ROOT / ".github/workflows/semantic-job-evidence-adapter-quality.yml" +_VENV_PATH = "/tmp/orgmetra-semantic-job-evidence-adapter-venv" + + +def test_quality_lane_executes_the_hash_bound_installed_wheel() -> None: + """Require tests and reviewed test dependencies to execute inside an isolated venv.""" + workflow = _WORKFLOW_PATH.read_text(encoding="utf-8") + + assert "PYTHONPATH: packages/semantic-job-evidence-adapter/src" not in workflow + assert f"python -m venv {_VENV_PATH}" in workflow + assert ( + f'{_VENV_PATH}/bin/python -m pip install --require-hashes --no-deps ' + f'--only-binary=:all: -r "$GITHUB_WORKSPACE/.github/requirements/foundation-test.txt"' + in workflow + ) + assert "wheel_sha=\"$(sha256sum \"$wheel_path\" | awk '{print $1}')\"" in workflow + assert "for module in (coverage, pytest, pytest_cov):" in workflow + assert ( + f"{_VENV_PATH}/bin/python -m pytest " + '-c "$GITHUB_WORKSPACE/packages/semantic-job-evidence-adapter/pyproject.toml"' + in workflow + ) From 0ae489c2db8cff9b80dc7e2ebd5871e9532deabb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 12:11:10 -0700 Subject: [PATCH 22/43] fix(semantic-evidence): test exact installed wheel hermetically --- .../semantic-job-evidence-adapter-quality.yml | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/.github/workflows/semantic-job-evidence-adapter-quality.yml b/.github/workflows/semantic-job-evidence-adapter-quality.yml index a2f51e1f9..bf0f3b8c9 100644 --- a/.github/workflows/semantic-job-evidence-adapter-quality.yml +++ b/.github/workflows/semantic-job-evidence-adapter-quality.yml @@ -39,17 +39,55 @@ jobs: with: python-version: "3.14" check-latest: false - - name: Install reviewed test toolchain + - name: Install reviewed test and build toolchain run: | python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt + printf '%s\n' 'setuptools==84.0.0 --hash=sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670' > /tmp/orgmetra-semantic-job-evidence-build.txt + python -m pip install --require-hashes --no-deps --only-binary=:all: -r /tmp/orgmetra-semantic-job-evidence-build.txt python -m pip check - name: Compile adapter boundary run: python -m compileall -q packages/semantic-job-evidence-adapter/src packages/semantic-job-evidence-adapter/tests - - name: Test governed semantic source evidence with exact statement and branch coverage + - name: Build and install exact package artifact + run: | + rm -rf /tmp/orgmetra-semantic-job-evidence-adapter-build /tmp/orgmetra-semantic-job-evidence-adapter-dist /tmp/orgmetra-semantic-job-evidence-adapter-venv + cp -a packages/semantic-job-evidence-adapter /tmp/orgmetra-semantic-job-evidence-adapter-build + mkdir -p /tmp/orgmetra-semantic-job-evidence-adapter-dist + python -m pip wheel --no-deps --no-build-isolation --wheel-dir /tmp/orgmetra-semantic-job-evidence-adapter-dist /tmp/orgmetra-semantic-job-evidence-adapter-build + test "$(find /tmp/orgmetra-semantic-job-evidence-adapter-dist -maxdepth 1 -type f -name '*.whl' | wc -l)" -eq 1 + python -m venv /tmp/orgmetra-semantic-job-evidence-adapter-venv + /tmp/orgmetra-semantic-job-evidence-adapter-venv/bin/python -m pip install --require-hashes --no-deps --only-binary=:all: -r "$GITHUB_WORKSPACE/.github/requirements/foundation-test.txt" + wheel_path="$(find /tmp/orgmetra-semantic-job-evidence-adapter-dist -maxdepth 1 -type f -name '*.whl' -print -quit)" + wheel_sha="$(sha256sum "$wheel_path" | awk '{print $1}')" + printf 'orgmetra-semantic-job-evidence-adapter[test] @ file://%s --hash=sha256:%s\n' "$wheel_path" "$wheel_sha" > /tmp/orgmetra-semantic-job-evidence-install.txt + /tmp/orgmetra-semantic-job-evidence-adapter-venv/bin/python -m pip install --require-hashes --no-deps -r /tmp/orgmetra-semantic-job-evidence-install.txt + /tmp/orgmetra-semantic-job-evidence-adapter-venv/bin/python -m pip check + /tmp/orgmetra-semantic-job-evidence-adapter-venv/bin/python - <<'PY' + from importlib.metadata import metadata + from pathlib import Path + import coverage + import pytest + import pytest_cov + import orgmetra_semantic_job_evidence_adapter + + venv_root = Path("/tmp/orgmetra-semantic-job-evidence-adapter-venv").resolve() + module_path = Path(orgmetra_semantic_job_evidence_adapter.__file__).resolve() + if not module_path.is_relative_to(venv_root): + raise SystemExit(f"package imported outside isolated environment: {module_path}") + for module in (coverage, pytest, pytest_cov): + dependency_path = Path(module.__file__).resolve() + if not dependency_path.is_relative_to(venv_root): + raise SystemExit( + f"test dependency imported outside isolated environment: {dependency_path}" + ) + if "test" not in (metadata("orgmetra-semantic-job-evidence-adapter").get_all("Provides-Extra") or []): + raise SystemExit("built distribution does not expose the reviewed test extra") + PY + - name: Test installed semantic source evidence with exact statement and branch coverage env: - PYTHONPATH: packages/semantic-job-evidence-adapter/src COVERAGE_FILE: /tmp/orgmetra-semantic-job-evidence-adapter.coverage - run: python -m pytest -c packages/semantic-job-evidence-adapter/pyproject.toml packages/semantic-job-evidence-adapter/tests + run: | + cd /tmp + /tmp/orgmetra-semantic-job-evidence-adapter-venv/bin/python -m pytest -c "$GITHUB_WORKSPACE/packages/semantic-job-evidence-adapter/pyproject.toml" "$GITHUB_WORKSPACE/packages/semantic-job-evidence-adapter/tests" - name: Require clean checkout run: | git diff --exit-code From c1bd7c120b23a07f17be234e861a9abe122808b1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 12:11:28 -0700 Subject: [PATCH 23/43] docs(semantic-evidence): record installed-artifact quality contract --- packages/semantic-job-evidence-adapter/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/semantic-job-evidence-adapter/CHANGELOG.md b/packages/semantic-job-evidence-adapter/CHANGELOG.md index 7c08a9b86..223354cec 100644 --- a/packages/semantic-job-evidence-adapter/CHANGELOG.md +++ b/packages/semantic-job-evidence-adapter/CHANGELOG.md @@ -8,3 +8,4 @@ - Fail closed on malformed governance evidence, self-review, caller-defined primitive subclasses, dependency-contract drift, post-construction mutation, seal reset, and runtime type extension. - Repair the post-issuance integrity path so rewriting a payload together with a recomputed packet-owned seal still fails: the authoritative creation seal is held in a process-local, lock-protected issuance registry outside envelope-writable slots. - Add an exact-head quality workflow with exact 100% owned production statement and branch coverage plus clean-checkout enforcement. +- Build a wheel and execute the quality suite against the SHA-256-bound installed artifact in a fully isolated virtual environment; install the reviewed hash-pinned pytest/coverage toolchain inside that environment and fail closed if package or test-tool imports resolve outside it. From dd127ddd3ad3563ed34bbbf4ffcaf29c11fb8002 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 12:16:29 -0700 Subject: [PATCH 24/43] test(semantic-evidence): make docstring gate recursive and fail closed --- .../tests/test_docstrings.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/tests/test_docstrings.py b/packages/semantic-job-evidence-adapter/tests/test_docstrings.py index 5eeea7cae..be75b82cc 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_docstrings.py +++ b/packages/semantic-job-evidence-adapter/tests/test_docstrings.py @@ -12,14 +12,16 @@ def _python_files() -> tuple[Path, ...]: - """Return every owned Python source/test file in deterministic order.""" - return tuple(sorted((*SOURCE_ROOT.glob("*.py"), *TEST_ROOT.glob("*.py")))) + """Return every owned Python source/test file recursively in deterministic order.""" + return tuple(sorted({*SOURCE_ROOT.rglob("*.py"), *TEST_ROOT.rglob("*.py")})) def test_owned_python_modules_and_callables_are_documented() -> None: """Require beginner-readable docstrings on every owned module, class, and callable.""" + paths = _python_files() + assert paths, f"No owned Python files discovered under {SOURCE_ROOT} or {TEST_ROOT}" missing: list[str] = [] - for path in _python_files(): + for path in paths: tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path)) if ast.get_docstring(tree, clean=False) is None: missing.append(f"{path.relative_to(PACKAGE_ROOT)}:") From f80ed1cf124c8a75200043212a96ef090aef7d1b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 12:17:54 -0700 Subject: [PATCH 25/43] test(semantic-evidence): isolate runtime-subclass guard --- .../tests/test_envelope.py | 143 ++++++++++-------- 1 file changed, 76 insertions(+), 67 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py index c627cca59..4ed63f974 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_envelope.py +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -1,102 +1,104 @@ -"""Adversarial contract tests for governed Semantic Data Portal source evidence.""" +from __future__ import annotations -from dataclasses import replace from datetime import datetime, timezone from hashlib import sha256 -import json -from uuid import uuid1, uuid4 +from uuid import UUID, uuid4 import pytest from orgmetra_semantic_job_evidence_adapter import SemanticJobEvidenceEnvelope -SDP_REVISION = "e48aa13c4af7a4875d4b53e6a60b50405c265a2f" -DIGEST_A = "a" * 64 -DIGEST_B = "b" * 64 -DIGEST_C = "c" * 64 +def _reference(namespace: str) -> str: + """Return one canonical opaque UUIDv4 reference for tests.""" + return f"{namespace}:{uuid4()}" def values() -> dict[str, object]: - """Return one valid value-minimized ontology source-evidence fixture.""" + """Return one valid reviewed ontology-evidence envelope payload.""" return { "tenant_record_id": str(uuid4()), - "job_analysis_reference": f"job_analysis:{uuid4()}", - "ontology_request_reference": f"ontology_request:{uuid4()}", - "requesting_actor_reference": "actor:hr-analyst", + "job_analysis_reference": _reference("job_analysis"), + "ontology_request_reference": _reference("ontology_request"), + "requesting_actor_reference": "actor:job-analyst", "reviewing_actor_reference": "actor:job-analysis-reviewer", "resolution_use_code": "job_analysis_source_evidence", - "query_term_digest": DIGEST_A, - "response_evidence_digest": DIGEST_B, - "source_catalog_digest": DIGEST_C, - "semantic_data_portal_revision": SDP_REVISION, + "query_term_digest": "a" * 64, + "response_evidence_digest": "b" * 64, + "source_catalog_digest": "c" * 64, + "semantic_data_portal_revision": "e48aa13c4af7a4875d4b53e6a60b50405c265a2f", "api_operation": "POST /ontology/resolve", "evidence_version": 1, - "recorded_at": datetime(2026, 8, 22, 14, 50, 12, 123456, tzinfo=timezone.utc), + "recorded_at": datetime(2026, 8, 22, 12, 0, tzinfo=timezone.utc), } -def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: - """Canonical evidence contains governance/provenance only and has stable bytes.""" +def test_builds_value_minimized_non_authorizing_evidence() -> None: + """The canonical document binds provenance without carrying raw ontology or HR values.""" packet = SemanticJobEvidenceEnvelope(**values()) + document = packet.canonical_document() assert document["source_system"] == "semantic-data-portal" assert document["source_trust_state"] == "external_source_evidence" assert document["review_state"] == "requires_human_review" assert document["decision_authority_state"] == "not_authorized_for_job_or_employment_decision" - assert document["recorded_at"] == "2026-08-22T14:50:12.123456Z" - assert "query_term" not in document - assert "response" not in document - assert "person" not in document - expected_json = json.dumps(document, sort_keys=True, separators=(",", ":"), ensure_ascii=True) - assert packet.canonical_json() == expected_json - assert packet.evidence_digest() == sha256(expected_json.encode("utf-8")).hexdigest() - assert repr(packet) == "SemanticJobEvidenceEnvelope()" + assert document["recorded_at"] == "2026-08-22T12:00:00Z" + serialized = packet.canonical_json() + assert packet.evidence_digest() == sha256(serialized.encode("utf-8")).hexdigest() + for forbidden in ( + "raw_query", + "query_text", + "raw_response", + "person", + "candidate", + "worker", + "credential", + "score", + "employment_decision", + ): + assert forbidden not in serialized.lower() + + +def test_requires_distinct_requester_and_human_reviewer() -> None: + """The same actor cannot request and review imported ontology evidence.""" + candidate = values() + candidate["reviewing_actor_reference"] = candidate["requesting_actor_reference"] + with pytest.raises(ValueError, match="must differ"): + SemanticJobEvidenceEnvelope(**candidate) @pytest.mark.parametrize( ("field_name", "bad_value"), [ - ("tenant_record_id", "00000000-0000-0000-0000-000000000000"), + ("tenant_record_id", str(UUID(int=0))), + ("tenant_record_id", str(UUID(int=(1 << 128) - 1))), ("tenant_record_id", "not-a-uuid"), - ("tenant_record_id", str(uuid4()).upper()), - ("job_analysis_reference", f"job_analysis:{uuid1()}"), - ("job_analysis_reference", f"person:{uuid4()}"), - ("job_analysis_reference", "job_analysis:" + "a" * 181), - ("ontology_request_reference", f"ontology_request:{uuid1()}"), - ("ontology_request_reference", "ontology_request:not-a-uuid"), - ("requesting_actor_reference", "staff:analyst"), - ("reviewing_actor_reference", "actor:has space"), + ("job_analysis_reference", "job_analysis:not-a-uuid"), + ("job_analysis_reference", f"job_analysis:{UUID(int=0)}"), + ("job_analysis_reference", f"job_analysis:{UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')}"), + ("ontology_request_reference", "job_analysis:" + str(uuid4())), + ("requesting_actor_reference", "actor:"), + ("reviewing_actor_reference", "reviewer:" + str(uuid4())), ("query_term_digest", "A" * 64), - ("response_evidence_digest", "b" * 63), - ("source_catalog_digest", "not-a-digest"), - ("semantic_data_portal_revision", "0" * 40), + ("response_evidence_digest", "f" * 63), + ("source_catalog_digest", "x" * 64), + ("semantic_data_portal_revision", "latest"), ("api_operation", "POST /search/semantic"), - ("api_operation", ""), ("resolution_use_code", "automated_job_decision"), ("evidence_version", 0), ("evidence_version", 1_000_001), - ("evidence_version", True), - ("recorded_at", datetime(2026, 8, 22, 14, 50, 12)), + ("recorded_at", datetime(2026, 8, 22, 12, 0)), ], ) -def test_rejects_invalid_governance_evidence(field_name: str, bad_value: object) -> None: - """Malformed, unsafe, or unreviewed evidence fails closed at construction.""" +def test_rejects_malformed_or_unreviewed_evidence(field_name: str, bad_value: object) -> None: + """Malformed, unreviewed, or authority-expanding evidence fails closed.""" candidate = values() candidate[field_name] = bad_value with pytest.raises(ValueError): SemanticJobEvidenceEnvelope(**candidate) -def test_rejects_same_requester_and_reviewer() -> None: - """One actor cannot self-review ontology evidence for Job Analysis.""" - candidate = values() - candidate["reviewing_actor_reference"] = candidate["requesting_actor_reference"] - with pytest.raises(ValueError, match="must differ"): - SemanticJobEvidenceEnvelope(**candidate) - - class ForgedText(str): """Simulate caller text that lies during reviewed equality/hash operations.""" @@ -142,7 +144,7 @@ def test_rejects_runtime_subclasses_before_governance_comparison() -> None: for field_name, bad_value in ( ("resolution_use_code", ForgedText("automated_job_decision")), ("api_operation", ForgedText("POST /search/semantic")), - ("evidence_version", ForgedInt(999999999)), + ("evidence_version", ForgedInt(1)), ("recorded_at", ForgedDateTime(2026, 8, 22, tzinfo=timezone.utc)), ): candidate = values() @@ -159,35 +161,42 @@ def test_rejects_post_construction_rewrite() -> None: packet.canonical_json() -def test_replace_cannot_reseal_changed_evidence() -> None: - """Dataclass replacement cannot reset the issuance seal and create new authority.""" +def test_rejects_packet_seal_rewrite() -> None: + """Rewriting the packet-owned seal cannot bypass the authoritative creation seal.""" + packet = SemanticJobEvidenceEnvelope(**values()) + object.__setattr__(packet, "_creation_seal", "0" * 64) + with pytest.raises(ValueError, match="changed after construction"): + packet.canonical_document() + + +def test_rejects_replacement_and_seal_reset() -> None: + """Dataclass replacement cannot turn modified evidence into a newly issued envelope.""" + from dataclasses import replace + packet = SemanticJobEvidenceEnvelope(**values()) with pytest.raises(ValueError, match="changed after construction"): replace(packet, response_evidence_digest="d" * 64, _creation_seal=None) -def test_rejects_caller_supplied_seal_and_marker_rewrite() -> None: - """Private seal and issuance marker fields remain fail-closed under hostile access.""" +def test_rejects_caller_supplied_creation_seal() -> None: + """Callers cannot seed a pre-authorized creation seal during construction.""" candidate = values() candidate["_creation_seal"] = "0" * 64 with pytest.raises(ValueError, match="changed after construction"): SemanticJobEvidenceEnvelope(**candidate) - packet = SemanticJobEvidenceEnvelope(**values()) - object.__setattr__(packet, "_issuance_marker", object()) - with pytest.raises(ValueError, match="changed after construction"): - packet.canonical_document() - -def test_rejects_creation_seal_rewrite_even_when_payload_is_unchanged() -> None: - """The authoritative in-process seal cannot be replaced independently.""" +def test_rejects_post_issuance_marker_rewrite() -> None: + """Changing the one-way issuance marker invalidates emitted evidence.""" packet = SemanticJobEvidenceEnvelope(**values()) - object.__setattr__(packet, "_creation_seal", object()) + object.__setattr__(packet, "_issuance_marker", object()) with pytest.raises(ValueError, match="changed after construction"): packet.canonical_json() -def test_runtime_type_is_final() -> None: - """Subclasses cannot override derived trust state on the governed envelope.""" +def test_runtime_type_is_final_and_repr_is_redacted() -> None: + """The evidence type cannot be extended and its repr omits sensitive correlations.""" + packet = SemanticJobEvidenceEnvelope(**values()) with pytest.raises(TypeError, match="final"): type("DerivedEnvelope", (SemanticJobEvidenceEnvelope,), {}) + assert repr(packet) == "SemanticJobEvidenceEnvelope()" From bfb6b3c838c41b2b15762755290f5db55667f072 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 12:19:21 -0700 Subject: [PATCH 26/43] test(semantic-evidence): preserve suite while isolating type guard --- .../tests/test_envelope.py | 141 ++++++++---------- 1 file changed, 66 insertions(+), 75 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py index 4ed63f974..104c6aa60 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_envelope.py +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -1,104 +1,102 @@ -from __future__ import annotations +"""Adversarial contract tests for governed Semantic Data Portal source evidence.""" +from dataclasses import replace from datetime import datetime, timezone from hashlib import sha256 -from uuid import UUID, uuid4 +import json +from uuid import uuid1, uuid4 import pytest from orgmetra_semantic_job_evidence_adapter import SemanticJobEvidenceEnvelope -def _reference(namespace: str) -> str: - """Return one canonical opaque UUIDv4 reference for tests.""" - return f"{namespace}:{uuid4()}" +SDP_REVISION = "e48aa13c4af7a4875d4b53e6a60b50405c265a2f" +DIGEST_A = "a" * 64 +DIGEST_B = "b" * 64 +DIGEST_C = "c" * 64 def values() -> dict[str, object]: - """Return one valid reviewed ontology-evidence envelope payload.""" + """Return one valid value-minimized ontology source-evidence fixture.""" return { "tenant_record_id": str(uuid4()), - "job_analysis_reference": _reference("job_analysis"), - "ontology_request_reference": _reference("ontology_request"), - "requesting_actor_reference": "actor:job-analyst", + "job_analysis_reference": f"job_analysis:{uuid4()}", + "ontology_request_reference": f"ontology_request:{uuid4()}", + "requesting_actor_reference": "actor:hr-analyst", "reviewing_actor_reference": "actor:job-analysis-reviewer", "resolution_use_code": "job_analysis_source_evidence", - "query_term_digest": "a" * 64, - "response_evidence_digest": "b" * 64, - "source_catalog_digest": "c" * 64, - "semantic_data_portal_revision": "e48aa13c4af7a4875d4b53e6a60b50405c265a2f", + "query_term_digest": DIGEST_A, + "response_evidence_digest": DIGEST_B, + "source_catalog_digest": DIGEST_C, + "semantic_data_portal_revision": SDP_REVISION, "api_operation": "POST /ontology/resolve", "evidence_version": 1, - "recorded_at": datetime(2026, 8, 22, 12, 0, tzinfo=timezone.utc), + "recorded_at": datetime(2026, 8, 22, 14, 50, 12, 123456, tzinfo=timezone.utc), } -def test_builds_value_minimized_non_authorizing_evidence() -> None: - """The canonical document binds provenance without carrying raw ontology or HR values.""" +def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: + """Canonical evidence contains governance/provenance only and has stable bytes.""" packet = SemanticJobEvidenceEnvelope(**values()) - document = packet.canonical_document() assert document["source_system"] == "semantic-data-portal" assert document["source_trust_state"] == "external_source_evidence" assert document["review_state"] == "requires_human_review" assert document["decision_authority_state"] == "not_authorized_for_job_or_employment_decision" - assert document["recorded_at"] == "2026-08-22T12:00:00Z" - serialized = packet.canonical_json() - assert packet.evidence_digest() == sha256(serialized.encode("utf-8")).hexdigest() - for forbidden in ( - "raw_query", - "query_text", - "raw_response", - "person", - "candidate", - "worker", - "credential", - "score", - "employment_decision", - ): - assert forbidden not in serialized.lower() - - -def test_requires_distinct_requester_and_human_reviewer() -> None: - """The same actor cannot request and review imported ontology evidence.""" - candidate = values() - candidate["reviewing_actor_reference"] = candidate["requesting_actor_reference"] - with pytest.raises(ValueError, match="must differ"): - SemanticJobEvidenceEnvelope(**candidate) + assert document["recorded_at"] == "2026-08-22T14:50:12.123456Z" + assert "query_term" not in document + assert "response" not in document + assert "person" not in document + expected_json = json.dumps(document, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + assert packet.canonical_json() == expected_json + assert packet.evidence_digest() == sha256(expected_json.encode("utf-8")).hexdigest() + assert repr(packet) == "SemanticJobEvidenceEnvelope()" @pytest.mark.parametrize( ("field_name", "bad_value"), [ - ("tenant_record_id", str(UUID(int=0))), - ("tenant_record_id", str(UUID(int=(1 << 128) - 1))), + ("tenant_record_id", "00000000-0000-0000-0000-000000000000"), ("tenant_record_id", "not-a-uuid"), - ("job_analysis_reference", "job_analysis:not-a-uuid"), - ("job_analysis_reference", f"job_analysis:{UUID(int=0)}"), - ("job_analysis_reference", f"job_analysis:{UUID('6ba7b810-9dad-11d1-80b4-00c04fd430c8')}"), - ("ontology_request_reference", "job_analysis:" + str(uuid4())), - ("requesting_actor_reference", "actor:"), - ("reviewing_actor_reference", "reviewer:" + str(uuid4())), + ("tenant_record_id", str(uuid4()).upper()), + ("job_analysis_reference", f"job_analysis:{uuid1()}"), + ("job_analysis_reference", f"person:{uuid4()}"), + ("job_analysis_reference", "job_analysis:" + "a" * 181), + ("ontology_request_reference", f"ontology_request:{uuid1()}"), + ("ontology_request_reference", "ontology_request:not-a-uuid"), + ("requesting_actor_reference", "staff:analyst"), + ("reviewing_actor_reference", "actor:has space"), ("query_term_digest", "A" * 64), - ("response_evidence_digest", "f" * 63), - ("source_catalog_digest", "x" * 64), - ("semantic_data_portal_revision", "latest"), + ("response_evidence_digest", "b" * 63), + ("source_catalog_digest", "not-a-digest"), + ("semantic_data_portal_revision", "0" * 40), ("api_operation", "POST /search/semantic"), + ("api_operation", ""), ("resolution_use_code", "automated_job_decision"), ("evidence_version", 0), ("evidence_version", 1_000_001), - ("recorded_at", datetime(2026, 8, 22, 12, 0)), + ("evidence_version", True), + ("recorded_at", datetime(2026, 8, 22, 14, 50, 12)), ], ) -def test_rejects_malformed_or_unreviewed_evidence(field_name: str, bad_value: object) -> None: - """Malformed, unreviewed, or authority-expanding evidence fails closed.""" +def test_rejects_invalid_governance_evidence(field_name: str, bad_value: object) -> None: + """Malformed, unsafe, or unreviewed evidence fails closed at construction.""" candidate = values() candidate[field_name] = bad_value with pytest.raises(ValueError): SemanticJobEvidenceEnvelope(**candidate) +def test_rejects_same_requester_and_reviewer() -> None: + """One actor cannot self-review ontology evidence for Job Analysis.""" + candidate = values() + candidate["reviewing_actor_reference"] = candidate["requesting_actor_reference"] + with pytest.raises(ValueError, match="must differ"): + SemanticJobEvidenceEnvelope(**candidate) + + class ForgedText(str): """Simulate caller text that lies during reviewed equality/hash operations.""" @@ -161,42 +159,35 @@ def test_rejects_post_construction_rewrite() -> None: packet.canonical_json() -def test_rejects_packet_seal_rewrite() -> None: - """Rewriting the packet-owned seal cannot bypass the authoritative creation seal.""" - packet = SemanticJobEvidenceEnvelope(**values()) - object.__setattr__(packet, "_creation_seal", "0" * 64) - with pytest.raises(ValueError, match="changed after construction"): - packet.canonical_document() - - -def test_rejects_replacement_and_seal_reset() -> None: - """Dataclass replacement cannot turn modified evidence into a newly issued envelope.""" - from dataclasses import replace - +def test_replace_cannot_reseal_changed_evidence() -> None: + """Dataclass replacement cannot reset the issuance seal and create new authority.""" packet = SemanticJobEvidenceEnvelope(**values()) with pytest.raises(ValueError, match="changed after construction"): replace(packet, response_evidence_digest="d" * 64, _creation_seal=None) -def test_rejects_caller_supplied_creation_seal() -> None: - """Callers cannot seed a pre-authorized creation seal during construction.""" +def test_rejects_caller_supplied_seal_and_marker_rewrite() -> None: + """Private seal and issuance marker fields remain fail-closed under hostile access.""" candidate = values() candidate["_creation_seal"] = "0" * 64 with pytest.raises(ValueError, match="changed after construction"): SemanticJobEvidenceEnvelope(**candidate) - -def test_rejects_post_issuance_marker_rewrite() -> None: - """Changing the one-way issuance marker invalidates emitted evidence.""" packet = SemanticJobEvidenceEnvelope(**values()) object.__setattr__(packet, "_issuance_marker", object()) with pytest.raises(ValueError, match="changed after construction"): - packet.canonical_json() + packet.canonical_document() -def test_runtime_type_is_final_and_repr_is_redacted() -> None: - """The evidence type cannot be extended and its repr omits sensitive correlations.""" +def test_rejects_creation_seal_rewrite_even_when_payload_is_unchanged() -> None: + """The authoritative in-process seal cannot be replaced independently.""" packet = SemanticJobEvidenceEnvelope(**values()) + object.__setattr__(packet, "_creation_seal", object()) + with pytest.raises(ValueError, match="changed after construction"): + packet.canonical_json() + + +def test_runtime_type_is_final() -> None: + """Subclasses cannot override derived trust state on the governed envelope.""" with pytest.raises(TypeError, match="final"): type("DerivedEnvelope", (SemanticJobEvidenceEnvelope,), {}) - assert repr(packet) == "SemanticJobEvidenceEnvelope()" From e766b42b356cc40ddd84ca5a094c59c9f45af634 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:09:41 -0700 Subject: [PATCH 27/43] test(semantic-job): pin integrity-checked export snapshot --- .../tests/test_envelope.py | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py index 104c6aa60..d47fa19b2 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_envelope.py +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -187,6 +187,29 @@ def test_rejects_creation_seal_rewrite_even_when_payload_is_unchanged() -> None: packet.canonical_json() +def test_canonical_export_reuses_the_exact_integrity_checked_snapshot(monkeypatch: pytest.MonkeyPatch) -> None: + """A mutation after the checked snapshot cannot leak different canonical evidence.""" + packet = SemanticJobEvidenceEnvelope(**values()) + expected_json = packet.canonical_json() + original_payload = SemanticJobEvidenceEnvelope._payload + mutated = False + + def mutate_after_snapshot(self: SemanticJobEvidenceEnvelope) -> dict[str, object]: + """Mutate the live packet immediately after returning one payload snapshot.""" + nonlocal mutated + payload = original_payload(self) + if not mutated: + mutated = True + object.__setattr__(self, "response_evidence_digest", "d" * 64) + return payload + + monkeypatch.setattr(SemanticJobEvidenceEnvelope, "_payload", mutate_after_snapshot) + + assert packet.canonical_json() == expected_json + with pytest.raises(ValueError, match="changed after construction"): + packet.canonical_json() + + def test_runtime_type_is_final() -> None: """Subclasses cannot override derived trust state on the governed envelope.""" with pytest.raises(TypeError, match="final"): From 29428885a00e089bb58a7f0fda4a113932e0d150 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:10:13 -0700 Subject: [PATCH 28/43] fix(semantic-job): export the verified evidence snapshot --- .../envelope.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py index ced6e2337..a169061dd 100644 --- a/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py +++ b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py @@ -206,14 +206,16 @@ def _canonical_payload_json(self) -> str: """Serialize the live evidence deterministically without consulting its creation seal.""" return json.dumps(self._payload(), sort_keys=True, separators=(",", ":"), ensure_ascii=True) - def _assert_integrity(self) -> None: - """Reject post-construction rewriting before canonical evidence can leave this boundary.""" + def _assert_integrity(self) -> tuple[dict[str, object], str]: + """Return the exact checked snapshot while rejecting post-construction rewriting.""" self._validate_fields() if self._issuance_marker is not _USED_ISSUANCE_MARKER: raise ValueError("semantic job evidence changed after construction") packet_seal = self._creation_seal authoritative_seal = _authoritative_creation_seal(self) - live_seal = _seal(self._canonical_payload_json()) + payload = self._payload() + payload_json = json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + live_seal = _seal(payload_json) if ( type(packet_seal) is not str or type(authoritative_seal) is not str @@ -221,16 +223,17 @@ def _assert_integrity(self) -> None: or not hmac.compare_digest(live_seal, authoritative_seal) ): raise ValueError("semantic job evidence changed after construction") + return payload, payload_json def canonical_document(self) -> dict[str, object]: - """Return a fresh canonical document only while issuance evidence remains intact.""" - self._assert_integrity() - return self._payload() + """Return the exact canonical document snapshot that passed integrity verification.""" + payload, _ = self._assert_integrity() + return payload def canonical_json(self) -> str: - """Return deterministic canonical JSON for immutable audit/outbox correlation.""" - self._assert_integrity() - return self._canonical_payload_json() + """Return the exact deterministic JSON snapshot that passed integrity verification.""" + _, payload_json = self._assert_integrity() + return payload_json def evidence_digest(self) -> str: """Return SHA-256 of the exact canonical evidence bytes.""" From 8c72323c9d092bb69df00514b43099e8fe05402e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:10:42 -0700 Subject: [PATCH 29/43] test(semantic-job): bind declared Python support to CI --- .../tests/test_python_support_contract.py | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/tests/test_python_support_contract.py diff --git a/packages/semantic-job-evidence-adapter/tests/test_python_support_contract.py b/packages/semantic-job-evidence-adapter/tests/test_python_support_contract.py new file mode 100644 index 000000000..85d9879b9 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/tests/test_python_support_contract.py @@ -0,0 +1,20 @@ +"""Executable compatibility contract for the semantic evidence package support range.""" + +from pathlib import Path +import tomllib + + +PACKAGE_ROOT = Path(__file__).resolve().parents[1] +REPOSITORY_ROOT = PACKAGE_ROOT.parents[1] +WORKFLOW_PATH = REPOSITORY_ROOT / ".github" / "workflows" / "semantic-job-evidence-adapter-quality.yml" + + +def test_declared_python_range_matches_the_hosted_compatibility_matrix() -> None: + """Bound public Python support to the minor versions exercised by hosted CI.""" + pyproject = tomllib.loads((PACKAGE_ROOT / "pyproject.toml").read_text(encoding="utf-8")) + assert pyproject["project"]["requires-python"] == ">=3.12,<3.15" + + workflow = WORKFLOW_PATH.read_text(encoding="utf-8") + assert "matrix:" in workflow + assert 'python-version: ["3.12", "3.13", "3.14"]' in workflow + assert "python-version: ${{ matrix.python-version }}" in workflow From 609bb5463e837ad87e4d5f144d1f8ac5dc25ba99 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:10:51 -0700 Subject: [PATCH 30/43] fix(semantic-job): bound declared Python support --- packages/semantic-job-evidence-adapter/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/semantic-job-evidence-adapter/pyproject.toml b/packages/semantic-job-evidence-adapter/pyproject.toml index 952e799b5..2b58166d2 100644 --- a/packages/semantic-job-evidence-adapter/pyproject.toml +++ b/packages/semantic-job-evidence-adapter/pyproject.toml @@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta" name = "orgmetra-semantic-job-evidence-adapter" version = "0.1.0" description = "Fail-closed Semantic Data Portal ontology evidence boundary for Orgmetra job analysis." -requires-python = ">=3.12" +requires-python = ">=3.12,<3.15" [project.optional-dependencies] test = ["pytest>=8.3", "pytest-cov>=5.0"] From f16984a962bf962d95b41e67ed1401be9daa311a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:11:06 -0700 Subject: [PATCH 31/43] fix(semantic-job): test every declared Python minor --- .../workflows/semantic-job-evidence-adapter-quality.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/semantic-job-evidence-adapter-quality.yml b/.github/workflows/semantic-job-evidence-adapter-quality.yml index bf0f3b8c9..a6cdca13e 100644 --- a/.github/workflows/semantic-job-evidence-adapter-quality.yml +++ b/.github/workflows/semantic-job-evidence-adapter-quality.yml @@ -21,9 +21,13 @@ concurrency: jobs: unit: - name: Semantic source evidence contract and 100% coverage + name: Semantic source evidence contract and 100% coverage (Python ${{ matrix.python-version }}) runs-on: ubuntu-latest timeout-minutes: 10 + strategy: + fail-fast: false + matrix: + python-version: ["3.12", "3.13", "3.14"] steps: - name: Checkout exact candidate uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -37,7 +41,7 @@ jobs: - name: Set up Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: - python-version: "3.14" + python-version: ${{ matrix.python-version }} check-latest: false - name: Install reviewed test and build toolchain run: | From 69e7647c0a6f3b4fe325bc3fb1c5a7071d79c616 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:12:45 -0700 Subject: [PATCH 32/43] docs(semantic-job): define process-local seal boundary --- packages/semantic-job-evidence-adapter/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/semantic-job-evidence-adapter/README.md b/packages/semantic-job-evidence-adapter/README.md index d2974396d..b092a079c 100644 --- a/packages/semantic-job-evidence-adapter/README.md +++ b/packages/semantic-job-evidence-adapter/README.md @@ -27,8 +27,16 @@ Orgmetra does not read Semantic Data Portal application tables. The foreign serv Trust-bearing text, integers, and timestamps must be exact built-in runtime types before equality, membership, bounds, UUID parsing, or serialization. Packet-owned references use canonical UUIDv4 suffixes; the tenant ID follows Orgmetra's canonical non-sentinel operational UUID contract. The envelope is final and detects post-construction rewriting before canonical evidence leaves the boundary. Its packet-owned HMAC is only a consistency value: the authoritative creation seal is held in a lock-protected process-local issuance registry outside envelope-writable slots, so rewriting both payload and packet seal still fails closed. +Canonical export returns the exact payload snapshot whose seal was verified; it does not re-read live fields after the integrity decision. This closes a same-process mutation window in which the checked bytes and emitted bytes could otherwise diverge. + +The issuance registry and process seal key are intentionally process-local tamper evidence, not durable cryptographic attestation. Copy/deepcopy, pickle/unpickle, worker-process transfer, or process restart does not recreate issuance authority; a restored envelope fails closed. If durable evidence is needed, persist the already-emitted `canonical_json()` bytes and `evidence_digest()` in Orgmetra's immutable audit/outbox boundary rather than serializing the live envelope object. A future requirement for independent long-term envelope revalidation would need a separately governed managed/rotatable signing or MAC key boundary; this package does not claim one. + +## Python compatibility + +The package currently declares and tests Python `>=3.12,<3.15`. Hosted quality evidence runs the installed wheel and its reviewed test toolchain on Python 3.12, 3.13, and 3.14. A new Python minor must be added to the hosted compatibility matrix before the public support range is widened. + ## Testing -The dedicated quality lane runs the package tests with exact 100% owned production statement and branch coverage and requires a clean checkout. Adversarial regressions cover malformed references/digests, self-review, runtime-subclass forgery, invalid dependency revision/API use, payload-only mutation, packet-seal mutation, payload plus recomputed-seal forgery, replacement/seal reset, and runtime-type extension. +The dedicated quality lane runs the package tests with exact 100% owned production statement and branch coverage and requires a clean checkout. Adversarial regressions cover malformed references/digests, self-review, runtime-subclass forgery, invalid dependency revision/API use, payload-only mutation, packet-seal mutation, payload plus recomputed-seal forgery, checked-snapshot export, replacement/seal reset, and runtime-type extension. See `docs/traceability/semantic-job-evidence.md`, `docs/adr/semantic-job-source-evidence.md`, and `docs/doctoring/semantic-job-evidence-references.md` for the governed rationale and evidence map. From c4fb2a1adad35889cf1c9883c2b1530e63f75eb8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:12:59 -0700 Subject: [PATCH 33/43] docs(semantic-job): record snapshot and runtime boundaries --- docs/adr/semantic-job-source-evidence.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/adr/semantic-job-source-evidence.md b/docs/adr/semantic-job-source-evidence.md index 253fbbc0a..f0e3c703f 100644 --- a/docs/adr/semantic-job-source-evidence.md +++ b/docs/adr/semantic-job-source-evidence.md @@ -26,16 +26,21 @@ The canonical evidence always records `external_source_evidence`, `requires_huma Semantic Data Portal remains read-only to this Orgmetra lane. No foreign application table is queried. Provider revision/API drift fails closed until explicitly reviewed. Raw ontology content, PII, credentials, scores, and decisions stay outside this value-minimized envelope. -Trust-bearing runtime primitives are accepted only as exact built-in types before caller-overridable equality, hashing, comparison, parsing, or serialization can run. Creation-time evidence is sealed in process and its authoritative seal is held in a lock-protected issuance registry outside envelope-writable slots. Canonical export revalidates live fields against that external seal, so changing the payload together with a recomputed packet-owned seal still fails closed. +Trust-bearing runtime primitives are accepted only as exact built-in types before caller-overridable equality, hashing, comparison, parsing, or serialization can run. Creation-time evidence is sealed in process and its authoritative seal is held in a lock-protected issuance registry outside envelope-writable slots. Canonical export verifies one canonical payload snapshot and returns that same snapshot/JSON rather than rereading live fields after the integrity decision, so checked and emitted evidence cannot diverge through an intervening same-process mutation. + +The issuance registry and process MAC key are intentionally process-local. Copy/deepcopy, pickle/unpickle, worker transfer, and process restart do not recreate an envelope's issuance authority; restored envelope objects fail closed. Durable systems must persist the already-emitted canonical JSON and its evidence digest through Orgmetra's immutable audit/outbox boundary, not serialize a live envelope and expect it to regain process-local validation state. If long-term independent revalidation becomes a requirement, a separately governed managed and rotatable key/signing boundary must be designed; it is not claimed by this slice. + +The package's supported runtime is deliberately bounded to Python `>=3.12,<3.15` and the dedicated quality workflow executes the installed artifact on 3.12, 3.13, and 3.14 before support is claimed. New Python minors require explicit compatibility evidence before widening that range. ## Consequences - Buyers can trace a Job Analysis source claim to an exact external contract revision and evidence digests without treating that source as authoritative by syntax alone. - Human review remains explicit and separable from source retrieval. - A future Semantic Data Portal contract change requires an Orgmetra review/update rather than silently changing evidence semantics. -- This slice does not implement network transport, foreign retries, foreign authorization, raw ontology storage, Job Analysis approval, or employment decisions. +- Process-local tamper evidence is safe to use only in the issuing process; durable evidence uses canonical bytes/digest plus the repository's immutable audit/outbox controls. +- This slice does not implement network transport, foreign retries, foreign authorization, raw ontology storage, Job Analysis approval, employment decisions, or durable signing-key management. - The approach is compatible with W3C provenance principles: source entities and activities remain externally owned while Orgmetra records bounded provenance needed for its own evidence chain. ## Verification -The package quality lane requires exact-current-head tests, exact 100% owned production statement and branch coverage, adversarial runtime-integrity regressions, and a clean checkout. Repository-level Foundation/SAST/Security/Recovery evidence remains separately required by live merge governance. +The package quality lane requires exact-current-head tests, exact 100% owned production statement and branch coverage, installed-wheel execution across the declared Python minor range, adversarial runtime-integrity regressions, and a clean checkout. Repository-level Foundation/SAST/Security/Recovery evidence remains separately required by live merge governance. From c7f382263659bfb5f5eac678da991f978793690c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:13:13 -0700 Subject: [PATCH 34/43] test(semantic-job): centralize shared evidence fixture --- .../tests/conftest.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 packages/semantic-job-evidence-adapter/tests/conftest.py diff --git a/packages/semantic-job-evidence-adapter/tests/conftest.py b/packages/semantic-job-evidence-adapter/tests/conftest.py new file mode 100644 index 000000000..915c18a80 --- /dev/null +++ b/packages/semantic-job-evidence-adapter/tests/conftest.py @@ -0,0 +1,29 @@ +"""Shared pytest fixtures for the semantic job evidence adapter contract.""" + +from datetime import datetime, timezone +from uuid import uuid4 + +import pytest + + +SDP_REVISION = "e48aa13c4af7a4875d4b53e6a60b50405c265a2f" + + +@pytest.fixture +def semantic_values() -> dict[str, object]: + """Return one fresh valid value-minimized ontology source-evidence fixture.""" + return { + "tenant_record_id": str(uuid4()), + "job_analysis_reference": f"job_analysis:{uuid4()}", + "ontology_request_reference": f"ontology_request:{uuid4()}", + "requesting_actor_reference": "actor:hr-analyst", + "reviewing_actor_reference": "actor:job-analysis-reviewer", + "resolution_use_code": "job_analysis_source_evidence", + "query_term_digest": "a" * 64, + "response_evidence_digest": "b" * 64, + "source_catalog_digest": "c" * 64, + "semantic_data_portal_revision": SDP_REVISION, + "api_operation": "POST /ontology/resolve", + "evidence_version": 1, + "recorded_at": datetime(2026, 8, 22, 14, 50, 12, 123456, tzinfo=timezone.utc), + } From 78574c4fbcbfef9d7630279d826a2b9e1940af70 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:13:19 -0700 Subject: [PATCH 35/43] test(semantic-job): remove cross-test-module fixture import --- .../tests/test_creation_seal_integrity.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py b/packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py index 599cda8c9..158743afa 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py +++ b/packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py @@ -4,12 +4,13 @@ import orgmetra_semantic_job_evidence_adapter.envelope as envelope_module from orgmetra_semantic_job_evidence_adapter import SemanticJobEvidenceEnvelope -from test_envelope import values -def test_recomputed_packet_owned_seal_cannot_authorize_rewritten_evidence() -> None: +def test_recomputed_packet_owned_seal_cannot_authorize_rewritten_evidence( + semantic_values: dict[str, object], +) -> None: """Rewriting payload plus its packet-owned seal must still fail closed.""" - packet = SemanticJobEvidenceEnvelope(**values()) + packet = SemanticJobEvidenceEnvelope(**semantic_values) object.__setattr__(packet, "response_evidence_digest", "d" * 64) forged_seal = envelope_module._seal(packet._canonical_payload_json()) object.__setattr__(packet, "_creation_seal", forged_seal) From 5f6ed07df7f95d56e6f59528dd5b450d448fb049 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:13:45 -0700 Subject: [PATCH 36/43] test(semantic-job): consume shared pytest evidence fixture --- .../tests/test_envelope.py | 75 ++++++++----------- 1 file changed, 31 insertions(+), 44 deletions(-) diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py index d47fa19b2..5b662d44d 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_envelope.py +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -11,34 +11,11 @@ from orgmetra_semantic_job_evidence_adapter import SemanticJobEvidenceEnvelope -SDP_REVISION = "e48aa13c4af7a4875d4b53e6a60b50405c265a2f" -DIGEST_A = "a" * 64 -DIGEST_B = "b" * 64 -DIGEST_C = "c" * 64 - - -def values() -> dict[str, object]: - """Return one valid value-minimized ontology source-evidence fixture.""" - return { - "tenant_record_id": str(uuid4()), - "job_analysis_reference": f"job_analysis:{uuid4()}", - "ontology_request_reference": f"ontology_request:{uuid4()}", - "requesting_actor_reference": "actor:hr-analyst", - "reviewing_actor_reference": "actor:job-analysis-reviewer", - "resolution_use_code": "job_analysis_source_evidence", - "query_term_digest": DIGEST_A, - "response_evidence_digest": DIGEST_B, - "source_catalog_digest": DIGEST_C, - "semantic_data_portal_revision": SDP_REVISION, - "api_operation": "POST /ontology/resolve", - "evidence_version": 1, - "recorded_at": datetime(2026, 8, 22, 14, 50, 12, 123456, tzinfo=timezone.utc), - } - - -def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: +def test_canonical_evidence_is_value_minimized_and_deterministic( + semantic_values: dict[str, object], +) -> None: """Canonical evidence contains governance/provenance only and has stable bytes.""" - packet = SemanticJobEvidenceEnvelope(**values()) + packet = SemanticJobEvidenceEnvelope(**semantic_values) document = packet.canonical_document() assert document["source_system"] == "semantic-data-portal" @@ -81,17 +58,19 @@ def test_canonical_evidence_is_value_minimized_and_deterministic() -> None: ("recorded_at", datetime(2026, 8, 22, 14, 50, 12)), ], ) -def test_rejects_invalid_governance_evidence(field_name: str, bad_value: object) -> None: +def test_rejects_invalid_governance_evidence( + semantic_values: dict[str, object], field_name: str, bad_value: object +) -> None: """Malformed, unsafe, or unreviewed evidence fails closed at construction.""" - candidate = values() + candidate = semantic_values.copy() candidate[field_name] = bad_value with pytest.raises(ValueError): SemanticJobEvidenceEnvelope(**candidate) -def test_rejects_same_requester_and_reviewer() -> None: +def test_rejects_same_requester_and_reviewer(semantic_values: dict[str, object]) -> None: """One actor cannot self-review ontology evidence for Job Analysis.""" - candidate = values() + candidate = semantic_values.copy() candidate["reviewing_actor_reference"] = candidate["requesting_actor_reference"] with pytest.raises(ValueError, match="must differ"): SemanticJobEvidenceEnvelope(**candidate) @@ -137,7 +116,9 @@ class ForgedDateTime(datetime): """Represent caller-executable temporal behavior at the trust boundary.""" -def test_rejects_runtime_subclasses_before_governance_comparison() -> None: +def test_rejects_runtime_subclasses_before_governance_comparison( + semantic_values: dict[str, object], +) -> None: """Caller-defined primitives cannot forge reviewed state or canonical evidence.""" for field_name, bad_value in ( ("resolution_use_code", ForgedText("automated_job_decision")), @@ -145,51 +126,57 @@ def test_rejects_runtime_subclasses_before_governance_comparison() -> None: ("evidence_version", ForgedInt(1)), ("recorded_at", ForgedDateTime(2026, 8, 22, tzinfo=timezone.utc)), ): - candidate = values() + candidate = semantic_values.copy() candidate[field_name] = bad_value with pytest.raises(ValueError): SemanticJobEvidenceEnvelope(**candidate) -def test_rejects_post_construction_rewrite() -> None: +def test_rejects_post_construction_rewrite(semantic_values: dict[str, object]) -> None: """Valid-looking field replacement cannot rewrite already-issued evidence.""" - packet = SemanticJobEvidenceEnvelope(**values()) + packet = SemanticJobEvidenceEnvelope(**semantic_values) object.__setattr__(packet, "response_evidence_digest", "d" * 64) with pytest.raises(ValueError, match="changed after construction"): packet.canonical_json() -def test_replace_cannot_reseal_changed_evidence() -> None: +def test_replace_cannot_reseal_changed_evidence(semantic_values: dict[str, object]) -> None: """Dataclass replacement cannot reset the issuance seal and create new authority.""" - packet = SemanticJobEvidenceEnvelope(**values()) + packet = SemanticJobEvidenceEnvelope(**semantic_values) with pytest.raises(ValueError, match="changed after construction"): replace(packet, response_evidence_digest="d" * 64, _creation_seal=None) -def test_rejects_caller_supplied_seal_and_marker_rewrite() -> None: +def test_rejects_caller_supplied_seal_and_marker_rewrite( + semantic_values: dict[str, object], +) -> None: """Private seal and issuance marker fields remain fail-closed under hostile access.""" - candidate = values() + candidate = semantic_values.copy() candidate["_creation_seal"] = "0" * 64 with pytest.raises(ValueError, match="changed after construction"): SemanticJobEvidenceEnvelope(**candidate) - packet = SemanticJobEvidenceEnvelope(**values()) + packet = SemanticJobEvidenceEnvelope(**semantic_values) object.__setattr__(packet, "_issuance_marker", object()) with pytest.raises(ValueError, match="changed after construction"): packet.canonical_document() -def test_rejects_creation_seal_rewrite_even_when_payload_is_unchanged() -> None: +def test_rejects_creation_seal_rewrite_even_when_payload_is_unchanged( + semantic_values: dict[str, object], +) -> None: """The authoritative in-process seal cannot be replaced independently.""" - packet = SemanticJobEvidenceEnvelope(**values()) + packet = SemanticJobEvidenceEnvelope(**semantic_values) object.__setattr__(packet, "_creation_seal", object()) with pytest.raises(ValueError, match="changed after construction"): packet.canonical_json() -def test_canonical_export_reuses_the_exact_integrity_checked_snapshot(monkeypatch: pytest.MonkeyPatch) -> None: +def test_canonical_export_reuses_the_exact_integrity_checked_snapshot( + semantic_values: dict[str, object], monkeypatch: pytest.MonkeyPatch +) -> None: """A mutation after the checked snapshot cannot leak different canonical evidence.""" - packet = SemanticJobEvidenceEnvelope(**values()) + packet = SemanticJobEvidenceEnvelope(**semantic_values) expected_json = packet.canonical_json() original_payload = SemanticJobEvidenceEnvelope._payload mutated = False From b89be458429c2a3cdd5a9d2c26f7fe786079d482 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:14:15 -0700 Subject: [PATCH 37/43] docs(semantic-job): trace verified snapshot and compatibility --- docs/traceability/semantic-job-evidence.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/traceability/semantic-job-evidence.md b/docs/traceability/semantic-job-evidence.md index 87b03ea56..76babc615 100644 --- a/docs/traceability/semantic-job-evidence.md +++ b/docs/traceability/semantic-job-evidence.md @@ -13,15 +13,20 @@ | Minimize HR/audit exposure | query term, response and source catalog represented only by SHA-256 digests | no raw query/response, PII, credential, score, or decision in canonical evidence | | Preserve exact source provenance | foreign revision, API operation, source-system/trust-state, evidence version, UTC recorded time | provider drift fails closed | | Prevent runtime evidence forgery | exact built-in primitives, UUID/reference/digest validation, final runtime type | adversarial subclass regressions | -| Prevent post-issuance rewrite | packet consistency seal plus lock-protected process-local authoritative issuance seal, live-field revalidation before canonical export | payload-only, seal-only, payload+recomputed-seal, replace, and marker-tamper regressions | -| Maintain exact owned production coverage | dedicated `Semantic Job Evidence Adapter Quality` workflow | 100% statement and branch coverage required | +| Prevent post-issuance rewrite | packet consistency seal plus lock-protected process-local authoritative issuance seal | payload-only, seal-only, payload+recomputed-seal, replace, and marker-tamper regressions | +| Prevent checked/emitted evidence divergence | canonical export returns the exact payload/JSON snapshot used for live seal verification | deterministic mutation-between-check-and-return regression | +| Keep process-local issuance semantics explicit | restored/copied envelope objects do not regain issuance registry state; durable systems persist emitted canonical JSON + digest | README/ADR boundary; managed rotatable long-term seal is future work only | +| Bound declared Python compatibility to evidence | `requires-python = ">=3.12,<3.15"`; hosted matrix executes 3.12, 3.13, 3.14 | support range cannot widen without new current-head CI evidence | +| Maintain exact owned production coverage | dedicated `Semantic Job Evidence Adapter Quality` workflow | 100% statement and branch coverage required on every matrix runtime | ## Test mapping -`packages/semantic-job-evidence-adapter/tests/test_envelope.py` verifies canonical value minimization, reviewed trust states, tenant/reference validity, requester/reviewer separation, source revision/API binding, bounded evidence versions, exact UTC recorded time, hostile runtime subclasses, post-construction mutation, dataclass replacement/seal reset, marker/seal tampering, redacted repr, and final runtime type. +`packages/semantic-job-evidence-adapter/tests/test_envelope.py` verifies canonical value minimization, reviewed trust states, tenant/reference validity, requester/reviewer separation, source revision/API binding, bounded evidence versions, exact UTC recorded time, hostile runtime subclasses, post-construction mutation, dataclass replacement/seal reset, marker/seal tampering, checked-snapshot export, redacted repr, and final runtime type. `packages/semantic-job-evidence-adapter/tests/test_creation_seal_integrity.py` proves that rewriting a valid trust-bearing field together with a freshly recomputed packet-owned HMAC cannot authorize changed evidence because the authoritative creation seal is stored outside envelope-writable slots. +`packages/semantic-job-evidence-adapter/tests/test_python_support_contract.py` binds public Python support metadata to the hosted 3.12/3.13/3.14 compatibility matrix. + ## Non-claims -This active PR does not prove the truth of Semantic Data Portal content, does not authenticate actor syntax, does not implement the network client, does not directly approve a Job Analysis, and does not authorize a hiring or other employment decision. Those authorities remain with their owning Orgmetra and dedicated-writer boundaries. +This active PR does not prove the truth of Semantic Data Portal content, does not authenticate actor syntax, does not implement the network client, does not directly approve a Job Analysis, and does not authorize a hiring or other employment decision. The process-local issuance seal is tamper evidence, not durable cryptographic attestation or a managed signing service. Those authorities remain with their owning Orgmetra and dedicated-writer boundaries. From 0197b948839a7fbcdf04e4b396317a00f5010bab Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:14:22 -0700 Subject: [PATCH 38/43] docs(semantic-job): keep active changes unreleased --- packages/semantic-job-evidence-adapter/CHANGELOG.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/semantic-job-evidence-adapter/CHANGELOG.md b/packages/semantic-job-evidence-adapter/CHANGELOG.md index 223354cec..7c5b21fda 100644 --- a/packages/semantic-job-evidence-adapter/CHANGELOG.md +++ b/packages/semantic-job-evidence-adapter/CHANGELOG.md @@ -1,11 +1,14 @@ # Changelog -## 0.1.0 — active PR +## Unreleased - Add a value-minimized, human-review-required Semantic Data Portal ontology evidence envelope for Job Analysis. - Pin the reviewed read-only dependency revision and `POST /ontology/resolve` API operation. - Bind tenant, Job Analysis scope, accountable actors, source/query/response digests, evidence version, and UTC system-recorded time without copying raw ontology or HR content. - Fail closed on malformed governance evidence, self-review, caller-defined primitive subclasses, dependency-contract drift, post-construction mutation, seal reset, and runtime type extension. - Repair the post-issuance integrity path so rewriting a payload together with a recomputed packet-owned seal still fails: the authoritative creation seal is held in a process-local, lock-protected issuance registry outside envelope-writable slots. +- Return the exact canonical payload/JSON snapshot that passed seal verification so an intervening same-process mutation cannot make checked bytes and emitted bytes diverge. +- Document the process-local issuance boundary: copied/restored envelope objects fail closed, while durable audit/outbox persistence stores emitted canonical JSON and evidence digest rather than the live envelope object. +- Bound declared runtime support to Python `>=3.12,<3.15` and execute the installed wheel on Python 3.12, 3.13, and 3.14 before claiming compatibility. - Add an exact-head quality workflow with exact 100% owned production statement and branch coverage plus clean-checkout enforcement. - Build a wheel and execute the quality suite against the SHA-256-bound installed artifact in a fully isolated virtual environment; install the reviewed hash-pinned pytest/coverage toolchain inside that environment and fail closed if package or test-tool imports resolve outside it. From a94c08702a1a2768560f0dd652337d8ebe2c8844 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:15:53 -0700 Subject: [PATCH 39/43] fix(ci): admit reviewed coverage wheels for Python 3.12-3.14 --- .github/requirements/foundation-test.txt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/requirements/foundation-test.txt b/.github/requirements/foundation-test.txt index 40d926005..2383d246d 100644 --- a/.github/requirements/foundation-test.txt +++ b/.github/requirements/foundation-test.txt @@ -1,6 +1,9 @@ -# Reviewed Foundation CI test toolchain for CPython 3.14 on GitHub-hosted Ubuntu x86_64. +# Reviewed Foundation CI test toolchain for CPython 3.12-3.14 on GitHub-hosted Ubuntu x86_64. # Version and artifact hash changes must be reverified against the official PyPI release JSON. -coverage==7.14.2 --hash=sha256:cda36d8e7bfd63b3e44e75163265429caa5d935b672b00f71bccc8c010518c64 +coverage==7.14.2 \ + --hash=sha256:8b4910cce599cd2438f8da65f5ef199a70a1cdb6ab314926df78271ca5954240 \ + --hash=sha256:1d9a1b5813d00ea6151f6ccf64d1fa16892771dfdda12ba87162d15ec4ea3e1e \ + --hash=sha256:cda36d8e7bfd63b3e44e75163265429caa5d935b672b00f71bccc8c010518c64 iniconfig==2.3.0 --hash=sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12 packaging==26.2 --hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e pluggy==1.6.0 --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746 From 0e97ff357f83453259adba56ba015b7d29136188 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:16:18 -0700 Subject: [PATCH 40/43] docs(semantic-job): record Python compatibility evidence source --- docs/doctoring/semantic-job-evidence-references.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/doctoring/semantic-job-evidence-references.md b/docs/doctoring/semantic-job-evidence-references.md index 38744ef2b..73d2b0c0a 100644 --- a/docs/doctoring/semantic-job-evidence-references.md +++ b/docs/doctoring/semantic-job-evidence-references.md @@ -2,7 +2,7 @@ ## Scope -These references support the active-PR decision to keep foreign ontology output as provenance-bearing source evidence that requires human review, rather than copying a dedicated-writer service or treating semantic resolution as authoritative Job/employment decision evidence. +These references support the active-PR decision to keep foreign ontology output as provenance-bearing source evidence that requires human review, rather than copying a dedicated-writer service or treating semantic resolution as authoritative Job/employment decision evidence. They also record the primary package metadata used to bind the adapter's declared Python support to its hosted compatibility evidence. ## References (APA 7) @@ -10,6 +10,8 @@ ContextualWisdomLab. (2026). *Semantic Data Portal* (Revision e48aa13c4af7a4875d Lebo, T., Sahoo, S., & McGuinness, D. (Eds.). (2013). *PROV-O: The PROV ontology* (W3C Recommendation). World Wide Web Consortium. https://www.w3.org/TR/prov-o/ +Python Software Foundation. (2026). *coverage 7.14.2 release metadata* [JSON metadata]. Python Package Index. https://pypi.org/pypi/coverage/7.14.2/json + Tabassi, E. (2023). *Artificial intelligence risk management framework (AI RMF 1.0)* (NIST AI 100-1). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.100-1 ## Evidence notes @@ -17,4 +19,5 @@ Tabassi, E. (2023). *Artificial intelligence risk management framework (AI RMF 1 - The pinned Semantic Data Portal README publishes `POST /ontology/resolve` as an ontology/terminology API. That is the exact foreign operation recorded by this Orgmetra adapter; the dependency remains read-only. - W3C PROV-O is a W3C Recommendation for interoperable provenance representation across heterogeneous systems. The Orgmetra envelope uses a small application-specific provenance record rather than claiming PROV-O serialization compliance. - NIST AI RMF 1.0 remains the published final framework while NIST develops revisions/profiles. Its risk-management framing supports keeping model/semantic outputs governed and reviewable. This package does not claim AI RMF conformity or certification. +- The official PyPI JSON for coverage 7.14.2 advertises Python 3.12, 3.13, and 3.14 support and publishes distinct SHA-256 digests for their CPython Linux wheels. The Orgmetra hash lock admits only the exact reviewed 3.12/3.13/3.14 coverage wheel hashes used by the hosted matrix; it does not disable `--require-hashes` or broaden dependency versions. - No psychometric/statistical estimator is implemented in this slice, so no research-only statistical claim is introduced and no foreign psychometric kernel is duplicated. From d200597485669f3f60dfcb3cb33d550764c18a5e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:17:52 -0700 Subject: [PATCH 41/43] fix(ci): keep multi-runtime coverage hashes on one requirement --- .github/requirements/foundation-test.txt | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/requirements/foundation-test.txt b/.github/requirements/foundation-test.txt index 2383d246d..6fc4e5ab9 100644 --- a/.github/requirements/foundation-test.txt +++ b/.github/requirements/foundation-test.txt @@ -1,9 +1,6 @@ # Reviewed Foundation CI test toolchain for CPython 3.12-3.14 on GitHub-hosted Ubuntu x86_64. # Version and artifact hash changes must be reverified against the official PyPI release JSON. -coverage==7.14.2 \ - --hash=sha256:8b4910cce599cd2438f8da65f5ef199a70a1cdb6ab314926df78271ca5954240 \ - --hash=sha256:1d9a1b5813d00ea6151f6ccf64d1fa16892771dfdda12ba87162d15ec4ea3e1e \ - --hash=sha256:cda36d8e7bfd63b3e44e75163265429caa5d935b672b00f71bccc8c010518c64 +coverage==7.14.2 --hash=sha256:8b4910cce599cd2438f8da65f5ef199a70a1cdb6ab314926df78271ca5954240 --hash=sha256:1d9a1b5813d00ea6151f6ccf64d1fa16892771dfdda12ba87162d15ec4ea3e1e --hash=sha256:cda36d8e7bfd63b3e44e75163265429caa5d935b672b00f71bccc8c010518c64 iniconfig==2.3.0 --hash=sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12 packaging==26.2 --hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e pluggy==1.6.0 --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746 From 193e18388885961274700ae7ade3b6f4c4452a0d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 22 Aug 2026 13:18:12 -0700 Subject: [PATCH 42/43] fix(ci): validate reviewed multi-runtime coverage hashes --- .../test_foundation_ci_dependency_hygiene.sh | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/tests/test_foundation_ci_dependency_hygiene.sh b/tests/test_foundation_ci_dependency_hygiene.sh index 6a6cb51a8..1e3c013c3 100644 --- a/tests/test_foundation_ci_dependency_hygiene.sh +++ b/tests/test_foundation_ci_dependency_hygiene.sh @@ -65,7 +65,7 @@ if [[ "${#package_lines[@]}" -ne 7 ]]; then fi for package_line in "${package_lines[@]}"; do - if [[ ! "${package_line}" =~ ^[A-Za-z0-9._-]+==[0-9][A-Za-z0-9._-]*[[:space:]]--hash=sha256:[0-9a-f]{64}$ ]]; then + if [[ ! "${package_line}" =~ ^[A-Za-z0-9._-]+==[0-9][A-Za-z0-9._-]*([[:space:]]--hash=sha256:[0-9a-f]{64})+$ ]]; then printf 'Unpinned or unhashed Foundation CI requirement: %s\n' "${package_line}" >&2 exit 1 fi @@ -77,3 +77,22 @@ for package_name in coverage iniconfig packaging pluggy Pygments pytest pytest-c exit 1 fi done + +coverage_line="$(printf '%s\n' "${package_lines[@]}" | grep -E '^coverage==')" +expected_coverage_hashes=( + "8b4910cce599cd2438f8da65f5ef199a70a1cdb6ab314926df78271ca5954240" + "1d9a1b5813d00ea6151f6ccf64d1fa16892771dfdda12ba87162d15ec4ea3e1e" + "cda36d8e7bfd63b3e44e75163265429caa5d935b672b00f71bccc8c010518c64" +) +for expected_hash in "${expected_coverage_hashes[@]}"; do + if [[ "${coverage_line}" != *"--hash=sha256:${expected_hash}"* ]]; then + printf 'Foundation CI coverage requirement is missing reviewed artifact hash: %s\n' "${expected_hash}" >&2 + exit 1 + fi +done + +actual_coverage_hash_count="$(grep -o -- '--hash=sha256:[0-9a-f]\{64\}' <<<"${coverage_line}" | wc -l)" +if [[ "${actual_coverage_hash_count}" -ne "${#expected_coverage_hashes[@]}" ]]; then + printf 'Foundation CI coverage requirement must contain exactly the reviewed Python 3.12-3.14 artifact hashes.\n' >&2 + exit 1 +fi From c340e7599f147b25fab4c94cd2042a96d6128235 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 30 Aug 2026 03:51:13 +0900 Subject: [PATCH 43/43] fix(semantic-job): require opaque actor references --- docs/adr/semantic-job-source-evidence.md | 2 +- docs/traceability/semantic-job-evidence.md | 2 +- packages/semantic-job-evidence-adapter/CHANGELOG.md | 1 + packages/semantic-job-evidence-adapter/README.md | 2 +- .../orgmetra_semantic_job_evidence_adapter/envelope.py | 8 ++------ packages/semantic-job-evidence-adapter/tests/conftest.py | 4 ++-- .../semantic-job-evidence-adapter/tests/test_envelope.py | 1 + 7 files changed, 9 insertions(+), 11 deletions(-) diff --git a/docs/adr/semantic-job-source-evidence.md b/docs/adr/semantic-job-source-evidence.md index f0e3c703f..e6b70a654 100644 --- a/docs/adr/semantic-job-source-evidence.md +++ b/docs/adr/semantic-job-source-evidence.md @@ -16,7 +16,7 @@ Orgmetra owns a final, immutable `SemanticJobEvidenceEnvelope` that binds: 1. tenant and Job Analysis scope; 2. an opaque Orgmetra ontology-request reference; -3. distinct requesting and human-reviewing actor references; +3. distinct requesting and human-reviewing opaque `actor:` UUIDv4 references; 4. the closed use `job_analysis_source_evidence`; 5. SHA-256 digests for query-term evidence, response evidence, and source-catalog state; 6. the reviewed Semantic Data Portal revision `e48aa13c4af7a4875d4b53e6a60b50405c265a2f` and `POST /ontology/resolve` operation; diff --git a/docs/traceability/semantic-job-evidence.md b/docs/traceability/semantic-job-evidence.md index 76babc615..de5a289af 100644 --- a/docs/traceability/semantic-job-evidence.md +++ b/docs/traceability/semantic-job-evidence.md @@ -8,7 +8,7 @@ |---|---|---| | Consume only a published foreign contract | reviewed Semantic Data Portal revision `e48aa13c4af7a4875d4b53e6a60b50405c265a2f`; exact `POST /ontology/resolve` operation | read-only dependency; no foreign table access | | Bind source evidence to Orgmetra scope | canonical tenant, `job_analysis:` and `ontology_request:` references | Orgmetra-owned evidence envelope | -| Require accountable human review | distinct `actor:` requester and reviewer; canonical state `requires_human_review` | syntax is correlation only; host identity/scope resolution remains authoritative | +| Require accountable human review | distinct `actor:` UUIDv4 requester and reviewer; canonical state `requires_human_review` | syntax is correlation only; host identity/scope resolution remains authoritative | | Prevent semantic evidence from becoming a decision | canonical state `not_authorized_for_job_or_employment_decision` | source evidence cannot authorize Job/employment action | | Minimize HR/audit exposure | query term, response and source catalog represented only by SHA-256 digests | no raw query/response, PII, credential, score, or decision in canonical evidence | | Preserve exact source provenance | foreign revision, API operation, source-system/trust-state, evidence version, UTC recorded time | provider drift fails closed | diff --git a/packages/semantic-job-evidence-adapter/CHANGELOG.md b/packages/semantic-job-evidence-adapter/CHANGELOG.md index 7c5b21fda..94518ae3d 100644 --- a/packages/semantic-job-evidence-adapter/CHANGELOG.md +++ b/packages/semantic-job-evidence-adapter/CHANGELOG.md @@ -5,6 +5,7 @@ - Add a value-minimized, human-review-required Semantic Data Portal ontology evidence envelope for Job Analysis. - Pin the reviewed read-only dependency revision and `POST /ontology/resolve` API operation. - Bind tenant, Job Analysis scope, accountable actors, source/query/response digests, evidence version, and UTC system-recorded time without copying raw ontology or HR content. +- Require opaque canonical `actor:` UUIDv4 correlations so human-readable actor handles cannot enter durable evidence. - Fail closed on malformed governance evidence, self-review, caller-defined primitive subclasses, dependency-contract drift, post-construction mutation, seal reset, and runtime type extension. - Repair the post-issuance integrity path so rewriting a payload together with a recomputed packet-owned seal still fails: the authoritative creation seal is held in a process-local, lock-protected issuance registry outside envelope-writable slots. - Return the exact canonical payload/JSON snapshot that passed seal verification so an intervening same-process mutation cannot make checked bytes and emitted bytes diverge. diff --git a/packages/semantic-job-evidence-adapter/README.md b/packages/semantic-job-evidence-adapter/README.md index b092a079c..f9ac6edef 100644 --- a/packages/semantic-job-evidence-adapter/README.md +++ b/packages/semantic-job-evidence-adapter/README.md @@ -25,7 +25,7 @@ Orgmetra does not read Semantic Data Portal application tables. The foreign serv ## Evidence integrity -Trust-bearing text, integers, and timestamps must be exact built-in runtime types before equality, membership, bounds, UUID parsing, or serialization. Packet-owned references use canonical UUIDv4 suffixes; the tenant ID follows Orgmetra's canonical non-sentinel operational UUID contract. The envelope is final and detects post-construction rewriting before canonical evidence leaves the boundary. Its packet-owned HMAC is only a consistency value: the authoritative creation seal is held in a lock-protected process-local issuance registry outside envelope-writable slots, so rewriting both payload and packet seal still fails closed. +Trust-bearing text, integers, and timestamps must be exact built-in runtime types before equality, membership, bounds, UUID parsing, or serialization. Packet-owned references, including actor correlations, use canonical UUIDv4 suffixes; the tenant ID follows Orgmetra's canonical non-sentinel operational UUID contract. The envelope is final and detects post-construction rewriting before canonical evidence leaves the boundary. Its packet-owned HMAC is only a consistency value: the authoritative creation seal is held in a lock-protected process-local issuance registry outside envelope-writable slots, so rewriting both payload and packet seal still fails closed. Canonical export returns the exact payload snapshot whose seal was verified; it does not re-read live fields after the integrity decision. This closes a same-process mutation window in which the checked bytes and emitted bytes could otherwise diverge. diff --git a/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py index a169061dd..21dfb6924 100644 --- a/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py +++ b/packages/semantic-job-evidence-adapter/src/orgmetra_semantic_job_evidence_adapter/envelope.py @@ -20,7 +20,6 @@ _NEW_ISSUANCE_MARKER = object() _USED_ISSUANCE_MARKER = object() _DIGEST_PATTERN = re.compile(r"[0-9a-f]{64}") -_ACTOR_PATTERN = re.compile(r"actor:[A-Za-z0-9._~-]{1,128}") _ALLOWED_RESOLUTION_USES = frozenset({"job_analysis_source_evidence"}) _CREATION_SEALS: dict[int, str] = {} _CREATION_SEALS_LOCK = RLock() @@ -82,11 +81,8 @@ def _validate_reference(value: object, field_name: str, namespace: str) -> str: def _validate_actor_reference(value: object, field_name: str) -> str: - """Require bounded opaque actor correlation without treating syntax as authentication.""" - text = _require_text(value, field_name) - if _ACTOR_PATTERN.fullmatch(text) is None: - raise ValueError(f"{field_name} must be a bounded actor: reference") - return text + """Require opaque actor correlation with a canonical UUIDv4 suffix.""" + return _validate_reference(value, field_name, "actor") def _validate_digest(value: object, field_name: str) -> str: diff --git a/packages/semantic-job-evidence-adapter/tests/conftest.py b/packages/semantic-job-evidence-adapter/tests/conftest.py index 915c18a80..07a27756e 100644 --- a/packages/semantic-job-evidence-adapter/tests/conftest.py +++ b/packages/semantic-job-evidence-adapter/tests/conftest.py @@ -16,8 +16,8 @@ def semantic_values() -> dict[str, object]: "tenant_record_id": str(uuid4()), "job_analysis_reference": f"job_analysis:{uuid4()}", "ontology_request_reference": f"ontology_request:{uuid4()}", - "requesting_actor_reference": "actor:hr-analyst", - "reviewing_actor_reference": "actor:job-analysis-reviewer", + "requesting_actor_reference": f"actor:{uuid4()}", + "reviewing_actor_reference": f"actor:{uuid4()}", "resolution_use_code": "job_analysis_source_evidence", "query_term_digest": "a" * 64, "response_evidence_digest": "b" * 64, diff --git a/packages/semantic-job-evidence-adapter/tests/test_envelope.py b/packages/semantic-job-evidence-adapter/tests/test_envelope.py index 5b662d44d..0af059612 100644 --- a/packages/semantic-job-evidence-adapter/tests/test_envelope.py +++ b/packages/semantic-job-evidence-adapter/tests/test_envelope.py @@ -44,6 +44,7 @@ def test_canonical_evidence_is_value_minimized_and_deterministic( ("ontology_request_reference", f"ontology_request:{uuid1()}"), ("ontology_request_reference", "ontology_request:not-a-uuid"), ("requesting_actor_reference", "staff:analyst"), + ("requesting_actor_reference", "actor:hr-analyst"), ("reviewing_actor_reference", "actor:has space"), ("query_term_digest", "A" * 64), ("response_evidence_digest", "b" * 63),