-
Notifications
You must be signed in to change notification settings - Fork 0
feat(talent): connect accepted offer evidence to confirmed-hire authority #108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
seonghobae
wants to merge
22
commits into
feat/candidate-offer-response-evidence
Choose a base branch
from
feat/offer-to-hire-close
base: feat/candidate-offer-response-evidence
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
d9775c3
test(talent): define offer-to-hire close contract
seonghobae 82ea57e
test(talent): run exact-head offer-to-hire close gate
seonghobae 92bd07d
feat(talent): govern accepted offer to confirmed hire
seonghobae 8e673ce
feat(talent): export offer-to-hire close boundary
seonghobae 47b6039
build(talent): declare candidate response dependency
seonghobae 9dfc1a0
test(talent): cover public offer-close packaging boundary
seonghobae 37f45b7
test(talent): harden offer-to-hire integrity regressions
seonghobae df75946
fix(talent): remove redundant response integrity branch
seonghobae 127db00
docs(talent): trace offer-to-hire close boundary
seonghobae a51daec
docs(talent): doctor offer-to-hire close references
seonghobae c733b05
docs(talent): record offer-to-hire close change
seonghobae 5cd23b6
docs(talent): explain accepted-offer hire close
seonghobae 6969e4d
test(talent): gate offer-close docs and changelog
seonghobae e8a2726
test(talent): require authorization before offer resolution
seonghobae 21e992d
fix(talent): authorize before candidate offer resolution
seonghobae 944e738
test(talent): include authorization-order regression
seonghobae 9494caf
docs(talent): trace pre-resolution authorization
seonghobae 9df5c8a
docs(talent): document pre-resolution authorization
seonghobae 766472a
docs(talent): record authorization-order hardening
seonghobae d15d20e
fix(talent): validate response envelope before pre-resolution authori…
seonghobae 5027c77
merge(candidate-offer-response): adapt offer-to-hire stack to repaire…
seonghobae d465d1c
ci(offer-to-hire): watch kernel dependency changes
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| name: Offer To Hire Close Quality | ||
|
|
||
| on: | ||
| pull_request: | ||
| paths: | ||
| - "services/people-api/pyproject.toml" | ||
| - "services/people-api/src/orgmetra_people_api/__init__.py" | ||
| - "services/people-api/src/orgmetra_people_api/offer_close.py" | ||
| - "services/people-api/src/orgmetra_people_api/hire.py" | ||
| - "services/people-api/src/orgmetra_people_api/auth.py" | ||
| - "services/people-api/src/orgmetra_people_api/authorization.py" | ||
| - "services/people-api/tests/test_offer_to_hire_*.py" | ||
| - "services/people-api/README.md" | ||
| - "services/people-api/CHANGELOG.md" | ||
| - "packages/candidate-offer-response/**" | ||
| - "packages/keyverse-adapter/**" | ||
| - "packages/hris-kernel/**" | ||
| - "docs/traceability/offer-to-hire-close.md" | ||
| - "docs/doctoring/offer-to-hire-close-references.md" | ||
| - ".github/requirements/foundation-test.txt" | ||
| - ".github/workflows/offer-to-hire-close-quality.yml" | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| concurrency: | ||
| group: offer-to-hire-close-quality-${{ github.event.pull_request.number || github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| contract: | ||
| name: Offer acceptance to confirmed-hire contract | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| steps: | ||
| - name: Checkout exact candidate | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| ref: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| persist-credentials: false | ||
| - name: Prove exact candidate checkout | ||
| env: | ||
| ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} | ||
| run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" | ||
| - name: Set up exact Python runtime | ||
| 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: Compile governed boundary | ||
| run: | | ||
| python -m compileall -q \ | ||
| services/people-api/src \ | ||
| packages/keyverse-adapter/src \ | ||
| packages/candidate-offer-response/src \ | ||
| packages/hris-kernel/src \ | ||
| services/people-api/tests/test_offer_to_hire_close.py \ | ||
| services/people-api/tests/test_offer_to_hire_authorization_order.py | ||
| - name: Test exact offer-to-hire boundary with 100% owned coverage | ||
| env: | ||
| PYTHONPATH: services/people-api/src:packages/keyverse-adapter/src:packages/candidate-offer-response/src:packages/hris-kernel/src | ||
| COVERAGE_FILE: /tmp/orgmetra-offer-to-hire-close.coverage | ||
| run: >- | ||
| python -m pytest | ||
| -o 'addopts=--cov=orgmetra_people_api.offer_close --cov-branch --cov-report=term-missing --cov-fail-under=100' | ||
| services/people-api/tests/test_offer_to_hire_close.py | ||
| services/people-api/tests/test_offer_to_hire_authorization_order.py | ||
| - name: Require public export and declared candidate-response dependency | ||
| env: | ||
| PYTHONPATH: services/people-api/src:packages/keyverse-adapter/src:packages/candidate-offer-response/src:packages/hris-kernel/src | ||
| run: | | ||
| python - <<'PY' | ||
| import orgmetra_people_api | ||
| from orgmetra_people_api import close_accepted_offer_to_hire | ||
|
|
||
| assert close_accepted_offer_to_hire is orgmetra_people_api.close_accepted_offer_to_hire | ||
| pyproject = open("services/people-api/pyproject.toml", encoding="utf-8").read() | ||
| assert '"orgmetra-candidate-offer-response==0.1.0"' in pyproject | ||
| PY | ||
| - name: Require buyer-readable governance documentation | ||
| run: | | ||
| grep -F 'CandidateOfferHireAuthority' services/people-api/README.md | ||
| grep -F 'not an autonomous or model-derived employment decision' docs/traceability/offer-to-hire-close.md | ||
| grep -F 'U.S. Equal Employment Opportunity Commission' docs/doctoring/offer-to-hire-close-references.md | ||
| grep -F 'close_accepted_offer_to_hire' services/people-api/CHANGELOG.md | ||
| - name: Require clean checkout | ||
| run: | | ||
| git diff --exit-code | ||
| test -z "$(git status --porcelain)" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| # Offer-to-hire close references | ||
|
|
||
| Reviewed 2026-08-24. These sources inform the governance principle that a candidate response and prior selection evidence remain evidence inputs to an accountable employer decision process; they do not turn candidate acknowledgement, an assessment score, or an automated signal into employment authority by themselves. | ||
|
|
||
| ## Primary / authoritative sources | ||
|
|
||
| U.S. Equal Employment Opportunity Commission. (2007, December 1). *Employment tests and selection procedures*. https://www.eeoc.gov/laws/guidance/employment-tests-and-selection-procedures | ||
|
|
||
| - The EEOC identifies employment tests and other selection procedures as subject to federal anti-discrimination law and directs employers to ensure that selection procedures are properly validated for the positions and purposes for which they are used. | ||
| - Orgmetra therefore preserves the existing accountable selection-decision authorization boundary rather than allowing an offer-response packet to bypass it. | ||
|
|
||
| U.S. Equal Employment Opportunity Commission. (n.d.). *Regulations and guidelines*. Retrieved August 24, 2026, from https://www.eeoc.gov/regulations-and-guidelines | ||
|
|
||
| - The current EEOC regulations index identifies 29 C.F.R. Part 1607 as the Uniform Guidelines on Employee Selection Procedures. | ||
| - This repository treats the Uniform Guidelines as a governing selection-procedure reference, not as a software certification claim. | ||
|
|
||
| Society for Industrial and Organizational Psychology. (2023, January 21). *Considerations and recommendations for the validation and use of AI-based assessments for employee selection*. https://www.siop.org/wp-content/uploads/legacy/SIOP%20Considerations%20and%20Recommendations%20for%20the%20Validation%20and%20Use%20of%20AI-Based%20Assessments%20for%20Employee%20Selection%20010323.pdf | ||
|
|
||
| - SIOP states that AI-based assessments used for hiring and promotion should meet the same scrutiny and standards applied to traditional employment tests and emphasizes documentation for verification and auditing. | ||
| - #108 does not introduce an AI decision path. The reference supports the broader Orgmetra rule that evidence provenance and accountable human/employer authority remain distinct from any evidence-generating mechanism. | ||
|
|
||
| ## Repository interpretation | ||
|
|
||
| The cited materials do not prescribe Orgmetra's exact API shape. The software contract is an engineering control derived from the product's high-impact-decision requirements: candidate acceptance is necessary evidence for closing an accepted offer, while the authoritative candidate/offer/selection mapping, purpose-bound authorization, and immutable HR mutation remain separate controlled boundaries. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| # Offer-to-hire close traceability | ||
|
|
||
| ## Status | ||
|
|
||
| - **Protected-main truth:** `develop@9e3e4847510e1e612b48474ba42b177b8ed824df` already contains the governed `accept_confirmed_hire(...)` path. It authorizes one immutable `selection_decision` with purpose-bound policy before an injected mutation port may materialize Person, Employment, candidate-to-worker conversion, audit, and outbox facts. | ||
| - **Parent active PR:** #80 owns `CandidateOfferResponsePacket`, a value-minimized candidate-originated `offer_accepted` / `offer_declined` evidence packet that is explicitly `not_authorized_to_hire`. | ||
| - **This active stacked PR:** #108 first requires the authenticated principal to be purpose-bound to the exact hire selection decision, then connects an intact `offer_accepted` packet to the existing confirmed-hire path only after an authoritative host re-resolves candidate identity, candidate profile, exact offer approval/terms provenance, response identity, and the immutable selection decision. | ||
| - **Not shipped:** #108 is not protected-main truth and remains dependency-constrained on #80. Its checks/reviews must not be transferred from #80; after #80 integrates, this lane must retarget to fresh `develop` and obtain fresh exact-head People/Foundation/SAST/Security/Recovery evidence. | ||
|
|
||
| ## Safety and authority contract | ||
|
|
||
| | Concern | Executable boundary | | ||
| |---|---| | ||
| | Authorization before sensitive resolution | `close_accepted_offer_to_hire(...)` purpose-authorizes the exact `selection_decision` and `candidate_worker_conversion` operation before invoking the candidate/offer authority resolver. Wrong-purpose, wrong-scope, or foreign-tenant callers therefore cannot use protected candidate/offer resolution as an oracle. | | ||
| | Candidate decline | With a valid hire authorization context, `offer_declined` stops before the authoritative resolver or hire mutation port. | | ||
| | Candidate response is not hire authority | The bridge accepts only canonical `CandidateOfferResponsePacket` evidence, then requires `CandidateOfferHireAuthority.verify_offer_acceptance(...)`; it never writes HR facts directly. | | ||
| | Tenant isolation | Candidate-response tenant must equal the `HireAcceptanceCommand` tenant, and the returned authority evidence must bind the same tenant. | | ||
| | Candidate linkage | The authority resolves the packet's opaque candidate-profile reference to the exact `candidate_profile_id` in the hire command. | | ||
| | Selection-decision linkage | The authority must bind the exact immutable `selection_decision_id` consumed by the protected confirmed-hire authorization path. | | ||
| | Offer provenance | Response SHA-256, offer-approval digest, offer-terms digest, and external candidate actor must exactly match the snapshotted candidate response. | | ||
| | Concurrent / post-construction response mutation | Candidate-response canonical evidence is verified before authority work and revalidated after it; a mutated packet fails closed before hire materialization. | | ||
| | Authority runtime integrity | `CandidateOfferHireVerification` is copied into an exact built-in/runtime-owned verification object and all UUID, digest, actor, and authority-reference fields are revalidated before use. | | ||
| | High-impact human/authorization boundary | The bridge delegates consequential mutation to existing `accept_confirmed_hire(...)`, which independently reauthorizes purpose, operation scope, authorized field set, authenticated principal, and exact selection-decision target immediately before persistence. | | ||
| | PII minimization | The bridge carries only correlation identifiers, evidence digests, candidate actor correlation, and the already-existing hire command. It does not duplicate offer compensation, candidate profile values, assessment scores, or free-form candidate text. | | ||
|
|
||
| ## Executable evidence | ||
|
|
||
| `services/people-api/tests/test_offer_to_hire_close.py` defines regressions for decline-before-resolution, valid accepted-offer delegation, tenant/candidate/selection mismatches, evidence digest/actor mismatch, response mutation before and during authority work, runtime-type forgery, malformed authority evidence, and post-construction authority-evidence rewriting. | ||
|
|
||
| `services/people-api/tests/test_offer_to_hire_authorization_order.py` independently proves that a denied purpose-bound request cannot invoke the protected candidate/offer authority resolver or hire persistence boundary. | ||
|
|
||
| `.github/workflows/offer-to-hire-close-quality.yml` is the dedicated exact-head gate for this slice. The current stacked PR must remain Draft whenever this gate or any applicable integration gate is absent, queued, pending, cancelled, skipped, neutral, failed, stale, or otherwise non-terminal. A stack-local GREEN result would still not authorize merge before #80 integrates and the descendant is revalidated against fresh protected `develop`. | ||
|
|
||
| ## Ownership | ||
|
|
||
| Orgmetra owns this bridge and the existing confirmed-hire application boundary. Keyverse remains the read-only identity owner through its published identity contract; #108 does not mutate Keyverse or query foreign application tables. Offer response remains candidate evidence, not an autonomous or model-derived employment decision. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # People API changelog | ||
|
|
||
| ## Unreleased | ||
|
|
||
| ### Added | ||
|
|
||
| - Add `close_accepted_offer_to_hire(...)` as a governed bridge from an intact candidate `offer_accepted` evidence packet to the existing authoritative confirmed-hire path. | ||
| - Add `CandidateOfferHireAuthority` and redacted `CandidateOfferHireVerification` contracts so candidate identity, candidate profile, exact offer provenance, and immutable selection decision are re-resolved before any hire materialization. | ||
| - Add fail-closed regressions for decline handling, tenant/candidate/selection mismatch, evidence mismatch, response tampering, authority-evidence runtime forgery, post-construction rewriting, and authorization ordering. | ||
|
|
||
| ### Security / governance | ||
|
|
||
| - Candidate offer response remains necessary but non-authorizing evidence; it cannot directly create Person, Employment, or candidate-to-worker facts. | ||
| - Require purpose-bound authorization for the exact `materialize_worker` selection decision before protected candidate/offer authority resolution, then independently reauthorize through existing `accept_confirmed_hire(...)` immediately before persistence. | ||
| - This change is stacked on candidate-offer-response PR #80 and is not protected-main truth until its parent integrates and this descendant is freshly revalidated against protected `develop`. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.