From 668975ea2c7ffc8a61f4f4edf9b74753e808f37e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:48:24 +0900 Subject: [PATCH 01/20] test(ci): pin explicit runner image contract --- tests/test_github_actions_runner_image.py | 46 +++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/test_github_actions_runner_image.py diff --git a/tests/test_github_actions_runner_image.py b/tests/test_github_actions_runner_image.py new file mode 100644 index 000000000..c54d23621 --- /dev/null +++ b/tests/test_github_actions_runner_image.py @@ -0,0 +1,46 @@ +"""Regression contract for deterministic GitHub-hosted runner image selection. + +Orgmetra uses an explicit supported Ubuntu image instead of the moving +``ubuntu-latest`` alias. This is an operability contract: the organization has +observed ``ubuntu-latest`` runs remain unassigned while explicit +``ubuntu-24.04`` canaries acquire GitHub-hosted runners. Queued evidence remains +non-passing; this test only prevents reintroducing the ambiguous selector. +""" + +from __future__ import annotations + +from pathlib import Path +import unittest + + +ROOT = Path(__file__).resolve().parents[1] +WORKFLOWS = ROOT / ".github" / "workflows" + + +class GitHubActionsRunnerImageContractTest(unittest.TestCase): + """Keep every repository-owned workflow on an explicit supported image.""" + + def test_all_repository_workflows_pin_ubuntu_24_04(self) -> None: + """Reject ``ubuntu-latest`` and require explicit Ubuntu 24.04 jobs.""" + workflow_paths = sorted(WORKFLOWS.glob("*.yml")) + self.assertTrue(workflow_paths, "Orgmetra must keep repository-owned workflows") + + violations: list[str] = [] + missing_explicit_image: list[str] = [] + for workflow_path in workflow_paths: + workflow = workflow_path.read_text(encoding="utf-8") + if "runs-on: ubuntu-latest" in workflow: + violations.append(workflow_path.name) + if "runs-on:" in workflow and "runs-on: ubuntu-24.04" not in workflow: + missing_explicit_image.append(workflow_path.name) + + self.assertEqual([], violations, f"ubuntu-latest remains in: {violations}") + self.assertEqual( + [], + missing_explicit_image, + f"explicit ubuntu-24.04 runner is missing from: {missing_explicit_image}", + ) + + +if __name__ == "__main__": # pragma: no cover - normal execution is via unittest discovery. + unittest.main() From 955f573872aae7e5ee3888df595f88558b02af5c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:49:15 +0900 Subject: [PATCH 02/20] ci: pin candidate evidence runner image --- .github/workflows/candidate-evidence-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/candidate-evidence-quality.yml b/.github/workflows/candidate-evidence-quality.yml index 45d02a7d1..2f63abc85 100644 --- a/.github/workflows/candidate-evidence-quality.yml +++ b/.github/workflows/candidate-evidence-quality.yml @@ -23,7 +23,7 @@ concurrency: jobs: unit: name: Candidate evidence contract and 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate From 3cf8a3d5a97c47af16b931fa0b8b7f783bcb5cea Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:49:35 +0900 Subject: [PATCH 03/20] ci: pin criterion runner image --- .github/workflows/criterion-temporal-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/criterion-temporal-quality.yml b/.github/workflows/criterion-temporal-quality.yml index af41ad310..8bfd4945c 100644 --- a/.github/workflows/criterion-temporal-quality.yml +++ b/.github/workflows/criterion-temporal-quality.yml @@ -22,7 +22,7 @@ concurrency: jobs: postgres: name: Criterion recorded-time and UTC boundaries - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 services: postgres: From f6a5c0dcc348a4e99fac7ec9a0ed7b468bbc2250 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:50:15 +0900 Subject: [PATCH 04/20] ci: pin foundation runners and execute regression --- .github/workflows/foundation-ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/foundation-ci.yml b/.github/workflows/foundation-ci.yml index 1da833955..8e6c7208f 100644 --- a/.github/workflows/foundation-ci.yml +++ b/.github/workflows/foundation-ci.yml @@ -24,7 +24,7 @@ concurrency: jobs: validate: name: Foundation validation - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate @@ -48,6 +48,8 @@ jobs: check-latest: false - name: Compile validation code run: python -m compileall -q tests + - name: Prove explicit GitHub-hosted runner image contract + run: python -m unittest tests.test_github_actions_runner_image - name: Validate foundation pack run: npm run validate - name: Prove Foundation CI dependency hygiene @@ -70,7 +72,7 @@ jobs: postgres_contract: name: PostgreSQL integrity contracts - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 strategy: fail-fast: false From 5b36e250eab1a14c91a755a25fd1c1dc54798892 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:50:47 +0900 Subject: [PATCH 05/20] ci: pin job-analysis runner images --- .github/workflows/job-analysis-api-quality.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/job-analysis-api-quality.yml b/.github/workflows/job-analysis-api-quality.yml index 1e944644c..b7edba6de 100644 --- a/.github/workflows/job-analysis-api-quality.yml +++ b/.github/workflows/job-analysis-api-quality.yml @@ -32,7 +32,7 @@ concurrency: jobs: unit: name: Job-analysis API contract and 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate @@ -67,7 +67,7 @@ jobs: postgres: name: Job-analysis PostgreSQL integration - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 12 services: postgres: From 73fd23e4a7fb969c060e330b82354ab89e3849a2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:51:06 +0900 Subject: [PATCH 06/20] ci: pin migration adapter runner image --- .github/workflows/migration-adapter-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/migration-adapter-quality.yml b/.github/workflows/migration-adapter-quality.yml index 9e8d5f26e..48568a4a2 100644 --- a/.github/workflows/migration-adapter-quality.yml +++ b/.github/workflows/migration-adapter-quality.yml @@ -23,7 +23,7 @@ concurrency: jobs: unit: name: Migration handoff contract and 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate From 8a25480a8f0e2e8a39713a2c4b8c159c0280d6ba Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:51:27 +0900 Subject: [PATCH 07/20] ci: pin naruon adapter runner image --- .github/workflows/naruon-adapter-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/naruon-adapter-quality.yml b/.github/workflows/naruon-adapter-quality.yml index 5ecab2ee0..b4908f8c6 100644 --- a/.github/workflows/naruon-adapter-quality.yml +++ b/.github/workflows/naruon-adapter-quality.yml @@ -22,7 +22,7 @@ concurrency: jobs: unit: name: Naruon calendar contract and 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate From ed57fa80b212e93820cdc4e0c131c64e6281321f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:51:48 +0900 Subject: [PATCH 08/20] ci: pin offer approval runner image --- .github/workflows/offer-approval-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/offer-approval-quality.yml b/.github/workflows/offer-approval-quality.yml index 1ecff719a..b1160f9a3 100644 --- a/.github/workflows/offer-approval-quality.yml +++ b/.github/workflows/offer-approval-quality.yml @@ -23,7 +23,7 @@ concurrency: jobs: unit: name: Offer approval contract and 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate From d5be73cfe734908f1601bec60185e341ec8e805b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:52:11 +0900 Subject: [PATCH 09/20] ci: pin people API runner image --- .github/workflows/people-api-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/people-api-quality.yml b/.github/workflows/people-api-quality.yml index aabaf54a7..c494c5403 100644 --- a/.github/workflows/people-api-quality.yml +++ b/.github/workflows/people-api-quality.yml @@ -24,7 +24,7 @@ concurrency: jobs: unit: name: People API contract and 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate From cd9ba293b9e29a646d3f8486acece46f5b784446 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:52:38 +0900 Subject: [PATCH 10/20] ci: pin recovery rehearsal runner image --- .github/workflows/recovery-rehearsal-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/recovery-rehearsal-quality.yml b/.github/workflows/recovery-rehearsal-quality.yml index d181f01fe..13b5422f1 100644 --- a/.github/workflows/recovery-rehearsal-quality.yml +++ b/.github/workflows/recovery-rehearsal-quality.yml @@ -19,7 +19,7 @@ concurrency: jobs: restore-rehearsal: name: PostgreSQL restore rehearsal - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 15 services: source_postgres: From db57312315f946e42971dec7bbb41faa6eb6f623 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:52:54 +0900 Subject: [PATCH 11/20] ci: pin requisition review runner image --- .github/workflows/requisition-review-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/requisition-review-quality.yml b/.github/workflows/requisition-review-quality.yml index 31dfc4a30..1a550386a 100644 --- a/.github/workflows/requisition-review-quality.yml +++ b/.github/workflows/requisition-review-quality.yml @@ -25,7 +25,7 @@ concurrency: jobs: unit: name: Requisition review contract and 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate From 71f873395cbc93888aba1a56e79db00899058dd1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:53:11 +0900 Subject: [PATCH 12/20] ci: pin selection review runner image --- .github/workflows/selection-review-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/selection-review-quality.yml b/.github/workflows/selection-review-quality.yml index c4d1b9c1c..f3b0c6416 100644 --- a/.github/workflows/selection-review-quality.yml +++ b/.github/workflows/selection-review-quality.yml @@ -25,7 +25,7 @@ concurrency: jobs: unit: name: Selection review contract and 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate From 25c8e82e112116326bb54cdbb9a6a736821a9158 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:53:28 +0900 Subject: [PATCH 13/20] ci: pin workforce intelligence runner image --- .github/workflows/workforce-intelligence-quality.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/workforce-intelligence-quality.yml b/.github/workflows/workforce-intelligence-quality.yml index e63f1125f..b7f5c15a8 100644 --- a/.github/workflows/workforce-intelligence-quality.yml +++ b/.github/workflows/workforce-intelligence-quality.yml @@ -20,7 +20,7 @@ concurrency: jobs: unit: name: Workforce composition and HRIS kernel 100% coverage - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 timeout-minutes: 10 steps: - name: Checkout exact candidate From cc37b7c46bd7400cf2020d5adb8b2727d463fdaf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Tue, 1 Sep 2026 23:56:58 +0900 Subject: [PATCH 14/20] fix(ci): reseal foundation manifest for runner pins --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 97f2bab14..71d7a3838 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":"ec9c0fdd26cd825977371290e9890cf48eaa0ddf0312c06e3c5350f9d22355ff","bytes":4513,"lines":125},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"770d700ddc9f531bda03b07cea7ccd37f6f7361ccf56d24e6a940092b0f4f11e","bytes":4157,"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}]} From 6accfd7322e4a46d73fad96f01ae9d53e9678966 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 00:16:28 +0900 Subject: [PATCH 15/20] fix(ci): reseal recovery manifest for runner pin --- recovery-manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recovery-manifest.json b/recovery-manifest.json index aee84ec66..ddc2f58ff 100644 --- a/recovery-manifest.json +++ b/recovery-manifest.json @@ -1 +1 @@ -{"package":"orgmetra-recovery-rehearsal","version":"0.1.0","files":[{"path":".github/workflows/recovery-rehearsal-quality.yml","sha256":"055e05887358977dc405f9a1bb289cdde1623221b8ec3bd731201b34dd105ac7","bytes":3536,"lines":97},{"path":"docs/traceability/restore-rehearsal.md","sha256":"e4cf63847d03ad890918234d36b338a5f7c0b5561b86ca8bfcfb7cca416eedd4","bytes":7209,"lines":42},{"path":"tests/recovery-rehearsal.test.mjs","sha256":"0102e526fcb5f1d8809b3ffd02aec32075bf1a6e28462432e122a49c0bc9d6e6","bytes":8695,"lines":140},{"path":".github/scripts/restore-rehearsal-postgres.sh","sha256":"7b2e468898d5cae9897dc0337da5ce4e229fe9d980d2961b648a558081fdf5fe","bytes":17307,"lines":412}]} +{"package":"orgmetra-recovery-rehearsal","version":"0.1.0","files":[{"path":".github/workflows/recovery-rehearsal-quality.yml","sha256":"2b756877d129e98d6453b33c24a0d165572d3576190a7119cee4a6a9b509774e","bytes":3535,"lines":97},{"path":"docs/traceability/restore-rehearsal.md","sha256":"e4cf63847d03ad890918234d36b338a5f7c0b5561b86ca8bfcfb7cca416eedd4","bytes":7209,"lines":42},{"path":"tests/recovery-rehearsal.test.mjs","sha256":"0102e526fcb5f1d8809b3ffd02aec32075bf1a6e28462432e122a49c0bc9d6e6","bytes":8695,"lines":140},{"path":".github/scripts/restore-rehearsal-postgres.sh","sha256":"7b2e468898d5cae9897dc0337da5ce4e229fe9d980d2961b648a558081fdf5fe","bytes":17307,"lines":412}]} From b10099f8da6ff0493a2842e389e4a2b7a4a9a06f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 00:53:34 +0900 Subject: [PATCH 16/20] chore(ci): reacquire current central workflow evidence From c417924d10500319385db66a3e92101e1a4b0ac7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 07:14:20 +0900 Subject: [PATCH 17/20] test(ci): enforce every runner selector exactly --- tests/test_github_actions_runner_image.py | 85 ++++++++++++++++++----- 1 file changed, 67 insertions(+), 18 deletions(-) diff --git a/tests/test_github_actions_runner_image.py b/tests/test_github_actions_runner_image.py index c54d23621..72d17495d 100644 --- a/tests/test_github_actions_runner_image.py +++ b/tests/test_github_actions_runner_image.py @@ -1,44 +1,93 @@ """Regression contract for deterministic GitHub-hosted runner image selection. -Orgmetra uses an explicit supported Ubuntu image instead of the moving -``ubuntu-latest`` alias. This is an operability contract: the organization has -observed ``ubuntu-latest`` runs remain unassigned while explicit -``ubuntu-24.04`` canaries acquire GitHub-hosted runners. Queued evidence remains -non-passing; this test only prevents reintroducing the ambiguous selector. +Orgmetra uses an explicit supported Ubuntu image instead of moving aliases, +other image versions, or expression-driven selectors. Queued evidence remains +non-passing; this test only protects the repository-owned runner contract. """ from __future__ import annotations from pathlib import Path +import re import unittest ROOT = Path(__file__).resolve().parents[1] WORKFLOWS = ROOT / ".github" / "workflows" +_RUNS_ON_PATTERN = re.compile(r"^\s*runs-on\s*:\s*(.*?)\s*(?:#.*)?$") +_EXPECTED_RUNNER = "ubuntu-24.04" + + +def _workflow_paths() -> list[Path]: + """Return every repository-owned YAML workflow regardless of extension.""" + return sorted({*WORKFLOWS.glob("*.yml"), *WORKFLOWS.glob("*.yaml")}) + + +def _runner_declarations(workflow: str) -> list[tuple[int, str]]: + """Return line-numbered scalar ``runs-on`` declarations without YAML comments.""" + declarations: list[tuple[int, str]] = [] + for line_number, line in enumerate(workflow.splitlines(), start=1): + match = _RUNS_ON_PATTERN.match(line) + if match is None: + continue + value = match.group(1).strip() + if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}: + value = value[1:-1] + declarations.append((line_number, value)) + return declarations class GitHubActionsRunnerImageContractTest(unittest.TestCase): - """Keep every repository-owned workflow on an explicit supported image.""" + """Keep every repository-owned runner declaration on one explicit image.""" - def test_all_repository_workflows_pin_ubuntu_24_04(self) -> None: - """Reject ``ubuntu-latest`` and require explicit Ubuntu 24.04 jobs.""" - workflow_paths = sorted(WORKFLOWS.glob("*.yml")) + def test_all_repository_workflow_runner_selectors_are_exact(self) -> None: + """Reject aliases, expressions, other versions, and missing runner declarations.""" + workflow_paths = _workflow_paths() self.assertTrue(workflow_paths, "Orgmetra must keep repository-owned workflows") + missing: list[str] = [] violations: list[str] = [] - missing_explicit_image: list[str] = [] for workflow_path in workflow_paths: - workflow = workflow_path.read_text(encoding="utf-8") - if "runs-on: ubuntu-latest" in workflow: - violations.append(workflow_path.name) - if "runs-on:" in workflow and "runs-on: ubuntu-24.04" not in workflow: - missing_explicit_image.append(workflow_path.name) + declarations = _runner_declarations(workflow_path.read_text(encoding="utf-8")) + if not declarations: + missing.append(workflow_path.name) + continue + for line_number, value in declarations: + if value != _EXPECTED_RUNNER: + violations.append(f"{workflow_path.name}:{line_number}={value!r}") - self.assertEqual([], violations, f"ubuntu-latest remains in: {violations}") + self.assertEqual([], missing, f"runs-on declaration is missing from: {missing}") self.assertEqual( [], - missing_explicit_image, - f"explicit ubuntu-24.04 runner is missing from: {missing_explicit_image}", + violations, + f"runner selectors must resolve exactly to {_EXPECTED_RUNNER}: {violations}", + ) + + def test_runner_parser_rejects_dynamic_and_noncanonical_values(self) -> None: + """Keep the validator sensitive to aliases, expressions, lists, and other images.""" + sample = "\n".join( + ( + "runs-on: ubuntu-latest", + "runs-on: ${{ matrix.runner }}", + "runs-on: ubuntu-22.04", + "runs-on: [self-hosted, linux]", + "runs-on: 'ubuntu-24.04'", + ) + ) + declarations = _runner_declarations(sample) + self.assertEqual( + [ + "ubuntu-latest", + "${{ matrix.runner }}", + "ubuntu-22.04", + "[self-hosted, linux]", + "ubuntu-24.04", + ], + [value for _, value in declarations], + ) + self.assertEqual( + 1, + sum(value == _EXPECTED_RUNNER for _, value in declarations), ) From 810764c97cfc5fb8e6def2bfa9cb451154fb3b3a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 07:24:48 +0900 Subject: [PATCH 18/20] test(ci): distinguish YAML comments in runner selectors --- tests/test_github_actions_runner_image.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_github_actions_runner_image.py b/tests/test_github_actions_runner_image.py index 72d17495d..79baedc23 100644 --- a/tests/test_github_actions_runner_image.py +++ b/tests/test_github_actions_runner_image.py @@ -90,6 +90,24 @@ def test_runner_parser_rejects_dynamic_and_noncanonical_values(self) -> None: sum(value == _EXPECTED_RUNNER for _, value in declarations), ) + def test_runner_parser_only_strips_yaml_comment_tokens(self) -> None: + """Do not mistake a hash inside a plain or quoted scalar for a YAML comment.""" + sample = "\n".join( + ( + "runs-on: ubuntu-24.04 # supported image", + "runs-on: ubuntu-24.04#not-a-comment", + "runs-on: 'ubuntu-24.04#not-a-comment'", + ) + ) + self.assertEqual( + [ + "ubuntu-24.04", + "ubuntu-24.04#not-a-comment", + "ubuntu-24.04#not-a-comment", + ], + [value for _, value in _runner_declarations(sample)], + ) + if __name__ == "__main__": # pragma: no cover - normal execution is via unittest discovery. unittest.main() From f795f6673c55ab2393faa0739e3763b7c9b7c85d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 07:28:59 +0900 Subject: [PATCH 19/20] fix(ci): parse runner YAML comments without truncating scalars --- tests/test_github_actions_runner_image.py | 30 +++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/tests/test_github_actions_runner_image.py b/tests/test_github_actions_runner_image.py index 79baedc23..979515941 100644 --- a/tests/test_github_actions_runner_image.py +++ b/tests/test_github_actions_runner_image.py @@ -14,7 +14,7 @@ ROOT = Path(__file__).resolve().parents[1] WORKFLOWS = ROOT / ".github" / "workflows" -_RUNS_ON_PATTERN = re.compile(r"^\s*runs-on\s*:\s*(.*?)\s*(?:#.*)?$") +_RUNS_ON_PATTERN = re.compile(r"^\s*runs-on\s*:\s*(.*?)\s*$") _EXPECTED_RUNNER = "ubuntu-24.04" @@ -23,6 +23,32 @@ def _workflow_paths() -> list[Path]: return sorted({*WORKFLOWS.glob("*.yml"), *WORKFLOWS.glob("*.yaml")}) +def _strip_yaml_comment(value: str) -> str: + """Strip only YAML comments, preserving hash characters inside scalar text.""" + quote: str | None = None + index = 0 + while index < len(value): + char = value[index] + if quote == "'": + if char == "'": + if index + 1 < len(value) and value[index + 1] == "'": + index += 2 + continue + quote = None + elif quote == '"': + if char == "\\" and index + 1 < len(value): + index += 2 + continue + if char == '"': + quote = None + elif char in {"'", '"'}: + quote = char + elif char == "#" and (index == 0 or value[index - 1].isspace()): + return value[:index].rstrip() + index += 1 + return value.strip() + + def _runner_declarations(workflow: str) -> list[tuple[int, str]]: """Return line-numbered scalar ``runs-on`` declarations without YAML comments.""" declarations: list[tuple[int, str]] = [] @@ -30,7 +56,7 @@ def _runner_declarations(workflow: str) -> list[tuple[int, str]]: match = _RUNS_ON_PATTERN.match(line) if match is None: continue - value = match.group(1).strip() + value = _strip_yaml_comment(match.group(1)) if len(value) >= 2 and value[0] == value[-1] and value[0] in {"'", '"'}: value = value[1:-1] declarations.append((line_number, value)) From 0cc583fb58175bbc0015b090b91ed4b489eec445 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 22:55:20 +0900 Subject: [PATCH 20/20] ci(actions): consolidate repository quality workflows Collapse duplicate repository-owned PR quality jobs into one exact-head Foundation CI job while retaining the path-scoped recovery rehearsal. Preserve all unit, service, and PostgreSQL gates with PR-only concurrency and dynamic database isolation. Signed-off-by: Seongho Bae --- .../workflows/candidate-evidence-quality.yml | 57 --- .../workflows/criterion-temporal-quality.yml | 58 --- .github/workflows/foundation-ci.yml | 144 +++--- .../workflows/job-analysis-api-quality.yml | 105 ---- .../workflows/migration-adapter-quality.yml | 57 --- .github/workflows/naruon-adapter-quality.yml | 56 --- .github/workflows/offer-approval-quality.yml | 57 --- .github/workflows/people-api-quality.yml | 58 --- .../workflows/recovery-rehearsal-quality.yml | 18 +- .../workflows/requisition-review-quality.yml | 59 --- .../workflows/selection-review-quality.yml | 59 --- .../workforce-intelligence-quality.yml | 54 -- CHANGELOG.md | 1 + .../0011-bitemporal-workforce-composition.md | 2 +- docs/adr/0012-governed-migration-handoff.md | 2 +- docs/traceability/naruon-calendar-intent.md | 2 +- docs/traceability/requisition-review.md | 2 +- docs/traceability/selection-review.md | 2 +- docs/traceability/workforce-composition.md | 2 +- manifest.json | 476 +++++++++++++++++- packages/requisition-review/CHANGELOG.md | 2 +- recovery-manifest.json | 2 +- scripts/foundation-contract-core.mjs | 1 - .../tests/test_workflow_contract.py | 20 +- .../tests/test_workflow_contract.py | 13 +- tests/foundation-contract.test.mjs | 5 +- .../test_foundation_ci_dependency_hygiene.sh | 23 +- tests/test_github_actions_runner_image.py | 65 +++ tests/validate_repository.py | 1 - 29 files changed, 673 insertions(+), 730 deletions(-) delete mode 100644 .github/workflows/candidate-evidence-quality.yml delete mode 100644 .github/workflows/criterion-temporal-quality.yml delete mode 100644 .github/workflows/job-analysis-api-quality.yml delete mode 100644 .github/workflows/migration-adapter-quality.yml delete mode 100644 .github/workflows/naruon-adapter-quality.yml delete mode 100644 .github/workflows/offer-approval-quality.yml delete mode 100644 .github/workflows/people-api-quality.yml delete mode 100644 .github/workflows/requisition-review-quality.yml delete mode 100644 .github/workflows/selection-review-quality.yml delete mode 100644 .github/workflows/workforce-intelligence-quality.yml diff --git a/.github/workflows/candidate-evidence-quality.yml b/.github/workflows/candidate-evidence-quality.yml deleted file mode 100644 index 2f63abc85..000000000 --- a/.github/workflows/candidate-evidence-quality.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Candidate Evidence Quality - -on: - pull_request: - branches: - - develop - paths: - - "packages/candidate-evidence/**" - - ".github/requirements/foundation-test.txt" - - ".github/workflows/candidate-evidence-quality.yml" - - "docs/adr/0025-governed-candidate-evidence-intake.md" - - "docs/doctoring/candidate-evidence-intake-references.md" - - "docs/traceability/candidate-evidence-intake.md" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: candidate-evidence-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: Candidate evidence contract and 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile candidate evidence package - run: python -m compileall -q packages/candidate-evidence/src packages/candidate-evidence/tests - - name: Test candidate evidence with exact statement and branch coverage - env: - PYTHONPATH: packages/candidate-evidence/src - COVERAGE_FILE: /tmp/orgmetra-candidate-evidence.coverage - run: python -m pytest -c packages/candidate-evidence/pyproject.toml packages/candidate-evidence/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/criterion-temporal-quality.yml b/.github/workflows/criterion-temporal-quality.yml deleted file mode 100644 index 8bfd4945c..000000000 --- a/.github/workflows/criterion-temporal-quality.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: Criterion Temporal Quality - -on: - pull_request: - branches: - - bootstrap - - develop - - main - paths: - - "database/migrations/0011_criterion_observation_scope.sql" - - "tests/test_criterion_observation_scope_postgres.sh" - - ".github/workflows/criterion-temporal-quality.yml" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: criterion-temporal-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - postgres: - name: Criterion recorded-time and UTC boundaries - runs-on: ubuntu-24.04 - timeout-minutes: 10 - services: - postgres: - image: postgres:16.14@sha256:33f923b05f64ca54ac4401c01126a6b92afe839a0aa0a52bc5aeb5cc958e5f20 - env: - POSTGRES_USER: orgmetra - POSTGRES_PASSWORD: orgmetra - POSTGRES_DB: orgmetra - ports: - - 5432:5432 - options: >- - --health-cmd "pg_isready -U orgmetra -d orgmetra" - --health-interval 5s - --health-timeout 5s - --health-retries 10 - env: - DATABASE_URL: postgresql://orgmetra:orgmetra@localhost:5432/orgmetra - 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: Prove recorded-time and UTC boundaries - run: bash tests/test_criterion_observation_scope_postgres.sh - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/foundation-ci.yml b/.github/workflows/foundation-ci.yml index 8e6c7208f..6b475d6f2 100644 --- a/.github/workflows/foundation-ci.yml +++ b/.github/workflows/foundation-ci.yml @@ -4,28 +4,25 @@ on: pull_request: branches: - develop - - bootstrap - - main - - feat/foundation-product-baseline push: branches: - - bootstrap - - main - - feat/audit-outbox-envelope + - develop workflow_dispatch: permissions: contents: read concurrency: - group: foundation-ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + group: foundation-ci-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: - validate: - name: Foundation validation + quality: + name: Repository quality runs-on: ubuntu-24.04 - timeout-minutes: 10 + timeout-minutes: 60 + env: + ORGMETRA_POSTGRES_IMAGE: postgres:16.14@sha256:33f923b05f64ca54ac4401c01126a6b92afe839a0aa0a52bc5aeb5cc958e5f20 steps: - name: Checkout exact candidate uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -46,22 +43,79 @@ jobs: with: node-version: "24" check-latest: false - - name: Compile validation code - run: python -m compileall -q tests + - name: Compile owned Python boundaries + run: >- + python -m compileall -q tests packages services - name: Prove explicit GitHub-hosted runner image contract run: python -m unittest tests.test_github_actions_runner_image - name: Validate foundation pack run: npm run validate - name: Prove Foundation CI dependency hygiene run: bash tests/test_foundation_ci_dependency_hygiene.sh - - name: Prove HRIS kernel - env: - PYTHONPATH: packages/hris-kernel/src:packages/keyverse-adapter/src + - 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 - python -m pytest packages/hris-kernel/tests - python -m pytest packages/keyverse-adapter/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 + PYTHONPATH=packages/hris-kernel/src COVERAGE_FILE=/tmp/orgmetra-hris-kernel.coverage python -m pytest -c packages/hris-kernel/pyproject.toml packages/hris-kernel/tests + PYTHONPATH=packages/keyverse-adapter/src COVERAGE_FILE=/tmp/orgmetra-keyverse-adapter.coverage python -m pytest -c packages/keyverse-adapter/pyproject.toml packages/keyverse-adapter/tests + PYTHONPATH=packages/migration-adapter/src COVERAGE_FILE=/tmp/orgmetra-migration-adapter.coverage python -m pytest -c packages/migration-adapter/pyproject.toml packages/migration-adapter/tests + PYTHONPATH=packages/naruon-adapter/src COVERAGE_FILE=/tmp/orgmetra-naruon-adapter.coverage python -m pytest -c packages/naruon-adapter/pyproject.toml packages/naruon-adapter/tests + PYTHONPATH=packages/offer-approval/src COVERAGE_FILE=/tmp/orgmetra-offer-approval.coverage python -m pytest -c packages/offer-approval/pyproject.toml packages/offer-approval/tests + PYTHONPATH=packages/requisition-review/src COVERAGE_FILE=/tmp/orgmetra-requisition-review.coverage python -m pytest -c packages/requisition-review/pyproject.toml packages/requisition-review/tests + PYTHONPATH=packages/selection-review/src COVERAGE_FILE=/tmp/orgmetra-selection-review.coverage python -m pytest -c packages/selection-review/pyproject.toml packages/selection-review/tests + PYTHONPATH=services/job-analysis-api/src:packages/hris-kernel/src:packages/keyverse-adapter/src COVERAGE_FILE=/tmp/orgmetra-job-analysis-api.coverage python -m pytest -c services/job-analysis-api/pyproject.toml services/job-analysis-api/tests + PYTHONPATH=services/people-api/src:packages/hris-kernel/src:packages/keyverse-adapter/src COVERAGE_FILE=/tmp/orgmetra-people-api.coverage python -m pytest -c services/people-api/pyproject.toml services/people-api/tests + - name: Run PostgreSQL contracts in isolated containers + env: + PGPASSWORD: orgmetra + run: | + contracts=( + test_bitemporal_postgres.sh + test_tenant_isolation_postgres.sh + test_evidence_sealing_postgres.sh + test_operational_uuid_postgres.sh + test_audit_outbox_postgres.sh + test_outbox_claim_postgres.sh + test_outbox_dead_letter_postgres.sh + test_audit_outbox_hardening_postgres.sh + test_candidate_worker_conversion_postgres.sh + test_validity_study_case_postgres.sh + test_criterion_observation_scope_postgres.sh + test_people_mutation_idempotency_postgres.sh + test_job_analysis_snapshot_postgres.sh + ) + for contract in "${contracts[@]}"; do + container_name="orgmetra-${GITHUB_RUN_ID}-${contract%.sh}" + docker run --detach --name "$container_name" \ + --env POSTGRES_USER=orgmetra \ + --env POSTGRES_PASSWORD=orgmetra \ + --env POSTGRES_DB=orgmetra \ + --publish 127.0.0.1::5432 \ + "$ORGMETRA_POSTGRES_IMAGE" + trap 'docker rm --force "$container_name" >/dev/null 2>&1 || true' EXIT + postgres_binding="$(docker port "$container_name" 5432/tcp)" + postgres_port="${postgres_binding##*:}" + database_url="postgresql://orgmetra:orgmetra@127.0.0.1:$postgres_port/orgmetra" + for attempt in {1..30}; do + if psql "$database_url" -Atqc 'SELECT 1' >/dev/null 2>&1; then + break + fi + if [[ "$attempt" -eq 30 ]]; then + docker logs "$container_name" + exit 1 + fi + sleep 1 + done + DATABASE_URL="$database_url" bash "tests/$contract" + if [[ "$contract" == "test_job_analysis_snapshot_postgres.sh" ]]; then + DATABASE_URL="$database_url" bash tests/test_job_analysis_snapshot_schema_hardening.sh + fi + docker rm --force "$container_name" >/dev/null + trap - EXIT + done - name: Print exact manifest repair data if: failure() run: python tests/validate_repository.py --print-manifest @@ -69,57 +123,3 @@ jobs: run: | git diff --exit-code test -z "$(git status --porcelain)" - - postgres_contract: - name: PostgreSQL integrity contracts - runs-on: ubuntu-24.04 - timeout-minutes: 10 - strategy: - fail-fast: false - matrix: - contract: - - test_bitemporal_postgres.sh - - test_tenant_isolation_postgres.sh - - test_evidence_sealing_postgres.sh - - test_operational_uuid_postgres.sh - - test_audit_outbox_postgres.sh - - test_outbox_claim_postgres.sh - - test_outbox_dead_letter_postgres.sh - - test_audit_outbox_hardening_postgres.sh - - test_candidate_worker_conversion_postgres.sh - - test_validity_study_case_postgres.sh - - test_criterion_observation_scope_postgres.sh - - test_people_mutation_idempotency_postgres.sh - - test_job_analysis_snapshot_postgres.sh - services: - postgres: - image: postgres:16.14@sha256:33f923b05f64ca54ac4401c01126a6b92afe839a0aa0a52bc5aeb5cc958e5f20 - env: - POSTGRES_USER: orgmetra - POSTGRES_PASSWORD: orgmetra - POSTGRES_DB: orgmetra - ports: - - 5432:5432 - options: >- - --health-cmd "pg_isready -U orgmetra -d orgmetra" - --health-interval 5s - --health-timeout 5s - --health-retries 10 - env: - DATABASE_URL: postgresql://orgmetra:orgmetra@localhost:5432/orgmetra - 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: Run PostgreSQL contract - run: bash "tests/${{ matrix.contract }}" - - name: Prove test is read-only - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/job-analysis-api-quality.yml b/.github/workflows/job-analysis-api-quality.yml deleted file mode 100644 index b7edba6de..000000000 --- a/.github/workflows/job-analysis-api-quality.yml +++ /dev/null @@ -1,105 +0,0 @@ -name: Job-Analysis API Quality - -on: - pull_request: - branches: - - develop - paths: - - "services/job-analysis-api/**" - - "packages/hris-kernel/**" - - "packages/keyverse-adapter/**" - - "database/migrations/0013_job_analysis_snapshot.sql" - - "tests/test_job_analysis_snapshot_postgres.sh" - - "tests/test_job_analysis_snapshot_schema_hardening.sh" - - "tests/validate_repository.py" - - "scripts/foundation-contract-core.mjs" - - "schemas/openapi.yaml" - - "manifest.json" - - "docs/adr/0007-governed-job-analysis-evidence.md" - - "docs/adr/0014-job-analysis-snapshot-persistence.md" - - ".github/requirements/foundation-test.txt" - - ".github/workflows/foundation-ci.yml" - - ".github/workflows/job-analysis-api-quality.yml" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: job-analysis-api-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: Job-analysis API contract and 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile job-analysis API boundary - run: python -m compileall -q services/job-analysis-api/src packages/hris-kernel/src packages/keyverse-adapter/src services/job-analysis-api/tests - - name: Test governed job-analysis contracts with exact statement and branch coverage - env: - PYTHONPATH: services/job-analysis-api/src:packages/hris-kernel/src:packages/keyverse-adapter/src - COVERAGE_FILE: /tmp/orgmetra-job-analysis-api.coverage - run: python -m pytest -c services/job-analysis-api/pyproject.toml services/job-analysis-api/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" - - postgres: - name: Job-analysis PostgreSQL integration - runs-on: ubuntu-24.04 - timeout-minutes: 12 - services: - postgres: - image: postgres:16.14@sha256:33f923b05f64ca54ac4401c01126a6b92afe839a0aa0a52bc5aeb5cc958e5f20 - env: - POSTGRES_USER: orgmetra - POSTGRES_PASSWORD: orgmetra - POSTGRES_DB: orgmetra - ports: - - 5432:5432 - options: >- - --health-cmd "pg_isready -U orgmetra -d orgmetra" - --health-interval 5s - --health-timeout 5s - --health-retries 10 - env: - DATABASE_URL: postgresql://orgmetra:orgmetra@localhost:5432/orgmetra - 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: Run persisted job-analysis PostgreSQL contract - run: | - bash tests/test_job_analysis_snapshot_postgres.sh - bash tests/test_job_analysis_snapshot_schema_hardening.sh - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/migration-adapter-quality.yml b/.github/workflows/migration-adapter-quality.yml deleted file mode 100644 index 48568a4a2..000000000 --- a/.github/workflows/migration-adapter-quality.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Migration Adapter Quality - -on: - pull_request: - branches: - - develop - paths: - - "packages/migration-adapter/**" - - ".github/requirements/foundation-test.txt" - - ".github/workflows/migration-adapter-quality.yml" - - "docs/adr/0012-governed-migration-handoff.md" - - "docs/doctoring/migration-handoff-references.md" - - "docs/traceability/migration-handoff.md" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: migration-adapter-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: Migration handoff contract and 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile migration adapter - run: python -m compileall -q packages/migration-adapter/src packages/migration-adapter/tests - - name: Test migration contract with exact statement and branch coverage - env: - PYTHONPATH: packages/migration-adapter/src - COVERAGE_FILE: /tmp/orgmetra-migration-adapter.coverage - run: python -m pytest -c packages/migration-adapter/pyproject.toml packages/migration-adapter/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/naruon-adapter-quality.yml b/.github/workflows/naruon-adapter-quality.yml deleted file mode 100644 index b4908f8c6..000000000 --- a/.github/workflows/naruon-adapter-quality.yml +++ /dev/null @@ -1,56 +0,0 @@ -name: Naruon Adapter Quality - -on: - pull_request: - branches: - - bootstrap - - develop - - main - paths: - - "packages/naruon-adapter/**" - - ".github/requirements/foundation-test.txt" - - ".github/workflows/naruon-adapter-quality.yml" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: naruon-adapter-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: Naruon calendar contract and 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile Naruon adapter boundary - run: python -m compileall -q packages/naruon-adapter/src packages/naruon-adapter/tests - - name: Test Naruon calendar contract with exact statement and branch coverage - env: - PYTHONPATH: packages/naruon-adapter/src - COVERAGE_FILE: /tmp/orgmetra-naruon-adapter.coverage - run: python -m pytest -c packages/naruon-adapter/pyproject.toml packages/naruon-adapter/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/offer-approval-quality.yml b/.github/workflows/offer-approval-quality.yml deleted file mode 100644 index b1160f9a3..000000000 --- a/.github/workflows/offer-approval-quality.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: Offer Approval Quality - -on: - pull_request: - branches: - - develop - paths: - - "packages/offer-approval/**" - - ".github/requirements/foundation-test.txt" - - ".github/workflows/offer-approval-quality.yml" - - "docs/adr/0017-governed-offer-approval.md" - - "docs/doctoring/offer-approval-references.md" - - "docs/traceability/offer-approval.md" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: offer-approval-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: Offer approval contract and 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile offer approval package - run: python -m compileall -q packages/offer-approval/src packages/offer-approval/tests - - name: Test offer approval with exact statement and branch coverage - env: - PYTHONPATH: packages/offer-approval/src - COVERAGE_FILE: /tmp/orgmetra-offer-approval.coverage - run: python -m pytest -c packages/offer-approval/pyproject.toml packages/offer-approval/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/people-api-quality.yml b/.github/workflows/people-api-quality.yml deleted file mode 100644 index c494c5403..000000000 --- a/.github/workflows/people-api-quality.yml +++ /dev/null @@ -1,58 +0,0 @@ -name: People API Quality - -on: - pull_request: - branches: - - bootstrap - - develop - - main - paths: - - "services/people-api/**" - - "packages/hris-kernel/**" - - "packages/keyverse-adapter/**" - - ".github/requirements/foundation-test.txt" - - ".github/workflows/people-api-quality.yml" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: people-api-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: People API contract and 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile People API boundary - run: python -m compileall -q services/people-api/src packages/hris-kernel/src packages/keyverse-adapter/src services/people-api/tests - - name: Test governed People contracts with exact statement and branch coverage - env: - PYTHONPATH: services/people-api/src:packages/hris-kernel/src:packages/keyverse-adapter/src - COVERAGE_FILE: /tmp/orgmetra-people-api.coverage - run: python -m pytest -c services/people-api/pyproject.toml services/people-api/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/recovery-rehearsal-quality.yml b/.github/workflows/recovery-rehearsal-quality.yml index 13b5422f1..ea0f41ad0 100644 --- a/.github/workflows/recovery-rehearsal-quality.yml +++ b/.github/workflows/recovery-rehearsal-quality.yml @@ -4,17 +4,31 @@ on: pull_request: branches: - develop + paths: + - ".github/scripts/restore-rehearsal-postgres.sh" + - ".github/workflows/recovery-rehearsal-quality.yml" + - "database/migrations/**" + - "docs/traceability/restore-rehearsal.md" + - "recovery-manifest.json" + - "tests/recovery-rehearsal.test.mjs" push: branches: - develop + paths: + - ".github/scripts/restore-rehearsal-postgres.sh" + - ".github/workflows/recovery-rehearsal-quality.yml" + - "database/migrations/**" + - "docs/traceability/restore-rehearsal.md" + - "recovery-manifest.json" + - "tests/recovery-rehearsal.test.mjs" workflow_dispatch: permissions: contents: read concurrency: - group: recovery-rehearsal-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + group: recovery-rehearsal-quality-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} jobs: restore-rehearsal: diff --git a/.github/workflows/requisition-review-quality.yml b/.github/workflows/requisition-review-quality.yml deleted file mode 100644 index 1a550386a..000000000 --- a/.github/workflows/requisition-review-quality.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Requisition Review Quality - -on: - pull_request: - branches: - - develop - paths: - - "packages/requisition-review/**" - - ".github/requirements/foundation-test.txt" - - ".github/workflows/requisition-review-quality.yml" - - "docs/adr/0013-governed-requisition-review-packet.md" - - "docs/doctoring/requisition-review-references.md" - - "docs/traceability/requisition-review.md" - - "docs/TRACEABILITY.md" - - "CHANGELOG.md" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: requisition-review-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: Requisition review contract and 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile requisition review package - run: python -m compileall -q packages/requisition-review/src packages/requisition-review/tests - - name: Test requisition review contract with exact statement and branch coverage - env: - PYTHONPATH: packages/requisition-review/src - COVERAGE_FILE: /tmp/orgmetra-requisition-review.coverage - run: python -m pytest -c packages/requisition-review/pyproject.toml packages/requisition-review/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/selection-review-quality.yml b/.github/workflows/selection-review-quality.yml deleted file mode 100644 index f3b0c6416..000000000 --- a/.github/workflows/selection-review-quality.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Selection Review Quality - -on: - pull_request: - branches: - - develop - paths: - - "packages/selection-review/**" - - ".github/requirements/foundation-test.txt" - - ".github/workflows/selection-review-quality.yml" - - "docs/adr/0001-orgmetra-authoritative-hris-record.md" - - "docs/doctoring/selection-review-references.md" - - "docs/traceability/selection-review.md" - - "docs/TRACEABILITY.md" - - "CHANGELOG.md" - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: selection-review-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: Selection review contract and 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: "3.14" - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile selection review package - run: python -m compileall -q packages/selection-review/src packages/selection-review/tests - - name: Test selection review contract with exact statement and branch coverage - env: - PYTHONPATH: packages/selection-review/src - COVERAGE_FILE: /tmp/orgmetra-selection-review.coverage - run: python -m pytest -c packages/selection-review/pyproject.toml packages/selection-review/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/.github/workflows/workforce-intelligence-quality.yml b/.github/workflows/workforce-intelligence-quality.yml deleted file mode 100644 index b7f5c15a8..000000000 --- a/.github/workflows/workforce-intelligence-quality.yml +++ /dev/null @@ -1,54 +0,0 @@ -name: Workforce Intelligence Quality - -on: - pull_request: - branches: - - develop - paths: - - '.github/workflows/workforce-intelligence-quality.yml' - - '.github/requirements/foundation-test.txt' - - 'packages/hris-kernel/**' - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: workforce-intelligence-quality-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - unit: - name: Workforce composition and HRIS kernel 100% coverage - runs-on: ubuntu-24.04 - timeout-minutes: 10 - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout - env: - ORGMETRA_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: test "$(git rev-parse HEAD)" = "$ORGMETRA_EXPECTED_HEAD_SHA" - - name: Set up Python - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 - with: - python-version: '3.14' - check-latest: false - - name: Install reviewed test toolchain - run: | - python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt - python -m pip check - - name: Compile HRIS workforce boundary - run: python -m compileall -q packages/hris-kernel/src packages/hris-kernel/tests - - name: Test complete HRIS kernel with exact statement and branch coverage - env: - PYTHONPATH: packages/hris-kernel/src - COVERAGE_FILE: /tmp/orgmetra-workforce.coverage - run: python -m pytest -c packages/hris-kernel/pyproject.toml packages/hris-kernel/tests - - name: Require clean checkout - run: | - git diff --exit-code - test -z "$(git status --porcelain)" diff --git a/CHANGELOG.md b/CHANGELOG.md index 99f4752d7..16454da3d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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. diff --git a/docs/adr/0011-bitemporal-workforce-composition.md b/docs/adr/0011-bitemporal-workforce-composition.md index 7e9302870..11f137ee4 100644 --- a/docs/adr/0011-bitemporal-workforce-composition.md +++ b/docs/adr/0011-bitemporal-workforce-composition.md @@ -46,7 +46,7 @@ Orgmetra will expose a pure `WorkforceCompositionSnapshot` derived from authorit ## Verification -`packages/hris-kernel/tests/test_workforce_composition.py`, `packages/hris-kernel/tests/test_workforce_composition_boundaries.py`, and `packages/hris-kernel/tests/test_workforce_position_capacity.py` require tenant isolation, concurrent-employment person deduplication, active/leave composition, terminated exclusion, future-effective and late-recorded exclusion, FTE and unassigned-person reporting, deterministic canonical evidence, historical recorded-time reconstruction, duplicate-version rejection, overlapping-exclusive-employment rejection, position-seat over-allocation rejection, assignment-person integrity, per-employment allocation-integrity reuse, and timezone-aware knowledge cutoffs. `.github/workflows/workforce-intelligence-quality.yml` checks out the exact candidate SHA and runs the complete HRIS kernel with the package's 100% statement and branch coverage threshold. +`packages/hris-kernel/tests/test_workforce_composition.py`, `packages/hris-kernel/tests/test_workforce_composition_boundaries.py`, and `packages/hris-kernel/tests/test_workforce_position_capacity.py` require tenant isolation, concurrent-employment person deduplication, active/leave composition, terminated exclusion, future-effective and late-recorded exclusion, FTE and unassigned-person reporting, deterministic canonical evidence, historical recorded-time reconstruction, duplicate-version rejection, overlapping-exclusive-employment rejection, position-seat over-allocation rejection, assignment-person integrity, per-employment allocation-integrity reuse, and timezone-aware knowledge cutoffs. `.github/workflows/foundation-ci.yml` checks out the exact candidate SHA and runs the complete HRIS kernel with the package's 100% statement and branch coverage threshold. ## References diff --git a/docs/adr/0012-governed-migration-handoff.md b/docs/adr/0012-governed-migration-handoff.md index ec9ab40f0..90f04d6bc 100644 --- a/docs/adr/0012-governed-migration-handoff.md +++ b/docs/adr/0012-governed-migration-handoff.md @@ -56,4 +56,4 @@ This slice does not authenticate an operator, authorize access to the underlying `packages/migration-adapter/tests/test_handoff.py` requires exact 100% owned statement and branch coverage. It covers deterministic canonicalization, exact SHA-256 derivation from canonical JSON, all supported HRIS object families, malformed or reserved tenant IDs, malformed governance references/codes, non-boolean human confirmation, digest/proposal errors, bounded-record enforcement, duplicate/unsupported targets, dependency-revision drift, direct-constructor invariant bypass attempts, immutability, and safe failure messages. -`.github/workflows/migration-adapter-quality.yml` checks out the exact candidate SHA, installs the repository's reviewed hashed Python test toolchain, compiles the package, runs the full package test suite with 100% statement/branch thresholds, and requires a clean checkout. +`.github/workflows/foundation-ci.yml` checks out the exact candidate SHA, installs the repository's reviewed hashed Python test toolchain once, compiles the package, runs the full package test suite with 100% statement/branch thresholds, and requires a clean checkout. diff --git a/docs/traceability/naruon-calendar-intent.md b/docs/traceability/naruon-calendar-intent.md index 790447641..58fd889c3 100644 --- a/docs/traceability/naruon-calendar-intent.md +++ b/docs/traceability/naruon-calendar-intent.md @@ -11,7 +11,7 @@ Active-PR only. This evidence does not describe protected-`develop` product trut | Do not leak HR identifiers or free-form PII into calendar summary text | ADR 0010 | fixed `_ACTION_SUMMARIES`; audit context is kept separate from request body | `test_builds_confirmed_intent_without_pii_or_provider_execution` | | Do not mutate a provider while the current foreign create-execution contract is defective | Naruon owner handoff in `ContextualWisdomLab/naruon#1350`; ADR 0010 | request body always sets `execute_provider=false`; response validator rejects any reported provider execution or execution metadata | response-drift parameter matrix | | Fail closed on Naruon contract/provenance drift | ADR 0010 | `validate_calendar_intent_response` requires exact response/provenance keys, CalDAV/customer-owned mode, create semantics, target consistency, intent-only status and bounded metadata | response-drift parameter matrix plus auto-selected-target regression | -| Keep local adapter evidence exact and independently reproducible | Orgmetra quality rules | `.github/workflows/naruon-adapter-quality.yml` checks exact candidate SHA, reviewed hashed test dependencies, compilation, 100% statement/branch coverage and clean checkout | hosted `Naruon Adapter Quality` run on each exact PR head plus local RED/GREEN development evidence | +| Keep local adapter evidence exact and independently reproducible | Orgmetra quality rules | `.github/workflows/foundation-ci.yml` checks exact candidate SHA, reviewed hashed test dependencies, compilation, 100% statement/branch coverage and clean checkout | hosted exact-head Foundation CI run plus local RED/GREEN development evidence | | Use current authoritative calendar/HTTP references without duplicating provider protocol logic | ADR 0010 | no CalDAV/iCalendar implementation in Orgmetra | `docs/doctoring/naruon-calendar-intent-references.md` | ## Foreign-owner revalidation gate diff --git a/docs/traceability/requisition-review.md b/docs/traceability/requisition-review.md index ca9bfe0ec..add4f20ba 100644 --- a/docs/traceability/requisition-review.md +++ b/docs/traceability/requisition-review.md @@ -20,7 +20,7 @@ | Bound opening cardinality | `requested_opening_count` | bool/non-integer/zero/>100 rejection and exact-position one-seat invariant | | Produce stable immutable correlation evidence | canonical JSON plus SHA-256 | deterministic serialization and independent SHA-256 recomputation regression | | Avoid host-time ambiguity | timezone-aware `generated_at`, canonical UTC rendering | naive/unknown-offset rejection, non-UTC-to-UTC canonicalization, and fractional-second preservation regressions | -| Meet owned production coverage gate | `orgmetra_requisition_review` | Requisition Review Quality requires exact 100% statement and branch coverage | +| Meet owned production coverage gate | `orgmetra_requisition_review` | Foundation CI requires exact 100% statement and branch coverage | ## Authority boundary diff --git a/docs/traceability/selection-review.md b/docs/traceability/selection-review.md index 1b5e40601..077ad45ca 100644 --- a/docs/traceability/selection-review.md +++ b/docs/traceability/selection-review.md @@ -19,7 +19,7 @@ | Preserve tenant and accountable reviewer context | canonical operational tenant UUID plus UUID-backed `actor:` reviewer reference, fixed purpose, reviewed reason, and canonical evidence version | reserved/noncanonical UUID, malformed reference, closed-reason, and bounded evidence-version regressions | | Produce stable immutable correlation evidence | canonical JSON plus SHA-256 | deterministic JSON and independent SHA-256 recomputation regression | | Avoid host-time ambiguity | timezone-aware `generated_at`, canonical UTC rendering | naive/unknown-offset rejection and non-UTC-to-UTC canonicalization regression | -| Meet owned production coverage gate | `orgmetra_selection_review` | Selection Review Quality requires exact 100% statement and branch coverage | +| Meet owned production coverage gate | `orgmetra_selection_review` | Foundation CI requires exact 100% statement and branch coverage | ## Authority boundary diff --git a/docs/traceability/workforce-composition.md b/docs/traceability/workforce-composition.md index c33c5ca0d..f02e4b8ef 100644 --- a/docs/traceability/workforce-composition.md +++ b/docs/traceability/workforce-composition.md @@ -17,4 +17,4 @@ Active-PR only. This evidence does not describe protected-`develop` product trut | Make aggregate evidence reproducible | ADR 0011 | sorted status tuples, deterministic JSON encoding and SHA-256 over exact UTF-8 bytes | reversed-input fixture requires identical canonical JSON and digest; empty-workforce fixture requires stable empty status evidence | | Keep workforce intelligence descriptive | ADR 0011 | module contains no recommendation, decision, protected-attribute inference or persistence API | public package boundary and code review; high-impact actions remain outside this slice | | Ground scope in current authoritative standards without claiming certification | ISO 30414:2025 public catalogue metadata; ADR 0011 | no proprietary ISO metric text is embedded in production code | `docs/doctoring/workforce-composition-references.md` | -| Keep exact owned coverage reproducible | Orgmetra quality policy | `.github/workflows/workforce-intelligence-quality.yml` checks exact candidate SHA and runs the complete HRIS kernel | hosted exact-head workflow with package 100% statement/branch threshold | +| Keep exact owned coverage reproducible | Orgmetra quality policy | `.github/workflows/foundation-ci.yml` checks exact candidate SHA and runs the complete HRIS kernel | hosted exact-head workflow with package 100% statement/branch threshold | diff --git a/manifest.json b/manifest.json index 71d7a3838..f7b6cf55e 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":"ec9c0fdd26cd825977371290e9890cf48eaa0ddf0312c06e3c5350f9d22355ff","bytes":4513,"lines":125},{"path":".github/workflows/job-analysis-api-quality.yml","sha256":"770d700ddc9f531bda03b07cea7ccd37f6f7361ccf56d24e6a940092b0f4f11e","bytes":4157,"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": "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": "f2d2e0b488c0440533effa821808f2f17e37d92f8fb586174c2fdb594f760ca5", + "bytes": 17539, + "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": "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 + } + ] +} diff --git a/packages/requisition-review/CHANGELOG.md b/packages/requisition-review/CHANGELOG.md index 8143538ca..d6e99feb8 100644 --- a/packages/requisition-review/CHANGELOG.md +++ b/packages/requisition-review/CHANGELOG.md @@ -8,7 +8,7 @@ - Separate Job and optional Position references, with an exact Position restricted to one opening. - Versioned job-requirements and headcount-authorization references without copying source-system payloads. - Deterministic canonical JSON and SHA-256 correlation evidence. -- Exact 100% owned production statement and branch coverage requirement through Requisition Review Quality. +- Exact 100% owned production statement and branch coverage requirement through Foundation CI. ### Security and privacy diff --git a/recovery-manifest.json b/recovery-manifest.json index ddc2f58ff..00deb35ad 100644 --- a/recovery-manifest.json +++ b/recovery-manifest.json @@ -1 +1 @@ -{"package":"orgmetra-recovery-rehearsal","version":"0.1.0","files":[{"path":".github/workflows/recovery-rehearsal-quality.yml","sha256":"2b756877d129e98d6453b33c24a0d165572d3576190a7119cee4a6a9b509774e","bytes":3535,"lines":97},{"path":"docs/traceability/restore-rehearsal.md","sha256":"e4cf63847d03ad890918234d36b338a5f7c0b5561b86ca8bfcfb7cca416eedd4","bytes":7209,"lines":42},{"path":"tests/recovery-rehearsal.test.mjs","sha256":"0102e526fcb5f1d8809b3ffd02aec32075bf1a6e28462432e122a49c0bc9d6e6","bytes":8695,"lines":140},{"path":".github/scripts/restore-rehearsal-postgres.sh","sha256":"7b2e468898d5cae9897dc0337da5ce4e229fe9d980d2961b648a558081fdf5fe","bytes":17307,"lines":412}]} +{"package":"orgmetra-recovery-rehearsal","version":"0.1.0","files":[{"path":".github/workflows/recovery-rehearsal-quality.yml","sha256":"b2fe78ca19946aa1082d1a756fd277766908b49153d7cc8fc7184dceebdca078","bytes":4156,"lines":111},{"path":"docs/traceability/restore-rehearsal.md","sha256":"e4cf63847d03ad890918234d36b338a5f7c0b5561b86ca8bfcfb7cca416eedd4","bytes":7209,"lines":42},{"path":"tests/recovery-rehearsal.test.mjs","sha256":"0102e526fcb5f1d8809b3ffd02aec32075bf1a6e28462432e122a49c0bc9d6e6","bytes":8695,"lines":140},{"path":".github/scripts/restore-rehearsal-postgres.sh","sha256":"7b2e468898d5cae9897dc0337da5ce4e229fe9d980d2961b648a558081fdf5fe","bytes":17307,"lines":412}]} diff --git a/scripts/foundation-contract-core.mjs b/scripts/foundation-contract-core.mjs index 1e9fb267c..4aacefb3c 100644 --- a/scripts/foundation-contract-core.mjs +++ b/scripts/foundation-contract-core.mjs @@ -21,7 +21,6 @@ export const REQUIRED_FILES = Object.freeze([ 'manifest.json', 'package.json', '.github/workflows/foundation-ci.yml', - '.github/workflows/job-analysis-api-quality.yml', 'docs/PRD.md', 'docs/TRD.md', 'docs/USER_STORIES.md', diff --git a/services/job-analysis-api/tests/test_workflow_contract.py b/services/job-analysis-api/tests/test_workflow_contract.py index 441ca21f9..ad75a4206 100644 --- a/services/job-analysis-api/tests/test_workflow_contract.py +++ b/services/job-analysis-api/tests/test_workflow_contract.py @@ -8,19 +8,19 @@ def _workflow(path: str) -> str: return Path(path).read_text(encoding="utf-8") -def test_job_analysis_api_quality_runs_on_current_default_branch_pull_requests() -> None: - """Keep service coverage evidence alive when Orgmetra's default branch changes.""" - assert " - develop\n" in _workflow(".github/workflows/job-analysis-api-quality.yml") - - -def test_job_analysis_quality_reruns_when_foundation_contract_changes() -> None: - """Revalidate the service when its asserted foundation workflow changes.""" - workflow = _workflow(".github/workflows/job-analysis-api-quality.yml") - assert ' - ".github/workflows/foundation-ci.yml"\n' in workflow +def test_foundation_ci_runs_job_analysis_on_default_branch_pull_requests() -> None: + """Keep Job Analysis coverage in the single repository quality workflow.""" + workflow = _workflow(".github/workflows/foundation-ci.yml") + assert " - develop\n" in workflow + assert "services/job-analysis-api/pyproject.toml services/job-analysis-api/tests" in workflow def test_foundation_ci_includes_job_analysis_postgres_contract() -> None: - """Keep the snapshot persistence contract in the PostgreSQL integrity matrix.""" + """Keep snapshot persistence in the isolated PostgreSQL contract sequence.""" workflow = _workflow(".github/workflows/foundation-ci.yml") assert "test_job_analysis_snapshot_postgres.sh" in workflow + assert "test_job_analysis_snapshot_schema_hardening.sh" in workflow + assert workflow.index('DATABASE_URL="$database_url" bash "tests/$contract"') < workflow.index( + 'DATABASE_URL="$database_url" bash tests/test_job_analysis_snapshot_schema_hardening.sh' + ) assert " - develop\n" in workflow diff --git a/services/people-api/tests/test_workflow_contract.py b/services/people-api/tests/test_workflow_contract.py index b456df1e8..00b47f251 100644 --- a/services/people-api/tests/test_workflow_contract.py +++ b/services/people-api/tests/test_workflow_contract.py @@ -8,11 +8,8 @@ def _workflow(path: str) -> str: return Path(path).read_text(encoding="utf-8") -def test_people_api_quality_runs_on_current_default_branch_pull_requests() -> None: - """Keep service coverage evidence alive when Orgmetra's default branch changes.""" - assert " - develop\n" in _workflow(".github/workflows/people-api-quality.yml") - - -def test_foundation_ci_runs_on_current_default_branch_pull_requests() -> None: - """Keep repository integrity evidence alive on the current integration branch.""" - assert " - develop\n" in _workflow(".github/workflows/foundation-ci.yml") +def test_foundation_ci_runs_people_api_on_default_branch_pull_requests() -> None: + """Keep People API coverage in the single repository quality workflow.""" + workflow = _workflow(".github/workflows/foundation-ci.yml") + assert " - develop\n" in workflow + assert "services/people-api/pyproject.toml services/people-api/tests" in workflow diff --git a/tests/foundation-contract.test.mjs b/tests/foundation-contract.test.mjs index 72b18466f..c2f8f7589 100644 --- a/tests/foundation-contract.test.mjs +++ b/tests/foundation-contract.test.mjs @@ -112,9 +112,10 @@ test('PostgreSQL CI service image is pinned to the approved immutable PostgreSQL ); assert.match( workflow, - /image: postgres:16\.14@sha256:33f923b05f64ca54ac4401c01126a6b92afe839a0aa0a52bc5aeb5cc958e5f20/ + /ORGMETRA_POSTGRES_IMAGE: postgres:16\.14@sha256:33f923b05f64ca54ac4401c01126a6b92afe839a0aa0a52bc5aeb5cc958e5f20/ ); - assert.doesNotMatch(workflow, /^\s*image:\s*postgres:16\s*$/m); + assert.match(workflow, /docker run[\s\S]*"\$ORGMETRA_POSTGRES_IMAGE"/); + assert.doesNotMatch(workflow, /postgres:16(?:\s|$)/m); }); test('Python and Node require the identical foundation artifact set', () => { diff --git a/tests/test_foundation_ci_dependency_hygiene.sh b/tests/test_foundation_ci_dependency_hygiene.sh index 6a6cb51a8..2c0f5087f 100644 --- a/tests/test_foundation_ci_dependency_hygiene.sh +++ b/tests/test_foundation_ci_dependency_hygiene.sh @@ -6,8 +6,19 @@ workflow_path="${repository_root}/.github/workflows/foundation-ci.yml" requirements_path="${repository_root}/.github/requirements/foundation-test.txt" expected_install="python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt" -expected_pythonpath="PYTHONPATH: packages/hris-kernel/src:packages/keyverse-adapter/src" expected_default_pr_target=$' pull_request:\n branches:\n - develop\n' +expected_pythonpaths=( + "packages/candidate-evidence/src" + "packages/hris-kernel/src" + "packages/keyverse-adapter/src" + "packages/migration-adapter/src" + "packages/naruon-adapter/src" + "packages/offer-approval/src" + "packages/requisition-review/src" + "packages/selection-review/src" + "services/job-analysis-api/src:packages/hris-kernel/src:packages/keyverse-adapter/src" + "services/people-api/src:packages/hris-kernel/src:packages/keyverse-adapter/src" +) if ! grep -Fq -- "${expected_install}" "${workflow_path}"; then printf 'Foundation CI must install only the hash-locked test toolchain.\n' >&2 @@ -19,10 +30,12 @@ if grep -Eq -- 'python -m pip install .*packages/' "${workflow_path}"; then exit 1 fi -if ! grep -Fq -- "${expected_pythonpath}" "${workflow_path}"; then - printf 'Foundation CI must import repository-local packages directly from their src trees.\n' >&2 - exit 1 -fi +for expected_pythonpath in "${expected_pythonpaths[@]}"; do + if ! grep -Fq -- "PYTHONPATH=${expected_pythonpath} COVERAGE_FILE=" "${workflow_path}"; then + printf 'Foundation CI must import repository-local src tree directly: %s\n' "${expected_pythonpath}" >&2 + exit 1 + fi +done if ! grep -Fq -- "${expected_default_pr_target}" "${workflow_path}"; then printf 'Foundation CI must run for pull requests targeting the repository default branch develop.\n' >&2 diff --git a/tests/test_github_actions_runner_image.py b/tests/test_github_actions_runner_image.py index 979515941..6007c7724 100644 --- a/tests/test_github_actions_runner_image.py +++ b/tests/test_github_actions_runner_image.py @@ -16,6 +16,21 @@ WORKFLOWS = ROOT / ".github" / "workflows" _RUNS_ON_PATTERN = re.compile(r"^\s*runs-on\s*:\s*(.*?)\s*$") _EXPECTED_RUNNER = "ubuntu-24.04" +_CENTRAL_WORKFLOW_NAMES = { + "close-empty-pr.yml", + "codeql-pr.yml", + "dependency-review.yml", + "noema-review.yml", + "opencode-review.yml", + "pr-governance.yml", + "sast-semgrep.yml", + "security-scan.yml", + "strix.yml", +} +_EXPECTED_LOCAL_WORKFLOWS = { + "foundation-ci.yml", + "recovery-rehearsal-quality.yml", +} def _workflow_paths() -> list[Path]: @@ -135,5 +150,55 @@ def test_runner_parser_only_strips_yaml_comment_tokens(self) -> None: ) +class GitHubActionsQueueContractTest(unittest.TestCase): + """Keep local workflows bounded and same-PR cancellation isolated.""" + + def test_local_workflow_inventory_is_minimal_and_not_centrally_duplicated(self) -> None: + """Retain only repository-owned quality and recovery execution.""" + workflow_names = {path.name for path in _workflow_paths()} + self.assertEqual(_EXPECTED_LOCAL_WORKFLOWS, workflow_names) + self.assertTrue(workflow_names.isdisjoint(_CENTRAL_WORKFLOW_NAMES)) + + def test_workflow_concurrency_is_repository_and_pull_request_scoped(self) -> None: + """Cancel only an older head of the same workflow, repository, and PR.""" + for workflow_path in _workflow_paths(): + workflow = workflow_path.read_text(encoding="utf-8") + expected_group = ( + f"group: {workflow_path.stem}-" + "${{ github.repository }}-" + "${{ github.event.pull_request.number || github.run_id }}" + ) + self.assertIn(expected_group, workflow) + self.assertIn( + "cancel-in-progress: ${{ github.event_name == 'pull_request' }}", + workflow, + ) + + def test_foundation_workflow_expands_to_one_job(self) -> None: + """Do not recreate the previous matrix-driven 60-job admission pressure.""" + workflow = (WORKFLOWS / "foundation-ci.yml").read_text(encoding="utf-8") + jobs = workflow.split("\njobs:\n", maxsplit=1)[1] + job_keys = re.findall(r"^ ([a-z][a-z0-9_-]*):$", jobs, flags=re.MULTILINE) + self.assertEqual(["quality"], job_keys) + self.assertNotIn("matrix:", jobs) + + def test_postgres_contracts_wait_on_the_dynamic_host_port(self) -> None: + """Prove Docker port forwarding is usable before running each database contract.""" + workflow = (WORKFLOWS / "foundation-ci.yml").read_text(encoding="utf-8") + dynamic_publish = "--publish 127.0.0.1::5432" + port_lookup = 'postgres_binding="$(docker port "$container_name" 5432/tcp)"' + host_probe = "psql \"$database_url\" -Atqc 'SELECT 1'" + contract_run = 'DATABASE_URL="$database_url" bash "tests/$contract"' + self.assertIn(dynamic_publish, workflow) + self.assertIn('postgres_port="${postgres_binding##*:}"', workflow) + self.assertIn( + 'database_url="postgresql://orgmetra:orgmetra@127.0.0.1:$postgres_port/orgmetra"', + workflow, + ) + self.assertLess(workflow.index(dynamic_publish), workflow.index(port_lookup)) + self.assertLess(workflow.index(port_lookup), workflow.index(host_probe)) + self.assertLess(workflow.index(host_probe), workflow.index(contract_run)) + + if __name__ == "__main__": # pragma: no cover - normal execution is via unittest discovery. unittest.main() diff --git a/tests/validate_repository.py b/tests/validate_repository.py index fe0a329ff..d9d4c15a3 100644 --- a/tests/validate_repository.py +++ b/tests/validate_repository.py @@ -24,7 +24,6 @@ "manifest.json", "package.json", ".github/workflows/foundation-ci.yml", - ".github/workflows/job-analysis-api-quality.yml", "docs/PRD.md", "docs/TRD.md", "docs/USER_STORIES.md",