Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .github/workflows/foundation-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,33 @@ jobs:
run: npm run validate
- name: Prove Foundation CI dependency hygiene
run: bash tests/test_foundation_ci_dependency_hygiene.sh
- name: Set up exact Position Reporting Change Review Python
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.14.7"
check-latest: false
- name: Install reviewed test toolchain
run: |
python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt
python -m pip check
- name: Run Position reporting change review installed-artifact contract
run: |
printf '%s\n' 'setuptools==84.0.0 --hash=sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670' > /tmp/orgmetra-position-reporting-change-review-build.txt
python -m pip install --require-hashes --no-deps --only-binary=:all: -r /tmp/orgmetra-position-reporting-change-review-build.txt
rm -rf /tmp/orgmetra-position-reporting-change-review-build /tmp/orgmetra-position-reporting-change-review-dist /tmp/orgmetra-position-reporting-change-review-venv
cp -a packages/position-reporting-change-review /tmp/orgmetra-position-reporting-change-review-build
mkdir -p /tmp/orgmetra-position-reporting-change-review-dist
python -m pip wheel --no-deps --no-build-isolation --wheel-dir /tmp/orgmetra-position-reporting-change-review-dist /tmp/orgmetra-position-reporting-change-review-build
test "$(find /tmp/orgmetra-position-reporting-change-review-dist -maxdepth 1 -type f -name '*.whl' | wc -l)" -eq 1
python -m venv /tmp/orgmetra-position-reporting-change-review-venv
/tmp/orgmetra-position-reporting-change-review-venv/bin/python -m pip install --require-hashes --no-deps --only-binary=:all: -r "$GITHUB_WORKSPACE/.github/requirements/foundation-test.txt"
wheel_path="$(find /tmp/orgmetra-position-reporting-change-review-dist -maxdepth 1 -type f -name '*.whl' -print -quit)"
wheel_sha="$(sha256sum "$wheel_path" | awk '{print $1}')"
printf 'orgmetra-position-reporting-change-review[test] @ file://%s --hash=sha256:%s\n' "$wheel_path" "$wheel_sha" > /tmp/orgmetra-position-reporting-change-review-install.txt
/tmp/orgmetra-position-reporting-change-review-venv/bin/python -m pip install --require-hashes --no-deps -r /tmp/orgmetra-position-reporting-change-review-install.txt
/tmp/orgmetra-position-reporting-change-review-venv/bin/python -m pip check
cd /tmp
COVERAGE_FILE=/tmp/orgmetra-position-reporting-change-review.coverage /tmp/orgmetra-position-reporting-change-review-venv/bin/python -m pytest -c "$GITHUB_WORKSPACE/packages/position-reporting-change-review/pyproject.toml" "$GITHUB_WORKSPACE/packages/position-reporting-change-review/tests"
- name: Run owned unit and service contracts once
run: |
PYTHONPATH=packages/candidate-evidence/src COVERAGE_FILE=/tmp/orgmetra-candidate-evidence.coverage python -m pytest -c packages/candidate-evidence/pyproject.toml packages/candidate-evidence/tests
Expand Down
37 changes: 37 additions & 0 deletions docs/adr/0095-governed-position-reporting-change-review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# ADR 0095: Governed Position reporting-change review before authoritative mutation

- **Status:** Proposed — active PR truth only
- **Date:** 2026-08-23

## Context

Orgmetra already separates Job, Position and Assignment and models effective/business time separately from system-recorded time. Buyers also need defensible organizational reporting-line change controls: a manager-position reassignment can alter authority, span of control, approvals and workforce reporting even when no Person record is changed.

Protected `develop` does not yet ship an authoritative Position-reporting mutation boundary. Active PR #94 adds a read-only bitemporal Position-to-Position hierarchy, but active-PR behavior cannot be treated as protected-main truth or imported as an undeclared branch dependency. A review artifact can still be valuable now if it remains transport-neutral, fail-closed and explicitly unable to mutate HRIS data.

NIST SP 800-53 Rev. 5 Release 5.2.0 retains AC-5 separation-of-duties principles and AU-3 audit-record content/minimization considerations. NIST Privacy Framework 1.0 is the current final Privacy Framework while 1.1 remains non-final; its risk-based minimization framing supports keeping Person/worker values outside this organizational change envelope. RFC 9562 defines UUIDv4 and UUIDv7 and supports preserving the HRIS owner's operational UUID evolution while using UUIDv4 for leaf-owned random correlation references. These sources inform design controls; they are not certification or legal-compliance claims.

## Decision

Add `PositionReportingChangeReviewPacket` as a bounded pre-mutation evidence contract that:

1. binds one authoritative tenant plus subordinate, current-manager and proposed-manager Position references without copying Person identity or worker values;
2. binds `effective_on` as business time and `recorded_at` as a separately canonicalized system-recorded evidence instant;
3. binds exact Position-scope and organization-scope SHA-256 evidence plus a controlled reporting-change reason and explicit evidence version;
4. requires requester/reviewer reference inequality as an early guard but still requires authoritative actor resolution before mutation;
5. rejects subordinate=current manager, subordinate=proposed manager and current=proposed manager to prevent self-reporting and no-op evidence;
6. keeps `review_state=requires_human_review`, `scope_verification_state=requires_authoritative_resolution`, `mutation_state=not_authorized_to_apply`, and `decision_authority=human_review_only` immutable;
7. requires the host, immediately before mutation, to re-resolve all three Position records and the current solid-line relationship in the exact tenant and bitemporal coordinate, prove Position validity/staffability, authoritative reviewer separation, no cycle and no multiple visible solid-line managers, and then produce immutable audit/outbox evidence; and
8. performs no database mutation, no cross-service application-table SQL, no identity-provider write and no autonomous employment decision.

Operational HRIS-owned UUIDs remain canonical non-sentinel UUIDs rather than being narrowed to UUIDv4. Packet-owned change/actor correlation references require canonical UUIDv4. The package uses a process-local creation seal only to detect in-process post-construction evidence mutation; durable reference uniqueness and durable immutability remain responsibilities of authoritative persistence/audit boundaries.

## Consequences

A buyer can inspect and hash a minimally identifying, human-review-only reporting reassignment before any organizational truth changes. The packet explicitly separates review evidence from mutation authority and makes the next authoritative checks visible instead of implying that identifier syntax proves organizational validity.

The deliberate limitation is that the packet cannot establish that the current reporting relationship exists, that the proposed manager is valid at the requested date, that the change is policy/legal compliant, or that persistence succeeded. Those claims require authoritative runtime evidence after the relevant HRIS capability is integrated.

## References

See `docs/doctoring/position-reporting-change-review-references.md`.
18 changes: 18 additions & 0 deletions docs/doctoring/position-reporting-change-review-references.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Position reporting-change review references

Verified against official primary-source pages on 2026-08-23. These references inform the governance/evidence boundary only. Orgmetra does not claim NIST certification, universal legal compliance, or conformance merely because this package uses these design principles.

## APA 7

Boeckl, K., & Lefkovitz, N. (2020). *NIST Privacy Framework: A tool for improving privacy through enterprise risk management, Version 1.0* (NIST CSWP 10). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.CSWP.10

Davis, K., Peabody, B., & Leach, P. (2024). *Universally unique IDentifiers (UUIDs)* (RFC 9562). RFC Editor. https://doi.org/10.17487/RFC9562

Joint Task Force. (2020). *Security and privacy controls for information systems and organizations* (NIST Special Publication 800-53 Rev. 5; Release 5.2.0 supplemental control catalog current as of August 2025). National Institute of Standards and Technology. https://doi.org/10.6028/NIST.SP.800-53r5

## Applied boundary

- NIST SP 800-53 Rev. 5 AC-5 supports separation of duties. Orgmetra therefore treats requester/reviewer string inequality only as an early syntactic guard and requires authoritative actor resolution before reporting-line mutation.
- NIST SP 800-53 Rev. 5 AU-3 requires useful audit context while explicitly recognizing privacy risk in audit records. The packet therefore records organizational correlation, outcome state, reason category and timing while excluding Person identity, compensation, ratings and free-form worker narratives.
- NIST Privacy Framework 1.0 is the final framework used here for privacy-risk/minimization framing. NIST's public site currently presents Version 1.1 as non-final work; this ADR does not treat 1.1 as a final standard.
- RFC 9562 defines both UUIDv4 and UUIDv7. Orgmetra preserves the authoritative HRIS operational UUID contract, including UUIDv7, while leaf-owned change and actor correlation references use UUIDv4 to avoid silently redefining core identifier ownership.
28 changes: 28 additions & 0 deletions docs/traceability/position-reporting-change-review.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Position reporting-change review traceability

**Status:** active PR / proposed capability. Not protected-main truth until merged from one fully validated exact head.

## Current protected-parent adoption

Feature predecessor `adf055d79d188ba18d06ecf80dc1117858c987f4` was non-destructively reconciled with protected `develop@eb9757f8649aaad026a9865508d9aad50c1a7a4f` by ordinary two-parent adoption commit `2317c367aa200e2cd1636cc26dd96c8b01966804`. The resulting tree preserves the protected #161 repository-workflow consolidation and does not import mutable #94 source. Historical checks on the predecessor remain causal evidence only; the resulting successor must reacquire all applicable exact-head gates before Ready or merge.

Fresh Foundation execution on successor `c0975db9f976fda93696591ac04a9787cde4aef5` exposed a repository-workflow reconciliation RED before package tests: the feature tree had resurrected its package-local quality workflow with `runs-on: ubuntu-latest`, violating protected #161's exact `ubuntu-24.04` runner and two-local-workflow inventory contract. The repair keeps the leaf retired and moves its exact installed-wheel, hash-bound installation, pinned CPython 3.14.7 and 100% coverage contract into canonical one-job Foundation CI.

| Requirement | Design / implementation evidence | Executable evidence |
|---|---|---|
| Keep reporting authority attached to Position rather than Person | Packet carries subordinate/current-manager/proposed-manager `position_record:` references and no Person identifier | `test_builds_value_minimized_human_review_packet`, `test_operational_position_references_accept_uuid7` |
| Preserve authoritative identifier ownership | Tenant and Position references accept canonical non-sentinel operational UUIDs; leaf-owned change and actor references require canonical UUIDv4 | invalid trust-evidence matrix plus UUIDv7 interoperability regression |
| Keep review separate from mutation authority | Fixed `mutation_state=not_authorized_to_apply`, `decision_authority=human_review_only`, mandatory human review | `test_direct_construction_cannot_weaken_governance` |
| Require authoritative bitemporal scope before mutation | Fixed `requires_authoritative_resolution`; next action requires exact tenant, `effective_on`, current system-recorded cutoff, Position validity/staffability and current relationship resolution | `test_next_action_preserves_authoritative_bitemporal_and_audit_boundary` |
| Prevent obvious invalid reporting proposals | subordinate/current/proposed Position references must be pairwise different | `test_rejects_ambiguous_reporting_or_actor_relationships` |
| Require authoritative cycle/cardinality checks | next action explicitly rejects cycles and multiple visible solid-line managers before mutation | `test_next_action_preserves_authoritative_bitemporal_and_audit_boundary` |
| Separate requester and reviewer | identical actor references are rejected locally; next action still requires authoritative identity separation | ambiguous relationship regression and next-action regression |
| Minimize durable privacy surface | no Person identifier, worker value, compensation, rating or free-form reason; controlled reason vocabulary only | value-minimization regression and invalid reason matrix |
| Preserve business time vs system-recorded time | exact `effective_on` date is distinct from exact fixed-offset `recorded_at`, canonicalized to UTC | fixed-offset and noncanonical temporal regressions |
| Bind reviewed organizational evidence | Position-scope and organization-scope snapshots require lowercase SHA-256 digests | invalid digest matrix and deterministic canonical-evidence regression |
| Prevent checked-vs-emitted runtime forgery | exact built-in text/int/date/datetime primitives and creation-time canonical seal | hostile runtime-subclass regressions and post-construction tamper regression |
| Require immutable audit/outbox before mutation | next action routes only after authoritative resolution and requires immutable audit/outbox evidence | next-action regression |
| Exact 100% owned statement/branch coverage and installed artifact truth | canonical Foundation builds one exact wheel, hash-binds installation, uses pinned CPython 3.14.7 and executes the package suite under its unchanged 100% statement/branch threshold | `.github/workflows/foundation-ci.yml`; `test_repository_contract.py` |
| Governance-only edits still enter required validation | canonical Foundation triggers for every pull request to `develop`; the package regression keeps the retired leaf from returning and pins the installed-artifact step | `test_canonical_foundation_executes_installed_artifact_contract` |

The packet deliberately cannot prove that the current reporting edge exists, that a proposed manager is authorized or legally permissible, or that persistence succeeded. Those remain authoritative HRIS/runtime/policy evidence and must not be inferred from a packet digest.
6 changes: 3 additions & 3 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
"files": [
{
"path": ".github/workflows/foundation-ci.yml",
"sha256": "b6a4365936b66803a8112f034c77d53d33301a7a798ed4f68746a4f2d8b081d7",
"bytes": 6651,
"lines": 125
"sha256": "81ae584c9c3dd89d7e86011550d9afec439f17b46a1b21db2fc8104f9149aab3",
"bytes": 9199,
"lines": 148
},
{
"path": ".gitignore",
Expand Down
14 changes: 14 additions & 0 deletions packages/position-reporting-change-review/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Changelog

## Unreleased

### Added

- Governed pre-mutation review packet for one solid-line Position-to-Position reporting reassignment.
- Separate subordinate, current-manager and proposed-manager Position correlations with self-reporting and no-op change rejection.
- Business-effective date plus separately recorded system evidence time.
- Position-scope and organization-scope SHA-256 evidence binding, controlled reporting-change reasons, requester/reviewer separation and explicit evidence versioning.
- Fail-closed `requires_authoritative_resolution`, `not_authorized_to_apply` and `human_review_only` states.
- PII/worker-value/employment-decision minimization, redacted representation, exact runtime-type validation and post-construction canonical-evidence tamper detection.
- Exact installed-wheel quality execution with pinned CPython 3.14.7 and 100% owned statement/branch coverage.
- Retire the package-specific workflow after protected repository-workflow consolidation and preserve the same installed-artifact contract inside canonical one-job Foundation CI.
28 changes: 28 additions & 0 deletions packages/position-reporting-change-review/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Orgmetra Position Reporting Change Review

`orgmetra-position-reporting-change-review` is a transport-neutral, pre-mutation governance contract for reviewing a change to one solid-line Position-to-Position reporting relationship.

## Protected-main truth and scope

Protected `develop` keeps Job, Position and Assignment as separate HRIS concepts but does not yet ship an authoritative reporting-line mutation service. An active Position-reporting hierarchy PR adds read-only bitemporal relationship reconstruction; this package does not import it, depend on its branch, or treat active-PR behavior as protected-main truth.

The review packet binds an authoritative tenant, subordinate Position, current manager Position, proposed manager Position, requested business-effective date, exact Position/organization scope digests, controlled reason, requester, reviewer, evidence version and system-recorded time. It contains no Person identifier, worker value, compensation, performance rating, free-form reason or LLM decision.

## What happens next

A valid packet is **not permission to change HRIS data**. Before any reporting-line mutation, the host must re-resolve the three Position records and the current solid-line relationship in the exact tenant at `effective_on` and the current system-recorded cutoff; prove the Positions are valid and staffable; prove requester/reviewer authoritative identity separation; reject self-reporting, cycles and multiple visible solid-line managers; verify the reviewed evidence digests and reason; and only then invoke the future authoritative mutation boundary with immutable audit/outbox evidence.

The package performs no database write, no direct cross-service application-table SQL, no identity-provider mutation and no autonomous employment decision.

## Identifier and evidence rules

- `tenant_record_id` follows the protected HRIS canonical non-sentinel operational UUID contract, including UUIDv7.
- Position references use `position_record:<canonical operational UUID>` so the leaf package does not duplicate a UUIDv4-only rule over HRIS-owned records.
- The packet-owned `position_reporting_change:` reference and `actor:` review correlations require canonical UUIDv4.
- Position and organization scope snapshots are bound by lowercase SHA-256 digests rather than copied values.
- `effective_on` is business time. `recorded_at` is the system-recorded evidence instant and is canonicalized to UTC RFC 3339 text.
- `mutation_state=not_authorized_to_apply`, `scope_verification_state=requires_authoritative_resolution`, and `decision_authority=human_review_only` are fail-closed constants.

## Quality evidence

The dedicated workflow builds the exact wheel from the PR head, installs it through a SHA-256-bound requirement, runs the installed artifact on pinned CPython 3.14.7, requires exact 100% owned statement/branch coverage, and leaves the checkout clean. Repository-level tests require ADR, doctoring and traceability-only edits to trigger the same gate.
24 changes: 24 additions & 0 deletions packages/position-reporting-change-review/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[build-system]
requires = ["setuptools>=84"]
build-backend = "setuptools.build_meta"

[project]
name = "orgmetra-position-reporting-change-review"
version = "0.1.0"
description = "Governed Position reporting-change review evidence for Orgmetra."
requires-python = ">=3.14"

[project.optional-dependencies]
test = ["pytest>=8.3", "pytest-cov>=5.0"]

[tool.setuptools.packages.find]
where = ["src"]

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
"--cov=orgmetra_position_reporting_change_review",
"--cov-branch",
"--cov-report=term-missing",
"--cov-fail-under=100",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
"""Public API for governed Position reporting-change review evidence."""

from .review import (
PositionReportingChangeReviewPacket,
build_position_reporting_change_review_packet,
)

__all__ = [
"PositionReportingChangeReviewPacket",
"build_position_reporting_change_review_packet",
]
Loading
Loading