From 48f91850868dea86377d3e926ad0d9a45b5094dd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 22:15:25 -0700 Subject: [PATCH 01/80] test(hire): reject identity runtime subclasses --- .../test_hire_identity_runtime_integrity.py | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 services/people-api/tests/test_hire_identity_runtime_integrity.py diff --git a/services/people-api/tests/test_hire_identity_runtime_integrity.py b/services/people-api/tests/test_hire_identity_runtime_integrity.py new file mode 100644 index 000000000..88018ff9e --- /dev/null +++ b/services/people-api/tests/test_hire_identity_runtime_integrity.py @@ -0,0 +1,75 @@ +"""Runtime identity-integrity regressions for confirmed-hire contracts.""" + +from __future__ import annotations + +from datetime import date +from uuid import UUID + +import pytest + +from orgmetra_people_api.hire import HireAcceptanceCommand, HireAcceptanceResult + + +class _ForgedUUID(UUID): + """Attempt to make immutable hire evidence render a different identity.""" + + def __str__(self) -> str: + """Render a caller-chosen UUID instead of the underlying value.""" + return "0198a412-7000-7000-8000-ffffffffffff" + + +def _command(**overrides: object) -> HireAcceptanceCommand: + """Build one otherwise-valid confirmed-hire command.""" + values: dict[str, object] = { + "tenant_record_id": UUID("0198a412-7000-7000-8000-000000000001"), + "candidate_profile_id": UUID("0198a412-7000-7000-8000-000000000010"), + "selection_decision_id": UUID("0198a412-7000-7000-8000-000000000011"), + "person_record_id": UUID("0198a412-7000-7000-8000-000000000020"), + "person_name_record_id": UUID("0198a412-7000-7000-8000-000000000021"), + "employment_record_id": UUID("0198a412-7000-7000-8000-000000000030"), + "employment_record_version_id": UUID("0198a412-7000-7000-8000-000000000031"), + "candidate_worker_conversion_record_id": UUID("0198a412-7000-7000-8000-000000000040"), + "audit_event_record_id": UUID("0198a412-7000-7000-8000-000000000050"), + "outbox_delivery_record_id": UUID("0198a412-7000-7000-8000-000000000051"), + "effective_from": date(2026, 8, 21), + "display_name": "Ada Lovelace", + "idempotency_key": "hire-runtime-integrity-21", + "employment_status_code": "active", + } + values.update(overrides) + return HireAcceptanceCommand(**values) # type: ignore[arg-type] + + +@pytest.mark.parametrize( + "field_name", + [ + "tenant_record_id", + "candidate_profile_id", + "selection_decision_id", + "person_record_id", + "person_name_record_id", + "employment_record_id", + "employment_record_version_id", + "candidate_worker_conversion_record_id", + "audit_event_record_id", + "outbox_delivery_record_id", + ], +) +def test_hire_command_rejects_uuid_subclasses_before_idempotency_or_persistence( + field_name: str, +) -> None: + """Caller-controlled UUID rendering cannot rewrite confirmed-hire semantics.""" + forged = _ForgedUUID("0198a412-7000-7000-8000-000000000123") + with pytest.raises(ValueError, match=f"{field_name} must be an operational UUID"): + _command(**{field_name: forged}) + + +def test_hire_result_rejects_uuid_subclasses_before_crossing_service_boundary() -> None: + """A persistence adapter cannot return identity objects with forged rendering.""" + forged = _ForgedUUID("0198a412-7000-7000-8000-000000000123") + with pytest.raises(ValueError, match="person_record_id must be an operational UUID"): + HireAcceptanceResult( + person_record_id=forged, + employment_record_id=UUID("0198a412-7000-7000-8000-000000000030"), + candidate_worker_conversion_record_id=UUID("0198a412-7000-7000-8000-000000000040"), + ) From ef3f9959047a1516e75311aa8ded0b7d841c4ef7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 22:16:12 -0700 Subject: [PATCH 02/80] test(hire): reject validation-bypassing contract subclasses --- .../test_hire_identity_runtime_integrity.py | 120 +++++++++++++++++- 1 file changed, 115 insertions(+), 5 deletions(-) diff --git a/services/people-api/tests/test_hire_identity_runtime_integrity.py b/services/people-api/tests/test_hire_identity_runtime_integrity.py index 88018ff9e..1b3a44c23 100644 --- a/services/people-api/tests/test_hire_identity_runtime_integrity.py +++ b/services/people-api/tests/test_hire_identity_runtime_integrity.py @@ -7,7 +7,15 @@ import pytest -from orgmetra_people_api.hire import HireAcceptanceCommand, HireAcceptanceResult +from orgmetra_keyverse_adapter import PurposeBoundAccessPolicy +from orgmetra_people_api.auth import AuthenticatedPrincipal +from orgmetra_people_api.hire import ( + HireAcceptanceCommand, + HireAcceptanceResult, + accept_confirmed_hire, +) + +TENANT = UUID("0198a412-7000-7000-8000-000000000001") class _ForgedUUID(UUID): @@ -18,10 +26,24 @@ def __str__(self) -> str: return "0198a412-7000-7000-8000-ffffffffffff" -def _command(**overrides: object) -> HireAcceptanceCommand: - """Build one otherwise-valid confirmed-hire command.""" +class _UnvalidatedHireCommand(HireAcceptanceCommand): + """Attempt to bypass base dataclass validation through dynamic post-init dispatch.""" + + def __post_init__(self) -> None: + """Intentionally skip the governed base validation.""" + + +class _UnvalidatedHireResult(HireAcceptanceResult): + """Attempt to return malformed persistence evidence through a result subclass.""" + + def __post_init__(self) -> None: + """Intentionally skip the governed base validation.""" + + +def _command_values(**overrides: object) -> dict[str, object]: + """Return one otherwise-valid confirmed-hire command mapping.""" values: dict[str, object] = { - "tenant_record_id": UUID("0198a412-7000-7000-8000-000000000001"), + "tenant_record_id": TENANT, "candidate_profile_id": UUID("0198a412-7000-7000-8000-000000000010"), "selection_decision_id": UUID("0198a412-7000-7000-8000-000000000011"), "person_record_id": UUID("0198a412-7000-7000-8000-000000000020"), @@ -37,7 +59,64 @@ def _command(**overrides: object) -> HireAcceptanceCommand: "employment_status_code": "active", } values.update(overrides) - return HireAcceptanceCommand(**values) # type: ignore[arg-type] + return values + + +def _command(**overrides: object) -> HireAcceptanceCommand: + """Build one otherwise-valid confirmed-hire command.""" + return HireAcceptanceCommand(**_command_values(**overrides)) # type: ignore[arg-type] + + +def _principal() -> AuthenticatedPrincipal: + """Return a principal authorized for the focused application-boundary tests.""" + return AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-21", + granted_scope_codes=frozenset({"orgmetra.people.materialize_worker"}), + ) + + +def _policy() -> PurposeBoundAccessPolicy: + """Return the exact purpose-bound policy for confirmed-hire materialization.""" + return PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="people-hire-v1", + resource_kind="selection_decision", + purpose_code="candidate_hire", + operation_code="materialize_worker", + required_scope_code="orgmetra.people.materialize_worker", + permitted_fields=frozenset({"candidate_worker_conversion"}), + ) + + +class _RecordingPort: + """Capture whether malformed commands cross the governed application boundary.""" + + def __init__(self) -> None: + self.called = False + + def accept_hire(self, *, command: HireAcceptanceCommand, authorization: object) -> HireAcceptanceResult: + """Return a valid opaque result while recording the call.""" + del authorization + self.called = True + return HireAcceptanceResult( + person_record_id=command.person_record_id, + employment_record_id=command.employment_record_id, + candidate_worker_conversion_record_id=command.candidate_worker_conversion_record_id, + ) + + +class _MalformedResultPort: + """Return an invalid subclass that skipped the result contract's post-init checks.""" + + def accept_hire(self, *, command: HireAcceptanceCommand, authorization: object) -> HireAcceptanceResult: + """Produce malformed result evidence after a valid authorization call.""" + del command, authorization + return _UnvalidatedHireResult( + person_record_id="not-a-uuid", # type: ignore[arg-type] + employment_record_id=UUID("0198a412-7000-7000-8000-000000000030"), + candidate_worker_conversion_record_id=UUID("0198a412-7000-7000-8000-000000000040"), + ) @pytest.mark.parametrize( @@ -73,3 +152,34 @@ def test_hire_result_rejects_uuid_subclasses_before_crossing_service_boundary() employment_record_id=UUID("0198a412-7000-7000-8000-000000000030"), candidate_worker_conversion_record_id=UUID("0198a412-7000-7000-8000-000000000040"), ) + + +def test_confirmed_hire_rejects_command_subclass_that_bypassed_post_init() -> None: + """Only an exact validated command may cross into authoritative persistence.""" + forged = _UnvalidatedHireCommand( + **_command_values(effective_from="not-a-business-date") # type: ignore[arg-type] + ) + port = _RecordingPort() + + with pytest.raises(TypeError, match="command must be a HireAcceptanceCommand"): + accept_confirmed_hire( + principal=_principal(), + command=forged, + purpose_code="candidate_hire", + policy=_policy(), + mutation_port=port, + ) + + assert port.called is False + + +def test_confirmed_hire_rejects_result_subclass_that_bypassed_post_init() -> None: + """Only an exact validated result may leave the authoritative mutation boundary.""" + with pytest.raises(TypeError, match="mutation_port must return HireAcceptanceResult"): + accept_confirmed_hire( + principal=_principal(), + command=_command(), + purpose_code="candidate_hire", + policy=_policy(), + mutation_port=_MalformedResultPort(), + ) From a78edadd06ca604d5f60f54dd8fed4962465618e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 22:16:29 -0700 Subject: [PATCH 03/80] fix(hire): protect governed identity and contract runtime types --- services/people-api/src/orgmetra_people_api/hire.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/hire.py b/services/people-api/src/orgmetra_people_api/hire.py index 6823f4c59..407bd9870 100644 --- a/services/people-api/src/orgmetra_people_api/hire.py +++ b/services/people-api/src/orgmetra_people_api/hire.py @@ -35,8 +35,8 @@ class HireDecisionIntegrityError(RuntimeError): def _validate_operational_uuid(field_name: str, value: object) -> None: - """Require a real UUID outside Orgmetra's reserved protocol sentinels.""" - if not isinstance(value, UUID) or value.int in (0, _MAX_UUID_INT): + """Require an exact UUID outside Orgmetra's reserved protocol sentinels.""" + if type(value) is not UUID or value.int in (0, _MAX_UUID_INT): raise ValueError(f"{field_name} must be an operational UUID.") @@ -147,7 +147,7 @@ def accept_confirmed_hire( ``materialize_worker`` operation and ``candidate_worker_conversion`` field; possession of an identity token or purpose string alone is insufficient. """ - if not isinstance(command, HireAcceptanceCommand): + if type(command) is not HireAcceptanceCommand: raise TypeError("command must be a HireAcceptanceCommand") if not isinstance(mutation_port, HireAcceptancePort): raise TypeError("mutation_port must implement HireAcceptancePort") @@ -164,6 +164,6 @@ def accept_confirmed_hire( policy=policy, ) result = mutation_port.accept_hire(command=command, authorization=authorization) - if not isinstance(result, HireAcceptanceResult): + if type(result) is not HireAcceptanceResult: raise TypeError("mutation_port must return HireAcceptanceResult") return result From 15c3ffc3119ee7b103b5da434ef4a7b2b2c179fe Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 22:21:10 -0700 Subject: [PATCH 04/80] test(people): reject mutation runtime type confusion --- .../test_people_mutation_runtime_integrity.py | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_runtime_integrity.py diff --git a/services/people-api/tests/test_people_mutation_runtime_integrity.py b/services/people-api/tests/test_people_mutation_runtime_integrity.py new file mode 100644 index 000000000..2b40dc67f --- /dev/null +++ b/services/people-api/tests/test_people_mutation_runtime_integrity.py @@ -0,0 +1,236 @@ +"""Runtime-integrity regressions for authoritative People mutations.""" + +from __future__ import annotations + +from datetime import date +from decimal import Decimal +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision, PurposeBoundAccessPolicy +from orgmetra_people_api.auth import AuthenticatedPrincipal +from orgmetra_people_api.mutations import ( + AssignmentMutationCommand, + EmploymentMutationCommand, + EmploymentMutationResult, + command_route, + create_employment_record, + mutation_command_digest, +) + +TENANT = UUID("0198a412-8000-7000-8000-000000000001") +PERSON = UUID("0198a412-8000-7000-8000-000000000020") +EMPLOYMENT = UUID("0198a412-8000-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-8000-7000-8000-000000000031") +AUDIT_EVENT = UUID("0198a412-8000-7000-8000-000000000080") +OUTBOX = UUID("0198a412-8000-7000-8000-000000000081") + + +class _ForgedUUID(UUID): + """Attempt to rewrite mutation identity text during canonical digesting.""" + + def __str__(self) -> str: + """Render an identity different from the underlying UUID.""" + return "0198a412-8000-7000-8000-ffffffffffff" + + +class _ForgedDecimal(Decimal): + """Attempt to rewrite an assignment ratio during canonical digesting.""" + + def __format__(self, spec: str) -> str: + """Render a ratio different from the underlying Decimal value.""" + del spec + return "0.9999" + + +class _UnvalidatedEmploymentCommand(EmploymentMutationCommand): + """Attempt to bypass base command validation through post-init dispatch.""" + + def __post_init__(self) -> None: + """Intentionally skip the governed base validation.""" + + +class _UnvalidatedEmploymentResult(EmploymentMutationResult): + """Attempt to bypass persistence-result validation.""" + + def __post_init__(self) -> None: + """Intentionally skip the governed base validation.""" + + +def _employment_values(**overrides: object) -> dict[str, object]: + """Return one otherwise-valid employment mutation command mapping.""" + values: dict[str, object] = { + "tenant_record_id": TENANT, + "person_record_id": PERSON, + "employment_record_id": EMPLOYMENT, + "employment_record_version_id": EMPLOYMENT_VERSION, + "audit_event_record_id": AUDIT_EVENT, + "outbox_delivery_record_id": OUTBOX, + "employment_status_code": "active", + "employment_concurrency_code": "exclusive", + "effective_from": date(2026, 8, 21), + "confirmation_reference": "human_confirmation:runtime-21", + "evidence_version_code": "decision_evidence_set:v1", + "idempotency_key": "mutation-runtime-key-21", + } + values.update(overrides) + return values + + +def _employment(**overrides: object) -> EmploymentMutationCommand: + """Build one exact employment mutation command.""" + return EmploymentMutationCommand(**_employment_values(**overrides)) # type: ignore[arg-type] + + +def _assignment(**overrides: object) -> AssignmentMutationCommand: + """Build one exact assignment mutation command.""" + values: dict[str, object] = { + "tenant_record_id": TENANT, + "employment_record_id": EMPLOYMENT, + "person_record_id": PERSON, + "position_record_id": UUID("0198a412-8000-7000-8000-000000000040"), + "assignment_record_id": UUID("0198a412-8000-7000-8000-000000000070"), + "audit_event_record_id": AUDIT_EVENT, + "outbox_delivery_record_id": OUTBOX, + "allocation_ratio": Decimal("1.0000"), + "effective_from": date(2026, 8, 21), + "confirmation_reference": "human_confirmation:runtime-21", + "evidence_version_code": "decision_evidence_set:v1", + "idempotency_key": "mutation-runtime-key-21", + } + values.update(overrides) + return AssignmentMutationCommand(**values) # type: ignore[arg-type] + + +def _decision() -> AuthorizationDecision: + """Build one minimal exact authorization decision for digest testing.""" + return AuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-21", + resource_reference=f"employment_record:{EMPLOYMENT.hex}", + policy_version_code="people-mutation-v1", + purpose_code="workforce_admin", + operation_code="create_record", + resource_kind="employment_record", + requested_fields=frozenset({"employment_record"}), + authorized_fields=frozenset({"employment_record"}), + reason_code="access_permitted", + next_action="Continue with only the authorized fields.", + ) + + +def test_mutation_command_rejects_uuid_subclass_before_digest_or_persistence() -> None: + """Caller-controlled UUID rendering cannot rewrite People mutation identity.""" + forged = _ForgedUUID("0198a412-8000-7000-8000-000000000123") + with pytest.raises(ValueError, match="person_record_id must be an operational UUID"): + _employment(person_record_id=forged) + + +def test_mutation_result_rejects_uuid_subclass_before_service_return() -> None: + """Persistence cannot return an identity object with forged rendering.""" + forged = _ForgedUUID("0198a412-8000-7000-8000-000000000123") + with pytest.raises(ValueError, match="employment_record_id must be an operational UUID"): + EmploymentMutationResult(employment_record_id=forged) + + +def test_assignment_rejects_decimal_subclass_before_canonical_ratio_digest() -> None: + """Allocation evidence cannot invoke caller-controlled Decimal formatting.""" + forged = _ForgedDecimal("0.5000") + with pytest.raises(ValueError, match="allocation_ratio must be a Decimal"): + _assignment(allocation_ratio=forged) + + +def test_command_helpers_reject_validation_bypassing_subclasses() -> None: + """Routing and digest helpers require exact validated mutation commands.""" + forged = _UnvalidatedEmploymentCommand( + **_employment_values(person_record_id="not-a-uuid") # type: ignore[arg-type] + ) + with pytest.raises(TypeError, match="governed People mutation command"): + command_route(forged) + with pytest.raises(TypeError, match="governed People mutation command"): + mutation_command_digest(command=forged, authorization=_decision()) + + +def test_create_employment_rejects_command_subclass_before_authorization_or_port() -> None: + """A command that skipped post-init validation cannot reach the mutation port.""" + forged = _UnvalidatedEmploymentCommand( + **_employment_values(person_record_id="not-a-uuid") # type: ignore[arg-type] + ) + principal = AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-21", + granted_scope_codes=frozenset({"orgmetra.people.write"}), + ) + policy = PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="people-mutation-v1", + resource_kind="employment_record", + purpose_code="workforce_admin", + operation_code="create_record", + required_scope_code="orgmetra.people.write", + permitted_fields=frozenset({"employment_record"}), + ) + + class _Port: + def create_employment(self, *, command: EmploymentMutationCommand, authorization: object) -> EmploymentMutationResult: + del command, authorization + pytest.fail("validation-bypassing command reached persistence") + + def create_position(self, *, command: object, authorization: object) -> object: + del command, authorization + raise AssertionError + + def create_assignment(self, *, command: object, authorization: object) -> object: + del command, authorization + raise AssertionError + + with pytest.raises(TypeError, match="command must be an EmploymentMutationCommand"): + create_employment_record( + principal=principal, + command=forged, + purpose_code="workforce_admin", + policy=policy, + mutation_port=_Port(), # type: ignore[arg-type] + ) + + +def test_create_employment_rejects_result_subclass_that_skipped_validation() -> None: + """Malformed result subclasses cannot cross the authoritative mutation boundary.""" + principal = AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-21", + granted_scope_codes=frozenset({"orgmetra.people.write"}), + ) + policy = PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="people-mutation-v1", + resource_kind="employment_record", + purpose_code="workforce_admin", + operation_code="create_record", + required_scope_code="orgmetra.people.write", + permitted_fields=frozenset({"employment_record"}), + ) + + class _Port: + def create_employment(self, *, command: EmploymentMutationCommand, authorization: object) -> EmploymentMutationResult: + del command, authorization + return _UnvalidatedEmploymentResult(employment_record_id="not-a-uuid") # type: ignore[arg-type] + + def create_position(self, *, command: object, authorization: object) -> object: + del command, authorization + raise AssertionError + + def create_assignment(self, *, command: object, authorization: object) -> object: + del command, authorization + raise AssertionError + + with pytest.raises(TypeError, match="mutation_port must return EmploymentMutationResult"): + create_employment_record( + principal=principal, + command=_employment(), + purpose_code="workforce_admin", + policy=policy, + mutation_port=_Port(), # type: ignore[arg-type] + ) From 6f9db105ce36f97e0e5c1174066cbd133956bb61 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 22:21:34 -0700 Subject: [PATCH 05/80] test(people): reject idempotency evidence runtime confusion --- ...eople_mutation_digest_runtime_integrity.py | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_digest_runtime_integrity.py diff --git a/services/people-api/tests/test_people_mutation_digest_runtime_integrity.py b/services/people-api/tests/test_people_mutation_digest_runtime_integrity.py new file mode 100644 index 000000000..efb67db23 --- /dev/null +++ b/services/people-api/tests/test_people_mutation_digest_runtime_integrity.py @@ -0,0 +1,104 @@ +"""Runtime-integrity regressions for People mutation idempotency evidence.""" + +from __future__ import annotations + +from datetime import date +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision +from orgmetra_people_api.mutations import ( + EmploymentMutationCommand, + idempotency_record_id, + mutation_command_digest, +) + +TENANT = UUID("0198a412-8000-7000-8000-000000000001") + + +class _ForgedUUID(UUID): + """Attempt to select idempotency identity with caller-controlled string rendering.""" + + def __str__(self) -> str: + """Render another tenant identifier while retaining the original UUID value.""" + return "0198a412-8000-7000-8000-ffffffffffff" + + +class _ForgedDecision(AuthorizationDecision): + """Attempt to rewrite immutable authorization evidence during digest construction.""" + + def __getattribute__(self, name: str) -> object: + """Forge only the actor value observed by digest construction.""" + if name == "actor_reference": + return "keyverse_subject:forged-actor" + return super().__getattribute__(name) + + +def _command() -> EmploymentMutationCommand: + """Build one exact employment mutation command.""" + return EmploymentMutationCommand( + tenant_record_id=TENANT, + person_record_id=UUID("0198a412-8000-7000-8000-000000000020"), + employment_record_id=UUID("0198a412-8000-7000-8000-000000000030"), + employment_record_version_id=UUID("0198a412-8000-7000-8000-000000000031"), + audit_event_record_id=UUID("0198a412-8000-7000-8000-000000000080"), + outbox_delivery_record_id=UUID("0198a412-8000-7000-8000-000000000081"), + employment_status_code="active", + employment_concurrency_code="exclusive", + effective_from=date(2026, 8, 21), + confirmation_reference="human_confirmation:runtime-21", + evidence_version_code="decision_evidence_set:v1", + idempotency_key="mutation-runtime-key-21", + ) + + +def _decision() -> AuthorizationDecision: + """Build one exact authorized mutation decision.""" + employment_id = _command().employment_record_id + return AuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-21", + resource_reference=f"employment_record:{employment_id.hex}", + policy_version_code="people-mutation-v1", + purpose_code="workforce_admin", + operation_code="create_record", + resource_kind="employment_record", + requested_fields=frozenset({"employment_record"}), + authorized_fields=frozenset({"employment_record"}), + reason_code="access_permitted", + next_action="Continue with only the authorized fields.", + ) + + +def test_idempotency_record_id_rejects_uuid_subclass_before_tenant_key_derivation() -> None: + """Idempotency identity cannot be derived from caller-controlled tenant rendering.""" + forged = _ForgedUUID("0198a412-8000-7000-8000-000000000001") + with pytest.raises(ValueError, match="tenant_record_id must be an operational UUID"): + idempotency_record_id( + tenant_record_id=forged, + command_route_value="employment-records", + idempotency_key="mutation-runtime-key-21", + ) + + +def test_mutation_digest_rejects_authorization_decision_subclasses() -> None: + """Digest evidence must use the exact decision produced by the authorization adapter.""" + base = _decision() + forged = _ForgedDecision( + allowed=base.allowed, + tenant_record_id=base.tenant_record_id, + actor_reference=base.actor_reference, + resource_reference=base.resource_reference, + policy_version_code=base.policy_version_code, + purpose_code=base.purpose_code, + operation_code=base.operation_code, + resource_kind=base.resource_kind, + requested_fields=base.requested_fields, + authorized_fields=base.authorized_fields, + reason_code=base.reason_code, + next_action=base.next_action, + ) + with pytest.raises(TypeError, match="authorization must be an AuthorizationDecision"): + mutation_command_digest(command=_command(), authorization=forged) From e98cd1c745c815138b4d171fe1ea1eebf209a3d5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 20 Aug 2026 22:22:28 -0700 Subject: [PATCH 06/80] fix(people): protect mutation identity and idempotency runtime types --- .../src/orgmetra_people_api/mutations.py | 33 ++++++++++--------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index 6baeac684..bc8a6add9 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -47,8 +47,8 @@ class PeopleMutationIntegrityError(RuntimeError): def _validate_operational_uuid(field_name: str, value: object) -> None: - """Require a real UUID outside Orgmetra's reserved protocol sentinels.""" - if not isinstance(value, UUID) or value.int in (0, _MAX_UUID_INT): + """Require an exact UUID outside Orgmetra's reserved protocol sentinels.""" + if type(value) is not UUID or value.int in (0, _MAX_UUID_INT): raise ValueError(f"{field_name} must be an operational UUID.") @@ -83,11 +83,11 @@ def command_route( command: EmploymentMutationCommand | PositionMutationCommand | AssignmentMutationCommand, ) -> str: """Return the durable route that scopes one People mutation idempotency key.""" - if isinstance(command, EmploymentMutationCommand): + if type(command) is EmploymentMutationCommand: return "employment-records" - if isinstance(command, PositionMutationCommand): + if type(command) is PositionMutationCommand: return "position-records" - if isinstance(command, AssignmentMutationCommand): + if type(command) is AssignmentMutationCommand: return "assignment-records" raise TypeError("command must be a governed People mutation command") @@ -99,6 +99,7 @@ def idempotency_record_id( idempotency_key: str, ) -> UUID: """Derive a stable operational identity for one tenant/route/key binding.""" + _validate_operational_uuid("tenant_record_id", tenant_record_id) return uuid5( _IDEMPOTENCY_NAMESPACE, f"{tenant_record_id}:{command_route_value}:{idempotency_key}", @@ -115,9 +116,9 @@ def mutation_command_digest( Generated record identifiers are excluded so a retry that allocates fresh UUIDs still matches the first committed command. """ - if not isinstance(authorization, AuthorizationDecision): + if type(authorization) is not AuthorizationDecision: raise TypeError("authorization must be an AuthorizationDecision") - if isinstance(command, EmploymentMutationCommand): + if type(command) is EmploymentMutationCommand: route = "employment-records" semantic_command: dict[str, object] = { "confirmation_reference": command.confirmation_reference, @@ -127,7 +128,7 @@ def mutation_command_digest( "evidence_version_code": command.evidence_version_code, "person_record_id": str(command.person_record_id), } - elif isinstance(command, PositionMutationCommand): + elif type(command) is PositionMutationCommand: route = "position-records" semantic_command = { "confirmation_reference": command.confirmation_reference, @@ -137,7 +138,7 @@ def mutation_command_digest( "organization_unit_id": str(command.organization_unit_id), "position_status_code": command.position_status_code, } - elif isinstance(command, AssignmentMutationCommand): + elif type(command) is AssignmentMutationCommand: route = "assignment-records" semantic_command = { "allocation_ratio": _canonical_allocation_ratio(command.allocation_ratio), @@ -272,7 +273,7 @@ def __post_init__(self) -> None: _validate_operational_uuid(field_name, getattr(self, field_name)) if type(self.effective_from) is not date: raise ValueError("effective_from must be a business date.") - if not isinstance(self.allocation_ratio, Decimal): + if type(self.allocation_ratio) is not Decimal: raise ValueError("allocation_ratio must be a Decimal.") if not self.allocation_ratio.is_finite(): raise ValueError("allocation_ratio must be finite.") @@ -363,7 +364,7 @@ def create_employment_record( mutation_port: PeopleMutationPort, ) -> EmploymentMutationResult: """Authorize the exact employment target before persisting worker employment truth.""" - if not isinstance(command, EmploymentMutationCommand): + if type(command) is not EmploymentMutationCommand: raise TypeError("command must be an EmploymentMutationCommand") port = _require_port(mutation_port) authorization = authorize_resource_fields( @@ -378,7 +379,7 @@ def create_employment_record( policy=policy, ) result = port.create_employment(command=command, authorization=authorization) - if not isinstance(result, EmploymentMutationResult): + if type(result) is not EmploymentMutationResult: raise TypeError("mutation_port must return EmploymentMutationResult") return result @@ -392,7 +393,7 @@ def create_position_record( mutation_port: PeopleMutationPort, ) -> PositionMutationResult: """Authorize the exact position target before persisting a staffable seat.""" - if not isinstance(command, PositionMutationCommand): + if type(command) is not PositionMutationCommand: raise TypeError("command must be a PositionMutationCommand") port = _require_port(mutation_port) authorization = authorize_resource_fields( @@ -407,7 +408,7 @@ def create_position_record( policy=policy, ) result = port.create_position(command=command, authorization=authorization) - if not isinstance(result, PositionMutationResult): + if type(result) is not PositionMutationResult: raise TypeError("mutation_port must return PositionMutationResult") return result @@ -421,7 +422,7 @@ def create_assignment_record( mutation_port: PeopleMutationPort, ) -> AssignmentMutationResult: """Authorize the exact assignment target before persisting seat allocation.""" - if not isinstance(command, AssignmentMutationCommand): + if type(command) is not AssignmentMutationCommand: raise TypeError("command must be an AssignmentMutationCommand") port = _require_port(mutation_port) authorization = authorize_resource_fields( @@ -436,7 +437,7 @@ def create_assignment_record( policy=policy, ) result = port.create_assignment(command=command, authorization=authorization) - if not isinstance(result, AssignmentMutationResult): + if type(result) is not AssignmentMutationResult: raise TypeError("mutation_port must return AssignmentMutationResult") return result From ad38eb452ac1b072a146b5edf41a64a8e6553c78 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 17:32:10 -0700 Subject: [PATCH 07/80] test(people): reject forged hire authority runtime types --- ...stgres_hire_authority_runtime_integrity.py | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 services/people-api/tests/test_postgres_hire_authority_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_hire_authority_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_authority_runtime_integrity.py new file mode 100644 index 000000000..ff45c5232 --- /dev/null +++ b/services/people-api/tests/test_postgres_hire_authority_runtime_integrity.py @@ -0,0 +1,99 @@ +"""Adversarial runtime-integrity contracts for the PostgreSQL hire authority boundary.""" + +from __future__ import annotations + +from datetime import date +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision +from orgmetra_people_api.hire import HireAcceptanceCommand, HireDecisionIntegrityError +from orgmetra_people_api.postgres_hire import PostgresHireAcceptancePort + +TENANT = UUID("0198a412-7100-7000-8000-000000000001") +CANDIDATE = UUID("0198a412-7100-7000-8000-000000000010") +DECISION = UUID("0198a412-7100-7000-8000-000000000011") +PERSON = UUID("0198a412-7100-7000-8000-000000000020") +PERSON_NAME = UUID("0198a412-7100-7000-8000-000000000021") +EMPLOYMENT = UUID("0198a412-7100-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-7100-7000-8000-000000000031") +CONVERSION = UUID("0198a412-7100-7000-8000-000000000040") +AUDIT_EVENT = UUID("0198a412-7100-7000-8000-000000000050") +OUTBOX_DELIVERY = UUID("0198a412-7100-7000-8000-000000000051") +ACTOR = "keyverse_subject:operator-17" +PURPOSE = "candidate_hire" + + +class ForgedHireAcceptanceCommand(HireAcceptanceCommand): + """Represent a validation-bypassing caller-defined hire command subtype.""" + + +class ForgedAuthorizationDecision(AuthorizationDecision): + """Represent a caller-defined authorization subtype at a trust boundary.""" + + +def _command(command_type: type[HireAcceptanceCommand] = HireAcceptanceCommand) -> HireAcceptanceCommand: + """Build one deterministic valid hire command using the requested runtime type.""" + return command_type( + tenant_record_id=TENANT, + candidate_profile_id=CANDIDATE, + selection_decision_id=DECISION, + person_record_id=PERSON, + person_name_record_id=PERSON_NAME, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + candidate_worker_conversion_record_id=CONVERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX_DELIVERY, + effective_from=date(2026, 8, 18), + display_name="Ada Lovelace", + idempotency_key="hire-authority-runtime-integrity", + ) + + +def _authorization( + authorization_type: type[AuthorizationDecision] = AuthorizationDecision, +) -> AuthorizationDecision: + """Build one deterministic exact-scope allow decision using the requested runtime type.""" + return authorization_type( + allowed=True, + tenant_record_id=TENANT, + actor_reference=ACTOR, + resource_reference=f"selection_decision:{DECISION.hex}", + policy_version_code="people-hire-v1", + purpose_code=PURPOSE, + operation_code="materialize_worker", + resource_kind="selection_decision", + requested_fields=frozenset({"candidate_worker_conversion"}), + authorized_fields=frozenset({"candidate_worker_conversion"}), + reason_code="access_permitted", + next_action="continue", + ) + + +def _forbidden_connection_factory() -> object: + """Fail the regression if untrusted runtime input reaches database work.""" + raise AssertionError("database work must not begin for forged runtime authority objects") + + +def test_postgres_hire_port_rejects_command_subclass_before_database_work() -> None: + """Require the persistence authority to accept only the exact governed command type.""" + port = PostgresHireAcceptancePort(_forbidden_connection_factory) + + with pytest.raises(TypeError, match="command must be a HireAcceptanceCommand"): + port.accept_hire( + command=_command(ForgedHireAcceptanceCommand), + authorization=_authorization(), + ) + + +def test_postgres_hire_port_rejects_authorization_subclass_before_database_work() -> None: + """Require the persistence authority to accept only the exact governed authorization type.""" + port = PostgresHireAcceptancePort(_forbidden_connection_factory) + + with pytest.raises(HireDecisionIntegrityError, match="typed authorization decision"): + port.accept_hire( + command=_command(), + authorization=_authorization(ForgedAuthorizationDecision), + ) From 63eb051935df4291b2e423189503c0aec71b6ff1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 17:32:51 -0700 Subject: [PATCH 08/80] fix(people): require exact hire authority runtime types --- .../people-api/src/orgmetra_people_api/postgres_hire.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_hire.py b/services/people-api/src/orgmetra_people_api/postgres_hire.py index 4c328e02f..705caefe4 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_hire.py +++ b/services/people-api/src/orgmetra_people_api/postgres_hire.py @@ -176,7 +176,7 @@ def _is_aware_datetime(value: object) -> bool: def _validate_authorization(command: HireAcceptanceCommand, authorization: object) -> AuthorizationDecision: """Require an exact allow decision for this immutable selection decision.""" expected_reference = f"selection_decision:{command.selection_decision_id.hex}" - if not isinstance(authorization, AuthorizationDecision): + if type(authorization) is not AuthorizationDecision: raise HireDecisionIntegrityError("hire mutation requires a typed authorization decision") if ( not authorization.allowed @@ -304,7 +304,7 @@ def accept_hire( authority. Tenant/route/key advisory serialization prevents concurrent retries from racing the unique idempotency binding. """ - if not isinstance(command, HireAcceptanceCommand): + if type(command) is not HireAcceptanceCommand: raise TypeError("command must be a HireAcceptanceCommand") decision = _validate_authorization(command, authorization) @@ -453,4 +453,4 @@ def accept_hire( person_record_id=command.person_record_id, employment_record_id=command.employment_record_id, candidate_worker_conversion_record_id=command.candidate_worker_conversion_record_id, - ) + ) \ No newline at end of file From 27623490127834413c9ffd2dc900cb06e6ca00a6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 17:34:28 -0700 Subject: [PATCH 09/80] test(people): reject forged mutation authorization subtype --- ...utation_authorization_runtime_integrity.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 services/people-api/tests/test_postgres_mutation_authorization_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_mutation_authorization_runtime_integrity.py b/services/people-api/tests/test_postgres_mutation_authorization_runtime_integrity.py new file mode 100644 index 000000000..0273614cb --- /dev/null +++ b/services/people-api/tests/test_postgres_mutation_authorization_runtime_integrity.py @@ -0,0 +1,48 @@ +"""Adversarial runtime-integrity contract for PostgreSQL People mutation authorization.""" + +from __future__ import annotations + +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision +from orgmetra_people_api.postgres_mutations import ( + PeopleMutationIntegrityError, + _require_authorization, +) + +TENANT = UUID("0198a412-7100-7000-8000-000000000001") +RESOURCE = "employment_record:0198a412710070008000000000000030" +FIELDS = frozenset({"employment_record"}) + + +class ForgedAuthorizationDecision(AuthorizationDecision): + """Represent a validation-bypassing caller-defined authorization subtype.""" + + +def test_postgres_people_mutation_rejects_authorization_subclass() -> None: + """Require persistence authorization to use the exact governed decision runtime type.""" + forged = ForgedAuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-17", + resource_reference=RESOURCE, + policy_version_code="people-employment-v1", + purpose_code="workforce_admin", + operation_code="create_record", + resource_kind="employment_record", + requested_fields=FIELDS, + authorized_fields=FIELDS, + reason_code="access_permitted", + next_action="continue", + ) + + with pytest.raises(PeopleMutationIntegrityError, match="typed authorization decision"): + _require_authorization( + authorization=forged, + tenant_record_id=TENANT, + resource_reference=RESOURCE, + resource_kind="employment_record", + requested_fields=FIELDS, + ) From 76cb5b0d963ce5c2d273f23f8dce01444a38499a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 17:36:01 -0700 Subject: [PATCH 10/80] fix(people): require exact mutation authorization type --- .../people-api/src/orgmetra_people_api/postgres_mutations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index d94832cf8..1bfb9b086 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -322,7 +322,7 @@ def _require_authorization( requested_fields: frozenset[str], ) -> AuthorizationDecision: """Require an exact allow decision for the intended mutation target.""" - if not isinstance(authorization, AuthorizationDecision): + if type(authorization) is not AuthorizationDecision: raise PeopleMutationIntegrityError("people mutation requires a typed authorization decision") if ( not authorization.allowed From e859d208766463be243dd84443a615fbc2c83da1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 17:40:12 -0700 Subject: [PATCH 11/80] test(people): reject forged mutation command subtypes --- ...gres_mutation_command_runtime_integrity.py | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 services/people-api/tests/test_postgres_mutation_command_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_mutation_command_runtime_integrity.py b/services/people-api/tests/test_postgres_mutation_command_runtime_integrity.py new file mode 100644 index 000000000..9ba409249 --- /dev/null +++ b/services/people-api/tests/test_postgres_mutation_command_runtime_integrity.py @@ -0,0 +1,140 @@ +"""Adversarial runtime-integrity contracts for PostgreSQL People mutation commands.""" + +from __future__ import annotations + +from datetime import date +from decimal import Decimal +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision +from orgmetra_people_api.mutations import ( + AssignmentMutationCommand, + EmploymentMutationCommand, + PositionMutationCommand, +) +from orgmetra_people_api.postgres_mutations import PostgresPeopleMutationPort + +TENANT = UUID("0198a412-7100-7000-8000-000000000001") +PERSON = UUID("0198a412-7100-7000-8000-000000000020") +EMPLOYMENT = UUID("0198a412-7100-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-7100-7000-8000-000000000031") +ORGANIZATION = UUID("0198a412-7100-7000-8000-000000000040") +JOB = UUID("0198a412-7100-7000-8000-000000000041") +POSITION = UUID("0198a412-7100-7000-8000-000000000050") +POSITION_VERSION = UUID("0198a412-7100-7000-8000-000000000051") +ASSIGNMENT = UUID("0198a412-7100-7000-8000-000000000060") +AUDIT = UUID("0198a412-7100-7000-8000-000000000070") +OUTBOX = UUID("0198a412-7100-7000-8000-000000000071") + + +class ForgedEmploymentMutationCommand(EmploymentMutationCommand): + """Represent a validation-bypassing caller-defined employment command subtype.""" + + +class ForgedPositionMutationCommand(PositionMutationCommand): + """Represent a validation-bypassing caller-defined position command subtype.""" + + +class ForgedAssignmentMutationCommand(AssignmentMutationCommand): + """Represent a validation-bypassing caller-defined assignment command subtype.""" + + +def _authorization(resource_kind: str, record_id: UUID) -> AuthorizationDecision: + """Build one exact-scope allow decision for a People mutation target.""" + fields = frozenset({resource_kind}) + return AuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-17", + resource_reference=f"{resource_kind}:{record_id.hex}", + policy_version_code="people-mutation-v1", + purpose_code="workforce_admin", + operation_code="create_record", + resource_kind=resource_kind, + requested_fields=fields, + authorized_fields=fields, + reason_code="access_permitted", + next_action="continue", + ) + + +def _forbidden_connection_factory() -> object: + """Fail if a forged command crosses the persistence authority into database work.""" + raise AssertionError("database work must not begin for a forged People mutation command") + + +def test_postgres_employment_port_rejects_command_subclass_before_database_work() -> None: + """Require the employment persistence authority to accept only its exact command type.""" + command = ForgedEmploymentMutationCommand( + tenant_record_id=TENANT, + person_record_id=PERSON, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + audit_event_record_id=AUDIT, + outbox_delivery_record_id=OUTBOX, + employment_status_code="active", + employment_concurrency_code="exclusive", + effective_from=date(2026, 8, 22), + confirmation_reference="human_confirmation:employment-1", + evidence_version_code="employment-evidence-v1", + idempotency_key="employment-runtime-guard", + ) + port = PostgresPeopleMutationPort(_forbidden_connection_factory) + + with pytest.raises(TypeError, match="command must be an EmploymentMutationCommand"): + port.create_employment( + command=command, + authorization=_authorization("employment_record", EMPLOYMENT), + ) + + +def test_postgres_position_port_rejects_command_subclass_before_database_work() -> None: + """Require the position persistence authority to accept only its exact command type.""" + command = ForgedPositionMutationCommand( + tenant_record_id=TENANT, + organization_unit_id=ORGANIZATION, + job_profile_id=JOB, + position_record_id=POSITION, + position_record_version_id=POSITION_VERSION, + audit_event_record_id=AUDIT, + outbox_delivery_record_id=OUTBOX, + position_status_code="open", + effective_from=date(2026, 8, 22), + confirmation_reference="human_confirmation:position-1", + evidence_version_code="position-evidence-v1", + idempotency_key="position-runtime-guard", + ) + port = PostgresPeopleMutationPort(_forbidden_connection_factory) + + with pytest.raises(TypeError, match="command must be a PositionMutationCommand"): + port.create_position( + command=command, + authorization=_authorization("position_record", POSITION), + ) + + +def test_postgres_assignment_port_rejects_command_subclass_before_database_work() -> None: + """Require the assignment persistence authority to accept only its exact command type.""" + command = ForgedAssignmentMutationCommand( + tenant_record_id=TENANT, + employment_record_id=EMPLOYMENT, + person_record_id=PERSON, + position_record_id=POSITION, + assignment_record_id=ASSIGNMENT, + audit_event_record_id=AUDIT, + outbox_delivery_record_id=OUTBOX, + allocation_ratio=Decimal("1.0000"), + effective_from=date(2026, 8, 22), + confirmation_reference="human_confirmation:assignment-1", + evidence_version_code="assignment-evidence-v1", + idempotency_key="assignment-runtime-guard", + ) + port = PostgresPeopleMutationPort(_forbidden_connection_factory) + + with pytest.raises(TypeError, match="command must be an AssignmentMutationCommand"): + port.create_assignment( + command=command, + authorization=_authorization("assignment_record", ASSIGNMENT), + ) From 0196bf545b6254a410c99be80216ac977a706683 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 17:42:13 -0700 Subject: [PATCH 12/80] fix(people): require exact mutation command runtime types --- .../src/orgmetra_people_api/postgres_mutations.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index 1bfb9b086..63e01d086 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -534,7 +534,7 @@ def create_employment( authorization: AuthorizationDecision, ) -> EmploymentMutationResult: """Persist one employment after conversion and exclusivity checks.""" - if not isinstance(command, EmploymentMutationCommand): + if type(command) is not EmploymentMutationCommand: raise TypeError("command must be an EmploymentMutationCommand") decision = _require_authorization( authorization=authorization, @@ -637,7 +637,7 @@ def create_position( authorization: AuthorizationDecision, ) -> PositionMutationResult: """Persist one position after organization and job parent checks.""" - if not isinstance(command, PositionMutationCommand): + if type(command) is not PositionMutationCommand: raise TypeError("command must be a PositionMutationCommand") decision = _require_authorization( authorization=authorization, @@ -727,7 +727,7 @@ def create_assignment( authorization: AuthorizationDecision, ) -> AssignmentMutationResult: """Persist one assignment after conversion and kernel coverage checks.""" - if not isinstance(command, AssignmentMutationCommand): + if type(command) is not AssignmentMutationCommand: raise TypeError("command must be an AssignmentMutationCommand") decision = _require_authorization( authorization=authorization, From be156d88b41e53887cdc07a26c4f9fc51591699b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 18:04:39 -0700 Subject: [PATCH 13/80] test(people): reject forged mutation text evidence --- ..._people_mutation_text_runtime_integrity.py | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_text_runtime_integrity.py diff --git a/services/people-api/tests/test_people_mutation_text_runtime_integrity.py b/services/people-api/tests/test_people_mutation_text_runtime_integrity.py new file mode 100644 index 000000000..83afdcb66 --- /dev/null +++ b/services/people-api/tests/test_people_mutation_text_runtime_integrity.py @@ -0,0 +1,180 @@ +"""Reject caller-controlled text subclasses at authoritative People write boundaries.""" + +from __future__ import annotations + +from datetime import date +from uuid import UUID + +import pytest + +from orgmetra_people_api.hire import HireAcceptanceCommand +from orgmetra_people_api.mutations import EmploymentMutationCommand, PositionMutationCommand + +TENANT = UUID("0198a412-8000-7000-8000-000000000101") +PERSON = UUID("0198a412-8000-7000-8000-000000000102") +CANDIDATE = UUID("0198a412-8000-7000-8000-000000000103") +SELECTION_DECISION = UUID("0198a412-8000-7000-8000-000000000104") +EMPLOYMENT = UUID("0198a412-8000-7000-8000-000000000105") +EMPLOYMENT_VERSION = UUID("0198a412-8000-7000-8000-000000000106") +ORGANIZATION = UUID("0198a412-8000-7000-8000-000000000107") +JOB = UUID("0198a412-8000-7000-8000-000000000108") +POSITION = UUID("0198a412-8000-7000-8000-000000000109") +POSITION_VERSION = UUID("0198a412-8000-7000-8000-00000000010a") +PERSON_NAME = UUID("0198a412-8000-7000-8000-00000000010b") +CONVERSION = UUID("0198a412-8000-7000-8000-00000000010c") +AUDIT = UUID("0198a412-8000-7000-8000-00000000010d") +OUTBOX = UUID("0198a412-8000-7000-8000-00000000010e") + + +class _ForgedClosedCode(str): + """Present unsafe underlying text as the reviewed ``active`` status.""" + + def __hash__(self) -> int: + """Collide with the reviewed status during set lookup.""" + return hash("active") + + def __eq__(self, other: object) -> bool: + """Claim equality with the reviewed status while retaining unsafe text.""" + return other == "active" + + def __ne__(self, other: object) -> bool: + """Keep inequality consistent with the forged equality result.""" + return not self.__eq__(other) + + +class _ForgedConcurrencyCode(str): + """Present unsafe underlying text as the reviewed ``exclusive`` code.""" + + def __hash__(self) -> int: + """Collide with the reviewed concurrency code during set lookup.""" + return hash("exclusive") + + def __eq__(self, other: object) -> bool: + """Claim equality with the reviewed concurrency code.""" + return other == "exclusive" + + def __ne__(self, other: object) -> bool: + """Keep inequality consistent with the forged equality result.""" + return not self.__eq__(other) + + +class _ForgedIdempotencyKey(str): + """Hide an unsafe underlying key from length and character validation.""" + + def __len__(self) -> int: + """Pretend the key satisfies the governed length contract.""" + return 20 + + def __iter__(self): + """Yield only visible ASCII while retaining unsafe underlying text.""" + return iter("A" * 20) + + +class _ForgedDisplayName(str): + """Hide control-character PII from the mutable Person-name validation path.""" + + def encode(self, *args: object, **kwargs: object) -> bytes: + """Pretend the underlying text encodes as a harmless display name.""" + del args, kwargs + return b"Alice" + + def strip(self, *args: object, **kwargs: object) -> str: + """Pretend the underlying text contains usable non-whitespace content.""" + del args, kwargs + return "Alice" + + def __len__(self) -> int: + """Pretend the underlying text satisfies the bounded PII length.""" + return 5 + + def __iter__(self): + """Hide the underlying control character from character validation.""" + return iter("Alice") + + +def _employment(**overrides: object) -> EmploymentMutationCommand: + """Build one otherwise-valid high-impact employment mutation command.""" + values: dict[str, object] = { + "tenant_record_id": TENANT, + "person_record_id": PERSON, + "employment_record_id": EMPLOYMENT, + "employment_record_version_id": EMPLOYMENT_VERSION, + "audit_event_record_id": AUDIT, + "outbox_delivery_record_id": OUTBOX, + "employment_status_code": "active", + "employment_concurrency_code": "exclusive", + "effective_from": date(2026, 8, 22), + "confirmation_reference": "human_confirmation:text-runtime-22", + "evidence_version_code": "decision_evidence_set:v1", + "idempotency_key": "people-text-runtime-key-22", + } + values.update(overrides) + return EmploymentMutationCommand(**values) # type: ignore[arg-type] + + +def _position(**overrides: object) -> PositionMutationCommand: + """Build one otherwise-valid position mutation command.""" + values: dict[str, object] = { + "tenant_record_id": TENANT, + "organization_unit_id": ORGANIZATION, + "job_profile_id": JOB, + "position_record_id": POSITION, + "position_record_version_id": POSITION_VERSION, + "audit_event_record_id": AUDIT, + "outbox_delivery_record_id": OUTBOX, + "position_status_code": "active", + "effective_from": date(2026, 8, 22), + "confirmation_reference": "human_confirmation:text-runtime-22", + "evidence_version_code": "position_evidence:v1", + "idempotency_key": "position-text-runtime-key-22", + } + values.update(overrides) + return PositionMutationCommand(**values) # type: ignore[arg-type] + + +def _hire(**overrides: object) -> HireAcceptanceCommand: + """Build one otherwise-valid confirmed-hire command.""" + values: dict[str, object] = { + "tenant_record_id": TENANT, + "candidate_profile_id": CANDIDATE, + "selection_decision_id": SELECTION_DECISION, + "person_record_id": PERSON, + "person_name_record_id": PERSON_NAME, + "employment_record_id": EMPLOYMENT, + "employment_record_version_id": EMPLOYMENT_VERSION, + "candidate_worker_conversion_record_id": CONVERSION, + "audit_event_record_id": AUDIT, + "outbox_delivery_record_id": OUTBOX, + "effective_from": date(2026, 8, 22), + "display_name": "Alice Example", + "idempotency_key": "hire-text-runtime-key-22", + "employment_status_code": "active", + } + values.update(overrides) + return HireAcceptanceCommand(**values) # type: ignore[arg-type] + + +def test_rejects_status_string_subclass_that_forges_allow_list_membership() -> None: + """Canonical employment status text must be the exact value that was reviewed.""" + with pytest.raises(ValueError, match="employment_status_code"): + _employment(employment_status_code=_ForgedClosedCode("model_decided")) + with pytest.raises(ValueError, match="position_status_code"): + _position(position_status_code=_ForgedClosedCode("model_decided")) + + +def test_rejects_concurrency_string_subclass_that_forges_allow_list_membership() -> None: + """Concurrency evidence cannot substitute caller-defined equality semantics.""" + with pytest.raises(ValueError, match="employment_concurrency_code"): + _employment(employment_concurrency_code=_ForgedConcurrencyCode("shadow_parallel")) + + +def test_rejects_idempotency_string_subclass_that_forges_scalar_validation() -> None: + """Idempotency identity must bind the exact validated visible-ASCII text.""" + with pytest.raises(ValueError, match="idempotency_key"): + _employment(idempotency_key=_ForgedIdempotencyKey("\n")) + + +def test_rejects_display_name_string_subclass_before_person_pii_persistence() -> None: + """Necessary Person-name PII cannot hide control text behind overridden methods.""" + with pytest.raises(ValueError, match="display_name"): + _hire(display_name=_ForgedDisplayName("\n")) From 1967d7b85e13d9888f28982db194fe4edf89b8d2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 18:06:11 -0700 Subject: [PATCH 14/80] fix(people): require exact hire display-name text --- services/people-api/src/orgmetra_people_api/hire.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/hire.py b/services/people-api/src/orgmetra_people_api/hire.py index 407bd9870..e85a6dcc9 100644 --- a/services/people-api/src/orgmetra_people_api/hire.py +++ b/services/people-api/src/orgmetra_people_api/hire.py @@ -83,7 +83,7 @@ def __post_init__(self) -> None: _validate_operational_uuid(field_name, getattr(self, field_name)) if type(self.effective_from) is not date: raise ValueError("effective_from must be a business date.") - if not isinstance(self.display_name, str): + if type(self.display_name) is not str: raise ValueError("display_name must be a string.") try: self.display_name.encode("utf-8") From 23fc4f4ddc44d2561c4e7eae7dc1c34b0929c571 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 18:06:50 -0700 Subject: [PATCH 15/80] fix(people): require exact governed mutation text --- .../people-api/src/orgmetra_people_api/mutations.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index bc8a6add9..40a5ecadc 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -66,7 +66,7 @@ def _validate_evidence_version(value: object) -> None: def validate_idempotency_key(value: object) -> str: """Require the same visible-ASCII Idempotency-Key contract as the HTTP boundary.""" - if not isinstance(value, str) or not (_IDEMPOTENCY_MIN <= len(value) <= _IDEMPOTENCY_MAX): + if type(value) is not str or not (_IDEMPOTENCY_MIN <= len(value) <= _IDEMPOTENCY_MAX): raise ValueError("idempotency_key must be 16 to 200 visible ASCII characters.") if any(ord(character) < 0x21 or ord(character) > 0x7E for character in value): raise ValueError("idempotency_key must be 16 to 200 visible ASCII characters.") @@ -192,10 +192,10 @@ def __post_init__(self) -> None: _validate_operational_uuid(field_name, getattr(self, field_name)) if type(self.effective_from) is not date: raise ValueError("effective_from must be a business date.") - if not isinstance(self.employment_status_code, str) or self.employment_status_code not in _EMPLOYMENT_STATUSES: + if type(self.employment_status_code) is not str or self.employment_status_code not in _EMPLOYMENT_STATUSES: raise ValueError("employment_status_code must be active, leave, or terminated.") if ( - not isinstance(self.employment_concurrency_code, str) + type(self.employment_concurrency_code) is not str or self.employment_concurrency_code not in _CONCURRENCY_CODES ): raise ValueError("employment_concurrency_code must be exclusive or concurrent.") @@ -235,7 +235,7 @@ def __post_init__(self) -> None: _validate_operational_uuid(field_name, getattr(self, field_name)) if type(self.effective_from) is not date: raise ValueError("effective_from must be a business date.") - if not isinstance(self.position_status_code, str) or self.position_status_code not in _POSITION_STATUSES: + if type(self.position_status_code) is not str or self.position_status_code not in _POSITION_STATUSES: raise ValueError("position_status_code must be a staffable or closed seat status.") _validate_confirmation(self.confirmation_reference) _validate_evidence_version(self.evidence_version_code) @@ -446,4 +446,4 @@ def parse_allocation_ratio(raw_value: object) -> Decimal: """Parse the OpenAPI allocation token into an exact four-decimal ratio.""" if not isinstance(raw_value, str) or re.fullmatch(r"^(0\.[0-9]{4}|1\.0000)$", raw_value) is None: raise ValueError("allocation_ratio must match 0.0001-1.0000 four-decimal form.") - return Decimal(raw_value) + return Decimal(raw_value) \ No newline at end of file From c397053ba62dfaf4dd84d6b3d581fccb756e55bb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 28 Aug 2026 19:01:55 +0900 Subject: [PATCH 16/80] fix(people): close remaining governed text gaps --- CHANGELOG.md | 1 + manifest.json | 2 +- .../src/orgmetra_people_api/hire.py | 2 +- .../src/orgmetra_people_api/mutations.py | 6 +++--- ..._people_mutation_text_runtime_integrity.py | 20 +++++++++++++++++++ 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 99f4752d7..8646658c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ All notable changes to Orgmetra will be documented in this file. - Made assignment coverage status-aware: `active` and `leave` remain staffable while `terminated` and other non-eligible employment statuses fail closed. - Made organization hierarchy reconstruction fail closed on a cycle at the requested tenant, effective day, and knowledge cutoff while ignoring future-recorded and foreign-tenant facts. - Build the outbox due-work index concurrently during migration 0008, requiring that index step to run outside an explicit transaction block so established queues do not block writers while the index is built; pre-index hardening and post-index privileged role setup use separate explicit transactions. +- Active-PR People mutation commands now require exact built-in governance text and hire status values before digesting or persisting high-impact employment evidence. ### Security diff --git a/manifest.json b/manifest.json index 97f2bab14..7234d93d9 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1 @@ -{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"32cc4ef78d1eca557fa01731026840be01211a043eb0ada552e4e6cb9eace353","bytes":17295,"lines":76},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} +{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"d5e14a326a99cc450114c3502a1adf0b4515667005de20f276eaefb0093b5715","bytes":17462,"lines":77},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} diff --git a/services/people-api/src/orgmetra_people_api/hire.py b/services/people-api/src/orgmetra_people_api/hire.py index e85a6dcc9..0d8bbbd7e 100644 --- a/services/people-api/src/orgmetra_people_api/hire.py +++ b/services/people-api/src/orgmetra_people_api/hire.py @@ -95,7 +95,7 @@ def __post_init__(self) -> None: raise ValueError("display_name must not contain control characters.") validate_idempotency_key(self.idempotency_key) if ( - not isinstance(self.employment_status_code, str) + type(self.employment_status_code) is not str or _STATUS_CODE_PATTERN.fullmatch(self.employment_status_code) is None ): raise ValueError("employment_status_code must be a lower snake_case code.") diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index 40a5ecadc..ada1c59aa 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -54,13 +54,13 @@ def _validate_operational_uuid(field_name: str, value: object) -> None: def _validate_confirmation(value: object) -> None: """Require one namespaced human-confirmation reference.""" - if not isinstance(value, str) or _REFERENCE_PATTERN.fullmatch(value) is None: + if type(value) is not str or _REFERENCE_PATTERN.fullmatch(value) is None: raise ValueError("confirmation_reference must be a namespaced opaque reference.") def _validate_evidence_version(value: object) -> None: """Require one whitespace-free evidence version token.""" - if not isinstance(value, str) or _VERSION_PATTERN.fullmatch(value) is None: + if type(value) is not str or _VERSION_PATTERN.fullmatch(value) is None: raise ValueError("evidence_version_code must be a whitespace-free version token.") @@ -446,4 +446,4 @@ def parse_allocation_ratio(raw_value: object) -> Decimal: """Parse the OpenAPI allocation token into an exact four-decimal ratio.""" if not isinstance(raw_value, str) or re.fullmatch(r"^(0\.[0-9]{4}|1\.0000)$", raw_value) is None: raise ValueError("allocation_ratio must match 0.0001-1.0000 four-decimal form.") - return Decimal(raw_value) \ No newline at end of file + return Decimal(raw_value) diff --git a/services/people-api/tests/test_people_mutation_text_runtime_integrity.py b/services/people-api/tests/test_people_mutation_text_runtime_integrity.py index 83afdcb66..2b0bad992 100644 --- a/services/people-api/tests/test_people_mutation_text_runtime_integrity.py +++ b/services/people-api/tests/test_people_mutation_text_runtime_integrity.py @@ -92,6 +92,14 @@ def __iter__(self): return iter("Alice") +class _ForgedGovernanceText(str): + """Present reviewed governance text with caller-defined rendering semantics.""" + + def __str__(self) -> str: + """Render a different value if canonical evidence later formats the field.""" + return "caller_defined_governance_text" + + def _employment(**overrides: object) -> EmploymentMutationCommand: """Build one otherwise-valid high-impact employment mutation command.""" values: dict[str, object] = { @@ -160,6 +168,8 @@ def test_rejects_status_string_subclass_that_forges_allow_list_membership() -> N _employment(employment_status_code=_ForgedClosedCode("model_decided")) with pytest.raises(ValueError, match="position_status_code"): _position(position_status_code=_ForgedClosedCode("model_decided")) + with pytest.raises(ValueError, match="employment_status_code"): + _hire(employment_status_code=_ForgedClosedCode("model_decided")) def test_rejects_concurrency_string_subclass_that_forges_allow_list_membership() -> None: @@ -178,3 +188,13 @@ def test_rejects_display_name_string_subclass_before_person_pii_persistence() -> """Necessary Person-name PII cannot hide control text behind overridden methods.""" with pytest.raises(ValueError, match="display_name"): _hire(display_name=_ForgedDisplayName("\n")) + + +def test_rejects_governance_text_subclasses_before_digest_or_persistence() -> None: + """Confirmation and evidence text must retain the exact reviewed runtime value.""" + with pytest.raises(ValueError, match="confirmation_reference"): + _employment( + confirmation_reference=_ForgedGovernanceText("human_confirmation:text-runtime-22") + ) + with pytest.raises(ValueError, match="evidence_version_code"): + _position(evidence_version_code=_ForgedGovernanceText("position_evidence:v1")) From 399010c5ce2480e13ee43c4f9ff233f96d23c247 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 23:21:32 +0900 Subject: [PATCH 17/80] merge(people): preserve #161 changelog delta after restack --- CHANGELOG.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8646658c1..98d5b3e55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ All notable changes to Orgmetra will be documented in this file. - `employment_record_version.employment_concurrency_code` constrained to `exclusive` or `concurrent`. - ADR 0005 for exclusive employment and staffable seats. - `orgmetra_hris_kernel` 0.3.0 with identity-scoped bitemporal resolution, assignment-employment coverage, allocation-portfolio checks, and a Memorial Hospital RN correction case at 100% statement and branch coverage. -- `employment_record_version` and `position_record_version` so employment and position identity stay stable across retroactive corrections. +- `employment_record_version` and `position_record_version` so corrections no longer mint a new employment or position identifier. - `assignment_record.employment_record_id` bound to the same person as the covering employment. - `orgmetra_keyverse_adapter` that binds an opaque Keyverse subject to a person and rejects passwords, passkeys, and tokens. - Design tokens for the repeating HR actions: approve, review, correct, request evidence, compare, export, and escalate. @@ -37,6 +37,7 @@ All notable changes to Orgmetra will be documented in this file. ### Changed +- Consolidated repository-owned PR validation from twelve workflows into one Foundation CI job, while keeping the dual-cluster recovery rehearsal separately path-scoped. Central required review and security workflows remain organization-owned. - New predictive-validity membership must use one normalized worker-level case; the three independent validity-study decision/evidence/outcome link relations are historical read surfaces only and can no longer accept new rows. A case insert also rejects a criterion observation whose recorded interval is already closed at `linked_at`. - Canonicalized service identifiers as two-or-more-word `snake_case` across architecture, deployment, ACL, metrics, and client contracts. - Separated fast-mlsirm, TEPP, and Psychometrics Commons into immutable external scientific contracts. From 19685924a16d7b7bae80f23d55fde04c6a3acd27 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 23:23:52 +0900 Subject: [PATCH 18/80] fix(ci): reseal People manifest after protected restack --- manifest.json | 476 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 475 insertions(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 7234d93d9..956e51d26 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1,475 @@ -{"package":"orgmetra-foundation-pack","version":"0.1.0","generated_for_branch":"feat/audit-outbox-envelope","files":[{"path":".github/workflows/foundation-ci.yml","sha256":"12686a3bbd6445e6fdb202b4137dae118ddeeab1efb0c7f18ea6c8fa19d62537","bytes":4379,"lines":123},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"352dc78931dd94afea3e88912d38dcc4b562a004112f199f3d7a12d22b6d637a","bytes":4159,"lines":105},{"path":".gitignore","sha256":"145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21","bytes":375,"lines":37},{"path":"AGENTS.md","sha256":"28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16","bytes":2246,"lines":34},{"path":"ARCHITECTURE.md","sha256":"52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850","bytes":7864,"lines":107},{"path":"CHANGELOG.md","sha256":"d5e14a326a99cc450114c3502a1adf0b4515667005de20f276eaefb0093b5715","bytes":17462,"lines":77},{"path":"CLAUDE.md","sha256":"add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f","bytes":1229,"lines":20},{"path":"LICENSE","sha256":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","bytes":11358,"lines":202},{"path":"NOTICE","sha256":"34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042","bytes":305,"lines":4},{"path":"README.md","sha256":"1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6","bytes":3785,"lines":81},{"path":"database/migrations/0001_foundation_schema.sql","sha256":"ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd","bytes":38747,"lines":916},{"path":"database/migrations/0002_sealed_evidence_digest.sql","sha256":"93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c","bytes":6649,"lines":202},{"path":"database/migrations/0003_audit_outbox_persistence.sql","sha256":"2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc","bytes":15417,"lines":423},{"path":"database/migrations/0004_outbox_delivery_claim.sql","sha256":"d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef","bytes":9451,"lines":234},{"path":"database/migrations/0005_outbox_delivery_finalization.sql","sha256":"b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961","bytes":6125,"lines":170},{"path":"database/migrations/0006_outbox_delivery_dead_letter.sql","sha256":"c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7","bytes":24919,"lines":628},{"path":"database/migrations/0007_outbox_retry_exhaustion.sql","sha256":"812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5","bytes":19081,"lines":476},{"path":"database/migrations/0008_audit_outbox_review_hardening.sql","sha256":"c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b","bytes":17562,"lines":448},{"path":"database/migrations/0009_candidate_worker_conversion_governance.sql","sha256":"4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9","bytes":11537,"lines":281},{"path":"database/migrations/0010_validity_study_case_integrity.sql","sha256":"3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1","bytes":11979,"lines":313},{"path":"database/migrations/0011_criterion_observation_scope.sql","sha256":"f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9","bytes":7444,"lines":165},{"path":"database/migrations/0012_people_mutation_idempotency.sql","sha256":"52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69","bytes":3162,"lines":76},{"path":"database/migrations/0013_job_analysis_snapshot.sql","sha256":"b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee","bytes":12713,"lines":260},{"path":"docs/API_CONTRACT.md","sha256":"63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589","bytes":4555,"lines":76},{"path":"docs/DATA_MODEL.md","sha256":"6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a","bytes":13366,"lines":85},{"path":"docs/ERD.md","sha256":"546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe","bytes":6964,"lines":70},{"path":"docs/OPERABILITY.md","sha256":"82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62","bytes":11189,"lines":71},{"path":"docs/PRD.md","sha256":"3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1","bytes":5490,"lines":111},{"path":"docs/SECURITY.md","sha256":"01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac","bytes":11185,"lines":64},{"path":"docs/STORYBOARD.md","sha256":"6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2","bytes":1342,"lines":28},{"path":"docs/STORYBOOK.md","sha256":"82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9","bytes":1389,"lines":50},{"path":"docs/TEST_STRATEGY.md","sha256":"d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8","bytes":16534,"lines":135},{"path":"docs/THREAT_MODEL.md","sha256":"f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252","bytes":6736,"lines":23},{"path":"docs/TRACEABILITY.md","sha256":"dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e","bytes":11462,"lines":40},{"path":"docs/TRD.md","sha256":"23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077","bytes":9064,"lines":101},{"path":"docs/UML.md","sha256":"fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9","bytes":5528,"lines":122},{"path":"docs/USER_STORIES.md","sha256":"5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f","bytes":2670,"lines":37},{"path":"docs/WIREFRAMES.md","sha256":"b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e","bytes":2005,"lines":77},{"path":"docs/adr/0001-orgmetra-authoritative-hris-record.md","sha256":"0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572","bytes":6108,"lines":53},{"path":"docs/adr/0002-federated-cwl-integration-boundaries.md","sha256":"b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2","bytes":4072,"lines":44},{"path":"docs/adr/0003-bitemporal-hris-data-contract.md","sha256":"d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799","bytes":4453,"lines":47},{"path":"docs/adr/0004-employment-position-version-and-assignment-binding.md","sha256":"fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182","bytes":1872,"lines":30},{"path":"docs/adr/0005-exclusive-employment-and-staffable-seats.md","sha256":"10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b","bytes":2091,"lines":34},{"path":"docs/adr/0006-governed-audit-outbox-envelope.md","sha256":"827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd","bytes":14100,"lines":66},{"path":"docs/adr/0007-governed-job-analysis-evidence.md","sha256":"953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52","bytes":5653,"lines":57},{"path":"docs/adr/0008-purpose-bound-pii-authorization.md","sha256":"c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7","bytes":5988,"lines":55},{"path":"docs/adr/0009-performance-criterion-observation-scope.md","sha256":"1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64","bytes":7057,"lines":57},{"path":"docs/adr/0010-naruon-calendar-intent-boundary.md","sha256":"3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9","bytes":3917,"lines":35},{"path":"docs/adr/0011-bitemporal-workforce-composition.md","sha256":"1656ef8b57c836ef7936a8e9cb6a824681eb7563157a1ab0a29deb25849a457b","bytes":5568,"lines":53},{"path":"docs/adr/0012-governed-migration-handoff.md","sha256":"713855d670001d3964ecb36cc653830502fb1d82a58b9e39f564b6992dd2bd80","bytes":5965,"lines":59},{"path":"docs/adr/0013-governed-requisition-review-packet.md","sha256":"70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802","bytes":4693,"lines":46},{"path":"docs/adr/0014-job-analysis-snapshot-persistence.md","sha256":"a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105","bytes":5365,"lines":49},{"path":"docs/adr/README.md","sha256":"f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002","bytes":1838,"lines":18},{"path":"docs/doctoring/REFERENCES.md","sha256":"929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5","bytes":6352,"lines":69},{"path":"docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md","sha256":"b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd","bytes":8227,"lines":226},{"path":"docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md","sha256":"4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d","bytes":6237,"lines":187},{"path":"package.json","sha256":"59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5","bytes":388,"lines":9},{"path":"packages/hris-kernel/src/orgmetra_hris_kernel/audit.py","sha256":"3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190","bytes":7707,"lines":160},{"path":"packages/hris-kernel/tests/test_audit_outbox.py","sha256":"5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c","bytes":7556,"lines":200},{"path":"schemas/openapi.yaml","sha256":"09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f","bytes":29503,"lines":1020},{"path":"scripts/foundation-contract-core.mjs","sha256":"595e8381dbd62e97093b11eef818af5f04d6473ac592d57e3985ffbc2210d445","bytes":28173,"lines":689},{"path":"scripts/foundation-contract.mjs","sha256":"5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a","bytes":218,"lines":6},{"path":"tests/dispatcher-inventory.test.mjs","sha256":"09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261","bytes":1597,"lines":34},{"path":"tests/foundation-contract.test.mjs","sha256":"960306fd7cda7b982a52c4428a432d10a4f570430a5d39fb23aeca0b2ede0615","bytes":14860,"lines":386},{"path":"tests/openapi-contract.test.mjs","sha256":"80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc","bytes":6438,"lines":195},{"path":"tests/test_audit_outbox_hardening_postgres.sh","sha256":"518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0","bytes":13396,"lines":333},{"path":"tests/test_audit_outbox_postgres.sh","sha256":"e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2","bytes":13443,"lines":357},{"path":"tests/test_bitemporal_postgres.sh","sha256":"7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc","bytes":8209,"lines":230},{"path":"tests/test_candidate_worker_conversion_postgres.sh","sha256":"681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90","bytes":14673,"lines":344},{"path":"tests/test_criterion_observation_scope_postgres.sh","sha256":"0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d","bytes":17811,"lines":469},{"path":"tests/test_evidence_sealing_postgres.sh","sha256":"57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7","bytes":11349,"lines":370},{"path":"tests/test_job_analysis_snapshot_postgres.sh","sha256":"ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f","bytes":13542,"lines":296},{"path":"tests/test_operational_uuid_postgres.sh","sha256":"7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7","bytes":3346,"lines":101},{"path":"tests/test_outbox_claim_postgres.sh","sha256":"1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b","bytes":14817,"lines":429},{"path":"tests/test_outbox_dead_letter_postgres.sh","sha256":"0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d","bytes":14008,"lines":377},{"path":"tests/test_people_mutation_idempotency_postgres.sh","sha256":"3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5","bytes":16191,"lines":381},{"path":"tests/test_tenant_isolation_postgres.sh","sha256":"dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a","bytes":15134,"lines":388},{"path":"tests/test_validity_study_case_postgres.sh","sha256":"0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02","bytes":14708,"lines":301},{"path":"tests/validate_repository.py","sha256":"918cf92fd18d81572e9bd5f5daa7f033c32731e2e13f0d00661d1c1de30b12a9","bytes":27291,"lines":638}]} +{ + "package": "orgmetra-foundation-pack", + "version": "0.1.0", + "generated_for_branch": "feat/audit-outbox-envelope", + "files": [ + { + "path": ".github/workflows/foundation-ci.yml", + "sha256": "b6a4365936b66803a8112f034c77d53d33301a7a798ed4f68746a4f2d8b081d7", + "bytes": 6651, + "lines": 125 + }, + { + "path": ".gitignore", + "sha256": "145fda644f5209fa1fb3e3b40c9af9258bfac6d1a634bba2520fd08fe6d77a21", + "bytes": 375, + "lines": 37 + }, + { + "path": "AGENTS.md", + "sha256": "28f7b7bc010a7739cfdc3e793fb5d39a0e74b842ea9c190e9a251e2d0cbc3a16", + "bytes": 2246, + "lines": 34 + }, + { + "path": "ARCHITECTURE.md", + "sha256": "52d68786f7359c1a50d804996021e4c70e90accd2fff6f1a27c91de1dd8df850", + "bytes": 7864, + "lines": 107 + }, + { + "path": "CHANGELOG.md", + "sha256": "9ad6dad273c94c30741522ca87205ff24eb92c53becc8b53739d93acb28126f9", + "bytes": 17697, + "lines": 78 + }, + { + "path": "CLAUDE.md", + "sha256": "add33884f466d324e20875388d103de41c6e062938a6e98727dc83a87ffe976f", + "bytes": 1229, + "lines": 20 + }, + { + "path": "LICENSE", + "sha256": "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30", + "bytes": 11358, + "lines": 202 + }, + { + "path": "NOTICE", + "sha256": "34b4618e946bdd8d33407d6ac5279f0a0388f5e7c8f79d2e7d8c3c47d0266042", + "bytes": 305, + "lines": 4 + }, + { + "path": "README.md", + "sha256": "1a9fc400d26d8137ae5911488794a6d3fa915957c95f27b36a48cef0fdf823c6", + "bytes": 3785, + "lines": 81 + }, + { + "path": "database/migrations/0001_foundation_schema.sql", + "sha256": "ce2ae52fc66b2f99597ea5285df82c66f90caa46174fef4930d68a8b6177d0dd", + "bytes": 38747, + "lines": 916 + }, + { + "path": "database/migrations/0002_sealed_evidence_digest.sql", + "sha256": "93d659ca8e0e9293a83d5422d043be7b1022c5470a5b22670aa3416fa334a04c", + "bytes": 6649, + "lines": 202 + }, + { + "path": "database/migrations/0003_audit_outbox_persistence.sql", + "sha256": "2aa7bbb8220923ec584537c0cd46f0cba2b692d69d431f097b7df6db75235bfc", + "bytes": 15417, + "lines": 423 + }, + { + "path": "database/migrations/0004_outbox_delivery_claim.sql", + "sha256": "d4504acf7d58528a2a8f4f03d1584b868c8d3ba9046a007b9c2e7cfef993b2ef", + "bytes": 9451, + "lines": 234 + }, + { + "path": "database/migrations/0005_outbox_delivery_finalization.sql", + "sha256": "b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961", + "bytes": 6125, + "lines": 170 + }, + { + "path": "database/migrations/0006_outbox_delivery_dead_letter.sql", + "sha256": "c1fb91cdf98169fd6684984e86cb0a14fa19c8f1226028d2346a2a069df2b3c7", + "bytes": 24919, + "lines": 628 + }, + { + "path": "database/migrations/0007_outbox_retry_exhaustion.sql", + "sha256": "812f50d70ca5929c7eba964d34a208aedee660d11cc7ffc09d67688c4737e0d5", + "bytes": 19081, + "lines": 476 + }, + { + "path": "database/migrations/0008_audit_outbox_review_hardening.sql", + "sha256": "c3713a12db9d00fdc10005df1f86c07965e9555eefad78ca67e994537a739d9b", + "bytes": 17562, + "lines": 448 + }, + { + "path": "database/migrations/0009_candidate_worker_conversion_governance.sql", + "sha256": "4030666629a6b8deb383b8337ead4f09d6a945969313def2577a38f31f06cda9", + "bytes": 11537, + "lines": 281 + }, + { + "path": "database/migrations/0010_validity_study_case_integrity.sql", + "sha256": "3f594810ac9e1a6747a2bb4838e5ce65b921cb6e3d36fcdc3ff08b4a7579ebd1", + "bytes": 11979, + "lines": 313 + }, + { + "path": "database/migrations/0011_criterion_observation_scope.sql", + "sha256": "f9fe7c35f1ee7b167e1c2ba75a50a84febda9a6ccf8123b4f5726f51968694f9", + "bytes": 7444, + "lines": 165 + }, + { + "path": "database/migrations/0012_people_mutation_idempotency.sql", + "sha256": "52dbbb9ec7f9be5291593ba88f228d7fffd736dcb99547a08c1d6cad076afb69", + "bytes": 3162, + "lines": 76 + }, + { + "path": "database/migrations/0013_job_analysis_snapshot.sql", + "sha256": "b6553a5a4c94c4aa9f341a474e13bbe34db63044eda2446b3ebee178995977ee", + "bytes": 12713, + "lines": 260 + }, + { + "path": "docs/API_CONTRACT.md", + "sha256": "63533dff785da62b89e585d742a158e2aeb05913644f2bf9fb6486f281c2e589", + "bytes": 4555, + "lines": 76 + }, + { + "path": "docs/DATA_MODEL.md", + "sha256": "6ad29731ae7ee7aa5bf3a2d0bfef88894a35a2550edb2be3244d6f143d76444a", + "bytes": 13366, + "lines": 85 + }, + { + "path": "docs/ERD.md", + "sha256": "546001aa85c4fe020e0c39d881dc860daf7f69090596666fdf9092487b0725fe", + "bytes": 6964, + "lines": 70 + }, + { + "path": "docs/OPERABILITY.md", + "sha256": "82b2d3e70cec371ef35e9e0f982ac40fef84351976bc04b863b81d27023d5a62", + "bytes": 11189, + "lines": 71 + }, + { + "path": "docs/PRD.md", + "sha256": "3ad85ae633cce0fc7a93af39b21d7a7c70bb2efa786da6b12f3c5327906e34f1", + "bytes": 5490, + "lines": 111 + }, + { + "path": "docs/SECURITY.md", + "sha256": "01918512d8882060e9cff0c4aa8206e0eccbdfb61cfd7f829331123c7a9fe6ac", + "bytes": 11185, + "lines": 64 + }, + { + "path": "docs/STORYBOARD.md", + "sha256": "6e4ffb0eb03a80343f50d363ffc43b34da9348a44232dd947a9ff416ea92a3d2", + "bytes": 1342, + "lines": 28 + }, + { + "path": "docs/STORYBOOK.md", + "sha256": "82f79029b3c2b7a45393bad5ba8fabe61014d4b6149c7d4e73f70ba447f885e9", + "bytes": 1389, + "lines": 50 + }, + { + "path": "docs/TEST_STRATEGY.md", + "sha256": "d0a0bc3b54ed0fc7973747987f1afb117d6144c390b51ed9370eb571972a33f8", + "bytes": 16534, + "lines": 135 + }, + { + "path": "docs/THREAT_MODEL.md", + "sha256": "f314f375c2e41252536de224c7bc7e4a10ab8f340cb86642724e7399e32f4252", + "bytes": 6736, + "lines": 23 + }, + { + "path": "docs/TRACEABILITY.md", + "sha256": "dbf6fd91375ea28e05456d2a0c9ba629506cbac6f52f5dfda61ae68db2395f7e", + "bytes": 11462, + "lines": 40 + }, + { + "path": "docs/TRD.md", + "sha256": "23697d88a4882698e1a2782b7da3f2ccd0d3cd2d6d1bffe89b6597dc16851077", + "bytes": 9064, + "lines": 101 + }, + { + "path": "docs/UML.md", + "sha256": "fe67c37aa88e5814ceb2db7e8f7d8d85ca27a994802efbb7c75164b387adf0a9", + "bytes": 5528, + "lines": 122 + }, + { + "path": "docs/USER_STORIES.md", + "sha256": "5535b39d8c71a36c81f78e2d6dbd90a2d32e6541790f0d28f6dd4baf3ea7b45f", + "bytes": 2670, + "lines": 37 + }, + { + "path": "docs/WIREFRAMES.md", + "sha256": "b03aa6419aeaf5d42a5698c4d43a434c1633b7ac6fd0b0bd0cda979077adc56e", + "bytes": 2005, + "lines": 77 + }, + { + "path": "docs/adr/0001-orgmetra-authoritative-hris-record.md", + "sha256": "0f8055b73c63d3130321415ad53233588ff952aabd1a88952b39c71747253572", + "bytes": 6108, + "lines": 53 + }, + { + "path": "docs/adr/0002-federated-cwl-integration-boundaries.md", + "sha256": "b77165f2aacfa6f4fde994baf77d5879c6da3e8dae4fd2db0ed912d60ae9b3b2", + "bytes": 4072, + "lines": 44 + }, + { + "path": "docs/adr/0003-bitemporal-hris-data-contract.md", + "sha256": "d7f2660616622c1a7994b28aa66d99d13836bcf755735595f9609a41282ab799", + "bytes": 4453, + "lines": 47 + }, + { + "path": "docs/adr/0004-employment-position-version-and-assignment-binding.md", + "sha256": "fee89e700414abe0b1cffec2acc687e5e014634db8f5ef9e8a92abba5c3cf182", + "bytes": 1872, + "lines": 30 + }, + { + "path": "docs/adr/0005-exclusive-employment-and-staffable-seats.md", + "sha256": "10f0eb409f4fa32d2c5bed2d583d8b43be8e61b5cbef0e927e5bebb5f5c8f85b", + "bytes": 2091, + "lines": 34 + }, + { + "path": "docs/adr/0006-governed-audit-outbox-envelope.md", + "sha256": "827298ddd997b47f78a89e89911ad8ea72e517b7714303637f0329b8cb52cabd", + "bytes": 14100, + "lines": 66 + }, + { + "path": "docs/adr/0007-governed-job-analysis-evidence.md", + "sha256": "953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52", + "bytes": 5653, + "lines": 57 + }, + { + "path": "docs/adr/0008-purpose-bound-pii-authorization.md", + "sha256": "c5157d3bc58f3d8d29e03104dd15eb2911cc1bb66e2c92a935b26d7164648dc7", + "bytes": 5988, + "lines": 55 + }, + { + "path": "docs/adr/0009-performance-criterion-observation-scope.md", + "sha256": "1ac10bb2747b0a5b4d62f627825cfd7f978f3fa88d7575bffc23d56371240a64", + "bytes": 7057, + "lines": 57 + }, + { + "path": "docs/adr/0010-naruon-calendar-intent-boundary.md", + "sha256": "3e1050a964cc4ed76a1a0cf1e699ae5080acf8c9336f0decdd6d5229359db3c9", + "bytes": 3917, + "lines": 35 + }, + { + "path": "docs/adr/0011-bitemporal-workforce-composition.md", + "sha256": "dbe96dfd47066288cec835789de54cc4293f920d2ad4b0e0dba930191d7d249b", + "bytes": 5551, + "lines": 53 + }, + { + "path": "docs/adr/0012-governed-migration-handoff.md", + "sha256": "c7bfbda34996f717ed31f8307acc16a5d69ae464edb184ab5c8ec4b2d5763cbc", + "bytes": 5958, + "lines": 59 + }, + { + "path": "docs/adr/0013-governed-requisition-review-packet.md", + "sha256": "70bf2cbdf903a8793d6d8bc116a08331931090118341f42010236e09c6cc1802", + "bytes": 4693, + "lines": 46 + }, + { + "path": "docs/adr/0014-job-analysis-snapshot-persistence.md", + "sha256": "a7ab6fee50aaa63f7f407516a4cb39885faeb0fc6e5035ee8fc352ed73430105", + "bytes": 5365, + "lines": 49 + }, + { + "path": "docs/adr/README.md", + "sha256": "f3b3b5ed3b3b31a40a0a3696abf0065e3c25879b6be50077f38ffae742b9d002", + "bytes": 1838, + "lines": 18 + }, + { + "path": "docs/doctoring/REFERENCES.md", + "sha256": "929f7ee36df16279f028f726fcf039982180deb377746fe3804f3c0d090778d5", + "bytes": 6352, + "lines": 69 + }, + { + "path": "docs/superpowers/plans/2026-08-15-orgmetra-foundation-implementation-plan.md", + "sha256": "b64f21abb19373e780db8b9e64deb8ba9a6219ccf9625a651f25407b8691fcbd", + "bytes": 8227, + "lines": 226 + }, + { + "path": "docs/superpowers/specs/2026-08-15-orgmetra-foundation-design.md", + "sha256": "4a0e1a7943e40d12bd3082db3757045b4085e5a089fea7bc0d8a1565ffcbcf1d", + "bytes": 6237, + "lines": 187 + }, + { + "path": "package.json", + "sha256": "59ae9e3e67c3fba9320cb18439692395cdfd16ae5c24e3c4cf30d77d63ebabb5", + "bytes": 388, + "lines": 9 + }, + { + "path": "packages/hris-kernel/src/orgmetra_hris_kernel/audit.py", + "sha256": "3e5b7190cf857dc8c1fc7e898cef303060f34aabee6c27a9034d4d9650e33190", + "bytes": 7707, + "lines": 160 + }, + { + "path": "packages/hris-kernel/tests/test_audit_outbox.py", + "sha256": "5928dd7b97fe38d6b7472ce62966437e339058a59c3b301a93a7b5c05432b40c", + "bytes": 7556, + "lines": 200 + }, + { + "path": "schemas/openapi.yaml", + "sha256": "09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f", + "bytes": 29503, + "lines": 1020 + }, + { + "path": "scripts/foundation-contract-core.mjs", + "sha256": "9b03efbbdffa60a05f5924e8a61b1cbc3cd75c502df428a5920085e8d0bf3603", + "bytes": 28121, + "lines": 688 + }, + { + "path": "scripts/foundation-contract.mjs", + "sha256": "5242dcdbe0935775edf074462c82600e9bc4927d9fdc50c47727af915fd4b23a", + "bytes": 218, + "lines": 6 + }, + { + "path": "tests/dispatcher-inventory.test.mjs", + "sha256": "09f5e64410e6b7a26bf8d6ce61c50b737da2ea85d955f91eba63aa21f1537261", + "bytes": 1597, + "lines": 34 + }, + { + "path": "tests/foundation-contract.test.mjs", + "sha256": "648533b4aff8cee643df4afc06b463eda788e002e11d043971c8a16804c68501", + "bytes": 14943, + "lines": 387 + }, + { + "path": "tests/openapi-contract.test.mjs", + "sha256": "80c1610ef1c189fa325e55389501e0e51531ddf61ee335bb94d9cb3aa55a9fdc", + "bytes": 6438, + "lines": 195 + }, + { + "path": "tests/test_audit_outbox_hardening_postgres.sh", + "sha256": "518ba2f37ba6292943e5abe22c2599452b2f031a42e453b2493aedf8714421a0", + "bytes": 13396, + "lines": 333 + }, + { + "path": "tests/test_audit_outbox_postgres.sh", + "sha256": "e57a04920a0ba97fa6a06752d15ea150016ab8d44099e998c5c4f4067592b4d2", + "bytes": 13443, + "lines": 357 + }, + { + "path": "tests/test_bitemporal_postgres.sh", + "sha256": "7684b8c2ff52c044c081135515bd5aabbfd00e2daad0d471b0868701af2df6cc", + "bytes": 8209, + "lines": 230 + }, + { + "path": "tests/test_candidate_worker_conversion_postgres.sh", + "sha256": "681cb74d6cfa859ed92c6c2439881ea20c430ef8df94ec662e2807761a377f90", + "bytes": 14673, + "lines": 344 + }, + { + "path": "tests/test_criterion_observation_scope_postgres.sh", + "sha256": "0ee9539ee57f840c27d08009f7868cdc8662669df78a01dbc8be39216b8f1a3d", + "bytes": 17811, + "lines": 469 + }, + { + "path": "tests/test_evidence_sealing_postgres.sh", + "sha256": "57d16b632a0c60ffdcb4842ceb1cfe25d19c54cefeeefb622ff4fa6e83441ad7", + "bytes": 11349, + "lines": 370 + }, + { + "path": "tests/test_job_analysis_snapshot_postgres.sh", + "sha256": "ca9c323a1dd68cfc520277efbbb7495e37fb3ca027890928c8624e5b4f57403f", + "bytes": 13542, + "lines": 296 + }, + { + "path": "tests/test_operational_uuid_postgres.sh", + "sha256": "7378f98f0d4b3000e8ea641d8701f1540dbad71410b3637d81d799969e0f6ff7", + "bytes": 3346, + "lines": 101 + }, + { + "path": "tests/test_outbox_claim_postgres.sh", + "sha256": "1027806d436ebfe34e108c25b6a4001f43b9550f1d70057c6c0d7974323b0c9b", + "bytes": 14817, + "lines": 429 + }, + { + "path": "tests/test_outbox_dead_letter_postgres.sh", + "sha256": "0d728d578e64252e6079f2d141ddaa7fa9cfbf9784e625832273596d69a6e13d", + "bytes": 14008, + "lines": 377 + }, + { + "path": "tests/test_people_mutation_idempotency_postgres.sh", + "sha256": "3f57e12f80bd1b034c9aac54b669d8530106e3e26b3795689671fb53807b3cd5", + "bytes": 16191, + "lines": 381 + }, + { + "path": "tests/test_tenant_isolation_postgres.sh", + "sha256": "dd649435ef8ab9e57f0609c101917e36656a6d40d63de9bcdbdac23d764f6c3a", + "bytes": 15134, + "lines": 388 + }, + { + "path": "tests/test_validity_study_case_postgres.sh", + "sha256": "0070ad58300323c7f9900c5645e0df3106b36ccd245ae686e982c2fd6fa4dc02", + "bytes": 14708, + "lines": 301 + }, + { + "path": "tests/validate_repository.py", + "sha256": "091836b2f68600a30b08f7da2cea8b3bef10201a123da720a7369bf10985eec2", + "bytes": 27237, + "lines": 637 + } + ] +} From cde8df27fcffc0b4abee57178085ee0f2153c571 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 03:30:07 +0900 Subject: [PATCH 19/80] test(people): reject executable hire decision timestamps --- ...stgres_hire_timestamp_runtime_integrity.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 services/people-api/tests/test_postgres_hire_timestamp_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_hire_timestamp_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_timestamp_runtime_integrity.py new file mode 100644 index 000000000..539649261 --- /dev/null +++ b/services/people-api/tests/test_postgres_hire_timestamp_runtime_integrity.py @@ -0,0 +1,52 @@ +"""Runtime-integrity contracts for durable hire-decision timestamps.""" + +from datetime import datetime, timedelta, timezone, tzinfo +from zoneinfo import ZoneInfo + +from orgmetra_people_api.postgres_hire import _is_aware_datetime + + +class _ExecutableTimezone(tzinfo): + """Record forbidden offset resolution at the People durable boundary.""" + + def __init__(self) -> None: + self.calls = 0 + + def utcoffset(self, dt: datetime | None) -> timedelta: + """Fail if validation executes caller-defined timezone behavior.""" + del dt + self.calls += 1 + raise AssertionError("caller-defined timezone callback executed") + + +class _ExecutableDatetime(datetime): + """Fail if validation executes behavior from a datetime subtype.""" + + def utcoffset(self) -> timedelta: + """Expose subtype execution if the exact-type gate is missing.""" + raise AssertionError("datetime subtype callback executed") + + +def test_hire_timestamp_rejects_custom_timezone_before_callback() -> None: + """Exact datetime values cannot delegate offset validation to caller code.""" + provider = _ExecutableTimezone() + value = datetime(2026, 8, 18, 0, 0, tzinfo=provider) + + assert _is_aware_datetime(value) is False + assert provider.calls == 0 + + +def test_hire_timestamp_rejects_datetime_subtype_before_callback() -> None: + """Executable datetime subtypes are not durable selection-decision evidence.""" + value = _ExecutableDatetime(2026, 8, 18, 0, 0, tzinfo=timezone.utc) + + assert _is_aware_datetime(value) is False + + +def test_hire_timestamp_accepts_exact_standard_library_timezones() -> None: + """Psycopg-compatible standard-library timezone materialization stays valid.""" + utc_value = datetime(2026, 8, 18, 0, 0, tzinfo=timezone.utc) + seoul_value = datetime(2026, 8, 18, 9, 0, tzinfo=ZoneInfo("Asia/Seoul")) + + assert _is_aware_datetime(utc_value) is True + assert _is_aware_datetime(seoul_value) is True From 98882232244920f919c0fdaf9b7a2c6ee67879c9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 03:31:02 +0900 Subject: [PATCH 20/80] fix(people): exact-gate hire decision time providers --- .../src/orgmetra_people_api/postgres_hire.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_hire.py b/services/people-api/src/orgmetra_people_api/postgres_hire.py index 705caefe4..2378f67de 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_hire.py +++ b/services/people-api/src/orgmetra_people_api/postgres_hire.py @@ -12,12 +12,13 @@ from contextlib import AbstractContextManager from dataclasses import dataclass -from datetime import datetime +from datetime import datetime, timezone from hashlib import sha256 import json import re from typing import Any, Callable from uuid import UUID +from zoneinfo import ZoneInfo from orgmetra_hris_kernel.audit import AuditOutboxEvent from orgmetra_keyverse_adapter import AuthorizationDecision @@ -100,7 +101,7 @@ tenant_record_id, person_record_id, recorded_from -) VALUES (%s, %s, %s) +) VALUES (%s, %s, %s, %s) """.strip() _INSERT_PERSON_NAME_SQL = """ @@ -169,8 +170,12 @@ def _is_operational_uuid(value: object) -> bool: def _is_aware_datetime(value: object) -> bool: - """Return whether a value is a timezone-aware datetime with a real offset.""" - return isinstance(value, datetime) and value.tzinfo is not None and value.utcoffset() is not None + """Return whether durable time is exact and backed by an inert standard provider.""" + if type(value) is not datetime or value.tzinfo is None: + return False + if type(value.tzinfo) not in (timezone, ZoneInfo): + return False + return value.utcoffset() is not None def _validate_authorization(command: HireAcceptanceCommand, authorization: object) -> AuthorizationDecision: @@ -396,7 +401,6 @@ def accept_hire( ( command.tenant_record_id, command.person_name_record_id, - command.person_record_id, command.display_name, command.effective_from, transaction_recorded_at, From 61cba0fe82107c07b979a42e57f6cd64e75cdf8a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 03:32:27 +0900 Subject: [PATCH 21/80] fix(people): restore hire insert contract after timestamp repair --- services/people-api/src/orgmetra_people_api/postgres_hire.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_hire.py b/services/people-api/src/orgmetra_people_api/postgres_hire.py index 2378f67de..e183cd93f 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_hire.py +++ b/services/people-api/src/orgmetra_people_api/postgres_hire.py @@ -101,7 +101,7 @@ tenant_record_id, person_record_id, recorded_from -) VALUES (%s, %s, %s, %s) +) VALUES (%s, %s, %s) """.strip() _INSERT_PERSON_NAME_SQL = """ @@ -401,6 +401,7 @@ def accept_hire( ( command.tenant_record_id, command.person_name_record_id, + command.person_record_id, command.display_name, command.effective_from, transaction_recorded_at, From 42d988a7293c083f0d2160e770b4b1cedeb18d52 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 03:37:07 +0900 Subject: [PATCH 22/80] test(people): document executable timezone tripwire --- .../tests/test_postgres_hire_timestamp_runtime_integrity.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/people-api/tests/test_postgres_hire_timestamp_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_timestamp_runtime_integrity.py index 539649261..15f62ff86 100644 --- a/services/people-api/tests/test_postgres_hire_timestamp_runtime_integrity.py +++ b/services/people-api/tests/test_postgres_hire_timestamp_runtime_integrity.py @@ -10,6 +10,7 @@ class _ExecutableTimezone(tzinfo): """Record forbidden offset resolution at the People durable boundary.""" def __init__(self) -> None: + """Initialize the callback counter without resolving an offset.""" self.calls = 0 def utcoffset(self, dt: datetime | None) -> timedelta: From 792dfe37ca2ad99f8cfbca8ce688c8555bc62817 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 04:00:42 +0900 Subject: [PATCH 23/80] test(people): reject executable durable hire UUID evidence --- ...st_postgres_hire_uuid_runtime_integrity.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 services/people-api/tests/test_postgres_hire_uuid_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_hire_uuid_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_uuid_runtime_integrity.py new file mode 100644 index 000000000..7b12d98ad --- /dev/null +++ b/services/people-api/tests/test_postgres_hire_uuid_runtime_integrity.py @@ -0,0 +1,32 @@ +"""Runtime-integrity contracts for durable hire UUID evidence.""" + +from uuid import UUID + +from orgmetra_people_api.postgres_hire import _is_operational_uuid + + +_MAX_UUID_INT = (1 << 128) - 1 + + +class _ExecutableUUID(UUID): + """Expose any UUID attribute inspection performed before an exact-type gate.""" + + def __getattribute__(self, name: str) -> object: + """Fail when untrusted UUID evidence is inspected as if it were inert.""" + if name == "int": + raise AssertionError("UUID subtype behavior executed before exact-type validation") + return super().__getattribute__(name) + + +def test_hire_durable_uuid_rejects_subtype_before_identity_inspection() -> None: + """Database-returned UUID subtypes must fail without executing subtype behavior.""" + value = _ExecutableUUID("0198a412-7100-7000-8000-000000000060") + + assert _is_operational_uuid(value) is False + + +def test_hire_durable_uuid_accepts_only_operational_exact_uuid_values() -> None: + """Exact Psycopg-compatible UUID values remain valid except reserved sentinels.""" + assert _is_operational_uuid(UUID("0198a412-7100-7000-8000-000000000060")) is True + assert _is_operational_uuid(UUID(int=0)) is False + assert _is_operational_uuid(UUID(int=_MAX_UUID_INT)) is False From 6443ee54fd69e4bb3c0cf7e6d211087f87f91655 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 04:02:05 +0900 Subject: [PATCH 24/80] fix(people): exact-gate durable hire UUID evidence --- services/people-api/src/orgmetra_people_api/postgres_hire.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_hire.py b/services/people-api/src/orgmetra_people_api/postgres_hire.py index e183cd93f..07fefb41d 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_hire.py +++ b/services/people-api/src/orgmetra_people_api/postgres_hire.py @@ -166,7 +166,7 @@ def _is_operational_uuid(value: object) -> bool: """Return whether a value is an Orgmetra operational UUID.""" - return isinstance(value, UUID) and value.int not in (0, _MAX_UUID_INT) + return type(value) is UUID and value.int not in (0, _MAX_UUID_INT) def _is_aware_datetime(value: object) -> bool: @@ -458,4 +458,4 @@ def accept_hire( person_record_id=command.person_record_id, employment_record_id=command.employment_record_id, candidate_worker_conversion_record_id=command.candidate_worker_conversion_record_id, - ) \ No newline at end of file + ) From 2ac5a1165c1fce2cf9c500dd9c41c94dd39e5d67 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 05:03:44 +0900 Subject: [PATCH 25/80] test(people): reject executable hire idempotency digest text --- ...hire_idempotency_text_runtime_integrity.py | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 services/people-api/tests/test_postgres_hire_idempotency_text_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_hire_idempotency_text_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_idempotency_text_runtime_integrity.py new file mode 100644 index 000000000..8b3d73cbf --- /dev/null +++ b/services/people-api/tests/test_postgres_hire_idempotency_text_runtime_integrity.py @@ -0,0 +1,119 @@ +"""Runtime-integrity contracts for durable hire idempotency digest text.""" + +from __future__ import annotations + +from datetime import date +from typing import Any +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision +from orgmetra_people_api.hire import HireAcceptanceCommand, HireDecisionIntegrityError +from orgmetra_people_api.postgres_hire import _hire_command_digest, _replayed_hire + +TENANT = UUID("0198a412-7100-7000-8000-000000000001") +CANDIDATE = UUID("0198a412-7100-7000-8000-000000000010") +DECISION = UUID("0198a412-7100-7000-8000-000000000011") +PERSON = UUID("0198a412-7100-7000-8000-000000000020") +PERSON_NAME = UUID("0198a412-7100-7000-8000-000000000021") +EMPLOYMENT = UUID("0198a412-7100-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-7100-7000-8000-000000000031") +CONVERSION = UUID("0198a412-7100-7000-8000-000000000040") +AUDIT_EVENT = UUID("0198a412-7100-7000-8000-000000000050") +OUTBOX_DELIVERY = UUID("0198a412-7100-7000-8000-000000000051") +ACTOR = "keyverse_subject:operator-17" +PURPOSE = "candidate_hire" + + +class _ExecutableText(str): + """Expose comparison performed before exact durable-text validation.""" + + def __eq__(self, other: object) -> bool: + """Fail if untrusted text participates in trusted equality.""" + del other + raise AssertionError("text subtype equality executed before exact-type validation") + + def __ne__(self, other: object) -> bool: + """Fail if untrusted text participates in trusted inequality.""" + del other + raise AssertionError("text subtype inequality executed before exact-type validation") + + +class _ReplayCursor: + """Return one durable idempotency row without touching a real database.""" + + def __init__(self, row: tuple[object, object]) -> None: + """Store the single replay row returned after advisory serialization.""" + self._row = row + + def execute(self, statement: str, parameters: tuple[object, ...]) -> None: + """Accept the two read-side SQL calls used by replay resolution.""" + assert statement + assert parameters + + def fetchmany(self, size: int) -> list[tuple[object, object]]: + """Return the configured row using the adapter's bounded read size.""" + assert size == 2 + return [self._row] + + +def _command() -> HireAcceptanceCommand: + """Build one deterministic valid confirmed-hire command.""" + return HireAcceptanceCommand( + tenant_record_id=TENANT, + candidate_profile_id=CANDIDATE, + selection_decision_id=DECISION, + person_record_id=PERSON, + person_name_record_id=PERSON_NAME, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + candidate_worker_conversion_record_id=CONVERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX_DELIVERY, + effective_from=date(2026, 8, 18), + display_name="Ada Lovelace", + idempotency_key="hire-idempotency-text-runtime-integrity", + ) + + +def _authorization() -> AuthorizationDecision: + """Build the exact allow decision required for the confirmed-hire command.""" + return AuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference=ACTOR, + resource_reference=f"selection_decision:{DECISION.hex}", + policy_version_code="people-hire-v1", + purpose_code=PURPOSE, + operation_code="materialize_worker", + resource_kind="selection_decision", + requested_fields=frozenset({"candidate_worker_conversion"}), + authorized_fields=frozenset({"candidate_worker_conversion"}), + reason_code="access_permitted", + next_action="continue", + ) + + +def test_hire_replay_rejects_digest_subtype_before_comparison() -> None: + """Database-returned digest subtypes must fail without executing comparison hooks.""" + command = _command() + authorization = _authorization() + digest = _ExecutableText(_hire_command_digest(command, authorization)) + cursor: Any = _ReplayCursor((CONVERSION, digest)) + + with pytest.raises(HireDecisionIntegrityError, match="hire idempotency row is invalid"): + _replayed_hire(cursor, command=command, authorization=authorization) + + +def test_hire_replay_accepts_exact_builtin_digest_text() -> None: + """An exact persisted digest still replays the exact committed conversion.""" + command = _command() + authorization = _authorization() + digest = _hire_command_digest(command, authorization) + cursor: Any = _ReplayCursor((CONVERSION, digest)) + + result = _replayed_hire(cursor, command=command, authorization=authorization) + + assert result is not None + assert result.candidate_worker_conversion_record_id == CONVERSION From d81260f9fb6ce5be95c8346e468b78cd59742ff8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 05:08:33 +0900 Subject: [PATCH 26/80] fix(people): exact-gate durable hire idempotency digest text --- services/people-api/src/orgmetra_people_api/postgres_hire.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_hire.py b/services/people-api/src/orgmetra_people_api/postgres_hire.py index 07fefb41d..95086ac21 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_hire.py +++ b/services/people-api/src/orgmetra_people_api/postgres_hire.py @@ -238,7 +238,7 @@ def _replayed_hire( if len(rows) != 1 or len(rows[0]) != 2: raise HireDecisionIntegrityError("hire idempotency row is invalid") created_record_id, stored_digest = rows[0] - if not _is_operational_uuid(created_record_id) or not isinstance(stored_digest, str): + if not _is_operational_uuid(created_record_id) or type(stored_digest) is not str: raise HireDecisionIntegrityError("hire idempotency row is invalid") if stored_digest != _hire_command_digest(command, authorization): raise HireDecisionIntegrityError("hire idempotency key is bound to a different command") From 878e98be00ef71a7e6529503ff560342556d3593 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 05:11:19 +0900 Subject: [PATCH 27/80] test(people): reject executable hire provenance text --- ..._hire_provenance_text_runtime_integrity.py | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 services/people-api/tests/test_postgres_hire_provenance_text_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_hire_provenance_text_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_provenance_text_runtime_integrity.py new file mode 100644 index 000000000..ae9e57718 --- /dev/null +++ b/services/people-api/tests/test_postgres_hire_provenance_text_runtime_integrity.py @@ -0,0 +1,181 @@ +"""Runtime-integrity contracts for durable hire decision-provenance text.""" + +from __future__ import annotations + +from datetime import date, datetime, timezone +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision +from orgmetra_people_api.hire import HireAcceptanceCommand, HireDecisionIntegrityError +from orgmetra_people_api.postgres_hire import PostgresHireAcceptancePort + +TENANT = UUID("0198a412-7100-7000-8000-000000000001") +CANDIDATE = UUID("0198a412-7100-7000-8000-000000000010") +DECISION = UUID("0198a412-7100-7000-8000-000000000011") +PERSON = UUID("0198a412-7100-7000-8000-000000000020") +PERSON_NAME = UUID("0198a412-7100-7000-8000-000000000021") +EMPLOYMENT = UUID("0198a412-7100-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-7100-7000-8000-000000000031") +CONVERSION = UUID("0198a412-7100-7000-8000-000000000040") +AUDIT_EVENT = UUID("0198a412-7100-7000-8000-000000000050") +OUTBOX_DELIVERY = UUID("0198a412-7100-7000-8000-000000000051") +EVIDENCE_SET = UUID("0198a412-7100-7000-8000-000000000060") +DECIDED_AT = datetime(2026, 8, 18, 0, 0, tzinfo=timezone.utc) +TRANSACTION_AT = datetime(2026, 8, 18, 0, 1, tzinfo=timezone.utc) +ACTOR = "keyverse_subject:operator-17" +PURPOSE = "candidate_hire" +CONFIRMATION = "human_confirmation:review-88" + + +class _ExecutableText(str): + """Expose comparison performed before exact durable-text validation.""" + + def __eq__(self, other: object) -> bool: + """Fail if durable-row validation executes subtype equality.""" + del other + raise AssertionError("provenance text equality executed before exact-type validation") + + def __ne__(self, other: object) -> bool: + """Fail if durable-row validation executes subtype inequality.""" + del other + raise AssertionError("provenance text inequality executed before exact-type validation") + + +class _Cursor: + """Serve one idempotency miss followed by one decision-provenance row.""" + + def __init__(self, decision_row: tuple[object, ...]) -> None: + """Store the row and initialize transaction-observation state.""" + self._batches = [[], [decision_row]] + self.executions: list[str] = [] + + def __enter__(self) -> _Cursor: + """Return the same cursor for the transaction context.""" + return self + + def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> None: + """Leave exception handling to the connection context.""" + del exc_type, exc_value, traceback + + def execute(self, statement: str, parameters: tuple[object, ...] | None = None) -> None: + """Record SQL without evaluating trust-bearing row values.""" + del parameters + self.executions.append(statement) + + def fetchmany(self, size: int) -> list[tuple[object, ...]]: + """Return each bounded batch in adapter execution order.""" + assert size == 2 + return self._batches.pop(0)[:size] + + +class _Connection: + """Provide the focused cursor through a DB-API-style context boundary.""" + + def __init__(self, cursor: _Cursor) -> None: + """Retain the one cursor used by the focused durable-row test.""" + self._cursor = cursor + + def __enter__(self) -> _Connection: + """Return the same transaction connection.""" + return self + + def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> None: + """Leave exception propagation unchanged.""" + del exc_type, exc_value, traceback + + def cursor(self) -> _Cursor: + """Return the configured focused cursor.""" + return self._cursor + + +def _command() -> HireAcceptanceCommand: + """Build one deterministic valid confirmed-hire command.""" + return HireAcceptanceCommand( + tenant_record_id=TENANT, + candidate_profile_id=CANDIDATE, + selection_decision_id=DECISION, + person_record_id=PERSON, + person_name_record_id=PERSON_NAME, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + candidate_worker_conversion_record_id=CONVERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX_DELIVERY, + effective_from=date(2026, 8, 18), + display_name="Ada Lovelace", + idempotency_key="hire-provenance-text-runtime-integrity", + ) + + +def _authorization() -> AuthorizationDecision: + """Build the exact allow decision required for the confirmed-hire command.""" + return AuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference=ACTOR, + resource_reference=f"selection_decision:{DECISION.hex}", + policy_version_code="people-hire-v1", + purpose_code=PURPOSE, + operation_code="materialize_worker", + resource_kind="selection_decision", + requested_fields=frozenset({"candidate_worker_conversion"}), + authorized_fields=frozenset({"candidate_worker_conversion"}), + reason_code="access_permitted", + next_action="continue", + ) + + +def _decision_row(**overrides: object) -> tuple[object, ...]: + """Build one durable confirmed-hire provenance row in SQL column order.""" + values: dict[str, object] = { + "actor_reference": ACTOR, + "purpose_code": PURPOSE, + "decision_code": "hire", + "confirmation_reference": CONFIRMATION, + "decided_at": DECIDED_AT, + "decision_evidence_set_id": EVIDENCE_SET, + "transaction_recorded_at": TRANSACTION_AT, + } + values.update(overrides) + return ( + values["actor_reference"], + values["purpose_code"], + values["decision_code"], + values["confirmation_reference"], + values["decided_at"], + values["decision_evidence_set_id"], + values["transaction_recorded_at"], + ) + + +@pytest.mark.parametrize( + "field,value", + ( + ("actor_reference", _ExecutableText(ACTOR)), + ("purpose_code", _ExecutableText(PURPOSE)), + ("decision_code", _ExecutableText("hire")), + ("confirmation_reference", _ExecutableText(CONFIRMATION)), + ), +) +def test_hire_rejects_provenance_text_subtype_before_business_write(field: str, value: object) -> None: + """Database provenance text must be exact built-in text before semantic use.""" + cursor = _Cursor(_decision_row(**{field: value})) + port = PostgresHireAcceptancePort(lambda: _Connection(cursor)) + + with pytest.raises(HireDecisionIntegrityError, match="selection decision provenance text is invalid"): + port.accept_hire(command=_command(), authorization=_authorization()) + + assert not any("INSERT INTO public.person_record" in statement for statement in cursor.executions) + + +def test_hire_accepts_exact_builtin_provenance_text() -> None: + """Exact Psycopg-compatible text remains valid durable decision provenance.""" + cursor = _Cursor(_decision_row()) + port = PostgresHireAcceptancePort(lambda: _Connection(cursor)) + + result = port.accept_hire(command=_command(), authorization=_authorization()) + + assert result.candidate_worker_conversion_record_id == CONVERSION + assert any("INSERT INTO public.person_record" in statement for statement in cursor.executions) From c260b05ee1821db427473b1420c7e7098a9da93f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 05:13:14 +0900 Subject: [PATCH 28/80] fix(people): exact-gate durable hire provenance text --- .../src/orgmetra_people_api/postgres_hire.py | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_hire.py b/services/people-api/src/orgmetra_people_api/postgres_hire.py index 95086ac21..46c359d9b 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_hire.py +++ b/services/people-api/src/orgmetra_people_api/postgres_hire.py @@ -346,16 +346,23 @@ def accept_hire( transaction_recorded_at, ) = row + if any( + type(value) is not str + for value in ( + decision_actor_reference, + decision_purpose_code, + decision_code, + confirmation_reference, + ) + ): + raise HireDecisionIntegrityError("selection decision provenance text is invalid") if decision_code != "hire": raise HireDecisionIntegrityError("selection decision is not an explicit hire") if decision_actor_reference != decision.actor_reference: raise HireDecisionIntegrityError("selection decision actor does not match authorized actor") if decision_purpose_code != decision.purpose_code: raise HireDecisionIntegrityError("selection decision purpose does not match authorized purpose") - if ( - not isinstance(confirmation_reference, str) - or _REFERENCE_PATTERN.fullmatch(confirmation_reference) is None - ): + if _REFERENCE_PATTERN.fullmatch(confirmation_reference) is None: raise HireDecisionIntegrityError("selection decision lacks valid human confirmation") if not _is_operational_uuid(evidence_set_id): raise HireDecisionIntegrityError("selection decision evidence set identity is invalid") From 5514b745233da940dd730d2c9dfdb8aaf8630e99 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 05:32:41 +0900 Subject: [PATCH 29/80] test(people): reject executable durable hire row containers --- ...es_hire_row_container_runtime_integrity.py | 231 ++++++++++++++++++ 1 file changed, 231 insertions(+) create mode 100644 services/people-api/tests/test_postgres_hire_row_container_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_hire_row_container_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_row_container_runtime_integrity.py new file mode 100644 index 000000000..c084f9c48 --- /dev/null +++ b/services/people-api/tests/test_postgres_hire_row_container_runtime_integrity.py @@ -0,0 +1,231 @@ +"""Runtime-integrity contracts for durable hire row containers.""" + +from __future__ import annotations + +from datetime import date, datetime, timezone +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision +from orgmetra_people_api.hire import HireAcceptanceCommand, HireDecisionIntegrityError +from orgmetra_people_api.postgres_hire import PostgresHireAcceptancePort + +TENANT = UUID("0198a412-7100-7000-8000-000000000001") +CANDIDATE = UUID("0198a412-7100-7000-8000-000000000010") +DECISION = UUID("0198a412-7100-7000-8000-000000000011") +PERSON = UUID("0198a412-7100-7000-8000-000000000020") +PERSON_NAME = UUID("0198a412-7100-7000-8000-000000000021") +EMPLOYMENT = UUID("0198a412-7100-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-7100-7000-8000-000000000031") +CONVERSION = UUID("0198a412-7100-7000-8000-000000000040") +AUDIT_EVENT = UUID("0198a412-7100-7000-8000-000000000050") +OUTBOX_DELIVERY = UUID("0198a412-7100-7000-8000-000000000051") +EVIDENCE_SET = UUID("0198a412-7100-7000-8000-000000000060") +DECIDED_AT = datetime(2026, 8, 18, 0, 0, tzinfo=timezone.utc) +TRANSACTION_AT = datetime(2026, 8, 18, 0, 1, tzinfo=timezone.utc) +ACTOR = "keyverse_subject:operator-17" +PURPOSE = "candidate_hire" +CONFIRMATION = "human_confirmation:review-88" + + +class _ExecutableBatch(list[object]): + """Fail if a fetched row collection is consumed before exact-type validation.""" + + def __bool__(self) -> bool: + """Reject pre-gate truthiness.""" + raise AssertionError("row collection truthiness executed before exact-type validation") + + def __len__(self) -> int: + """Reject pre-gate length inspection.""" + raise AssertionError("row collection length executed before exact-type validation") + + def __getitem__(self, key: object) -> object: + """Reject pre-gate indexed access.""" + del key + raise AssertionError("row collection indexing executed before exact-type validation") + + def __iter__(self): + """Reject pre-gate row iteration.""" + raise AssertionError("row collection iteration executed before exact-type validation") + + +class _ExecutableRow(tuple): + """Fail if a fetched fixed row is consumed before exact-type validation.""" + + def __len__(self) -> int: + """Reject pre-gate row length inspection.""" + raise AssertionError("row length executed before exact-type validation") + + def __getitem__(self, key: object) -> object: + """Reject pre-gate row indexing.""" + del key + raise AssertionError("row indexing executed before exact-type validation") + + def __iter__(self): + """Reject pre-gate row iteration.""" + raise AssertionError("row iteration executed before exact-type validation") + + +class _Cursor: + """Serve configured bounded fetch batches and record executed SQL.""" + + def __init__(self, batches: list[object]) -> None: + """Store the exact fetch results in adapter execution order.""" + self._batches = list(batches) + self.executions: list[str] = [] + + def __enter__(self) -> _Cursor: + """Return the same cursor for the transaction context.""" + return self + + def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> None: + """Leave exception handling to the connection context.""" + del exc_type, exc_value, traceback + + def execute(self, statement: str, parameters: tuple[object, ...] | None = None) -> None: + """Record SQL without evaluating durable-row contents.""" + del parameters + self.executions.append(statement) + + def fetchmany(self, size: int) -> object: + """Return the next configured batch without touching its runtime hooks.""" + assert size == 2 + return self._batches.pop(0) + + +class _Connection: + """Provide the focused cursor through a DB-API-style context boundary.""" + + def __init__(self, cursor: _Cursor) -> None: + """Retain the one cursor used by the focused durable-row tests.""" + self._cursor = cursor + + def __enter__(self) -> _Connection: + """Return the same transaction connection.""" + return self + + def __exit__(self, exc_type: object, exc_value: object, traceback: object) -> None: + """Leave exception propagation unchanged.""" + del exc_type, exc_value, traceback + + def cursor(self) -> _Cursor: + """Return the configured focused cursor.""" + return self._cursor + + +def _command() -> HireAcceptanceCommand: + """Build one deterministic valid confirmed-hire command.""" + return HireAcceptanceCommand( + tenant_record_id=TENANT, + candidate_profile_id=CANDIDATE, + selection_decision_id=DECISION, + person_record_id=PERSON, + person_name_record_id=PERSON_NAME, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + candidate_worker_conversion_record_id=CONVERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX_DELIVERY, + effective_from=date(2026, 8, 18), + display_name="Ada Lovelace", + idempotency_key="hire-row-container-runtime-integrity", + ) + + +def _authorization() -> AuthorizationDecision: + """Build the exact allow decision required for the confirmed-hire command.""" + return AuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference=ACTOR, + resource_reference=f"selection_decision:{DECISION.hex}", + policy_version_code="people-hire-v1", + purpose_code=PURPOSE, + operation_code="materialize_worker", + resource_kind="selection_decision", + requested_fields=frozenset({"candidate_worker_conversion"}), + authorized_fields=frozenset({"candidate_worker_conversion"}), + reason_code="access_permitted", + next_action="continue", + ) + + +def _decision_row() -> tuple[object, ...]: + """Build one valid durable confirmed-hire provenance row.""" + return ( + ACTOR, + PURPOSE, + "hire", + CONFIRMATION, + DECIDED_AT, + EVIDENCE_SET, + TRANSACTION_AT, + ) + + +def _port(*batches: object) -> tuple[PostgresHireAcceptancePort, _Cursor]: + """Build a port whose cursor returns the supplied bounded batches.""" + cursor = _Cursor(list(batches)) + return PostgresHireAcceptancePort(lambda: _Connection(cursor)), cursor + + +def test_hire_rejects_executable_idempotency_batch_before_collection_hooks() -> None: + """Replay lookup must reject a batch subtype before truthiness or iteration.""" + port, cursor = _port(_ExecutableBatch()) + + with pytest.raises(HireDecisionIntegrityError, match="hire idempotency row is invalid"): + port.accept_hire(command=_command(), authorization=_authorization()) + + assert not any("selection_decision AS decision" in statement for statement in cursor.executions) + + +def test_hire_rejects_executable_idempotency_row_before_row_hooks() -> None: + """Replay lookup must reject a row subtype before length or unpacking.""" + port, cursor = _port([_ExecutableRow((CONVERSION, "digest"))]) + + with pytest.raises(HireDecisionIntegrityError, match="hire idempotency row is invalid"): + port.accept_hire(command=_command(), authorization=_authorization()) + + assert not any("selection_decision AS decision" in statement for statement in cursor.executions) + + +def test_hire_rejects_executable_provenance_batch_before_collection_hooks() -> None: + """Decision lookup must reject a batch subtype before truthiness or iteration.""" + port, cursor = _port([], _ExecutableBatch([_decision_row()])) + + with pytest.raises(HireDecisionIntegrityError, match="decision provenance row has an invalid shape"): + port.accept_hire(command=_command(), authorization=_authorization()) + + assert not any("INSERT INTO public.person_record" in statement for statement in cursor.executions) + + +def test_hire_rejects_executable_provenance_row_before_row_hooks() -> None: + """Decision lookup must reject a row subtype before length or unpacking.""" + port, cursor = _port([], [_ExecutableRow(_decision_row())]) + + with pytest.raises(HireDecisionIntegrityError, match="decision provenance row has an invalid shape"): + port.accept_hire(command=_command(), authorization=_authorization()) + + assert not any("INSERT INTO public.person_record" in statement for statement in cursor.executions) + + +def test_hire_rejects_wrong_width_exact_rows_at_the_container_boundary() -> None: + """Exact built-in rows still require their fixed SQL projection width.""" + replay_port, _ = _port([(CONVERSION,)]) + with pytest.raises(HireDecisionIntegrityError, match="hire idempotency row is invalid"): + replay_port.accept_hire(command=_command(), authorization=_authorization()) + + provenance_port, _ = _port([], [(_decision_row()[0],)]) + with pytest.raises(HireDecisionIntegrityError, match="decision provenance row has an invalid shape"): + provenance_port.accept_hire(command=_command(), authorization=_authorization()) + + +def test_hire_accepts_exact_builtin_batches_and_rows() -> None: + """Default Psycopg-compatible list batches and tuple rows remain accepted.""" + port, cursor = _port([], [_decision_row()]) + + result = port.accept_hire(command=_command(), authorization=_authorization()) + + assert result.candidate_worker_conversion_record_id == CONVERSION + assert any("INSERT INTO public.person_record" in statement for statement in cursor.executions) From adab34478eb8fbaed570b8a620739baa48e6c2f2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 05:34:20 +0900 Subject: [PATCH 30/80] fix(people): exact-gate durable hire row containers --- .../src/orgmetra_people_api/postgres_hire.py | 38 ++++++++++++++----- 1 file changed, 29 insertions(+), 9 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_hire.py b/services/people-api/src/orgmetra_people_api/postgres_hire.py index 46c359d9b..4bffbdb2d 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_hire.py +++ b/services/people-api/src/orgmetra_people_api/postgres_hire.py @@ -178,6 +178,18 @@ def _is_aware_datetime(value: object) -> bool: return value.utcoffset() is not None +def _unpack_fixed_rows(value: object, *, row_width: int, error_message: str) -> tuple[tuple[object, ...], ...]: + """Detach one bounded fixed projection only from inert built-in containers.""" + if type(value) not in (list, tuple): + raise HireDecisionIntegrityError(error_message) + rows: list[tuple[object, ...]] = [] + for row in value: + if type(row) not in (list, tuple) or len(row) != row_width: + raise HireDecisionIntegrityError(error_message) + rows.append(tuple(row)) + return tuple(rows) + + def _validate_authorization(command: HireAcceptanceCommand, authorization: object) -> AuthorizationDecision: """Require an exact allow decision for this immutable selection decision.""" expected_reference = f"selection_decision:{command.selection_decision_id.hex}" @@ -232,10 +244,14 @@ def _replayed_hire( key_parameters = (command.tenant_record_id, _HIRE_IDEMPOTENCY_ROUTE, command.idempotency_key) cursor.execute(_LOOKUP_HIRE_IDEMPOTENCY_SQL, key_parameters) cursor.execute(_READ_HIRE_IDEMPOTENCY_SQL, key_parameters) - rows = cursor.fetchmany(2) + rows = _unpack_fixed_rows( + cursor.fetchmany(2), + row_width=2, + error_message="hire idempotency row is invalid", + ) if not rows: return None - if len(rows) != 1 or len(rows[0]) != 2: + if len(rows) != 1: raise HireDecisionIntegrityError("hire idempotency row is invalid") created_record_id, stored_digest = rows[0] if not _is_operational_uuid(created_record_id) or type(stored_digest) is not str: @@ -282,8 +298,11 @@ class PostgresHireAcceptancePort: ``connection_factory`` must return a DB-API connection context manager whose successful exit commits and exceptional exit rolls back, as psycopg - connections do. Pooling, TLS, credentials, and database roles remain a - deployment concern outside this service package. + connections do. Fixed projections must cross this adapter boundary as exact + built-in list/tuple row collections containing exact built-in list/tuple + rows; custom row factories must normalize before durable evidence is read. + Pooling, TLS, credentials, and database roles remain a deployment concern + outside this service package. """ connection_factory: PostgresConnectionFactory @@ -328,14 +347,15 @@ def accept_hire( command.candidate_profile_id, ), ) - rows = cursor.fetchmany(2) + rows = _unpack_fixed_rows( + cursor.fetchmany(2), + row_width=7, + error_message="decision provenance row has an invalid shape", + ) if not rows: raise HireDecisionNotFound("confirmed hire decision with sealed evidence was not found") if len(rows) != 1: raise HireDecisionIntegrityError("multiple decision provenance rows matched the hire") - row = rows[0] - if len(row) != 7: - raise HireDecisionIntegrityError("decision provenance row has an invalid shape") ( decision_actor_reference, decision_purpose_code, @@ -344,7 +364,7 @@ def accept_hire( decided_at, evidence_set_id, transaction_recorded_at, - ) = row + ) = rows[0] if any( type(value) is not str From cf76786595f634d6d5ecb5f1e53fcf30859c76b7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 06:04:29 +0900 Subject: [PATCH 31/80] test(people): reject executable generic mutation row containers --- ...stgres_mutation_row_container_integrity.py | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 services/people-api/tests/test_postgres_mutation_row_container_integrity.py diff --git a/services/people-api/tests/test_postgres_mutation_row_container_integrity.py b/services/people-api/tests/test_postgres_mutation_row_container_integrity.py new file mode 100644 index 000000000..fc7b77fe3 --- /dev/null +++ b/services/people-api/tests/test_postgres_mutation_row_container_integrity.py @@ -0,0 +1,104 @@ +"""Executable-container regressions for generic People PostgreSQL projections.""" + +from __future__ import annotations + +import pytest + +import orgmetra_people_api.postgres_mutations as postgres_mutations +from orgmetra_people_api.mutations import PeopleMutationIntegrityError + + +class _ExecutableRows(list[object]): + """Tripwire outer row collection that must be rejected before container hooks.""" + + calls = 0 + + def __bool__(self) -> bool: + """Fail if durable validation asks this untrusted collection for truthiness.""" + type(self).calls += 1 + raise AssertionError("outer durable row collection executed __bool__") + + def __len__(self) -> int: + """Fail if durable validation asks this untrusted collection for cardinality.""" + type(self).calls += 1 + raise AssertionError("outer durable row collection executed __len__") + + def __getitem__(self, index: object) -> object: + """Fail if durable validation indexes this untrusted collection.""" + type(self).calls += 1 + raise AssertionError("outer durable row collection executed __getitem__") + + def __iter__(self): + """Fail if durable validation iterates this untrusted collection.""" + type(self).calls += 1 + raise AssertionError("outer durable row collection executed __iter__") + + +class _ExecutableRow(tuple[object, ...]): + """Tripwire fixed row that must be rejected before row hooks.""" + + calls = 0 + + def __len__(self) -> int: + """Fail if durable validation asks this untrusted row for width.""" + type(self).calls += 1 + raise AssertionError("durable row executed __len__") + + def __iter__(self): + """Fail if durable validation iterates this untrusted row.""" + type(self).calls += 1 + raise AssertionError("durable row executed __iter__") + + +@pytest.fixture(autouse=True) +def _reset_tripwires() -> None: + """Reset shared counters so each rejection proves zero callback execution.""" + _ExecutableRows.calls = 0 + _ExecutableRow.calls = 0 + + +def _unpack(value: object, *, row_width: int) -> tuple[tuple[object, ...], ...]: + """Resolve the production boundary explicitly so predecessor absence is RED.""" + unpack = getattr(postgres_mutations, "_unpack_fixed_rows", None) + assert unpack is not None, "generic People PostgreSQL adapter lacks a fixed-row trust boundary" + return unpack(value, row_width=row_width, error_message="durable projection is invalid") + + +def test_fixed_rows_reject_executable_outer_collection_before_hooks() -> None: + """Reject a list subtype before truthiness, length, indexing, or iteration executes.""" + rows = _ExecutableRows([(UUID_SENTINEL, "digest")]) + + with pytest.raises(PeopleMutationIntegrityError, match="durable projection is invalid"): + _unpack(rows, row_width=2) + + assert _ExecutableRows.calls == 0 + + +def test_fixed_rows_reject_executable_row_before_hooks() -> None: + """Reject a tuple subtype before width or iteration executes.""" + row = _ExecutableRow((UUID_SENTINEL, "digest")) + + with pytest.raises(PeopleMutationIntegrityError, match="durable projection is invalid"): + _unpack([row], row_width=2) + + assert _ExecutableRow.calls == 0 + + +def test_fixed_rows_reject_wrong_width_exact_row() -> None: + """Reject an inert built-in row whose SQL projection width is impossible.""" + with pytest.raises(PeopleMutationIntegrityError, match="durable projection is invalid"): + _unpack([(1, 2, 3)], row_width=2) + + +def test_fixed_rows_detach_exact_builtin_batches_and_rows() -> None: + """Accept exact built-in containers and return one inert tuple-of-tuples copy.""" + source = [[1, "a"], (2, "b")] + + detached = _unpack(source, row_width=2) + + assert detached == ((1, "a"), (2, "b")) + assert type(detached) is tuple + assert all(type(row) is tuple for row in detached) + + +UUID_SENTINEL = object() From 34c6e559768d98afa5353b110537188e2d7b9bd0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 06:19:56 +0900 Subject: [PATCH 32/80] fix(people): exact-gate generic mutation row containers --- .../orgmetra_people_api/postgres_mutations.py | 88 +++++++++++++++---- 1 file changed, 71 insertions(+), 17 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index 63e01d086..9aa41286e 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -261,6 +261,23 @@ def _is_aware_datetime(value: object) -> bool: return isinstance(value, datetime) and value.tzinfo is not None and value.utcoffset() is not None +def _unpack_fixed_rows( + value: object, + *, + row_width: int, + error_message: str, +) -> tuple[tuple[object, ...], ...]: + """Detach exact built-in DB row containers before projection values are inspected.""" + if type(value) not in (list, tuple): + raise PeopleMutationIntegrityError(error_message) + detached: list[tuple[object, ...]] = [] + for row in value: + if type(row) not in (list, tuple) or len(row) != row_width: + raise PeopleMutationIntegrityError(error_message) + detached.append(tuple(row)) + return tuple(detached) + + def _replayed_record_id( cursor: Any, *, @@ -273,10 +290,14 @@ def _replayed_record_id( key_parameters = (command.tenant_record_id, route, command.idempotency_key) cursor.execute(_LOOKUP_IDEMPOTENCY_SQL, key_parameters) cursor.execute(_READ_IDEMPOTENCY_SQL, key_parameters) - rows = cursor.fetchmany(2) + rows = _unpack_fixed_rows( + cursor.fetchmany(2), + row_width=2, + error_message="idempotency row is invalid", + ) if not rows: return None - if len(rows) != 1 or len(rows[0]) != 2: + if len(rows) != 1: raise PeopleMutationIntegrityError("idempotency row is invalid") created_record_id, stored_digest = rows[0] if not _is_operational_uuid(created_record_id) or not isinstance(stored_digest, str): @@ -485,15 +506,18 @@ def _assignment_from_row(tenant_record_id: UUID, row: tuple[object, ...]) -> Ass ) -def _require_one_conversion(rows: list[tuple[object, ...]]) -> tuple[UUID, datetime]: +def _require_one_conversion(rows: object) -> tuple[UUID, datetime]: """Require exactly one current conversion row and a usable transaction timestamp.""" - if not rows: + detached = _unpack_fixed_rows( + rows, + row_width=2, + error_message="conversion row has an invalid shape", + ) + if not detached: raise PeopleMutationIntegrityError("person has no governed candidate-worker conversion") - if len(rows) != 1: + if len(detached) != 1: raise PeopleMutationIntegrityError("multiple candidate-worker conversions matched the person") - if len(rows[0]) != 2: - raise PeopleMutationIntegrityError("conversion row has an invalid shape") - conversion_id, recorded_at = rows[0] + conversion_id, recorded_at = detached[0] if not _is_operational_uuid(conversion_id) or not _is_aware_datetime(recorded_at): raise PeopleMutationIntegrityError("conversion identity or transaction time is invalid") assert isinstance(conversion_id, UUID) @@ -504,8 +528,12 @@ def _require_one_conversion(rows: list[tuple[object, ...]]) -> tuple[UUID, datet def _post_lock_recorded_at(cursor: Any) -> datetime: """Read one database clock instant only after the relevant conflict lock is held.""" cursor.execute(_POST_LOCK_RECORDED_AT_SQL) - rows = cursor.fetchmany(2) - if len(rows) != 1 or len(rows[0]) != 1 or not _is_aware_datetime(rows[0][0]): + rows = _unpack_fixed_rows( + cursor.fetchmany(2), + row_width=1, + error_message="post-lock database clock row is invalid", + ) + if len(rows) != 1 or not _is_aware_datetime(rows[0][0]): raise PeopleMutationIntegrityError("post-lock database clock row is invalid") recorded_at = rows[0][0] assert isinstance(recorded_at, datetime) @@ -517,7 +545,9 @@ class PostgresPeopleMutationPort: """Persist People mutations and governance evidence in one DB transaction. ``connection_factory`` must return a DB-API connection context manager whose - successful exit commits and exceptional exit rolls back. + successful exit commits and exceptional exit rolls back. Fixed query + projections must arrive as exact built-in list/tuple batches and rows; + custom row factories must normalize before this trust boundary. """ connection_factory: PostgresConnectionFactory @@ -557,9 +587,14 @@ def create_employment( _EMPLOYMENT_VERSIONS_SQL, (command.tenant_record_id, command.person_record_id), ) + existing_rows = _unpack_fixed_rows( + cursor.fetchall(), + row_width=9, + error_message="employment version row has an invalid shape", + ) existing = [ _employment_version_from_row(command.tenant_record_id, row) - for row in cursor.fetchall() + for row in existing_rows ] proposed = EmploymentVersion( tenant_record_id=command.tenant_record_id, @@ -657,10 +692,14 @@ def create_position( _POSITION_PARENTS_SQL, (command.job_profile_id, command.tenant_record_id, command.organization_unit_id), ) - rows = cursor.fetchmany(2) + rows = _unpack_fixed_rows( + cursor.fetchmany(2), + row_width=3, + error_message="position parent row is invalid", + ) if not rows: raise PeopleMutationNotFound("organization unit or job profile was not found") - if len(rows) != 1 or len(rows[0]) != 3: + if len(rows) != 1: raise PeopleMutationIntegrityError("position parent row is invalid") organization_unit_id, job_profile_id, recorded_at = rows[0] if ( @@ -749,17 +788,27 @@ def create_assignment( _NAMED_EMPLOYMENT_VERSIONS_SQL, (command.tenant_record_id, command.employment_record_id), ) + employment_rows = _unpack_fixed_rows( + cursor.fetchall(), + row_width=9, + error_message="employment version row has an invalid shape", + ) employment_versions = [ _employment_version_from_row(command.tenant_record_id, row) - for row in cursor.fetchall() + for row in employment_rows ] cursor.execute( _NAMED_POSITION_VERSIONS_SQL, (command.tenant_record_id, command.position_record_id), ) + position_rows = _unpack_fixed_rows( + cursor.fetchall(), + row_width=7, + error_message="position version row has an invalid shape", + ) position_versions = [ _position_version_from_row(command.tenant_record_id, row) - for row in cursor.fetchall() + for row in position_rows ] recorded_at = _post_lock_recorded_at(cursor) cursor.execute( @@ -770,9 +819,14 @@ def create_assignment( command.position_record_id, ), ) + assignment_rows = _unpack_fixed_rows( + cursor.fetchall(), + row_width=9, + error_message="assignment row has an invalid shape", + ) existing_assignments = [ _assignment_from_row(command.tenant_record_id, row) - for row in cursor.fetchall() + for row in assignment_rows ] proposed = AssignmentFact( tenant_record_id=command.tenant_record_id, From e7f84b28bb4ff23f935b311bd0669292033e1f95 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 06:25:01 +0900 Subject: [PATCH 33/80] test(people): reject executable generic mutation durable scalars --- ...tgres_mutation_scalar_runtime_integrity.py | 81 +++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py new file mode 100644 index 000000000..f9f7218fa --- /dev/null +++ b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py @@ -0,0 +1,81 @@ +"""Runtime-integrity contracts for generic People durable scalar evidence.""" + +from datetime import datetime, timedelta, timezone, tzinfo +from uuid import UUID +from zoneinfo import ZoneInfo + +from orgmetra_people_api.postgres_mutations import _is_aware_datetime, _is_operational_uuid + + +_MAX_UUID_INT = (1 << 128) - 1 + + +class _ExecutableUUID(UUID): + """Expose UUID attribute inspection performed before an exact-type gate.""" + + def __getattribute__(self, name: str) -> object: + """Fail when untrusted UUID evidence is inspected as if it were inert.""" + if name == "int": + raise AssertionError("UUID subtype behavior executed before exact-type validation") + return super().__getattribute__(name) + + +class _ExecutableTimezone(tzinfo): + """Record forbidden offset resolution at the generic People durable boundary.""" + + def __init__(self) -> None: + """Initialize the callback counter without resolving an offset.""" + self.calls = 0 + + def utcoffset(self, dt: datetime | None) -> timedelta: + """Fail if validation executes caller-defined timezone behavior.""" + del dt + self.calls += 1 + raise AssertionError("caller-defined timezone callback executed") + + +class _ExecutableDatetime(datetime): + """Fail if validation executes behavior from a datetime subtype.""" + + def utcoffset(self) -> timedelta: + """Expose subtype execution if the exact-type gate is missing.""" + raise AssertionError("datetime subtype callback executed") + + +def test_generic_durable_uuid_rejects_subtype_before_identity_inspection() -> None: + """DB-returned UUID subtypes fail without executing subtype behavior.""" + value = _ExecutableUUID("0198a412-7100-7000-8000-000000000061") + + assert _is_operational_uuid(value) is False + + +def test_generic_durable_uuid_accepts_only_operational_exact_uuid_values() -> None: + """Exact Psycopg-compatible UUIDs remain valid except reserved sentinels.""" + assert _is_operational_uuid(UUID("0198a412-7100-7000-8000-000000000061")) is True + assert _is_operational_uuid(UUID(int=0)) is False + assert _is_operational_uuid(UUID(int=_MAX_UUID_INT)) is False + + +def test_generic_timestamp_rejects_custom_timezone_before_callback() -> None: + """Exact datetime values cannot delegate offset validation to caller code.""" + provider = _ExecutableTimezone() + value = datetime(2026, 9, 5, 0, 0, tzinfo=provider) + + assert _is_aware_datetime(value) is False + assert provider.calls == 0 + + +def test_generic_timestamp_rejects_datetime_subtype_before_callback() -> None: + """Executable datetime subtypes are not durable generic People evidence.""" + value = _ExecutableDatetime(2026, 9, 5, 0, 0, tzinfo=timezone.utc) + + assert _is_aware_datetime(value) is False + + +def test_generic_timestamp_accepts_exact_standard_library_timezones() -> None: + """Psycopg-compatible standard-library timezone materialization stays valid.""" + utc_value = datetime(2026, 9, 5, 0, 0, tzinfo=timezone.utc) + seoul_value = datetime(2026, 9, 5, 9, 0, tzinfo=ZoneInfo("Asia/Seoul")) + + assert _is_aware_datetime(utc_value) is True + assert _is_aware_datetime(seoul_value) is True From 36bdc32e52baf21cc8b3a716b1cef0af7b992ea0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 06:26:19 +0900 Subject: [PATCH 34/80] fix(people): exact-gate generic mutation durable scalars --- .../src/orgmetra_people_api/postgres_mutations.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index 9aa41286e..d49dab94a 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -10,10 +10,11 @@ from contextlib import AbstractContextManager from dataclasses import dataclass -from datetime import date, datetime +from datetime import date, datetime, timezone from decimal import Decimal from typing import Any, Callable from uuid import UUID +from zoneinfo import ZoneInfo from orgmetra_hris_kernel import ( AssignmentFact, @@ -252,13 +253,17 @@ def _is_operational_uuid(value: object) -> bool: - """Return whether a value is an Orgmetra operational UUID.""" - return isinstance(value, UUID) and value.int not in (0, _MAX_UUID_INT) + """Return whether a value is an exact operational UUID.""" + return type(value) is UUID and value.int not in (0, _MAX_UUID_INT) def _is_aware_datetime(value: object) -> bool: - """Return whether a value is a timezone-aware datetime with a real offset.""" - return isinstance(value, datetime) and value.tzinfo is not None and value.utcoffset() is not None + """Return whether durable time is exact and backed by an inert standard provider.""" + if type(value) is not datetime or value.tzinfo is None: + return False + if type(value.tzinfo) not in (timezone, ZoneInfo): + return False + return value.utcoffset() is not None def _unpack_fixed_rows( From 0498eaa17e4e3a74c0e50994076da93e61830eb2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 06:32:04 +0900 Subject: [PATCH 35/80] test(people): reject executable generic replay digest --- ...tgres_mutation_scalar_runtime_integrity.py | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py index f9f7218fa..12f28ae63 100644 --- a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py +++ b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py @@ -1,10 +1,18 @@ """Runtime-integrity contracts for generic People durable scalar evidence.""" from datetime import datetime, timedelta, timezone, tzinfo +from typing import Any from uuid import UUID from zoneinfo import ZoneInfo -from orgmetra_people_api.postgres_mutations import _is_aware_datetime, _is_operational_uuid +from orgmetra_people_api.mutations import PeopleMutationIntegrityError +from orgmetra_people_api.postgres_mutations import ( + _is_aware_datetime, + _is_operational_uuid, + _replayed_record_id, +) +from test_people_mutations import employment_command +from test_postgres_people_mutations import employment_authorization _MAX_UUID_INT = (1 << 128) - 1 @@ -42,6 +50,44 @@ def utcoffset(self) -> timedelta: raise AssertionError("datetime subtype callback executed") +class _ExecutableDigest(str): + """Expose digest comparison performed before an exact-type gate.""" + + def __new__(cls, value: str) -> _ExecutableDigest: + """Create one tripwire text value without invoking comparison behavior.""" + instance = super().__new__(cls, value) + instance.calls = 0 + return instance + + def __eq__(self, other: object) -> bool: + """Fail if durable replay validation executes subtype equality.""" + del other + self.calls += 1 + raise AssertionError("digest subtype equality executed before exact-type validation") + + def __ne__(self, other: object) -> bool: + """Fail if durable replay validation executes subtype inequality.""" + del other + self.calls += 1 + raise AssertionError("digest subtype inequality executed before exact-type validation") + + +class _ReplayCursor: + """Return one scripted exact built-in idempotency row.""" + + def __init__(self, row: tuple[object, object]) -> None: + """Store the row without inspecting its scalar values.""" + self.row = row + + def execute(self, sql: str, parameters: tuple[object, ...] | None = None) -> None: + """Accept the two replay lookup statements without side effects.""" + del sql, parameters + + def fetchmany(self, size: int) -> list[tuple[object, object]]: + """Return the scripted exact row within the requested bound.""" + return [self.row][:size] + + def test_generic_durable_uuid_rejects_subtype_before_identity_inspection() -> None: """DB-returned UUID subtypes fail without executing subtype behavior.""" value = _ExecutableUUID("0198a412-7100-7000-8000-000000000061") @@ -79,3 +125,23 @@ def test_generic_timestamp_accepts_exact_standard_library_timezones() -> None: assert _is_aware_datetime(utc_value) is True assert _is_aware_datetime(seoul_value) is True + + +def test_generic_replay_digest_rejects_subtype_before_comparison() -> None: + """Persisted digest subtypes fail without executing equality behavior.""" + command = employment_command() + digest = _ExecutableDigest("persisted-untrusted-digest") + cursor: Any = _ReplayCursor((command.employment_record_id, digest)) + + try: + _replayed_record_id( + cursor, + command=command, + authorization=employment_authorization(), + ) + except PeopleMutationIntegrityError as error: + assert str(error) == "idempotency row is invalid" + else: + raise AssertionError("digest subtype was not rejected") + + assert digest.calls == 0 From 55033e7d00023e0757971c63c1d893904f70332d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 06:33:29 +0900 Subject: [PATCH 36/80] fix(people): exact-gate generic replay digest --- .../people-api/src/orgmetra_people_api/postgres_mutations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index d49dab94a..9eec078c5 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -305,7 +305,7 @@ def _replayed_record_id( if len(rows) != 1: raise PeopleMutationIntegrityError("idempotency row is invalid") created_record_id, stored_digest = rows[0] - if not _is_operational_uuid(created_record_id) or not isinstance(stored_digest, str): + if not _is_operational_uuid(created_record_id) or type(stored_digest) is not str: raise PeopleMutationIntegrityError("idempotency row is invalid") if stored_digest != digest: raise PeopleMutationIntegrityError("idempotency key is bound to a different command") From 19f21291fadd9f0ca58aa30e2e8c554299757d69 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 07:04:28 +0900 Subject: [PATCH 37/80] test(people): reject executable persisted status text --- ...tgres_mutation_scalar_runtime_integrity.py | 104 +++++++++++++++++- 1 file changed, 103 insertions(+), 1 deletion(-) diff --git a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py index 12f28ae63..0f5e07dd3 100644 --- a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py +++ b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py @@ -1,14 +1,16 @@ """Runtime-integrity contracts for generic People durable scalar evidence.""" -from datetime import datetime, timedelta, timezone, tzinfo +from datetime import date, datetime, timedelta, timezone, tzinfo from typing import Any from uuid import UUID from zoneinfo import ZoneInfo from orgmetra_people_api.mutations import PeopleMutationIntegrityError from orgmetra_people_api.postgres_mutations import ( + _employment_version_from_row, _is_aware_datetime, _is_operational_uuid, + _position_version_from_row, _replayed_record_id, ) from test_people_mutations import employment_command @@ -72,6 +74,33 @@ def __ne__(self, other: object) -> bool: raise AssertionError("digest subtype inequality executed before exact-type validation") +class _ExecutableStatusText(str): + """Expose persisted status-code behavior before an exact durable type gate.""" + + def __new__(cls, value: str) -> _ExecutableStatusText: + """Create one status-code tripwire without invoking comparison behavior.""" + instance = super().__new__(cls, value) + instance.calls = 0 + return instance + + def __hash__(self) -> int: + """Fail if HRIS validation hashes persisted subtype text.""" + self.calls += 1 + raise AssertionError("status subtype hashing executed before exact-type validation") + + def __eq__(self, other: object) -> bool: + """Fail if HRIS validation compares persisted subtype text.""" + del other + self.calls += 1 + raise AssertionError("status subtype equality executed before exact-type validation") + + def __ne__(self, other: object) -> bool: + """Fail if HRIS validation compares persisted subtype text for inequality.""" + del other + self.calls += 1 + raise AssertionError("status subtype inequality executed before exact-type validation") + + class _ReplayCursor: """Return one scripted exact built-in idempotency row.""" @@ -145,3 +174,76 @@ def test_generic_replay_digest_rejects_subtype_before_comparison() -> None: raise AssertionError("digest subtype was not rejected") assert digest.calls == 0 + + +def test_employment_projection_rejects_status_subtype_before_kernel_behavior() -> None: + """Persisted Employment status text must be inert before HRIS fact construction.""" + status = _ExecutableStatusText("active") + row = ( + UUID("0198a412-7100-7000-8000-000000000071"), + UUID("0198a412-7100-7000-8000-000000000072"), + UUID("0198a412-7100-7000-8000-000000000073"), + status, + "exclusive", + date(2026, 9, 5), + None, + datetime(2026, 9, 5, 0, 0, tzinfo=timezone.utc), + None, + ) + + try: + _employment_version_from_row(UUID("0198a412-7100-7000-8000-000000000070"), row) + except PeopleMutationIntegrityError as error: + assert str(error) == "employment version row is invalid" + else: + raise AssertionError("employment status subtype was not rejected") + + assert status.calls == 0 + + +def test_employment_projection_rejects_concurrency_subtype_before_kernel_behavior() -> None: + """Persisted concurrency text must be inert before exclusivity validation can hash it.""" + concurrency = _ExecutableStatusText("exclusive") + row = ( + UUID("0198a412-7100-7000-8000-000000000081"), + UUID("0198a412-7100-7000-8000-000000000082"), + UUID("0198a412-7100-7000-8000-000000000083"), + "active", + concurrency, + date(2026, 9, 5), + None, + datetime(2026, 9, 5, 0, 0, tzinfo=timezone.utc), + None, + ) + + try: + _employment_version_from_row(UUID("0198a412-7100-7000-8000-000000000080"), row) + except PeopleMutationIntegrityError as error: + assert str(error) == "employment version row is invalid" + else: + raise AssertionError("employment concurrency subtype was not rejected") + + assert concurrency.calls == 0 + + +def test_position_projection_rejects_status_subtype_before_kernel_behavior() -> None: + """Persisted Position status text must be exact before assignment validation can compare it.""" + status = _ExecutableStatusText("active") + row = ( + UUID("0198a412-7100-7000-8000-000000000091"), + UUID("0198a412-7100-7000-8000-000000000092"), + status, + date(2026, 9, 5), + None, + datetime(2026, 9, 5, 0, 0, tzinfo=timezone.utc), + None, + ) + + try: + _position_version_from_row(UUID("0198a412-7100-7000-8000-000000000090"), row) + except PeopleMutationIntegrityError as error: + assert str(error) == "position version row is invalid" + else: + raise AssertionError("position status subtype was not rejected") + + assert status.calls == 0 From 2c0b1140a8a93af74560b4c98cc6d251c0bf347c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 07:08:15 +0900 Subject: [PATCH 38/80] fix(people): exact-gate persisted status codes --- .../src/orgmetra_people_api/postgres_mutations.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index 9eec078c5..22b5bf26c 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -404,8 +404,8 @@ def _employment_version_from_row(tenant_record_id: UUID, row: tuple[object, ...] not _is_operational_uuid(employment_record_id) or not _is_operational_uuid(employment_record_version_id) or not _is_operational_uuid(person_record_id) - or not isinstance(status_code, str) - or not isinstance(concurrency_code, str) + or type(status_code) is not str + or type(concurrency_code) is not str or type(effective_from) is not date or (effective_to is not None and type(effective_to) is not date) or not _is_aware_datetime(recorded_from) @@ -445,7 +445,7 @@ def _position_version_from_row(tenant_record_id: UUID, row: tuple[object, ...]) if ( not _is_operational_uuid(position_record_id) or not _is_operational_uuid(position_record_version_id) - or not isinstance(status_code, str) + or type(status_code) is not str or type(effective_from) is not date or (effective_to is not None and type(effective_to) is not date) or not _is_aware_datetime(recorded_from) From ad1c1dbd2dc1a185ba6a81178cb99b37e18b4ae8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 07:12:35 +0900 Subject: [PATCH 39/80] test(people): reject executable persisted allocation Decimal --- ...tgres_mutation_scalar_runtime_integrity.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py index 0f5e07dd3..035a467a1 100644 --- a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py +++ b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py @@ -1,12 +1,14 @@ """Runtime-integrity contracts for generic People durable scalar evidence.""" from datetime import date, datetime, timedelta, timezone, tzinfo +from decimal import Decimal from typing import Any from uuid import UUID from zoneinfo import ZoneInfo from orgmetra_people_api.mutations import PeopleMutationIntegrityError from orgmetra_people_api.postgres_mutations import ( + _assignment_from_row, _employment_version_from_row, _is_aware_datetime, _is_operational_uuid, @@ -101,6 +103,40 @@ def __ne__(self, other: object) -> bool: raise AssertionError("status subtype inequality executed before exact-type validation") +class _ExecutableDecimal(Decimal): + """Expose persisted allocation-ratio behavior before an exact durable type gate.""" + + def __new__(cls, value: str) -> _ExecutableDecimal: + """Create one Decimal tripwire without performing portfolio arithmetic.""" + instance = super().__new__(cls, value) + instance.calls = 0 + return instance + + def __gt__(self, other: object) -> bool: + """Fail if FTE validation compares persisted subtype allocation.""" + del other + self.calls += 1 + raise AssertionError("Decimal subtype comparison executed before exact-type validation") + + def __le__(self, other: object) -> bool: + """Fail if FTE validation compares persisted subtype allocation.""" + del other + self.calls += 1 + raise AssertionError("Decimal subtype comparison executed before exact-type validation") + + def __add__(self, other: object) -> Decimal: + """Fail if portfolio aggregation adds persisted subtype allocation.""" + del other + self.calls += 1 + raise AssertionError("Decimal subtype addition executed before exact-type validation") + + def __radd__(self, other: object) -> Decimal: + """Fail if portfolio aggregation reverse-adds persisted subtype allocation.""" + del other + self.calls += 1 + raise AssertionError("Decimal subtype reverse addition executed before exact-type validation") + + class _ReplayCursor: """Return one scripted exact built-in idempotency row.""" @@ -247,3 +283,28 @@ def test_position_projection_rejects_status_subtype_before_kernel_behavior() -> raise AssertionError("position status subtype was not rejected") assert status.calls == 0 + + +def test_assignment_projection_rejects_decimal_subtype_before_fte_math() -> None: + """Persisted allocation Decimal must be exact before portfolio comparison or summation.""" + allocation = _ExecutableDecimal("0.5000") + row = ( + UUID("0198a412-7100-7000-8000-0000000000a1"), + UUID("0198a412-7100-7000-8000-0000000000a2"), + UUID("0198a412-7100-7000-8000-0000000000a3"), + UUID("0198a412-7100-7000-8000-0000000000a4"), + allocation, + date(2026, 9, 5), + None, + datetime(2026, 9, 5, 0, 0, tzinfo=timezone.utc), + None, + ) + + try: + _assignment_from_row(UUID("0198a412-7100-7000-8000-0000000000a0"), row) + except PeopleMutationIntegrityError as error: + assert str(error) == "assignment row is invalid" + else: + raise AssertionError("assignment allocation Decimal subtype was not rejected") + + assert allocation.calls == 0 From 3a63e92c94113e1e75d6eef386c3ce9e86b165e6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 07:13:45 +0900 Subject: [PATCH 40/80] fix(people): exact-gate persisted allocation Decimal --- .../people-api/src/orgmetra_people_api/postgres_mutations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index 22b5bf26c..ce32beb9a 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -486,7 +486,7 @@ def _assignment_from_row(tenant_record_id: UUID, row: tuple[object, ...]) -> Ass or not _is_operational_uuid(employment_record_id) or not _is_operational_uuid(person_record_id) or not _is_operational_uuid(position_record_id) - or not isinstance(allocation_ratio, Decimal) + or type(allocation_ratio) is not Decimal or type(effective_from) is not date or (effective_to is not None and type(effective_to) is not date) or not _is_aware_datetime(recorded_from) From 11c30cd5d0514caf4096578a8337042e6a583e6e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 08:02:24 +0900 Subject: [PATCH 41/80] test(people): reject executable Position parent UUID evidence --- ..._position_parent_uuid_runtime_integrity.py | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 services/people-api/tests/test_postgres_position_parent_uuid_runtime_integrity.py diff --git a/services/people-api/tests/test_postgres_position_parent_uuid_runtime_integrity.py b/services/people-api/tests/test_postgres_position_parent_uuid_runtime_integrity.py new file mode 100644 index 000000000..96a9353c1 --- /dev/null +++ b/services/people-api/tests/test_postgres_position_parent_uuid_runtime_integrity.py @@ -0,0 +1,48 @@ +"""Runtime-integrity contract for durable Position parent identities.""" + +from uuid import UUID + +from orgmetra_people_api.mutations import PeopleMutationIntegrityError +from orgmetra_people_api.postgres_mutations import PostgresPeopleMutationPort +from test_people_mutations import JOB, ORGANIZATION, position_command +from test_postgres_people_mutations import ( + FakeConnection, + RECORDED_AT, + ScriptedCursor, + position_authorization, +) + + +class _ExecutableComparableUUID(UUID): + """Expose parent-identity comparison performed before an exact-type gate.""" + + def __eq__(self, other: object) -> bool: + """Fail if durable parent validation executes subtype equality.""" + del other + raise AssertionError("UUID subtype equality executed before exact-type validation") + + def __ne__(self, other: object) -> bool: + """Fail if durable parent validation executes subtype inequality.""" + del other + raise AssertionError("UUID subtype inequality executed before exact-type validation") + + +def test_position_parent_uuid_subtypes_reject_before_identity_comparison() -> None: + """Organization and Job UUID subtypes fail before their comparison hooks execute.""" + for parent_index, expected_parent in enumerate((ORGANIZATION, JOB)): + parent_uuid = _ExecutableComparableUUID(str(expected_parent)) + parent_row: list[object] = [ORGANIZATION, JOB, RECORDED_AT] + parent_row[parent_index] = parent_uuid + cursor = ScriptedCursor([[], [tuple(parent_row)]], []) + connection = FakeConnection(cursor) + port = PostgresPeopleMutationPort(lambda: connection) + + try: + port.create_position( + command=position_command(), + authorization=position_authorization(), + ) + except PeopleMutationIntegrityError as error: + assert str(error) == "position parent identity is invalid" + else: + raise AssertionError("position parent UUID subtype was not rejected") From 46884c24886654edb86a2233e690fd2cb4473c3a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 08:04:06 +0900 Subject: [PATCH 42/80] fix(people): validate Position parent UUIDs before equality --- .../people-api/src/orgmetra_people_api/postgres_mutations.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index ce32beb9a..d75e6a5c8 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -708,7 +708,9 @@ def create_position( raise PeopleMutationIntegrityError("position parent row is invalid") organization_unit_id, job_profile_id, recorded_at = rows[0] if ( - organization_unit_id != command.organization_unit_id + not _is_operational_uuid(organization_unit_id) + or not _is_operational_uuid(job_profile_id) + or organization_unit_id != command.organization_unit_id or job_profile_id != command.job_profile_id or not _is_aware_datetime(recorded_at) ): From 3e7eb2022a49a94f6ce383ef71df3bd18ffd0cb6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 09:31:09 +0900 Subject: [PATCH 43/80] test(people): prove post-construction mutation escapes runtime integrity --- ...le_mutation_post_construction_integrity.py | 190 ++++++++++++++++++ 1 file changed, 190 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_post_construction_integrity.py diff --git a/services/people-api/tests/test_people_mutation_post_construction_integrity.py b/services/people-api/tests/test_people_mutation_post_construction_integrity.py new file mode 100644 index 000000000..0475d877a --- /dev/null +++ b/services/people-api/tests/test_people_mutation_post_construction_integrity.py @@ -0,0 +1,190 @@ +"""Post-construction runtime-integrity regressions for governed People mutations.""" + +from __future__ import annotations + +from datetime import date +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision, PurposeBoundAccessPolicy +from orgmetra_people_api.auth import AuthenticatedPrincipal +from orgmetra_people_api.mutations import ( + AssignmentMutationCommand, + AssignmentMutationResult, + EmploymentMutationCommand, + EmploymentMutationResult, + PositionMutationCommand, + PositionMutationResult, + create_employment_record, + mutation_command_digest, +) + +TENANT = UUID("0198a412-a600-7000-8000-000000000001") +PERSON = UUID("0198a412-a600-7000-8000-000000000020") +EMPLOYMENT = UUID("0198a412-a600-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-a600-7000-8000-000000000031") +AUDIT_EVENT = UUID("0198a412-a600-7000-8000-000000000080") +OUTBOX = UUID("0198a412-a600-7000-8000-000000000081") + + +class _ExecutableUUID(UUID): + """Trip if a rewritten UUID is observed before exact runtime revalidation.""" + + @property + def hex(self) -> str: + """Fail if resource-reference rendering executes before validation.""" + raise AssertionError("rewritten UUID hex behavior must not execute") + + def __str__(self) -> str: + """Fail if canonical rendering executes before validation.""" + raise AssertionError("rewritten UUID string behavior must not execute") + + +def _command() -> EmploymentMutationCommand: + """Build one initially valid exact employment mutation command.""" + return EmploymentMutationCommand( + tenant_record_id=TENANT, + person_record_id=PERSON, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + employment_status_code="active", + employment_concurrency_code="exclusive", + effective_from=date(2026, 9, 5), + confirmation_reference="human_confirmation:post-construction-1", + evidence_version_code="employment-evidence-v1", + idempotency_key="post-construction-runtime-1", + ) + + +def _decision() -> AuthorizationDecision: + """Build exact authorization evidence for the employment command.""" + fields = frozenset({"employment_record"}) + return AuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-226", + resource_reference=f"employment_record:{EMPLOYMENT.hex}", + policy_version_code="people-mutation-v1", + purpose_code="workforce_admin", + operation_code="create_record", + resource_kind="employment_record", + requested_fields=fields, + authorized_fields=fields, + reason_code="access_permitted", + next_action="continue", + ) + + +def _principal() -> AuthenticatedPrincipal: + """Build one exact authenticated principal for service-boundary testing.""" + return AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-226", + granted_scope_codes=frozenset({"orgmetra.people.write"}), + ) + + +def _policy() -> PurposeBoundAccessPolicy: + """Build one exact purpose-bound policy for employment creation.""" + return PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="people-mutation-v1", + resource_kind="employment_record", + purpose_code="workforce_admin", + operation_code="create_record", + required_scope_code="orgmetra.people.write", + permitted_fields=frozenset({"employment_record"}), + ) + + +class _ResultPort: + """Return one supplied employment result while satisfying the mutation protocol.""" + + def __init__(self, result: EmploymentMutationResult) -> None: + """Retain the exact result supplied by the regression.""" + self.result = result + + def create_employment( + self, + *, + command: EmploymentMutationCommand, + authorization: AuthorizationDecision, + ) -> EmploymentMutationResult: + """Return the supplied employment result without changing it.""" + del command, authorization + return self.result + + def create_position( + self, + *, + command: PositionMutationCommand, + authorization: AuthorizationDecision, + ) -> PositionMutationResult: + """Reject unrelated position work in this focused regression port.""" + del command, authorization + raise AssertionError("position mutation is outside this regression") + + def create_assignment( + self, + *, + command: AssignmentMutationCommand, + authorization: AuthorizationDecision, + ) -> AssignmentMutationResult: + """Reject unrelated assignment work in this focused regression port.""" + del command, authorization + raise AssertionError("assignment mutation is outside this regression") + + +def test_digest_revalidates_exact_command_after_object_setattr_rewrite() -> None: + """Canonical digesting must reject rewritten command evidence before callbacks.""" + command = _command() + object.__setattr__( + command, + "person_record_id", + _ExecutableUUID("0198a412-a600-7000-8000-000000000099"), + ) + + with pytest.raises(ValueError, match="person_record_id must be an operational UUID"): + mutation_command_digest(command=command, authorization=_decision()) + + +def test_service_revalidates_exact_command_before_authorization_or_port_work() -> None: + """An exact command rewritten after construction must fail before field rendering.""" + command = _command() + object.__setattr__( + command, + "employment_record_id", + _ExecutableUUID("0198a412-a600-7000-8000-000000000098"), + ) + result = EmploymentMutationResult(employment_record_id=EMPLOYMENT) + + with pytest.raises(ValueError, match="employment_record_id must be an operational UUID"): + create_employment_record( + principal=_principal(), + command=command, + purpose_code="workforce_admin", + policy=_policy(), + mutation_port=_ResultPort(result), + ) + + +def test_service_revalidates_exact_result_after_port_rewrite() -> None: + """An exact result rewritten by a port must not cross the People service boundary.""" + result = EmploymentMutationResult(employment_record_id=EMPLOYMENT) + object.__setattr__( + result, + "employment_record_id", + _ExecutableUUID("0198a412-a600-7000-8000-000000000097"), + ) + + with pytest.raises(ValueError, match="employment_record_id must be an operational UUID"): + create_employment_record( + principal=_principal(), + command=_command(), + purpose_code="workforce_admin", + policy=_policy(), + mutation_port=_ResultPort(result), + ) From e278023faba22ef01ed96b9997b85fb88511fba5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 09:31:49 +0900 Subject: [PATCH 44/80] fix(people): revalidate mutation evidence at consumption boundaries --- services/people-api/src/orgmetra_people_api/mutations.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index ada1c59aa..544be6b5f 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -119,6 +119,7 @@ def mutation_command_digest( if type(authorization) is not AuthorizationDecision: raise TypeError("authorization must be an AuthorizationDecision") if type(command) is EmploymentMutationCommand: + EmploymentMutationCommand.__post_init__(command) route = "employment-records" semantic_command: dict[str, object] = { "confirmation_reference": command.confirmation_reference, @@ -129,6 +130,7 @@ def mutation_command_digest( "person_record_id": str(command.person_record_id), } elif type(command) is PositionMutationCommand: + PositionMutationCommand.__post_init__(command) route = "position-records" semantic_command = { "confirmation_reference": command.confirmation_reference, @@ -139,6 +141,7 @@ def mutation_command_digest( "position_status_code": command.position_status_code, } elif type(command) is AssignmentMutationCommand: + AssignmentMutationCommand.__post_init__(command) route = "assignment-records" semantic_command = { "allocation_ratio": _canonical_allocation_ratio(command.allocation_ratio), @@ -366,6 +369,7 @@ def create_employment_record( """Authorize the exact employment target before persisting worker employment truth.""" if type(command) is not EmploymentMutationCommand: raise TypeError("command must be an EmploymentMutationCommand") + EmploymentMutationCommand.__post_init__(command) port = _require_port(mutation_port) authorization = authorize_resource_fields( principal=principal, @@ -381,6 +385,7 @@ def create_employment_record( result = port.create_employment(command=command, authorization=authorization) if type(result) is not EmploymentMutationResult: raise TypeError("mutation_port must return EmploymentMutationResult") + EmploymentMutationResult.__post_init__(result) return result @@ -395,6 +400,7 @@ def create_position_record( """Authorize the exact position target before persisting a staffable seat.""" if type(command) is not PositionMutationCommand: raise TypeError("command must be a PositionMutationCommand") + PositionMutationCommand.__post_init__(command) port = _require_port(mutation_port) authorization = authorize_resource_fields( principal=principal, @@ -410,6 +416,7 @@ def create_position_record( result = port.create_position(command=command, authorization=authorization) if type(result) is not PositionMutationResult: raise TypeError("mutation_port must return PositionMutationResult") + PositionMutationResult.__post_init__(result) return result @@ -424,6 +431,7 @@ def create_assignment_record( """Authorize the exact assignment target before persisting seat allocation.""" if type(command) is not AssignmentMutationCommand: raise TypeError("command must be an AssignmentMutationCommand") + AssignmentMutationCommand.__post_init__(command) port = _require_port(mutation_port) authorization = authorize_resource_fields( principal=principal, @@ -439,6 +447,7 @@ def create_assignment_record( result = port.create_assignment(command=command, authorization=authorization) if type(result) is not AssignmentMutationResult: raise TypeError("mutation_port must return AssignmentMutationResult") + AssignmentMutationResult.__post_init__(result) return result From c7e0319df8b8603e862c61dfe0f402d7f58fc243 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 09:34:54 +0900 Subject: [PATCH 45/80] test(people): prove rewritten command reaches PostgreSQL authority --- ...es_mutation_post_construction_integrity.py | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 services/people-api/tests/test_postgres_mutation_post_construction_integrity.py diff --git a/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py b/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py new file mode 100644 index 000000000..6d02c2923 --- /dev/null +++ b/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py @@ -0,0 +1,79 @@ +"""Post-construction command-integrity regression for the PostgreSQL People port.""" + +from __future__ import annotations + +from datetime import date +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import AuthorizationDecision +from orgmetra_people_api.mutations import EmploymentMutationCommand +from orgmetra_people_api.postgres_mutations import PostgresPeopleMutationPort + +TENANT = UUID("0198a412-a700-7000-8000-000000000001") +PERSON = UUID("0198a412-a700-7000-8000-000000000020") +EMPLOYMENT = UUID("0198a412-a700-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-a700-7000-8000-000000000031") +AUDIT_EVENT = UUID("0198a412-a700-7000-8000-000000000080") +OUTBOX = UUID("0198a412-a700-7000-8000-000000000081") + + +class _ExecutableUUID(UUID): + """Trip if the PostgreSQL authority renders rewritten identity before validation.""" + + @property + def hex(self) -> str: + """Fail if authorization-reference rendering runs before command validation.""" + raise AssertionError("rewritten UUID hex behavior must not execute") + + +def _authorization() -> AuthorizationDecision: + """Build one exact authorization decision for the original employment identity.""" + fields = frozenset({"employment_record"}) + return AuthorizationDecision( + allowed=True, + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-227", + resource_reference=f"employment_record:{EMPLOYMENT.hex}", + policy_version_code="people-mutation-v1", + purpose_code="workforce_admin", + operation_code="create_record", + resource_kind="employment_record", + requested_fields=fields, + authorized_fields=fields, + reason_code="access_permitted", + next_action="continue", + ) + + +def _forbidden_connection_factory() -> object: + """Fail if rewritten command evidence reaches PostgreSQL transaction work.""" + raise AssertionError("database work must not begin for a rewritten mutation command") + + +def test_postgres_port_revalidates_exact_command_after_object_setattr_rewrite() -> None: + """Reject rewritten command identity before callback or database work.""" + command = EmploymentMutationCommand( + tenant_record_id=TENANT, + person_record_id=PERSON, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + employment_status_code="active", + employment_concurrency_code="exclusive", + effective_from=date(2026, 9, 5), + confirmation_reference="human_confirmation:post-construction-227", + evidence_version_code="employment-evidence-v1", + idempotency_key="post-construction-runtime-227", + ) + object.__setattr__( + command, + "employment_record_id", + _ExecutableUUID("0198a412-a700-7000-8000-000000000099"), + ) + port = PostgresPeopleMutationPort(_forbidden_connection_factory) + + with pytest.raises(ValueError, match="employment_record_id must be an operational UUID"): + port.create_employment(command=command, authorization=_authorization()) From 6826999598163aac10596c8eb1f71116a68ca952 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 09:36:24 +0900 Subject: [PATCH 46/80] fix(people): revalidate commands at PostgreSQL mutation entry --- .../people-api/src/orgmetra_people_api/postgres_mutations.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index d75e6a5c8..0ceec0130 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -571,6 +571,7 @@ def create_employment( """Persist one employment after conversion and exclusivity checks.""" if type(command) is not EmploymentMutationCommand: raise TypeError("command must be an EmploymentMutationCommand") + EmploymentMutationCommand.__post_init__(command) decision = _require_authorization( authorization=authorization, tenant_record_id=command.tenant_record_id, @@ -679,6 +680,7 @@ def create_position( """Persist one position after organization and job parent checks.""" if type(command) is not PositionMutationCommand: raise TypeError("command must be a PositionMutationCommand") + PositionMutationCommand.__post_init__(command) decision = _require_authorization( authorization=authorization, tenant_record_id=command.tenant_record_id, @@ -775,6 +777,7 @@ def create_assignment( """Persist one assignment after conversion and kernel coverage checks.""" if type(command) is not AssignmentMutationCommand: raise TypeError("command must be an AssignmentMutationCommand") + AssignmentMutationCommand.__post_init__(command) decision = _require_authorization( authorization=authorization, tenant_record_id=command.tenant_record_id, From 8c40a184acab06732ba88234910876247f215ceb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 09:43:43 +0900 Subject: [PATCH 47/80] test(people): cover all PostgreSQL rewritten command entries --- ...es_mutation_post_construction_integrity.py | 97 ++++++++++++++++--- 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py b/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py index 6d02c2923..251b1f146 100644 --- a/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py +++ b/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py @@ -1,20 +1,30 @@ -"""Post-construction command-integrity regression for the PostgreSQL People port.""" +"""Post-construction command-integrity regressions for the PostgreSQL People port.""" from __future__ import annotations from datetime import date +from decimal import Decimal from uuid import UUID import pytest from orgmetra_keyverse_adapter import AuthorizationDecision -from orgmetra_people_api.mutations import EmploymentMutationCommand +from orgmetra_people_api.mutations import ( + AssignmentMutationCommand, + EmploymentMutationCommand, + PositionMutationCommand, +) from orgmetra_people_api.postgres_mutations import PostgresPeopleMutationPort TENANT = UUID("0198a412-a700-7000-8000-000000000001") PERSON = UUID("0198a412-a700-7000-8000-000000000020") EMPLOYMENT = UUID("0198a412-a700-7000-8000-000000000030") EMPLOYMENT_VERSION = UUID("0198a412-a700-7000-8000-000000000031") +ORGANIZATION = UUID("0198a412-a700-7000-8000-000000000040") +JOB_PROFILE = UUID("0198a412-a700-7000-8000-000000000050") +POSITION = UUID("0198a412-a700-7000-8000-000000000060") +POSITION_VERSION = UUID("0198a412-a700-7000-8000-000000000061") +ASSIGNMENT = UUID("0198a412-a700-7000-8000-000000000070") AUDIT_EVENT = UUID("0198a412-a700-7000-8000-000000000080") OUTBOX = UUID("0198a412-a700-7000-8000-000000000081") @@ -28,18 +38,18 @@ def hex(self) -> str: raise AssertionError("rewritten UUID hex behavior must not execute") -def _authorization() -> AuthorizationDecision: - """Build one exact authorization decision for the original employment identity.""" - fields = frozenset({"employment_record"}) +def _authorization(*, resource_kind: str, record_id: UUID) -> AuthorizationDecision: + """Build one exact authorization decision for an original mutation identity.""" + fields = frozenset({resource_kind}) return AuthorizationDecision( allowed=True, tenant_record_id=TENANT, actor_reference="keyverse_subject:operator-227", - resource_reference=f"employment_record:{EMPLOYMENT.hex}", + resource_reference=f"{resource_kind}:{record_id.hex}", policy_version_code="people-mutation-v1", purpose_code="workforce_admin", operation_code="create_record", - resource_kind="employment_record", + resource_kind=resource_kind, requested_fields=fields, authorized_fields=fields, reason_code="access_permitted", @@ -52,8 +62,8 @@ def _forbidden_connection_factory() -> object: raise AssertionError("database work must not begin for a rewritten mutation command") -def test_postgres_port_revalidates_exact_command_after_object_setattr_rewrite() -> None: - """Reject rewritten command identity before callback or database work.""" +def test_postgres_employment_revalidates_exact_command_after_object_setattr_rewrite() -> None: + """Reject rewritten Employment identity before callback or database work.""" command = EmploymentMutationCommand( tenant_record_id=TENANT, person_record_id=PERSON, @@ -64,9 +74,9 @@ def test_postgres_port_revalidates_exact_command_after_object_setattr_rewrite() employment_status_code="active", employment_concurrency_code="exclusive", effective_from=date(2026, 9, 5), - confirmation_reference="human_confirmation:post-construction-227", + confirmation_reference="human_confirmation:post-construction-227-employment", evidence_version_code="employment-evidence-v1", - idempotency_key="post-construction-runtime-227", + idempotency_key="post-construction-runtime-227-employment", ) object.__setattr__( command, @@ -76,4 +86,67 @@ def test_postgres_port_revalidates_exact_command_after_object_setattr_rewrite() port = PostgresPeopleMutationPort(_forbidden_connection_factory) with pytest.raises(ValueError, match="employment_record_id must be an operational UUID"): - port.create_employment(command=command, authorization=_authorization()) + port.create_employment( + command=command, + authorization=_authorization(resource_kind="employment_record", record_id=EMPLOYMENT), + ) + + +def test_postgres_position_revalidates_exact_command_after_object_setattr_rewrite() -> None: + """Reject rewritten Position identity before callback or database work.""" + command = PositionMutationCommand( + tenant_record_id=TENANT, + organization_unit_id=ORGANIZATION, + job_profile_id=JOB_PROFILE, + position_record_id=POSITION, + position_record_version_id=POSITION_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + position_status_code="open", + effective_from=date(2026, 9, 5), + confirmation_reference="human_confirmation:post-construction-227-position", + evidence_version_code="position-evidence-v1", + idempotency_key="post-construction-runtime-227-position", + ) + object.__setattr__( + command, + "position_record_id", + _ExecutableUUID("0198a412-a700-7000-8000-000000000098"), + ) + port = PostgresPeopleMutationPort(_forbidden_connection_factory) + + with pytest.raises(ValueError, match="position_record_id must be an operational UUID"): + port.create_position( + command=command, + authorization=_authorization(resource_kind="position_record", record_id=POSITION), + ) + + +def test_postgres_assignment_revalidates_exact_command_after_object_setattr_rewrite() -> None: + """Reject rewritten Assignment identity before callback or database work.""" + command = AssignmentMutationCommand( + tenant_record_id=TENANT, + employment_record_id=EMPLOYMENT, + person_record_id=PERSON, + position_record_id=POSITION, + assignment_record_id=ASSIGNMENT, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + allocation_ratio=Decimal("1.0000"), + effective_from=date(2026, 9, 5), + confirmation_reference="human_confirmation:post-construction-227-assignment", + evidence_version_code="assignment-evidence-v1", + idempotency_key="post-construction-runtime-227-assignment", + ) + object.__setattr__( + command, + "assignment_record_id", + _ExecutableUUID("0198a412-a700-7000-8000-000000000097"), + ) + port = PostgresPeopleMutationPort(_forbidden_connection_factory) + + with pytest.raises(ValueError, match="assignment_record_id must be an operational UUID"): + port.create_assignment( + command=command, + authorization=_authorization(resource_kind="assignment_record", record_id=ASSIGNMENT), + ) From 1ab0bd0dc22d73293d1472946b00fe8f98d08d25 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 10:00:59 +0900 Subject: [PATCH 48/80] test(people): prove confirmed-hire post-construction integrity gap --- .../test_hire_post_construction_integrity.py | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 services/people-api/tests/test_hire_post_construction_integrity.py diff --git a/services/people-api/tests/test_hire_post_construction_integrity.py b/services/people-api/tests/test_hire_post_construction_integrity.py new file mode 100644 index 000000000..d22cdac8a --- /dev/null +++ b/services/people-api/tests/test_hire_post_construction_integrity.py @@ -0,0 +1,162 @@ +"""Reject post-construction rewrites at confirmed-hire consumer boundaries.""" + +from __future__ import annotations + +from datetime import date +from uuid import UUID + +import pytest + +from orgmetra_keyverse_adapter import PurposeBoundAccessPolicy +from orgmetra_people_api.auth import AuthenticatedPrincipal +from orgmetra_people_api.hire import ( + HireAcceptanceCommand, + HireAcceptanceResult, + accept_confirmed_hire, +) +from orgmetra_people_api.postgres_hire import PostgresHireAcceptancePort + +TENANT = UUID("0198a412-7800-7000-8000-000000000001") +SELECTION_DECISION = UUID("0198a412-7800-7000-8000-000000000002") +PERSON = UUID("0198a412-7800-7000-8000-000000000003") +EMPLOYMENT = UUID("0198a412-7800-7000-8000-000000000004") +CONVERSION = UUID("0198a412-7800-7000-8000-000000000005") + + +class _ExecutableUUID(UUID): + """Expose UUID rendering attempted before an exact runtime-type gate.""" + + def __getattribute__(self, name: str) -> object: + """Fail if a rewritten UUID is rendered before command revalidation.""" + if name == "hex": + raise AssertionError("UUID subtype behavior executed before command revalidation") + return super().__getattribute__(name) + + +class _RecordingPort: + """Record whether a rewritten command crosses the application boundary.""" + + def __init__(self) -> None: + """Start with no durable-port invocation.""" + self.called = False + + def accept_hire(self, *, command: HireAcceptanceCommand, authorization: object) -> HireAcceptanceResult: + """Return one valid result if the application incorrectly calls the port.""" + del authorization + self.called = True + return HireAcceptanceResult( + person_record_id=command.person_record_id, + employment_record_id=command.employment_record_id, + candidate_worker_conversion_record_id=command.candidate_worker_conversion_record_id, + ) + + +class _RewrittenResultPort: + """Return an exact result whose identity was rewritten after construction.""" + + def accept_hire(self, *, command: HireAcceptanceCommand, authorization: object) -> HireAcceptanceResult: + """Rewrite one exact result after its constructor invariant has already run.""" + del command, authorization + result = HireAcceptanceResult( + person_record_id=PERSON, + employment_record_id=EMPLOYMENT, + candidate_worker_conversion_record_id=CONVERSION, + ) + object.__setattr__(result, "person_record_id", "not-a-uuid") + return result + + +def _command() -> HireAcceptanceCommand: + """Build one valid confirmed-hire command before deliberate low-level rewrite.""" + return HireAcceptanceCommand( + tenant_record_id=TENANT, + candidate_profile_id=UUID("0198a412-7800-7000-8000-000000000010"), + selection_decision_id=SELECTION_DECISION, + person_record_id=PERSON, + person_name_record_id=UUID("0198a412-7800-7000-8000-000000000011"), + employment_record_id=EMPLOYMENT, + employment_record_version_id=UUID("0198a412-7800-7000-8000-000000000012"), + candidate_worker_conversion_record_id=CONVERSION, + audit_event_record_id=UUID("0198a412-7800-7000-8000-000000000013"), + outbox_delivery_record_id=UUID("0198a412-7800-7000-8000-000000000014"), + effective_from=date(2026, 9, 5), + display_name="Ada Lovelace", + idempotency_key="hire-post-construction-228", + employment_status_code="active", + ) + + +def _principal() -> AuthenticatedPrincipal: + """Return the authenticated principal for the application-boundary regression.""" + return AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:operator-228", + granted_scope_codes=frozenset({"orgmetra.people.materialize_worker"}), + ) + + +def _policy() -> PurposeBoundAccessPolicy: + """Return the purpose-bound policy for confirmed-hire materialization.""" + return PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="people-hire-v1", + resource_kind="selection_decision", + purpose_code="candidate_hire", + operation_code="materialize_worker", + required_scope_code="orgmetra.people.materialize_worker", + permitted_fields=frozenset({"candidate_worker_conversion"}), + ) + + +def _rewrite_selection_decision(command: HireAcceptanceCommand) -> None: + """Replace one validated UUID with executable subtype evidence after construction.""" + object.__setattr__( + command, + "selection_decision_id", + _ExecutableUUID("0198a412-7800-7000-8000-0000000000ff"), + ) + + +def _forbidden_connection_factory() -> object: + """Fail if a rewritten command reaches database acquisition.""" + raise AssertionError("database acquisition occurred before command revalidation") + + +def test_application_revalidates_rewritten_hire_command_before_authorization_rendering() -> None: + """A rewritten command must fail before UUID rendering or the mutation port.""" + command = _command() + _rewrite_selection_decision(command) + port = _RecordingPort() + + with pytest.raises(ValueError, match="selection_decision_id must be an operational UUID"): + accept_confirmed_hire( + principal=_principal(), + command=command, + purpose_code="candidate_hire", + policy=_policy(), + mutation_port=port, + ) + + assert port.called is False + + +def test_application_revalidates_rewritten_exact_hire_result_before_return() -> None: + """An exact result rewritten after construction must not leave the service boundary.""" + with pytest.raises(ValueError, match="person_record_id must be an operational UUID"): + accept_confirmed_hire( + principal=_principal(), + command=_command(), + purpose_code="candidate_hire", + policy=_policy(), + mutation_port=_RewrittenResultPort(), + ) + + +def test_postgres_port_revalidates_rewritten_hire_command_before_authorization_or_db() -> None: + """Direct durable-port entry must reject rewritten evidence before callbacks or DB work.""" + command = _command() + _rewrite_selection_decision(command) + port = PostgresHireAcceptancePort(connection_factory=_forbidden_connection_factory) + + with pytest.raises(ValueError, match="selection_decision_id must be an operational UUID"): + port.accept_hire(command=command, authorization=object()) # type: ignore[arg-type] From 0a394553c21df407ae4bafe8fee568c70d5e8e62 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 10:02:04 +0900 Subject: [PATCH 49/80] fix(people): revalidate confirmed-hire application evidence --- services/people-api/src/orgmetra_people_api/hire.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/people-api/src/orgmetra_people_api/hire.py b/services/people-api/src/orgmetra_people_api/hire.py index 0d8bbbd7e..135cfd8b1 100644 --- a/services/people-api/src/orgmetra_people_api/hire.py +++ b/services/people-api/src/orgmetra_people_api/hire.py @@ -149,6 +149,7 @@ def accept_confirmed_hire( """ if type(command) is not HireAcceptanceCommand: raise TypeError("command must be a HireAcceptanceCommand") + HireAcceptanceCommand.__post_init__(command) if not isinstance(mutation_port, HireAcceptancePort): raise TypeError("mutation_port must implement HireAcceptancePort") @@ -166,4 +167,5 @@ def accept_confirmed_hire( result = mutation_port.accept_hire(command=command, authorization=authorization) if type(result) is not HireAcceptanceResult: raise TypeError("mutation_port must return HireAcceptanceResult") + HireAcceptanceResult.__post_init__(result) return result From bf24c2e43f75e6e9438b228abb959157b4f7a589 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 10:02:53 +0900 Subject: [PATCH 50/80] fix(people): revalidate confirmed-hire durable entry command --- services/people-api/src/orgmetra_people_api/postgres_hire.py | 1 + 1 file changed, 1 insertion(+) diff --git a/services/people-api/src/orgmetra_people_api/postgres_hire.py b/services/people-api/src/orgmetra_people_api/postgres_hire.py index 4bffbdb2d..9ec7ff291 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_hire.py +++ b/services/people-api/src/orgmetra_people_api/postgres_hire.py @@ -330,6 +330,7 @@ def accept_hire( """ if type(command) is not HireAcceptanceCommand: raise TypeError("command must be a HireAcceptanceCommand") + HireAcceptanceCommand.__post_init__(command) decision = _validate_authorization(command, authorization) with self.connection_factory() as connection: From 2064a52a3c845f8b06d14296b8d5535e4c07a3c4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 11:04:24 +0900 Subject: [PATCH 51/80] test(people): expose post-validation command rewrite --- ...es_mutation_post_construction_integrity.py | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py b/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py index 251b1f146..4e6858494 100644 --- a/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py +++ b/services/people-api/tests/test_postgres_mutation_post_construction_integrity.py @@ -15,12 +15,14 @@ PositionMutationCommand, ) from orgmetra_people_api.postgres_mutations import PostgresPeopleMutationPort +from test_postgres_people_mutations import FakeConnection, RECORDED_AT, ScriptedCursor TENANT = UUID("0198a412-a700-7000-8000-000000000001") PERSON = UUID("0198a412-a700-7000-8000-000000000020") EMPLOYMENT = UUID("0198a412-a700-7000-8000-000000000030") EMPLOYMENT_VERSION = UUID("0198a412-a700-7000-8000-000000000031") ORGANIZATION = UUID("0198a412-a700-7000-8000-000000000040") +MUTATED_ORGANIZATION = UUID("0198a412-a700-7000-8000-000000000041") JOB_PROFILE = UUID("0198a412-a700-7000-8000-000000000050") POSITION = UUID("0198a412-a700-7000-8000-000000000060") POSITION_VERSION = UUID("0198a412-a700-7000-8000-000000000061") @@ -150,3 +152,48 @@ def test_postgres_assignment_revalidates_exact_command_after_object_setattr_rewr command=command, authorization=_authorization(resource_kind="assignment_record", record_id=ASSIGNMENT), ) + + +def test_postgres_position_detaches_validated_command_before_connection_factory_callback() -> None: + """Keep one validated Position snapshot across the caller-owned connection callback.""" + command = PositionMutationCommand( + tenant_record_id=TENANT, + organization_unit_id=ORGANIZATION, + job_profile_id=JOB_PROFILE, + position_record_id=POSITION, + position_record_version_id=POSITION_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + position_status_code="open", + effective_from=date(2026, 9, 5), + confirmation_reference="human_confirmation:post-construction-229-position", + evidence_version_code="position-evidence-v1", + idempotency_key="post-construction-runtime-229-position", + ) + cursor = ScriptedCursor( + [[], [(ORGANIZATION, JOB_PROFILE, RECORDED_AT)]], + [], + ) + connection = FakeConnection(cursor) + + def mutating_connection_factory() -> FakeConnection: + """Rewrite the caller's still-valid command only after authorization has completed.""" + object.__setattr__(command, "organization_unit_id", MUTATED_ORGANIZATION) + return connection + + port = PostgresPeopleMutationPort(mutating_connection_factory) + result = port.create_position( + command=command, + authorization=_authorization(resource_kind="position_record", record_id=POSITION), + ) + + assert result.position_record_id == POSITION + parent_query = next( + execution for execution in cursor.executions if "FROM public.organization_unit AS organization" in execution[0] + ) + assert parent_query[1] == (JOB_PROFILE, TENANT, ORGANIZATION) + insert_position = next( + execution for execution in cursor.executions if execution[0].startswith("INSERT INTO public.position_record (") + ) + assert insert_position[1] is not None + assert insert_position[1][2] == ORGANIZATION From e4cab11d32f22dc40841acbc9cf86c082bb25f67 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 11:05:58 +0900 Subject: [PATCH 52/80] fix(people): detach validated mutation commands before callbacks --- .../src/orgmetra_people_api/postgres_mutations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index 0ceec0130..ede1deefd 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -9,7 +9,7 @@ from __future__ import annotations from contextlib import AbstractContextManager -from dataclasses import dataclass +from dataclasses import dataclass, replace from datetime import date, datetime, timezone from decimal import Decimal from typing import Any, Callable @@ -571,7 +571,7 @@ def create_employment( """Persist one employment after conversion and exclusivity checks.""" if type(command) is not EmploymentMutationCommand: raise TypeError("command must be an EmploymentMutationCommand") - EmploymentMutationCommand.__post_init__(command) + command = replace(command) decision = _require_authorization( authorization=authorization, tenant_record_id=command.tenant_record_id, @@ -680,7 +680,7 @@ def create_position( """Persist one position after organization and job parent checks.""" if type(command) is not PositionMutationCommand: raise TypeError("command must be a PositionMutationCommand") - PositionMutationCommand.__post_init__(command) + command = replace(command) decision = _require_authorization( authorization=authorization, tenant_record_id=command.tenant_record_id, @@ -777,7 +777,7 @@ def create_assignment( """Persist one assignment after conversion and kernel coverage checks.""" if type(command) is not AssignmentMutationCommand: raise TypeError("command must be an AssignmentMutationCommand") - AssignmentMutationCommand.__post_init__(command) + command = replace(command) decision = _require_authorization( authorization=authorization, tenant_record_id=command.tenant_record_id, From 0daa68a00ca3132069ea515672bcea09cb8a2345 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 12:06:16 +0900 Subject: [PATCH 53/80] test(people): bind mutation results to commanded identities --- ...ople_mutation_result_identity_integrity.py | 301 ++++++++++++++++++ 1 file changed, 301 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_result_identity_integrity.py diff --git a/services/people-api/tests/test_people_mutation_result_identity_integrity.py b/services/people-api/tests/test_people_mutation_result_identity_integrity.py new file mode 100644 index 000000000..0871c8dc5 --- /dev/null +++ b/services/people-api/tests/test_people_mutation_result_identity_integrity.py @@ -0,0 +1,301 @@ +"""Result-to-command identity regressions for governed People mutations.""" + +from __future__ import annotations + +from datetime import date +from decimal import Decimal +import unittest +from uuid import UUID + +from orgmetra_keyverse_adapter import PurposeBoundAccessPolicy +from orgmetra_people_api.auth import AuthenticatedPrincipal +from orgmetra_people_api.hire import ( + HireAcceptanceCommand, + HireAcceptanceResult, + HireDecisionIntegrityError, + accept_confirmed_hire, +) +from orgmetra_people_api.mutations import ( + AssignmentMutationCommand, + AssignmentMutationResult, + EmploymentMutationCommand, + EmploymentMutationResult, + PeopleMutationIntegrityError, + PositionMutationCommand, + PositionMutationResult, + create_assignment_record, + create_employment_record, + create_position_record, +) + +TENANT = UUID("0198a412-b100-7000-8000-000000000001") +PERSON = UUID("0198a412-b100-7000-8000-000000000020") +PERSON_NAME = UUID("0198a412-b100-7000-8000-000000000021") +CANDIDATE = UUID("0198a412-b100-7000-8000-000000000022") +SELECTION_DECISION = UUID("0198a412-b100-7000-8000-000000000023") +EMPLOYMENT = UUID("0198a412-b100-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-b100-7000-8000-000000000031") +POSITION = UUID("0198a412-b100-7000-8000-000000000040") +POSITION_VERSION = UUID("0198a412-b100-7000-8000-000000000041") +ORGANIZATION = UUID("0198a412-b100-7000-8000-000000000050") +JOB = UUID("0198a412-b100-7000-8000-000000000060") +ASSIGNMENT = UUID("0198a412-b100-7000-8000-000000000070") +CONVERSION = UUID("0198a412-b100-7000-8000-000000000071") +AUDIT_EVENT = UUID("0198a412-b100-7000-8000-000000000080") +OUTBOX = UUID("0198a412-b100-7000-8000-000000000081") +OTHER = UUID("0198a412-b100-7000-8000-000000000099") +EFFECTIVE_FROM = date(2026, 9, 5) + +PRINCIPAL = AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:result-integrity-operator", + granted_scope_codes=frozenset( + { + "orgmetra.people.write", + "orgmetra.job_architecture.write", + "orgmetra.people.materialize_worker", + } + ), +) + + +def _employment_command() -> EmploymentMutationCommand: + """Build one governed Employment create command.""" + return EmploymentMutationCommand( + tenant_record_id=TENANT, + person_record_id=PERSON, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + employment_status_code="active", + employment_concurrency_code="exclusive", + effective_from=EFFECTIVE_FROM, + confirmation_reference="human_confirmation:result-integrity", + evidence_version_code="result-integrity-v1", + idempotency_key="result-integrity-employment-1", + ) + + +def _position_command() -> PositionMutationCommand: + """Build one governed Position create command.""" + return PositionMutationCommand( + tenant_record_id=TENANT, + organization_unit_id=ORGANIZATION, + job_profile_id=JOB, + position_record_id=POSITION, + position_record_version_id=POSITION_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + position_status_code="open", + effective_from=EFFECTIVE_FROM, + confirmation_reference="human_confirmation:result-integrity", + evidence_version_code="result-integrity-v1", + idempotency_key="result-integrity-position-1", + ) + + +def _assignment_command() -> AssignmentMutationCommand: + """Build one governed Assignment create command.""" + return AssignmentMutationCommand( + tenant_record_id=TENANT, + employment_record_id=EMPLOYMENT, + person_record_id=PERSON, + position_record_id=POSITION, + assignment_record_id=ASSIGNMENT, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + allocation_ratio=Decimal("1.0000"), + effective_from=EFFECTIVE_FROM, + confirmation_reference="human_confirmation:result-integrity", + evidence_version_code="result-integrity-v1", + idempotency_key="result-integrity-assignment-1", + ) + + +def _hire_command() -> HireAcceptanceCommand: + """Build one governed confirmed-hire command.""" + return HireAcceptanceCommand( + tenant_record_id=TENANT, + candidate_profile_id=CANDIDATE, + selection_decision_id=SELECTION_DECISION, + person_record_id=PERSON, + person_name_record_id=PERSON_NAME, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + candidate_worker_conversion_record_id=CONVERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + effective_from=EFFECTIVE_FROM, + display_name="Result Integrity Worker", + idempotency_key="result-integrity-hire-1", + ) + + +def _policy( + *, + resource_kind: str, + purpose_code: str, + operation_code: str, + scope_code: str, + field_name: str, +) -> PurposeBoundAccessPolicy: + """Build one exact purpose-bound policy for a mutation target.""" + return PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="result-integrity-v1", + resource_kind=resource_kind, + purpose_code=purpose_code, + operation_code=operation_code, + required_scope_code=scope_code, + permitted_fields=frozenset({field_name}), + ) + + +class _PeopleResultPort: + """Return supplied structurally valid results without honoring command identity.""" + + def __init__( + self, + *, + employment_result: EmploymentMutationResult | None = None, + position_result: PositionMutationResult | None = None, + assignment_result: AssignmentMutationResult | None = None, + ) -> None: + """Retain the result selected by each focused regression.""" + self.employment_result = employment_result + self.position_result = position_result + self.assignment_result = assignment_result + + def create_employment(self, *, command: EmploymentMutationCommand, authorization: object) -> EmploymentMutationResult: + """Return the configured Employment result.""" + del command, authorization + assert self.employment_result is not None + return self.employment_result + + def create_position(self, *, command: PositionMutationCommand, authorization: object) -> PositionMutationResult: + """Return the configured Position result.""" + del command, authorization + assert self.position_result is not None + return self.position_result + + def create_assignment(self, *, command: AssignmentMutationCommand, authorization: object) -> AssignmentMutationResult: + """Return the configured Assignment result.""" + del command, authorization + assert self.assignment_result is not None + return self.assignment_result + + +class _HireResultPort: + """Return one structurally valid confirmed-hire result supplied by the regression.""" + + def __init__(self, result: HireAcceptanceResult) -> None: + """Retain the result without deriving it from the command.""" + self.result = result + + def accept_hire(self, *, command: HireAcceptanceCommand, authorization: object) -> HireAcceptanceResult: + """Return the configured hire result.""" + del command, authorization + return self.result + + +class PeopleMutationResultIdentityTests(unittest.TestCase): + """Require generic People port results to name exactly the commanded records.""" + + def test_employment_result_must_match_command_identity(self) -> None: + """A valid but different Employment identity must fail closed.""" + with self.assertRaisesRegex(PeopleMutationIntegrityError, "employment result identity"): + create_employment_record( + principal=PRINCIPAL, + command=_employment_command(), + purpose_code="workforce_admin", + policy=_policy( + resource_kind="employment_record", + purpose_code="workforce_admin", + operation_code="create_record", + scope_code="orgmetra.people.write", + field_name="employment_record", + ), + mutation_port=_PeopleResultPort( + employment_result=EmploymentMutationResult(employment_record_id=OTHER) + ), + ) + + def test_position_result_must_match_command_identity(self) -> None: + """A valid but different Position identity must fail closed.""" + with self.assertRaisesRegex(PeopleMutationIntegrityError, "position result identity"): + create_position_record( + principal=PRINCIPAL, + command=_position_command(), + purpose_code="job_architecture_admin", + policy=_policy( + resource_kind="position_record", + purpose_code="job_architecture_admin", + operation_code="create_record", + scope_code="orgmetra.job_architecture.write", + field_name="position_record", + ), + mutation_port=_PeopleResultPort(position_result=PositionMutationResult(position_record_id=OTHER)), + ) + + def test_assignment_result_must_match_command_identity(self) -> None: + """A valid but different Assignment identity must fail closed.""" + with self.assertRaisesRegex(PeopleMutationIntegrityError, "assignment result identity"): + create_assignment_record( + principal=PRINCIPAL, + command=_assignment_command(), + purpose_code="workforce_admin", + policy=_policy( + resource_kind="assignment_record", + purpose_code="workforce_admin", + operation_code="create_record", + scope_code="orgmetra.people.write", + field_name="assignment_record", + ), + mutation_port=_PeopleResultPort( + assignment_result=AssignmentMutationResult(assignment_record_id=OTHER) + ), + ) + + +class HireResultIdentityTests(unittest.TestCase): + """Require confirmed-hire results to preserve every commanded authoritative identity.""" + + def test_hire_result_must_match_person_employment_and_conversion_identities(self) -> None: + """Any structurally valid but foreign hire identity must fail closed.""" + mismatched_results = ( + HireAcceptanceResult( + person_record_id=OTHER, + employment_record_id=EMPLOYMENT, + candidate_worker_conversion_record_id=CONVERSION, + ), + HireAcceptanceResult( + person_record_id=PERSON, + employment_record_id=OTHER, + candidate_worker_conversion_record_id=CONVERSION, + ), + HireAcceptanceResult( + person_record_id=PERSON, + employment_record_id=EMPLOYMENT, + candidate_worker_conversion_record_id=OTHER, + ), + ) + for result in mismatched_results: + with self.subTest(result=result), self.assertRaisesRegex(HireDecisionIntegrityError, "hire result identity"): + accept_confirmed_hire( + principal=PRINCIPAL, + command=_hire_command(), + purpose_code="candidate_hire", + policy=_policy( + resource_kind="selection_decision", + purpose_code="candidate_hire", + operation_code="materialize_worker", + scope_code="orgmetra.people.materialize_worker", + field_name="candidate_worker_conversion", + ), + mutation_port=_HireResultPort(result), + ) + + +if __name__ == "__main__": + unittest.main() From e09e557f956366b78b9e073d5f7cdb6d9e3e0790 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 12:07:27 +0900 Subject: [PATCH 54/80] fix(people): bind mutation results to command identities --- services/people-api/src/orgmetra_people_api/mutations.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index 544be6b5f..a510ea579 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -386,6 +386,8 @@ def create_employment_record( if type(result) is not EmploymentMutationResult: raise TypeError("mutation_port must return EmploymentMutationResult") EmploymentMutationResult.__post_init__(result) + if result.employment_record_id != command.employment_record_id: + raise PeopleMutationIntegrityError("employment result identity does not match command") return result @@ -417,6 +419,8 @@ def create_position_record( if type(result) is not PositionMutationResult: raise TypeError("mutation_port must return PositionMutationResult") PositionMutationResult.__post_init__(result) + if result.position_record_id != command.position_record_id: + raise PeopleMutationIntegrityError("position result identity does not match command") return result @@ -448,6 +452,8 @@ def create_assignment_record( if type(result) is not AssignmentMutationResult: raise TypeError("mutation_port must return AssignmentMutationResult") AssignmentMutationResult.__post_init__(result) + if result.assignment_record_id != command.assignment_record_id: + raise PeopleMutationIntegrityError("assignment result identity does not match command") return result From 40ef9b2c0bf860d90fde071795f7a907e96651d1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 12:07:43 +0900 Subject: [PATCH 55/80] fix(people): bind confirmed hire result identities --- services/people-api/src/orgmetra_people_api/hire.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/people-api/src/orgmetra_people_api/hire.py b/services/people-api/src/orgmetra_people_api/hire.py index 135cfd8b1..cb47905ba 100644 --- a/services/people-api/src/orgmetra_people_api/hire.py +++ b/services/people-api/src/orgmetra_people_api/hire.py @@ -168,4 +168,10 @@ def accept_confirmed_hire( if type(result) is not HireAcceptanceResult: raise TypeError("mutation_port must return HireAcceptanceResult") HireAcceptanceResult.__post_init__(result) + if ( + result.person_record_id != command.person_record_id + or result.employment_record_id != command.employment_record_id + or result.candidate_worker_conversion_record_id != command.candidate_worker_conversion_record_id + ): + raise HireDecisionIntegrityError("hire result identity does not match command") return result From 6142f7dd765727d80028ed147c31b6d9dea5fc63 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 12:08:35 +0900 Subject: [PATCH 56/80] test(people): bind result checks to pre-port targets --- ..._people_mutation_result_target_snapshot.py | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_result_target_snapshot.py diff --git a/services/people-api/tests/test_people_mutation_result_target_snapshot.py b/services/people-api/tests/test_people_mutation_result_target_snapshot.py new file mode 100644 index 000000000..17d56c9c6 --- /dev/null +++ b/services/people-api/tests/test_people_mutation_result_target_snapshot.py @@ -0,0 +1,202 @@ +"""Pre-port target binding regressions for People mutation results.""" + +from __future__ import annotations + +from datetime import date +import unittest +from uuid import UUID + +from orgmetra_keyverse_adapter import PurposeBoundAccessPolicy +from orgmetra_people_api.auth import AuthenticatedPrincipal +from orgmetra_people_api.hire import ( + HireAcceptanceCommand, + HireAcceptanceResult, + HireDecisionIntegrityError, + accept_confirmed_hire, +) +from orgmetra_people_api.mutations import ( + AssignmentMutationCommand, + AssignmentMutationResult, + EmploymentMutationCommand, + EmploymentMutationResult, + PeopleMutationIntegrityError, + PositionMutationCommand, + PositionMutationResult, + create_employment_record, +) + +TENANT = UUID("0198a412-b200-7000-8000-000000000001") +PERSON = UUID("0198a412-b200-7000-8000-000000000020") +PERSON_NAME = UUID("0198a412-b200-7000-8000-000000000021") +CANDIDATE = UUID("0198a412-b200-7000-8000-000000000022") +SELECTION_DECISION = UUID("0198a412-b200-7000-8000-000000000023") +EMPLOYMENT = UUID("0198a412-b200-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-b200-7000-8000-000000000031") +CONVERSION = UUID("0198a412-b200-7000-8000-000000000040") +AUDIT_EVENT = UUID("0198a412-b200-7000-8000-000000000050") +OUTBOX = UUID("0198a412-b200-7000-8000-000000000051") +OTHER = UUID("0198a412-b200-7000-8000-000000000099") +EFFECTIVE_FROM = date(2026, 9, 5) + +PRINCIPAL = AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:target-snapshot-operator", + granted_scope_codes=frozenset( + {"orgmetra.people.write", "orgmetra.people.materialize_worker"} + ), +) + + +def _employment_command() -> EmploymentMutationCommand: + """Build one valid Employment command whose target can be rewritten by a port.""" + return EmploymentMutationCommand( + tenant_record_id=TENANT, + person_record_id=PERSON, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + employment_status_code="active", + employment_concurrency_code="exclusive", + effective_from=EFFECTIVE_FROM, + confirmation_reference="human_confirmation:target-snapshot", + evidence_version_code="target-snapshot-v1", + idempotency_key="target-snapshot-employment-1", + ) + + +def _hire_command() -> HireAcceptanceCommand: + """Build one valid hire command whose target can be rewritten by a port.""" + return HireAcceptanceCommand( + tenant_record_id=TENANT, + candidate_profile_id=CANDIDATE, + selection_decision_id=SELECTION_DECISION, + person_record_id=PERSON, + person_name_record_id=PERSON_NAME, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + candidate_worker_conversion_record_id=CONVERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + effective_from=EFFECTIVE_FROM, + display_name="Target Snapshot Worker", + idempotency_key="target-snapshot-hire-1", + ) + + +def _policy( + *, + resource_kind: str, + purpose_code: str, + operation_code: str, + scope_code: str, + field_name: str, +) -> PurposeBoundAccessPolicy: + """Build one exact policy for the focused mutation boundary.""" + return PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="target-snapshot-v1", + resource_kind=resource_kind, + purpose_code=purpose_code, + operation_code=operation_code, + required_scope_code=scope_code, + permitted_fields=frozenset({field_name}), + ) + + +class _MutatingPeoplePort: + """Rewrite the caller command during the port call and report the rewritten identity.""" + + def create_employment( + self, + *, + command: EmploymentMutationCommand, + authorization: object, + ) -> EmploymentMutationResult: + """Replace the commanded Employment target before returning a valid result.""" + del authorization + object.__setattr__(command, "employment_record_id", OTHER) + return EmploymentMutationResult(employment_record_id=OTHER) + + def create_position( + self, + *, + command: PositionMutationCommand, + authorization: object, + ) -> PositionMutationResult: + """Reject unrelated Position work while satisfying the runtime protocol.""" + del command, authorization + raise AssertionError("position mutation is outside this regression") + + def create_assignment( + self, + *, + command: AssignmentMutationCommand, + authorization: object, + ) -> AssignmentMutationResult: + """Reject unrelated Assignment work while satisfying the runtime protocol.""" + del command, authorization + raise AssertionError("assignment mutation is outside this regression") + + +class _MutatingHirePort: + """Rewrite all hire targets during the port call and report those rewritten identities.""" + + def accept_hire( + self, + *, + command: HireAcceptanceCommand, + authorization: object, + ) -> HireAcceptanceResult: + """Replace authoritative targets after authorization but before service return.""" + del authorization + object.__setattr__(command, "person_record_id", OTHER) + object.__setattr__(command, "employment_record_id", OTHER) + object.__setattr__(command, "candidate_worker_conversion_record_id", OTHER) + return HireAcceptanceResult( + person_record_id=OTHER, + employment_record_id=OTHER, + candidate_worker_conversion_record_id=OTHER, + ) + + +class PeopleMutationResultTargetSnapshotTests(unittest.TestCase): + """Require result coherence against targets captured before executable port work.""" + + def test_employment_result_check_uses_pre_port_target(self) -> None: + """A port must not redefine the expected Employment identity by mutating the command.""" + with self.assertRaisesRegex(PeopleMutationIntegrityError, "employment result identity"): + create_employment_record( + principal=PRINCIPAL, + command=_employment_command(), + purpose_code="workforce_admin", + policy=_policy( + resource_kind="employment_record", + purpose_code="workforce_admin", + operation_code="create_record", + scope_code="orgmetra.people.write", + field_name="employment_record", + ), + mutation_port=_MutatingPeoplePort(), + ) + + def test_hire_result_check_uses_pre_port_targets(self) -> None: + """A port must not redefine Person/Employment/conversion result authority.""" + with self.assertRaisesRegex(HireDecisionIntegrityError, "hire result identity"): + accept_confirmed_hire( + principal=PRINCIPAL, + command=_hire_command(), + purpose_code="candidate_hire", + policy=_policy( + resource_kind="selection_decision", + purpose_code="candidate_hire", + operation_code="materialize_worker", + scope_code="orgmetra.people.materialize_worker", + field_name="candidate_worker_conversion", + ), + mutation_port=_MutatingHirePort(), + ) + + +if __name__ == "__main__": + unittest.main() From abd549202f5d8e7f88a212db318a3f19743e0e63 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 12:09:29 +0900 Subject: [PATCH 57/80] fix(people): compare results to detached pre-port targets --- services/people-api/src/orgmetra_people_api/mutations.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index a510ea579..04448298d 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -370,6 +370,7 @@ def create_employment_record( if type(command) is not EmploymentMutationCommand: raise TypeError("command must be an EmploymentMutationCommand") EmploymentMutationCommand.__post_init__(command) + expected_employment_record_id = UUID(int=command.employment_record_id.int) port = _require_port(mutation_port) authorization = authorize_resource_fields( principal=principal, @@ -386,7 +387,7 @@ def create_employment_record( if type(result) is not EmploymentMutationResult: raise TypeError("mutation_port must return EmploymentMutationResult") EmploymentMutationResult.__post_init__(result) - if result.employment_record_id != command.employment_record_id: + if result.employment_record_id != expected_employment_record_id: raise PeopleMutationIntegrityError("employment result identity does not match command") return result @@ -403,6 +404,7 @@ def create_position_record( if type(command) is not PositionMutationCommand: raise TypeError("command must be a PositionMutationCommand") PositionMutationCommand.__post_init__(command) + expected_position_record_id = UUID(int=command.position_record_id.int) port = _require_port(mutation_port) authorization = authorize_resource_fields( principal=principal, @@ -419,7 +421,7 @@ def create_position_record( if type(result) is not PositionMutationResult: raise TypeError("mutation_port must return PositionMutationResult") PositionMutationResult.__post_init__(result) - if result.position_record_id != command.position_record_id: + if result.position_record_id != expected_position_record_id: raise PeopleMutationIntegrityError("position result identity does not match command") return result @@ -436,6 +438,7 @@ def create_assignment_record( if type(command) is not AssignmentMutationCommand: raise TypeError("command must be an AssignmentMutationCommand") AssignmentMutationCommand.__post_init__(command) + expected_assignment_record_id = UUID(int=command.assignment_record_id.int) port = _require_port(mutation_port) authorization = authorize_resource_fields( principal=principal, @@ -452,7 +455,7 @@ def create_assignment_record( if type(result) is not AssignmentMutationResult: raise TypeError("mutation_port must return AssignmentMutationResult") AssignmentMutationResult.__post_init__(result) - if result.assignment_record_id != command.assignment_record_id: + if result.assignment_record_id != expected_assignment_record_id: raise PeopleMutationIntegrityError("assignment result identity does not match command") return result From 62a6b7ac2908dce2ea760c13123f8685a6f0eb5c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 12:10:48 +0900 Subject: [PATCH 58/80] fix(people): compare hire result to detached targets --- services/people-api/src/orgmetra_people_api/hire.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/hire.py b/services/people-api/src/orgmetra_people_api/hire.py index cb47905ba..16ad2c66d 100644 --- a/services/people-api/src/orgmetra_people_api/hire.py +++ b/services/people-api/src/orgmetra_people_api/hire.py @@ -150,6 +150,11 @@ def accept_confirmed_hire( if type(command) is not HireAcceptanceCommand: raise TypeError("command must be a HireAcceptanceCommand") HireAcceptanceCommand.__post_init__(command) + expected_person_record_id = UUID(int=command.person_record_id.int) + expected_employment_record_id = UUID(int=command.employment_record_id.int) + expected_conversion_record_id = UUID( + int=command.candidate_worker_conversion_record_id.int + ) if not isinstance(mutation_port, HireAcceptancePort): raise TypeError("mutation_port must implement HireAcceptancePort") @@ -169,9 +174,9 @@ def accept_confirmed_hire( raise TypeError("mutation_port must return HireAcceptanceResult") HireAcceptanceResult.__post_init__(result) if ( - result.person_record_id != command.person_record_id - or result.employment_record_id != command.employment_record_id - or result.candidate_worker_conversion_record_id != command.candidate_worker_conversion_record_id + result.person_record_id != expected_person_record_id + or result.employment_record_id != expected_employment_record_id + or result.candidate_worker_conversion_record_id != expected_conversion_record_id ): raise HireDecisionIntegrityError("hire result identity does not match command") return result From f7415084d801bc06be316b022f41f53763197882 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 13:02:29 +0900 Subject: [PATCH 59/80] test(people): bind mutation commands before authorization callbacks --- ...mutation_authorization_command_snapshot.py | 274 ++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_authorization_command_snapshot.py diff --git a/services/people-api/tests/test_people_mutation_authorization_command_snapshot.py b/services/people-api/tests/test_people_mutation_authorization_command_snapshot.py new file mode 100644 index 000000000..d67c91b18 --- /dev/null +++ b/services/people-api/tests/test_people_mutation_authorization_command_snapshot.py @@ -0,0 +1,274 @@ +"""Application command-snapshot regressions across purpose-bound authorization.""" + +from __future__ import annotations + +from datetime import date +from decimal import Decimal +import unittest +from uuid import UUID + +from orgmetra_keyverse_adapter import PurposeBoundAccessPolicy +from orgmetra_people_api.auth import AuthenticatedPrincipal +from orgmetra_people_api.mutations import ( + AssignmentMutationCommand, + AssignmentMutationResult, + EmploymentMutationCommand, + EmploymentMutationResult, + PositionMutationCommand, + PositionMutationResult, + create_assignment_record, + create_employment_record, + create_position_record, +) + +TENANT = UUID("0198a412-c100-7000-8000-000000000001") +PERSON = UUID("0198a412-c100-7000-8000-000000000010") +OTHER_PERSON = UUID("0198a412-c100-7000-8000-000000000011") +EMPLOYMENT = UUID("0198a412-c100-7000-8000-000000000020") +EMPLOYMENT_VERSION = UUID("0198a412-c100-7000-8000-000000000021") +ORGANIZATION = UUID("0198a412-c100-7000-8000-000000000030") +JOB = UUID("0198a412-c100-7000-8000-000000000040") +OTHER_JOB = UUID("0198a412-c100-7000-8000-000000000041") +POSITION = UUID("0198a412-c100-7000-8000-000000000050") +POSITION_VERSION = UUID("0198a412-c100-7000-8000-000000000051") +OTHER_POSITION = UUID("0198a412-c100-7000-8000-000000000052") +ASSIGNMENT = UUID("0198a412-c100-7000-8000-000000000060") +AUDIT_EVENT = UUID("0198a412-c100-7000-8000-000000000070") +OUTBOX = UUID("0198a412-c100-7000-8000-000000000071") +EFFECTIVE_FROM = date(2026, 9, 5) + +PRINCIPAL = AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:authorization-snapshot-operator", + granted_scope_codes=frozenset({"orgmetra.people.write"}), +) + + +class _MutatingResourceKind(str): + """Rewrite a retained caller command when policy comparison executes.""" + + def __new__( + cls, + value: str, + *, + command: object, + field_name: str, + replacement: object, + ) -> _MutatingResourceKind: + """Retain the caller command solely for the adversarial comparison callback.""" + instance = super().__new__(cls, value) + instance.command = command + instance.field_name = field_name + instance.replacement = replacement + return instance + + def _mutate_command(self) -> None: + """Simulate caller-owned executable policy behavior during authorization.""" + object.__setattr__(self.command, self.field_name, self.replacement) + + def __eq__(self, other: object) -> bool: + """Mutate before preserving ordinary string equality semantics.""" + self._mutate_command() + return str.__eq__(self, other) + + def __ne__(self, other: object) -> bool: + """Mutate before preserving ordinary string inequality semantics.""" + self._mutate_command() + return str.__ne__(self, other) + + +class _CapturingMutationPort: + """Capture the semantic command that crosses the application port boundary.""" + + employment_command: EmploymentMutationCommand | None = None + position_command: PositionMutationCommand | None = None + assignment_command: AssignmentMutationCommand | None = None + + def create_employment( + self, + *, + command: EmploymentMutationCommand, + authorization: object, + ) -> EmploymentMutationResult: + """Capture Employment semantics and return the commanded target identity.""" + del authorization + self.employment_command = command + return EmploymentMutationResult(employment_record_id=command.employment_record_id) + + def create_position( + self, + *, + command: PositionMutationCommand, + authorization: object, + ) -> PositionMutationResult: + """Capture Position semantics and return the commanded target identity.""" + del authorization + self.position_command = command + return PositionMutationResult(position_record_id=command.position_record_id) + + def create_assignment( + self, + *, + command: AssignmentMutationCommand, + authorization: object, + ) -> AssignmentMutationResult: + """Capture Assignment semantics and return the commanded target identity.""" + del authorization + self.assignment_command = command + return AssignmentMutationResult(assignment_record_id=command.assignment_record_id) + + +def _policy( + *, + resource_kind: str, + field_name: str, + command: object, + command_field_name: str, + replacement: object, +) -> PurposeBoundAccessPolicy: + """Build a valid policy whose resource-kind comparison mutates caller state.""" + return PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="authorization-snapshot-v1", + resource_kind=_MutatingResourceKind( + resource_kind, + command=command, + field_name=command_field_name, + replacement=replacement, + ), + purpose_code="workforce_admin", + operation_code="create_record", + required_scope_code="orgmetra.people.write", + permitted_fields=frozenset({field_name}), + ) + + +def _employment_command() -> EmploymentMutationCommand: + """Build one valid Employment command for authorization interleaving.""" + return EmploymentMutationCommand( + tenant_record_id=TENANT, + person_record_id=PERSON, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + employment_status_code="active", + employment_concurrency_code="exclusive", + effective_from=EFFECTIVE_FROM, + confirmation_reference="human_confirmation:authorization-snapshot", + evidence_version_code="authorization-snapshot-v1", + idempotency_key="authorization-snapshot-employment-1", + ) + + +def _position_command() -> PositionMutationCommand: + """Build one valid Position command for authorization interleaving.""" + return PositionMutationCommand( + tenant_record_id=TENANT, + organization_unit_id=ORGANIZATION, + job_profile_id=JOB, + position_record_id=POSITION, + position_record_version_id=POSITION_VERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + position_status_code="open", + effective_from=EFFECTIVE_FROM, + confirmation_reference="human_confirmation:authorization-snapshot", + evidence_version_code="authorization-snapshot-v1", + idempotency_key="authorization-snapshot-position-1", + ) + + +def _assignment_command() -> AssignmentMutationCommand: + """Build one valid Assignment command for authorization interleaving.""" + return AssignmentMutationCommand( + tenant_record_id=TENANT, + employment_record_id=EMPLOYMENT, + person_record_id=PERSON, + position_record_id=POSITION, + assignment_record_id=ASSIGNMENT, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + allocation_ratio=Decimal("0.5000"), + effective_from=EFFECTIVE_FROM, + confirmation_reference="human_confirmation:authorization-snapshot", + evidence_version_code="authorization-snapshot-v1", + idempotency_key="authorization-snapshot-assignment-1", + ) + + +class PeopleMutationAuthorizationCommandSnapshotTests(unittest.TestCase): + """Require authorization callbacks to see no caller-owned command authority.""" + + def test_employment_port_receives_pre_authorization_semantics(self) -> None: + """Policy execution may mutate caller state but not the Employment port command.""" + command = _employment_command() + port = _CapturingMutationPort() + create_employment_record( + principal=PRINCIPAL, + command=command, + purpose_code="workforce_admin", + policy=_policy( + resource_kind="employment_record", + field_name="employment_record", + command=command, + command_field_name="person_record_id", + replacement=OTHER_PERSON, + ), + mutation_port=port, + ) + self.assertEqual(command.person_record_id, OTHER_PERSON) + self.assertIsNotNone(port.employment_command) + assert port.employment_command is not None + self.assertEqual(port.employment_command.person_record_id, PERSON) + self.assertIsNot(port.employment_command, command) + + def test_position_port_receives_pre_authorization_semantics(self) -> None: + """Policy execution may mutate caller state but not the Position port command.""" + command = _position_command() + port = _CapturingMutationPort() + create_position_record( + principal=PRINCIPAL, + command=command, + purpose_code="workforce_admin", + policy=_policy( + resource_kind="position_record", + field_name="position_record", + command=command, + command_field_name="job_profile_id", + replacement=OTHER_JOB, + ), + mutation_port=port, + ) + self.assertEqual(command.job_profile_id, OTHER_JOB) + self.assertIsNotNone(port.position_command) + assert port.position_command is not None + self.assertEqual(port.position_command.job_profile_id, JOB) + self.assertIsNot(port.position_command, command) + + def test_assignment_port_receives_pre_authorization_semantics(self) -> None: + """Policy execution may mutate caller state but not the Assignment port command.""" + command = _assignment_command() + port = _CapturingMutationPort() + create_assignment_record( + principal=PRINCIPAL, + command=command, + purpose_code="workforce_admin", + policy=_policy( + resource_kind="assignment_record", + field_name="assignment_record", + command=command, + command_field_name="position_record_id", + replacement=OTHER_POSITION, + ), + mutation_port=port, + ) + self.assertEqual(command.position_record_id, OTHER_POSITION) + self.assertIsNotNone(port.assignment_command) + assert port.assignment_command is not None + self.assertEqual(port.assignment_command.position_record_id, POSITION) + self.assertIsNot(port.assignment_command, command) + + +if __name__ == "__main__": + unittest.main() From e4d538c3e5c0707b650e4eeefb7d91dc4611fe9e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 13:03:44 +0900 Subject: [PATCH 60/80] fix(people): detach commands before authorization callbacks --- services/people-api/src/orgmetra_people_api/mutations.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index 04448298d..bdc68d658 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -10,7 +10,7 @@ from __future__ import annotations -from dataclasses import dataclass +from dataclasses import dataclass, replace from datetime import date from decimal import Decimal from hashlib import sha256 @@ -369,7 +369,7 @@ def create_employment_record( """Authorize the exact employment target before persisting worker employment truth.""" if type(command) is not EmploymentMutationCommand: raise TypeError("command must be an EmploymentMutationCommand") - EmploymentMutationCommand.__post_init__(command) + command = replace(command) expected_employment_record_id = UUID(int=command.employment_record_id.int) port = _require_port(mutation_port) authorization = authorize_resource_fields( @@ -403,7 +403,7 @@ def create_position_record( """Authorize the exact position target before persisting a staffable seat.""" if type(command) is not PositionMutationCommand: raise TypeError("command must be a PositionMutationCommand") - PositionMutationCommand.__post_init__(command) + command = replace(command) expected_position_record_id = UUID(int=command.position_record_id.int) port = _require_port(mutation_port) authorization = authorize_resource_fields( @@ -437,7 +437,7 @@ def create_assignment_record( """Authorize the exact assignment target before persisting seat allocation.""" if type(command) is not AssignmentMutationCommand: raise TypeError("command must be an AssignmentMutationCommand") - AssignmentMutationCommand.__post_init__(command) + command = replace(command) expected_assignment_record_id = UUID(int=command.assignment_record_id.int) port = _require_port(mutation_port) authorization = authorize_resource_fields( From 5a6354a94a4098509d68a6d413c0dbe8b236f94f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 13:09:24 +0900 Subject: [PATCH 61/80] test(people): bind hire command before authorization callbacks --- ...est_hire_authorization_command_snapshot.py | 147 ++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 services/people-api/tests/test_hire_authorization_command_snapshot.py diff --git a/services/people-api/tests/test_hire_authorization_command_snapshot.py b/services/people-api/tests/test_hire_authorization_command_snapshot.py new file mode 100644 index 000000000..30804e05f --- /dev/null +++ b/services/people-api/tests/test_hire_authorization_command_snapshot.py @@ -0,0 +1,147 @@ +"""Application command-snapshot regression for confirmed-hire authorization.""" + +from __future__ import annotations + +from datetime import date +import unittest +from uuid import UUID + +from orgmetra_keyverse_adapter import PurposeBoundAccessPolicy +from orgmetra_people_api.auth import AuthenticatedPrincipal +from orgmetra_people_api.hire import ( + HireAcceptanceCommand, + HireAcceptanceResult, + accept_confirmed_hire, +) + +TENANT = UUID("0198a412-c200-7000-8000-000000000001") +CANDIDATE = UUID("0198a412-c200-7000-8000-000000000010") +SELECTION_DECISION = UUID("0198a412-c200-7000-8000-000000000011") +PERSON = UUID("0198a412-c200-7000-8000-000000000020") +PERSON_NAME = UUID("0198a412-c200-7000-8000-000000000021") +EMPLOYMENT = UUID("0198a412-c200-7000-8000-000000000030") +EMPLOYMENT_VERSION = UUID("0198a412-c200-7000-8000-000000000031") +CONVERSION = UUID("0198a412-c200-7000-8000-000000000040") +AUDIT_EVENT = UUID("0198a412-c200-7000-8000-000000000050") +OUTBOX = UUID("0198a412-c200-7000-8000-000000000051") +EFFECTIVE_FROM = date(2026, 9, 5) +ORIGINAL_DISPLAY_NAME = "Authorization Snapshot Worker" +MUTATED_DISPLAY_NAME = "Authorization Callback Rewrite" + +PRINCIPAL = AuthenticatedPrincipal( + tenant_record_id=TENANT, + actor_reference="keyverse_subject:hire-authorization-snapshot-operator", + granted_scope_codes=frozenset({"orgmetra.people.materialize_worker"}), +) + + +class _MutatingResourceKind(str): + """Rewrite retained caller hire data when policy comparison executes.""" + + def __new__( + cls, + value: str, + *, + command: HireAcceptanceCommand, + ) -> _MutatingResourceKind: + """Retain the caller command solely for the adversarial comparison callback.""" + instance = super().__new__(cls, value) + instance.command = command + return instance + + def _mutate_command(self) -> None: + """Rewrite valid PII after application validation but during authorization.""" + object.__setattr__(self.command, "display_name", MUTATED_DISPLAY_NAME) + + def __eq__(self, other: object) -> bool: + """Mutate before preserving ordinary string equality semantics.""" + self._mutate_command() + return str.__eq__(self, other) + + def __ne__(self, other: object) -> bool: + """Mutate before preserving ordinary string inequality semantics.""" + self._mutate_command() + return str.__ne__(self, other) + + +class _CapturingHirePort: + """Capture the hire command that crosses the application port boundary.""" + + command: HireAcceptanceCommand | None = None + + def accept_hire( + self, + *, + command: HireAcceptanceCommand, + authorization: object, + ) -> HireAcceptanceResult: + """Capture hire semantics and return the commanded authoritative identities.""" + del authorization + self.command = command + return HireAcceptanceResult( + person_record_id=command.person_record_id, + employment_record_id=command.employment_record_id, + candidate_worker_conversion_record_id=command.candidate_worker_conversion_record_id, + ) + + +def _command() -> HireAcceptanceCommand: + """Build one valid confirmed-hire command for authorization interleaving.""" + return HireAcceptanceCommand( + tenant_record_id=TENANT, + candidate_profile_id=CANDIDATE, + selection_decision_id=SELECTION_DECISION, + person_record_id=PERSON, + person_name_record_id=PERSON_NAME, + employment_record_id=EMPLOYMENT, + employment_record_version_id=EMPLOYMENT_VERSION, + candidate_worker_conversion_record_id=CONVERSION, + audit_event_record_id=AUDIT_EVENT, + outbox_delivery_record_id=OUTBOX, + effective_from=EFFECTIVE_FROM, + display_name=ORIGINAL_DISPLAY_NAME, + idempotency_key="hire-authorization-snapshot-1", + ) + + +def _policy(command: HireAcceptanceCommand) -> PurposeBoundAccessPolicy: + """Build a valid policy whose resource-kind comparison mutates caller state.""" + return PurposeBoundAccessPolicy( + tenant_record_id=TENANT, + policy_version_code="hire-authorization-snapshot-v1", + resource_kind=_MutatingResourceKind("selection_decision", command=command), + purpose_code="candidate_hire", + operation_code="materialize_worker", + required_scope_code="orgmetra.people.materialize_worker", + permitted_fields=frozenset({"candidate_worker_conversion"}), + ) + + +class HireAuthorizationCommandSnapshotTests(unittest.TestCase): + """Require authorization callbacks to have no authority over the port hire command.""" + + def test_hire_port_receives_pre_authorization_semantics(self) -> None: + """Policy execution may mutate caller PII but not the detached port command.""" + command = _command() + port = _CapturingHirePort() + + result = accept_confirmed_hire( + principal=PRINCIPAL, + command=command, + purpose_code="candidate_hire", + policy=_policy(command), + mutation_port=port, + ) + + self.assertEqual(command.display_name, MUTATED_DISPLAY_NAME) + self.assertIsNotNone(port.command) + assert port.command is not None + self.assertEqual(port.command.display_name, ORIGINAL_DISPLAY_NAME) + self.assertIsNot(port.command, command) + self.assertEqual(result.person_record_id, PERSON) + self.assertEqual(result.employment_record_id, EMPLOYMENT) + self.assertEqual(result.candidate_worker_conversion_record_id, CONVERSION) + + +if __name__ == "__main__": + unittest.main() From 9771be6d65bef77408cd5ad1ae316f0a8d8fb5e3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 13:09:41 +0900 Subject: [PATCH 62/80] fix(people): detach hire command before authorization callbacks --- services/people-api/src/orgmetra_people_api/hire.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/hire.py b/services/people-api/src/orgmetra_people_api/hire.py index 16ad2c66d..86ff5a625 100644 --- a/services/people-api/src/orgmetra_people_api/hire.py +++ b/services/people-api/src/orgmetra_people_api/hire.py @@ -8,7 +8,7 @@ from __future__ import annotations -from dataclasses import dataclass +from dataclasses import dataclass, replace from datetime import date import re from typing import Protocol, runtime_checkable @@ -149,7 +149,7 @@ def accept_confirmed_hire( """ if type(command) is not HireAcceptanceCommand: raise TypeError("command must be a HireAcceptanceCommand") - HireAcceptanceCommand.__post_init__(command) + command = replace(command) expected_person_record_id = UUID(int=command.person_record_id.int) expected_employment_record_id = UUID(int=command.employment_record_id.int) expected_conversion_record_id = UUID( From 6fcb1c45173b6d49d14f0dd34d0f986e28b9d256 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 14:06:41 +0900 Subject: [PATCH 63/80] test(people): reject allocation text runtime subtype --- ...utation_allocation_text_runtime_integrity.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_allocation_text_runtime_integrity.py diff --git a/services/people-api/tests/test_people_mutation_allocation_text_runtime_integrity.py b/services/people-api/tests/test_people_mutation_allocation_text_runtime_integrity.py new file mode 100644 index 000000000..6cc1af0e3 --- /dev/null +++ b/services/people-api/tests/test_people_mutation_allocation_text_runtime_integrity.py @@ -0,0 +1,17 @@ +"""Reject non-canonical allocation-ratio text before Decimal parsing.""" + +from __future__ import annotations + +import pytest + +from orgmetra_people_api.mutations import parse_allocation_ratio + + +class _AllocationRatioText(str): + """Represent a valid-looking allocation token with caller-defined runtime identity.""" + + +def test_parse_allocation_ratio_rejects_string_subclasses() -> None: + """Assignment allocation text must be the exact built-in value that was parsed.""" + with pytest.raises(ValueError, match="allocation_ratio"): + parse_allocation_ratio(_AllocationRatioText("0.2500")) From 7779a852b4bdd4fb281f6813a42960c425e361f6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 14:07:57 +0900 Subject: [PATCH 64/80] fix(people): require exact allocation text --- services/people-api/src/orgmetra_people_api/mutations.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index bdc68d658..69d825f24 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -462,6 +462,6 @@ def create_assignment_record( def parse_allocation_ratio(raw_value: object) -> Decimal: """Parse the OpenAPI allocation token into an exact four-decimal ratio.""" - if not isinstance(raw_value, str) or re.fullmatch(r"^(0\.[0-9]{4}|1\.0000)$", raw_value) is None: + if type(raw_value) is not str or re.fullmatch(r"^(0\.[0-9]{4}|1\.0000)$", raw_value) is None: raise ValueError("allocation_ratio must match 0.0001-1.0000 four-decimal form.") - return Decimal(raw_value) + return Decimal(raw_value) \ No newline at end of file From 8d3877650865f71c4d9708b06eb55f43a7cb7661 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 14:09:04 +0900 Subject: [PATCH 65/80] style(people): preserve source trailing newline --- services/people-api/src/orgmetra_people_api/mutations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index 69d825f24..7ada72d37 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -464,4 +464,4 @@ def parse_allocation_ratio(raw_value: object) -> Decimal: """Parse the OpenAPI allocation token into an exact four-decimal ratio.""" if type(raw_value) is not str or re.fullmatch(r"^(0\.[0-9]{4}|1\.0000)$", raw_value) is None: raise ValueError("allocation_ratio must match 0.0001-1.0000 four-decimal form.") - return Decimal(raw_value) \ No newline at end of file + return Decimal(raw_value) From abd5dc506d363897d0396dc9e75b1e389b47c71f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 14:24:07 +0900 Subject: [PATCH 66/80] test(people): expose zero allocation contract split --- ...ation_allocation_text_runtime_integrity.py | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/services/people-api/tests/test_people_mutation_allocation_text_runtime_integrity.py b/services/people-api/tests/test_people_mutation_allocation_text_runtime_integrity.py index 6cc1af0e3..f2f238356 100644 --- a/services/people-api/tests/test_people_mutation_allocation_text_runtime_integrity.py +++ b/services/people-api/tests/test_people_mutation_allocation_text_runtime_integrity.py @@ -2,16 +2,46 @@ from __future__ import annotations +from pathlib import Path +import re + import pytest from orgmetra_people_api.mutations import parse_allocation_ratio +_OPENAPI_PATH = Path(__file__).resolve().parents[3] / "schemas" / "openapi.yaml" + class _AllocationRatioText(str): """Represent a valid-looking allocation token with caller-defined runtime identity.""" +def _published_allocation_pattern() -> re.Pattern[str]: + """Read the Assignment allocation token pattern from the published OpenAPI contract.""" + schema = _OPENAPI_PATH.read_text(encoding="utf-8") + match = re.search( + r"allocation_ratio:\n\s+type: string\n\s+pattern: '([^']+)'", + schema, + ) + assert match is not None, "CreateAssignmentRecordCommand allocation pattern is missing" + return re.compile(match.group(1)) + + def test_parse_allocation_ratio_rejects_string_subclasses() -> None: """Assignment allocation text must be the exact built-in value that was parsed.""" with pytest.raises(ValueError, match="allocation_ratio"): parse_allocation_ratio(_AllocationRatioText("0.2500")) + + +def test_parse_allocation_ratio_rejects_zero_before_domain_construction() -> None: + """The HTTP scalar parser must enforce the same strictly-positive Assignment invariant.""" + with pytest.raises(ValueError, match="allocation_ratio"): + parse_allocation_ratio("0.0000") + + +def test_openapi_allocation_pattern_matches_the_strictly_positive_domain_range() -> None: + """Generated clients and handlers must not advertise zero as a valid Assignment ratio.""" + pattern = _published_allocation_pattern() + assert pattern.fullmatch("0.0000") is None + for token in ("0.0001", "0.2500", "0.9999", "1.0000"): + assert pattern.fullmatch(token) is not None From 7a95aa95a6a9cf4497b301ffee0748555d98776e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 14:27:22 +0900 Subject: [PATCH 67/80] fix(people): reject zero allocation before domain construction --- services/people-api/src/orgmetra_people_api/mutations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index 7ada72d37..d90bc6773 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -462,6 +462,6 @@ def create_assignment_record( def parse_allocation_ratio(raw_value: object) -> Decimal: """Parse the OpenAPI allocation token into an exact four-decimal ratio.""" - if type(raw_value) is not str or re.fullmatch(r"^(0\.[0-9]{4}|1\.0000)$", raw_value) is None: + if type(raw_value) is not str or re.fullmatch(r"^(0\.(?!0000)[0-9]{4}|1\.0000)$", raw_value) is None: raise ValueError("allocation_ratio must match 0.0001-1.0000 four-decimal form.") return Decimal(raw_value) From f659b652fbe307134792370ac273514f0b1830a0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 14:34:38 +0900 Subject: [PATCH 68/80] fix(api): align assignment allocation contract with domain invariant --- schemas/openapi.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/schemas/openapi.yaml b/schemas/openapi.yaml index 0fd397e92..c03ffab0b 100644 --- a/schemas/openapi.yaml +++ b/schemas/openapi.yaml @@ -641,7 +641,7 @@ components: format: uuid allocation_ratio: type: string - pattern: '^(0\.[0-9]{4}|1\.0000)$' + pattern: '^(0\.(?!0000)[0-9]{4}|1\.0000)$' effective_from: type: string format: date From da4b628fe344372ec22421cfa010e15105ad2c50 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 14:36:06 +0900 Subject: [PATCH 69/80] chore(manifest): reseal updated OpenAPI allocation contract --- manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 956e51d26..42d438d5e 100644 --- a/manifest.json +++ b/manifest.json @@ -83,7 +83,7 @@ }, { "path": "database/migrations/0005_outbox_delivery_finalization.sql", - "sha256": "b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961", + "sha256": "b7e8790595b288f7525d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961", "bytes": 6125, "lines": 170 }, @@ -353,8 +353,8 @@ }, { "path": "schemas/openapi.yaml", - "sha256": "09c1e43486779198574fe31b8bcabbd1c1f74beec7bf86245ae578061619838f", - "bytes": 29503, + "sha256": "c37522504d1f6ac6410eaac833dddbf09aacc85572da38a1cf7539541833ea8e", + "bytes": 29511, "lines": 1020 }, { From 8f986853a6f234c317e29080c4982bab34f3dc51 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 14:37:55 +0900 Subject: [PATCH 70/80] fix(manifest): restore unaffected outbox digest --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 42d438d5e..ac1648354 100644 --- a/manifest.json +++ b/manifest.json @@ -83,7 +83,7 @@ }, { "path": "database/migrations/0005_outbox_delivery_finalization.sql", - "sha256": "b7e8790595b288f7525d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961", + "sha256": "b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961", "bytes": 6125, "lines": 170 }, From d7440d40e46f59a2596167bbca54af2a79e901a4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 20:38:05 +0900 Subject: [PATCH 71/80] test(people): specify idempotent replay result evidence --- ...eople_mutation_idempotent_replay_result.py | 119 ++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 services/people-api/tests/test_people_mutation_idempotent_replay_result.py diff --git a/services/people-api/tests/test_people_mutation_idempotent_replay_result.py b/services/people-api/tests/test_people_mutation_idempotent_replay_result.py new file mode 100644 index 000000000..093c61960 --- /dev/null +++ b/services/people-api/tests/test_people_mutation_idempotent_replay_result.py @@ -0,0 +1,119 @@ +"""Result-receipt regressions for idempotent generic People mutation replay.""" + +from __future__ import annotations + +import unittest +from uuid import UUID + +from orgmetra_people_api.mutations import ( + AssignmentMutationCommand, + AssignmentMutationResult, + EmploymentMutationCommand, + EmploymentMutationResult, + PeopleMutationIntegrityError, + PositionMutationCommand, + PositionMutationResult, + create_assignment_record, + create_employment_record, + create_position_record, + mutation_command_digest, +) +from test_people_mutations import ( + ASSIGNMENT, + EMPLOYMENT, + POSITION, + PRINCIPAL, + assignment_command, + assignment_policy, + employment_command, + employment_policy, + position_command, + position_policy, +) + +NEW_EMPLOYMENT = UUID("0198a412-8200-7000-8000-000000000033") +NEW_POSITION = UUID("0198a412-8200-7000-8000-000000000044") +NEW_ASSIGNMENT = UUID("0198a412-8200-7000-8000-000000000077") + + +class ReplayReceiptPort: + """Return first-committed identities with independently checkable replay evidence.""" + + def __init__(self, *, digest_override: str | None = None) -> None: + self.digest_override = digest_override + + def _digest(self, *, command: object, authorization: object) -> str: + digest = mutation_command_digest(command=command, authorization=authorization) # type: ignore[arg-type] + return self.digest_override if self.digest_override is not None else digest + + def create_employment(self, *, command: EmploymentMutationCommand, authorization: object) -> EmploymentMutationResult: + return EmploymentMutationResult( + employment_record_id=EMPLOYMENT, + replay_command_digest=self._digest(command=command, authorization=authorization), + ) + + def create_position(self, *, command: PositionMutationCommand, authorization: object) -> PositionMutationResult: + return PositionMutationResult( + position_record_id=POSITION, + replay_command_digest=self._digest(command=command, authorization=authorization), + ) + + def create_assignment(self, *, command: AssignmentMutationCommand, authorization: object) -> AssignmentMutationResult: + return AssignmentMutationResult( + assignment_record_id=ASSIGNMENT, + replay_command_digest=self._digest(command=command, authorization=authorization), + ) + + +class PeopleMutationIdempotentReplayResultTests(unittest.TestCase): + """Reconcile first-committed replay identity with result-integrity hardening.""" + + def test_matching_replay_receipt_may_return_first_committed_identity(self) -> None: + port = ReplayReceiptPort() + + employment = create_employment_record( + principal=PRINCIPAL, + command=employment_command(employment_record_id=NEW_EMPLOYMENT), + purpose_code="workforce_admin", + policy=employment_policy(), + mutation_port=port, + ) + position = create_position_record( + principal=PRINCIPAL, + command=position_command(position_record_id=NEW_POSITION), + purpose_code="job_architecture_admin", + policy=position_policy(), + mutation_port=port, + ) + assignment = create_assignment_record( + principal=PRINCIPAL, + command=assignment_command(assignment_record_id=NEW_ASSIGNMENT), + purpose_code="workforce_admin", + policy=assignment_policy(), + mutation_port=port, + ) + + self.assertEqual(employment.employment_record_id, EMPLOYMENT) + self.assertEqual(position.position_record_id, POSITION) + self.assertEqual(assignment.assignment_record_id, ASSIGNMENT) + + def test_foreign_identity_with_mismatched_replay_digest_fails_closed(self) -> None: + with self.assertRaisesRegex(PeopleMutationIntegrityError, "replay evidence"): + create_employment_record( + principal=PRINCIPAL, + command=employment_command(employment_record_id=NEW_EMPLOYMENT), + purpose_code="workforce_admin", + policy=employment_policy(), + mutation_port=ReplayReceiptPort(digest_override="0" * 64), + ) + + def test_replay_digest_must_be_an_exact_string(self) -> None: + with self.assertRaisesRegex(ValueError, "replay_command_digest"): + EmploymentMutationResult( + employment_record_id=EMPLOYMENT, + replay_command_digest=object(), # type: ignore[arg-type] + ) + + +if __name__ == "__main__": + unittest.main() From cc1cc53f34908178495ff657930c3950ce5931f9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 20:39:16 +0900 Subject: [PATCH 72/80] fix(people): bind foreign replay identity to semantic digest --- .../src/orgmetra_people_api/mutations.py | 66 ++++++++++++++++--- 1 file changed, 57 insertions(+), 9 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/mutations.py b/services/people-api/src/orgmetra_people_api/mutations.py index d90bc6773..776c80955 100644 --- a/services/people-api/src/orgmetra_people_api/mutations.py +++ b/services/people-api/src/orgmetra_people_api/mutations.py @@ -289,37 +289,49 @@ def __post_init__(self) -> None: validate_idempotency_key(self.idempotency_key) +def _validate_replay_command_digest(value: object) -> None: + """Require exact inert replay evidence when a mutation result carries it.""" + if value is not None and type(value) is not str: + raise ValueError("replay_command_digest must be an exact string when present.") + + @dataclass(frozen=True, slots=True) class EmploymentMutationResult: - """Opaque identity returned after one committed employment mutation.""" + """Opaque identity and optional verified-replay evidence for one employment mutation.""" employment_record_id: UUID + replay_command_digest: str | None = None def __post_init__(self) -> None: """Prevent malformed persistence results from crossing the service boundary.""" _validate_operational_uuid("employment_record_id", self.employment_record_id) + _validate_replay_command_digest(self.replay_command_digest) @dataclass(frozen=True, slots=True) class PositionMutationResult: - """Opaque identity returned after one committed position mutation.""" + """Opaque identity and optional verified-replay evidence for one position mutation.""" position_record_id: UUID + replay_command_digest: str | None = None def __post_init__(self) -> None: """Prevent malformed persistence results from crossing the service boundary.""" _validate_operational_uuid("position_record_id", self.position_record_id) + _validate_replay_command_digest(self.replay_command_digest) @dataclass(frozen=True, slots=True) class AssignmentMutationResult: - """Opaque identity returned after one committed assignment mutation.""" + """Opaque identity and optional verified-replay evidence for one assignment mutation.""" assignment_record_id: UUID + replay_command_digest: str | None = None def __post_init__(self) -> None: """Prevent malformed persistence results from crossing the service boundary.""" _validate_operational_uuid("assignment_record_id", self.assignment_record_id) + _validate_replay_command_digest(self.replay_command_digest) @runtime_checkable @@ -358,6 +370,24 @@ def _require_port(mutation_port: object) -> PeopleMutationPort: return mutation_port +def _require_result_identity_or_replay( + *, + result_record_id: UUID, + expected_record_id: UUID, + replay_command_digest: str | None, + command: EmploymentMutationCommand | PositionMutationCommand | AssignmentMutationCommand, + authorization: AuthorizationDecision, + result_name: str, +) -> None: + """Accept a foreign identity only with replay evidence bound to this semantic command.""" + if replay_command_digest is not None: + if replay_command_digest != mutation_command_digest(command=command, authorization=authorization): + raise PeopleMutationIntegrityError(f"{result_name} replay evidence does not match command") + return + if result_record_id != expected_record_id: + raise PeopleMutationIntegrityError(f"{result_name} result identity does not match command") + + def create_employment_record( *, principal: AuthenticatedPrincipal, @@ -387,8 +417,14 @@ def create_employment_record( if type(result) is not EmploymentMutationResult: raise TypeError("mutation_port must return EmploymentMutationResult") EmploymentMutationResult.__post_init__(result) - if result.employment_record_id != expected_employment_record_id: - raise PeopleMutationIntegrityError("employment result identity does not match command") + _require_result_identity_or_replay( + result_record_id=result.employment_record_id, + expected_record_id=expected_employment_record_id, + replay_command_digest=result.replay_command_digest, + command=command, + authorization=authorization, + result_name="employment", + ) return result @@ -421,8 +457,14 @@ def create_position_record( if type(result) is not PositionMutationResult: raise TypeError("mutation_port must return PositionMutationResult") PositionMutationResult.__post_init__(result) - if result.position_record_id != expected_position_record_id: - raise PeopleMutationIntegrityError("position result identity does not match command") + _require_result_identity_or_replay( + result_record_id=result.position_record_id, + expected_record_id=expected_position_record_id, + replay_command_digest=result.replay_command_digest, + command=command, + authorization=authorization, + result_name="position", + ) return result @@ -455,8 +497,14 @@ def create_assignment_record( if type(result) is not AssignmentMutationResult: raise TypeError("mutation_port must return AssignmentMutationResult") AssignmentMutationResult.__post_init__(result) - if result.assignment_record_id != expected_assignment_record_id: - raise PeopleMutationIntegrityError("assignment result identity does not match command") + _require_result_identity_or_replay( + result_record_id=result.assignment_record_id, + expected_record_id=expected_assignment_record_id, + replay_command_digest=result.replay_command_digest, + command=command, + authorization=authorization, + result_name="assignment", + ) return result From a61617f0cdd6f1a2e29b512b2a3c66872af5ccc4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 20:41:34 +0900 Subject: [PATCH 73/80] fix(people): return verified idempotency replay receipt --- .../orgmetra_people_api/postgres_mutations.py | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/services/people-api/src/orgmetra_people_api/postgres_mutations.py b/services/people-api/src/orgmetra_people_api/postgres_mutations.py index ede1deefd..c2a5cef3f 100644 --- a/services/people-api/src/orgmetra_people_api/postgres_mutations.py +++ b/services/people-api/src/orgmetra_people_api/postgres_mutations.py @@ -288,8 +288,8 @@ def _replayed_record_id( *, command: EmploymentMutationCommand | PositionMutationCommand | AssignmentMutationCommand, authorization: AuthorizationDecision, -) -> UUID | None: - """Serialize one key, then return its committed record identity when present.""" +) -> tuple[UUID, str] | None: + """Serialize one key and return its committed identity plus verified semantic digest.""" route = command_route(command) digest = mutation_command_digest(command=command, authorization=authorization) key_parameters = (command.tenant_record_id, route, command.idempotency_key) @@ -310,7 +310,7 @@ def _replayed_record_id( if stored_digest != digest: raise PeopleMutationIntegrityError("idempotency key is bound to a different command") assert isinstance(created_record_id, UUID) - return created_record_id + return created_record_id, stored_digest def _record_idempotency( @@ -585,7 +585,11 @@ def create_employment( cursor.execute(_TENANT_CONTEXT_SQL, (str(command.tenant_record_id),)) replayed = _replayed_record_id(cursor, command=command, authorization=decision) if replayed is not None: - return EmploymentMutationResult(employment_record_id=replayed) + replayed_record_id, replay_digest = replayed + return EmploymentMutationResult( + employment_record_id=replayed_record_id, + replay_command_digest=replay_digest, + ) cursor.execute(_CONVERSION_SQL, (command.tenant_record_id, command.person_record_id)) _require_one_conversion(cursor.fetchmany(2)) recorded_at = _post_lock_recorded_at(cursor) @@ -694,7 +698,11 @@ def create_position( cursor.execute(_TENANT_CONTEXT_SQL, (str(command.tenant_record_id),)) replayed = _replayed_record_id(cursor, command=command, authorization=decision) if replayed is not None: - return PositionMutationResult(position_record_id=replayed) + replayed_record_id, replay_digest = replayed + return PositionMutationResult( + position_record_id=replayed_record_id, + replay_command_digest=replay_digest, + ) cursor.execute( _POSITION_PARENTS_SQL, (command.job_profile_id, command.tenant_record_id, command.organization_unit_id), @@ -791,7 +799,11 @@ def create_assignment( cursor.execute(_TENANT_CONTEXT_SQL, (str(command.tenant_record_id),)) replayed = _replayed_record_id(cursor, command=command, authorization=decision) if replayed is not None: - return AssignmentMutationResult(assignment_record_id=replayed) + replayed_record_id, replay_digest = replayed + return AssignmentMutationResult( + assignment_record_id=replayed_record_id, + replay_command_digest=replay_digest, + ) cursor.execute(_CONVERSION_SQL, (command.tenant_record_id, command.person_record_id)) _require_one_conversion(cursor.fetchmany(2)) cursor.execute( From 3f3b23a35a71f4fdaded3cb0cd1ee57412a7df05 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 23:13:45 +0900 Subject: [PATCH 74/80] test(people): cover fixed projection shape guards --- ...gres_mutation_projection_shape_coverage.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 services/people-api/tests/test_postgres_mutation_projection_shape_coverage.py diff --git a/services/people-api/tests/test_postgres_mutation_projection_shape_coverage.py b/services/people-api/tests/test_postgres_mutation_projection_shape_coverage.py new file mode 100644 index 000000000..c8e9e49a2 --- /dev/null +++ b/services/people-api/tests/test_postgres_mutation_projection_shape_coverage.py @@ -0,0 +1,27 @@ +"""Hosted-coverage regressions for fixed People PostgreSQL projection widths.""" + +from __future__ import annotations + +import pytest + +import orgmetra_people_api.postgres_mutations as postgres_mutations +from orgmetra_people_api.mutations import PeopleMutationIntegrityError + + +@pytest.mark.parametrize( + ("helper_name", "error_message"), + [ + ("_employment_version_from_row", "employment version row has an invalid shape"), + ("_position_version_from_row", "position version row has an invalid shape"), + ("_assignment_from_row", "assignment row has an invalid shape"), + ], +) +def test_fixed_projection_helpers_reject_wrong_width( + helper_name: str, + error_message: str, +) -> None: + """Cover each fail-closed width guard reported missing by exact-head Foundation CI.""" + helper = getattr(postgres_mutations, helper_name) + + with pytest.raises(PeopleMutationIntegrityError, match=error_message): + helper(postgres_mutations.UUID("10000000-0000-7000-8000-000000000001"), ()) From f933fbc2ce9b6d6d152d8046866553a757ff89f4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 00:18:10 +0900 Subject: [PATCH 75/80] test(people): use standard UUID attribute trap --- .../people-api/tests/test_hire_post_construction_integrity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/tests/test_hire_post_construction_integrity.py b/services/people-api/tests/test_hire_post_construction_integrity.py index d22cdac8a..3ba432939 100644 --- a/services/people-api/tests/test_hire_post_construction_integrity.py +++ b/services/people-api/tests/test_hire_post_construction_integrity.py @@ -29,7 +29,7 @@ class _ExecutableUUID(UUID): def __getattribute__(self, name: str) -> object: """Fail if a rewritten UUID is rendered before command revalidation.""" if name == "hex": - raise AssertionError("UUID subtype behavior executed before command revalidation") + raise AttributeError("UUID subtype behavior executed before command revalidation") return super().__getattribute__(name) From 4e9e04fb3d4730f94affeb67c90d5396622de23c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 00:18:52 +0900 Subject: [PATCH 76/80] test(people): use standard row-container trap errors --- .../test_postgres_hire_row_container_runtime_integrity.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/people-api/tests/test_postgres_hire_row_container_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_row_container_runtime_integrity.py index c084f9c48..a58ebfca0 100644 --- a/services/people-api/tests/test_postgres_hire_row_container_runtime_integrity.py +++ b/services/people-api/tests/test_postgres_hire_row_container_runtime_integrity.py @@ -34,7 +34,7 @@ class _ExecutableBatch(list[object]): def __bool__(self) -> bool: """Reject pre-gate truthiness.""" - raise AssertionError("row collection truthiness executed before exact-type validation") + raise TypeError("row collection truthiness executed before exact-type validation") def __len__(self) -> int: """Reject pre-gate length inspection.""" @@ -43,7 +43,7 @@ def __len__(self) -> int: def __getitem__(self, key: object) -> object: """Reject pre-gate indexed access.""" del key - raise AssertionError("row collection indexing executed before exact-type validation") + raise IndexError("row collection indexing executed before exact-type validation") def __iter__(self): """Reject pre-gate row iteration.""" @@ -60,7 +60,7 @@ def __len__(self) -> int: def __getitem__(self, key: object) -> object: """Reject pre-gate row indexing.""" del key - raise AssertionError("row indexing executed before exact-type validation") + raise IndexError("row indexing executed before exact-type validation") def __iter__(self): """Reject pre-gate row iteration.""" From 7485cb2856b3b119a5eaba141fb0ee958c8fae9a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 00:19:01 +0900 Subject: [PATCH 77/80] test(people): use standard durable UUID trap --- .../tests/test_postgres_hire_uuid_runtime_integrity.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/people-api/tests/test_postgres_hire_uuid_runtime_integrity.py b/services/people-api/tests/test_postgres_hire_uuid_runtime_integrity.py index 7b12d98ad..be18c536c 100644 --- a/services/people-api/tests/test_postgres_hire_uuid_runtime_integrity.py +++ b/services/people-api/tests/test_postgres_hire_uuid_runtime_integrity.py @@ -14,7 +14,7 @@ class _ExecutableUUID(UUID): def __getattribute__(self, name: str) -> object: """Fail when untrusted UUID evidence is inspected as if it were inert.""" if name == "int": - raise AssertionError("UUID subtype behavior executed before exact-type validation") + raise AttributeError("UUID subtype behavior executed before exact-type validation") return super().__getattribute__(name) From 59f6eae362d37f57e37807f39478c03a3294a93a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 00:19:18 +0900 Subject: [PATCH 78/80] test(people): use standard projection-container trap errors --- .../tests/test_postgres_mutation_row_container_integrity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/people-api/tests/test_postgres_mutation_row_container_integrity.py b/services/people-api/tests/test_postgres_mutation_row_container_integrity.py index fc7b77fe3..11545ca7c 100644 --- a/services/people-api/tests/test_postgres_mutation_row_container_integrity.py +++ b/services/people-api/tests/test_postgres_mutation_row_container_integrity.py @@ -16,7 +16,7 @@ class _ExecutableRows(list[object]): def __bool__(self) -> bool: """Fail if durable validation asks this untrusted collection for truthiness.""" type(self).calls += 1 - raise AssertionError("outer durable row collection executed __bool__") + raise TypeError("outer durable row collection executed __bool__") def __len__(self) -> int: """Fail if durable validation asks this untrusted collection for cardinality.""" @@ -26,7 +26,7 @@ def __len__(self) -> int: def __getitem__(self, index: object) -> object: """Fail if durable validation indexes this untrusted collection.""" type(self).calls += 1 - raise AssertionError("outer durable row collection executed __getitem__") + raise IndexError("outer durable row collection executed __getitem__") def __iter__(self): """Fail if durable validation iterates this untrusted collection.""" From 998e06f49e5f91d84b335992761f2c210ea0ec39 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 00:20:00 +0900 Subject: [PATCH 79/80] test(people): use standard scalar tripwire protocols --- ...test_postgres_mutation_scalar_runtime_integrity.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py index 035a467a1..57760565e 100644 --- a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py +++ b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py @@ -28,7 +28,7 @@ class _ExecutableUUID(UUID): def __getattribute__(self, name: str) -> object: """Fail when untrusted UUID evidence is inspected as if it were inert.""" if name == "int": - raise AssertionError("UUID subtype behavior executed before exact-type validation") + raise AttributeError("UUID subtype behavior executed before exact-type validation") return super().__getattribute__(name) @@ -85,10 +85,7 @@ def __new__(cls, value: str) -> _ExecutableStatusText: instance.calls = 0 return instance - def __hash__(self) -> int: - """Fail if HRIS validation hashes persisted subtype text.""" - self.calls += 1 - raise AssertionError("status subtype hashing executed before exact-type validation") + __hash__ = None def __eq__(self, other: object) -> bool: """Fail if HRIS validation compares persisted subtype text.""" @@ -116,13 +113,13 @@ def __gt__(self, other: object) -> bool: """Fail if FTE validation compares persisted subtype allocation.""" del other self.calls += 1 - raise AssertionError("Decimal subtype comparison executed before exact-type validation") + raise TypeError("Decimal subtype comparison executed before exact-type validation") def __le__(self, other: object) -> bool: """Fail if FTE validation compares persisted subtype allocation.""" del other self.calls += 1 - raise AssertionError("Decimal subtype comparison executed before exact-type validation") + raise TypeError("Decimal subtype comparison executed before exact-type validation") def __add__(self, other: object) -> Decimal: """Fail if portfolio aggregation adds persisted subtype allocation.""" From 4be7f1681959e43d32c8e85a8f2660da36ff6d9c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sun, 6 Sep 2026 02:27:48 +0900 Subject: [PATCH 80/80] test(people): use numeric protocol errors for Decimal tripwires --- .../tests/test_postgres_mutation_scalar_runtime_integrity.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py index 57760565e..5de9cbb1d 100644 --- a/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py +++ b/services/people-api/tests/test_postgres_mutation_scalar_runtime_integrity.py @@ -125,13 +125,13 @@ def __add__(self, other: object) -> Decimal: """Fail if portfolio aggregation adds persisted subtype allocation.""" del other self.calls += 1 - raise AssertionError("Decimal subtype addition executed before exact-type validation") + raise TypeError("Decimal subtype addition executed before exact-type validation") def __radd__(self, other: object) -> Decimal: """Fail if portfolio aggregation reverse-adds persisted subtype allocation.""" del other self.calls += 1 - raise AssertionError("Decimal subtype reverse addition executed before exact-type validation") + raise TypeError("Decimal subtype reverse addition executed before exact-type validation") class _ReplayCursor: