From bde2bd5472175ab7263ff27ff56a09c9d619e0c5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 01:23:53 +0900 Subject: [PATCH 01/17] ci: enforce declared Python package compatibility Move declared Python package compatibility into canonical Foundation ownership. Keep CPython 3.14 as the primary quality lane, add exact-head CPython 3.12/3.13 package compatibility on ubuntu-24.04, discover package contracts from pyproject metadata without package-name switchboards, retain package-owned 100% statement/branch coverage, and bind the compatibility test toolchain with reviewed hashes. Implements the source repair for #258 without closing it before protected integration. --- .../foundation-compatibility-test.txt | 9 ++ .github/workflows/foundation-ci.yml | 91 +++++++++++++++++-- .../foundation-python-compatibility.md | 61 +++++++++++++ manifest.json | 6 +- .../test_foundation_ci_dependency_hygiene.sh | 82 ++++++++++++++--- 5 files changed, 225 insertions(+), 24 deletions(-) create mode 100644 .github/requirements/foundation-compatibility-test.txt create mode 100644 docs/traceability/foundation-python-compatibility.md diff --git a/.github/requirements/foundation-compatibility-test.txt b/.github/requirements/foundation-compatibility-test.txt new file mode 100644 index 000000000..0c83fb3ed --- /dev/null +++ b/.github/requirements/foundation-compatibility-test.txt @@ -0,0 +1,9 @@ +# Reviewed Foundation compatibility toolchain for CPython 3.12-3.13 on GitHub-hosted Ubuntu x86_64. +# Coverage wheel hashes are the reviewed CPython 3.12 and 3.13 manylinux x86_64 artifacts. +coverage==7.14.2 --hash=sha256:8b4910cce599cd2438f8da65f5ef199a70a1cdb6ab314926df78271ca5954240 --hash=sha256:1d9a1b5813d00ea6151f6ccf64d1fa16892771dfdda12ba87162d15ec4ea3e1e +iniconfig==2.3.0 --hash=sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12 +packaging==26.2 --hash=sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e +pluggy==1.6.0 --hash=sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746 +Pygments==2.20.0 --hash=sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176 +pytest==9.1.1 --hash=sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c +pytest-cov==7.1.0 --hash=sha256:a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678 diff --git a/.github/workflows/foundation-ci.yml b/.github/workflows/foundation-ci.yml index 6b475d6f2..85a0fbbf2 100644 --- a/.github/workflows/foundation-ci.yml +++ b/.github/workflows/foundation-ci.yml @@ -56,16 +56,19 @@ jobs: run: | python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt python -m pip check - - name: Run owned unit and service contracts once + - name: Run owned package contracts once + run: | + set -euo pipefail + for pyproject in packages/*/pyproject.toml; do + package_dir="${pyproject%/pyproject.toml}" + [[ -d "$package_dir/src" && -d "$package_dir/tests" ]] || continue + package_name="$(basename "$package_dir")" + PYTHONPATH="$package_dir/src" \ + COVERAGE_FILE="/tmp/orgmetra-${package_name}.coverage" \ + python -m pytest -c "$pyproject" "$package_dir/tests" + done + - name: Run owned 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 @@ -123,3 +126,73 @@ jobs: run: | git diff --exit-code test -z "$(git status --porcelain)" + + python-compatibility: + name: Python ${{ matrix.python-version }} declared package compatibility + runs-on: ubuntu-24.04 + timeout-minutes: 30 + strategy: + fail-fast: false + matrix: + python-version: ["3.12", "3.13"] + 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 declared Python minor + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: ${{ matrix.python-version }} + check-latest: false + - name: Install reviewed compatibility toolchain + run: | + python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-compatibility-test.txt + python -m pip check + - name: Execute every package that declares this Python minor supported + env: + ORGMETRA_PYTHON_MINOR: ${{ matrix.python-version }} + run: | + set -euo pipefail + executed=0 + for pyproject in packages/*/pyproject.toml; do + package_dir="${pyproject%/pyproject.toml}" + [[ -d "$package_dir/src" && -d "$package_dir/tests" ]] || continue + if ! python - "$pyproject" <<'PY' + import sys + import tomllib + from pathlib import Path + from packaging.specifiers import SpecifierSet + from packaging.version import Version + + pyproject = Path(sys.argv[1]) + project = tomllib.loads(pyproject.read_text(encoding="utf-8")).get("project", {}) + requires_python = project.get("requires-python") + if not isinstance(requires_python, str) or not requires_python.strip(): + raise SystemExit(f"{pyproject}: project.requires-python is required") + runtime = Version(f"{sys.version_info.major}.{sys.version_info.minor}.0") + raise SystemExit(0 if runtime in SpecifierSet(requires_python) else 1) + PY + then + continue + fi + package_name="$(basename "$package_dir")" + python -m compileall -q "$package_dir/src" "$package_dir/tests" + PYTHONPATH="$package_dir/src" \ + COVERAGE_FILE="/tmp/orgmetra-${package_name}-${ORGMETRA_PYTHON_MINOR}.coverage" \ + python -m pytest -c "$pyproject" "$package_dir/tests" + executed=$((executed + 1)) + done + if [[ "$executed" -eq 0 ]]; then + printf 'No owned package declared Python %s support; compatibility evidence would be vacuous.\n' "$ORGMETRA_PYTHON_MINOR" >&2 + exit 1 + fi + - name: Require clean checkout + run: | + git diff --exit-code + test -z "$(git status --porcelain)" diff --git a/docs/traceability/foundation-python-compatibility.md b/docs/traceability/foundation-python-compatibility.md new file mode 100644 index 000000000..9a73f40ec --- /dev/null +++ b/docs/traceability/foundation-python-compatibility.md @@ -0,0 +1,61 @@ +# Foundation Python compatibility traceability + +## Authority + +- Repository: `ContextualWisdomLab/Orgmetra` +- Protected parent snapshot: `develop@eb9757f8649aaad026a9865508d9aad50c1a7a4f` +- Canonical repair issue: #258 +- Maturity: `implemented_on_active_pr` + +## Finding + +Protected Foundation CI executes repository-owned Python quality on CPython 3.14, while several merged +packages declare `requires-python = ">=3.12"`. The Structured Interview Plan work in #40 also declares +Python 3.12 support and carried real Python 3.12/3.13 compatibility jobs in its historical package-local +workflow. Protected #161 correctly retired package-local quality workflows, but adopting that deletion +without replacing the compatibility evidence would silently weaken the declared runtime contract. + +A package-local workflow is not restored. The compatibility capability belongs to the existing +`.github/workflows/foundation-ci.yml` owner. + +## Decision + +Foundation keeps its CPython 3.14 repository-quality lane and adds CPython 3.12 and 3.13 compatibility +lanes on the same pinned `ubuntu-24.04` runner image. Both primary and compatibility package execution +discover `packages/*/pyproject.toml` rather than naming packages in the workflow. + +For each compatibility runtime, Foundation reads `project.requires-python` with `tomllib` and +`packaging.specifiers.SpecifierSet`. A package is executed only when that runtime satisfies the package's +declared constraint. Every selected package is compiled and its own pytest configuration is executed from +its source tree. Package pytest contracts retain their existing exact statement and branch coverage gates. + +The primary CPython 3.14 toolchain remains bound by `.github/requirements/foundation-test.txt`. +CPython 3.12/3.13 use `.github/requirements/foundation-compatibility-test.txt`, installed with +`--require-hashes --no-deps --only-binary=:all:`. The compatibility lock reuses the reviewed versions from +the primary toolchain and binds the reviewed coverage wheels for both compatibility minors. + +## Invariants + +- `.github/workflows/foundation-ci.yml` remains the repository quality owner. +- Every Foundation job uses `ubuntu-24.04`; `ubuntu-latest` is rejected by executable hygiene checks. +- Compatibility discovery is package-neutral and contains no Interview Plan or Selection Monitoring switch. +- A compatibility lane fails if no owned package actually declares that runtime supported; static parsing + cannot satisfy the gate by itself. +- Exact-head checkout and a clean checkout after execution are required in every compatibility lane. +- Repository-local packages are not installed into the checkout as an implicit dependency workaround. +- Package-local quality workflows retired by protected #161 remain retired. + +## Scope boundary + +This change proves declared compatibility for Python packages under `packages/`. The two HTTP services +currently declare Python 3.11 support but are still exercised by Foundation only on the primary Python +runtime. No Python 3.11 service-compatibility claim is made by this change; that is a separate service +runtime contract rather than evidence for #258 or #40. + +## Adoption + +After this capability is integrated on protected `develop`, #40 can discard +`.github/workflows/interview-plan-quality.yml`, retain its `requires-python = ">=3.12"` declaration and +package tests, and receive Python 3.12/3.13/3.14 evidence through Foundation without adding a package name +to shared workflow logic. #42 should likewise adopt the protected generic package execution rather than +copying its mutable shared-dispatcher implementation. diff --git a/manifest.json b/manifest.json index f7b6cf55e..7f3f4f4ec 100644 --- a/manifest.json +++ b/manifest.json @@ -5,9 +5,9 @@ "files": [ { "path": ".github/workflows/foundation-ci.yml", - "sha256": "b6a4365936b66803a8112f034c77d53d33301a7a798ed4f68746a4f2d8b081d7", - "bytes": 6651, - "lines": 125 + "sha256": "bb6962ec9a3b265984895d4046b8165294d327af7661759cdee191a1a837df00", + "bytes": 8758, + "lines": 198 }, { "path": ".gitignore", diff --git a/tests/test_foundation_ci_dependency_hygiene.sh b/tests/test_foundation_ci_dependency_hygiene.sh index 2c0f5087f..e72f35f01 100644 --- a/tests/test_foundation_ci_dependency_hygiene.sh +++ b/tests/test_foundation_ci_dependency_hygiene.sh @@ -4,24 +4,25 @@ set -euo pipefail repository_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" workflow_path="${repository_root}/.github/workflows/foundation-ci.yml" requirements_path="${repository_root}/.github/requirements/foundation-test.txt" +compatibility_requirements_path="${repository_root}/.github/requirements/foundation-compatibility-test.txt" expected_install="python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt" +expected_compatibility_install="python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-compatibility-test.txt" 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" +expected_compatibility_matrix=' python-version: ["3.12", "3.13"]' +expected_package_discovery='for pyproject in packages/*/pyproject.toml; do' +expected_service_pythonpaths=( "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 + printf 'Foundation CI must install only the hash-locked primary test toolchain.\n' >&2 + exit 1 +fi + +if ! grep -Fq -- "${expected_compatibility_install}" "${workflow_path}"; then + printf 'Foundation CI must install the hash-locked compatibility toolchain.\n' >&2 exit 1 fi @@ -30,9 +31,34 @@ if grep -Eq -- 'python -m pip install .*packages/' "${workflow_path}"; then exit 1 fi -for expected_pythonpath in "${expected_pythonpaths[@]}"; do +if grep -Fq -- 'runs-on: ubuntu-latest' "${workflow_path}"; then + printf 'Foundation CI must pin every GitHub-hosted job to ubuntu-24.04.\n' >&2 + exit 1 +fi + +if [[ "$(grep -Fc -- 'runs-on: ubuntu-24.04' "${workflow_path}")" -ne 2 ]]; then + printf 'Foundation CI must pin both repository-quality and compatibility jobs to ubuntu-24.04.\n' >&2 + exit 1 +fi + +if ! grep -Fq -- "${expected_compatibility_matrix}" "${workflow_path}"; then + printf 'Foundation CI must execute declared package compatibility on Python 3.12 and 3.13.\n' >&2 + exit 1 +fi + +if [[ "$(grep -Fc -- "${expected_package_discovery}" "${workflow_path}")" -ne 2 ]]; then + printf 'Foundation CI must use package-neutral discovery in both primary and compatibility lanes.\n' >&2 + exit 1 +fi + +if grep -Eq -- 'packages/(interview-plan|selection-monitoring)' "${workflow_path}"; then + printf 'Foundation CI must not encode package-name switchboards for compatibility adoption.\n' >&2 + exit 1 +fi + +for expected_pythonpath in "${expected_service_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 + printf 'Foundation CI must preserve reviewed service source-tree execution: %s\n' "${expected_pythonpath}" >&2 exit 1 fi done @@ -84,9 +110,41 @@ for package_line in "${package_lines[@]}"; do fi done +if [[ ! -f "${compatibility_requirements_path}" ]]; then + printf 'Hash-locked Foundation compatibility requirements are missing.\n' >&2 + exit 1 +fi + +mapfile -t compatibility_package_lines < <( + grep -Ev '^[[:space:]]*(#|$)' "${compatibility_requirements_path}" +) +if [[ "${#compatibility_package_lines[@]}" -ne 7 ]]; then + printf 'Foundation compatibility requirements must contain the seven reviewed test packages.\n' >&2 + exit 1 +fi + +for package_line in "${compatibility_package_lines[@]}"; do + if [[ ! "${package_line}" =~ ^[A-Za-z0-9._-]+==[0-9][A-Za-z0-9._-]*([[:space:]]--hash=sha256:[0-9a-f]{64})+$ ]]; then + printf 'Unpinned or unhashed Foundation compatibility requirement: %s\n' "${package_line}" >&2 + exit 1 + fi +done + for package_name in coverage iniconfig packaging pluggy Pygments pytest pytest-cov; do if ! printf '%s\n' "${package_lines[@]}" | grep -Eq "^${package_name}=="; then printf 'Foundation CI requirement is missing: %s\n' "${package_name}" >&2 exit 1 fi + if ! printf '%s\n' "${compatibility_package_lines[@]}" | grep -Eq "^${package_name}=="; then + printf 'Foundation compatibility requirement is missing: %s\n' "${package_name}" >&2 + exit 1 + fi done + +coverage_compatibility_line="$( + printf '%s\n' "${compatibility_package_lines[@]}" | grep '^coverage==' +)" +if [[ "$(grep -o -- '--hash=sha256:[0-9a-f]\{64\}' <<<"${coverage_compatibility_line}" | wc -l | tr -d ' ')" -ne 2 ]]; then + printf 'Coverage compatibility requirement must bind reviewed CPython 3.12 and 3.13 wheels.\n' >&2 + exit 1 +fi From 4b2c6f605edf91406599177ea1aea0efd72aa99c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 01:43:54 +0900 Subject: [PATCH 02/17] fix(ci): fail closed on invalid Python compatibility metadata Distinguish a valid unsupported requires-python constraint from parser or metadata failure. Missing, blank, malformed, or invalid specifier metadata now fails the compatibility job instead of being converted into a package skip. Add executable Foundation hygiene coverage, update traceability, and reseal the exact Foundation workflow bytes. --- .github/workflows/foundation-ci.yml | 20 +++++++++++++++---- .../foundation-python-compatibility.md | 10 +++++++--- manifest.json | 6 +++--- .../test_foundation_ci_dependency_hygiene.sh | 12 +++++++++++ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/.github/workflows/foundation-ci.yml b/.github/workflows/foundation-ci.yml index 85a0fbbf2..fd39543be 100644 --- a/.github/workflows/foundation-ci.yml +++ b/.github/workflows/foundation-ci.yml @@ -163,11 +163,12 @@ jobs: for pyproject in packages/*/pyproject.toml; do package_dir="${pyproject%/pyproject.toml}" [[ -d "$package_dir/src" && -d "$package_dir/tests" ]] || continue - if ! python - "$pyproject" <<'PY' + compatibility_decision="$( + python - "$pyproject" <<'PY' import sys import tomllib from pathlib import Path - from packaging.specifiers import SpecifierSet + from packaging.specifiers import InvalidSpecifier, SpecifierSet from packaging.version import Version pyproject = Path(sys.argv[1]) @@ -176,11 +177,22 @@ jobs: if not isinstance(requires_python, str) or not requires_python.strip(): raise SystemExit(f"{pyproject}: project.requires-python is required") runtime = Version(f"{sys.version_info.major}.{sys.version_info.minor}.0") - raise SystemExit(0 if runtime in SpecifierSet(requires_python) else 1) + try: + supported = runtime in SpecifierSet(requires_python) + except InvalidSpecifier as exc: + raise SystemExit( + f"{pyproject}: invalid project.requires-python: {requires_python!r}" + ) from exc + print("supported" if supported else "unsupported") PY - then + )" + if [[ "$compatibility_decision" == "unsupported" ]]; then continue fi + if [[ "$compatibility_decision" != "supported" ]]; then + printf 'Unexpected compatibility decision for %s: %s\n' "$pyproject" "$compatibility_decision" >&2 + exit 1 + fi package_name="$(basename "$package_dir")" python -m compileall -q "$package_dir/src" "$package_dir/tests" PYTHONPATH="$package_dir/src" \ diff --git a/docs/traceability/foundation-python-compatibility.md b/docs/traceability/foundation-python-compatibility.md index 9a73f40ec..ac2bb6b1b 100644 --- a/docs/traceability/foundation-python-compatibility.md +++ b/docs/traceability/foundation-python-compatibility.md @@ -25,9 +25,11 @@ lanes on the same pinned `ubuntu-24.04` runner image. Both primary and compatibi discover `packages/*/pyproject.toml` rather than naming packages in the workflow. For each compatibility runtime, Foundation reads `project.requires-python` with `tomllib` and -`packaging.specifiers.SpecifierSet`. A package is executed only when that runtime satisfies the package's -declared constraint. Every selected package is compiled and its own pytest configuration is executed from -its source tree. Package pytest contracts retain their existing exact statement and branch coverage gates. +`packaging.specifiers.SpecifierSet`. A syntactically valid constraint that excludes the current minor may +skip that package. Missing, blank, non-string, malformed TOML, or invalid specifier metadata fails the +compatibility job instead of being reclassified as an unsupported runtime. Every selected package is +compiled and its own pytest configuration is executed from its source tree. Package pytest contracts retain +their existing exact statement and branch coverage gates. The primary CPython 3.14 toolchain remains bound by `.github/requirements/foundation-test.txt`. CPython 3.12/3.13 use `.github/requirements/foundation-compatibility-test.txt`, installed with @@ -39,6 +41,8 @@ the primary toolchain and binds the reviewed coverage wheels for both compatibil - `.github/workflows/foundation-ci.yml` remains the repository quality owner. - Every Foundation job uses `ubuntu-24.04`; `ubuntu-latest` is rejected by executable hygiene checks. - Compatibility discovery is package-neutral and contains no Interview Plan or Selection Monitoring switch. +- Invalid or missing `project.requires-python` metadata fails closed; only a valid constraint that excludes + the current minor may skip one package. - A compatibility lane fails if no owned package actually declares that runtime supported; static parsing cannot satisfy the gate by itself. - Exact-head checkout and a clean checkout after execution are required in every compatibility lane. diff --git a/manifest.json b/manifest.json index 7f3f4f4ec..8661ee0d2 100644 --- a/manifest.json +++ b/manifest.json @@ -5,9 +5,9 @@ "files": [ { "path": ".github/workflows/foundation-ci.yml", - "sha256": "bb6962ec9a3b265984895d4046b8165294d327af7661759cdee191a1a837df00", - "bytes": 8758, - "lines": 198 + "sha256": "26692278b68d87793b56ac302677eba376654f05e0737c3a961a343c56fcf0ec", + "bytes": 9345, + "lines": 210 }, { "path": ".gitignore", diff --git a/tests/test_foundation_ci_dependency_hygiene.sh b/tests/test_foundation_ci_dependency_hygiene.sh index e72f35f01..6470697aa 100644 --- a/tests/test_foundation_ci_dependency_hygiene.sh +++ b/tests/test_foundation_ci_dependency_hygiene.sh @@ -56,6 +56,18 @@ if grep -Eq -- 'packages/(interview-plan|selection-monitoring)' "${workflow_path exit 1 fi +if grep -Fq -- 'if ! python - "$pyproject"' "${workflow_path}"; then + printf 'Foundation compatibility selection must not convert metadata/parser failures into unsupported-package skips.\n' >&2 + exit 1 +fi + +if ! grep -Fq -- 'compatibility_decision="$(' "${workflow_path}" || + ! grep -Fq -- 'from packaging.specifiers import InvalidSpecifier, SpecifierSet' "${workflow_path}" || + ! grep -Fq -- 'Unexpected compatibility decision for %s: %s' "${workflow_path}"; then + printf 'Foundation compatibility selection must fail closed on invalid requires-python metadata.\n' >&2 + exit 1 +fi + for expected_pythonpath in "${expected_service_pythonpaths[@]}"; do if ! grep -Fq -- "PYTHONPATH=${expected_pythonpath} COVERAGE_FILE=" "${workflow_path}"; then printf 'Foundation CI must preserve reviewed service source-tree execution: %s\n' "${expected_pythonpath}" >&2 From 08c4ac6fd3094e7eb69c7a95a36663530649acd2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 02:14:33 +0900 Subject: [PATCH 03/17] fix(ci): evaluate exact Python runtime patch --- .github/workflows/foundation-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/foundation-ci.yml b/.github/workflows/foundation-ci.yml index fd39543be..3b533c1bd 100644 --- a/.github/workflows/foundation-ci.yml +++ b/.github/workflows/foundation-ci.yml @@ -176,7 +176,7 @@ jobs: requires_python = project.get("requires-python") if not isinstance(requires_python, str) or not requires_python.strip(): raise SystemExit(f"{pyproject}: project.requires-python is required") - runtime = Version(f"{sys.version_info.major}.{sys.version_info.minor}.0") + runtime = Version(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") try: supported = runtime in SpecifierSet(requires_python) except InvalidSpecifier as exc: From 0168ff2dc930fffa9e2a265b1f1142332269a91c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 02:15:00 +0900 Subject: [PATCH 04/17] test(ci): reject fabricated Python patch versions --- tests/test_foundation_ci_dependency_hygiene.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/test_foundation_ci_dependency_hygiene.sh b/tests/test_foundation_ci_dependency_hygiene.sh index 6470697aa..afb364b30 100644 --- a/tests/test_foundation_ci_dependency_hygiene.sh +++ b/tests/test_foundation_ci_dependency_hygiene.sh @@ -68,6 +68,17 @@ if ! grep -Fq -- 'compatibility_decision="$(' "${workflow_path}" || exit 1 fi +expected_exact_runtime='runtime = Version(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")' +if ! grep -Fq -- "${expected_exact_runtime}" "${workflow_path}"; then + printf 'Foundation compatibility selection must evaluate requires-python against the exact executed interpreter patch.\n' >&2 + exit 1 +fi + +if grep -Fq -- 'runtime = Version(f"{sys.version_info.major}.{sys.version_info.minor}.0")' "${workflow_path}"; then + printf 'Foundation compatibility selection must not fabricate a .0 patch for requires-python checks.\n' >&2 + exit 1 +fi + for expected_pythonpath in "${expected_service_pythonpaths[@]}"; do if ! grep -Fq -- "PYTHONPATH=${expected_pythonpath} COVERAGE_FILE=" "${workflow_path}"; then printf 'Foundation CI must preserve reviewed service source-tree execution: %s\n' "${expected_pythonpath}" >&2 From c06319fb2c8dbe3714b0dcf4978f2346f0f8ddaf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 02:15:15 +0900 Subject: [PATCH 05/17] docs(ci): trace exact interpreter compatibility --- .../foundation-python-compatibility.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/docs/traceability/foundation-python-compatibility.md b/docs/traceability/foundation-python-compatibility.md index ac2bb6b1b..d21930c08 100644 --- a/docs/traceability/foundation-python-compatibility.md +++ b/docs/traceability/foundation-python-compatibility.md @@ -25,11 +25,13 @@ lanes on the same pinned `ubuntu-24.04` runner image. Both primary and compatibi discover `packages/*/pyproject.toml` rather than naming packages in the workflow. For each compatibility runtime, Foundation reads `project.requires-python` with `tomllib` and -`packaging.specifiers.SpecifierSet`. A syntactically valid constraint that excludes the current minor may -skip that package. Missing, blank, non-string, malformed TOML, or invalid specifier metadata fails the -compatibility job instead of being reclassified as an unsupported runtime. Every selected package is -compiled and its own pytest configuration is executed from its source tree. Package pytest contracts retain -their existing exact statement and branch coverage gates. +`packaging.specifiers.SpecifierSet`. The selector evaluates that specifier against the actual interpreter +release installed by `actions/setup-python`, using `sys.version_info.major`, `minor`, and `micro`; it does +not fabricate a `.0` patch. A syntactically valid constraint may skip a package only when it excludes that +exact executed interpreter release. Missing, blank, non-string, malformed TOML, or invalid specifier +metadata fails the compatibility job instead of being reclassified as an unsupported runtime. Every +selected package is compiled and its own pytest configuration is executed from its source tree. Package +pytest contracts retain their existing exact statement and branch coverage gates. The primary CPython 3.14 toolchain remains bound by `.github/requirements/foundation-test.txt`. CPython 3.12/3.13 use `.github/requirements/foundation-compatibility-test.txt`, installed with @@ -42,7 +44,9 @@ the primary toolchain and binds the reviewed coverage wheels for both compatibil - Every Foundation job uses `ubuntu-24.04`; `ubuntu-latest` is rejected by executable hygiene checks. - Compatibility discovery is package-neutral and contains no Interview Plan or Selection Monitoring switch. - Invalid or missing `project.requires-python` metadata fails closed; only a valid constraint that excludes - the current minor may skip one package. + the actual executed interpreter patch may skip one package. +- Patch-sensitive PEP 440 constraints are evaluated against the real interpreter release, never a fabricated + `major.minor.0` surrogate. - A compatibility lane fails if no owned package actually declares that runtime supported; static parsing cannot satisfy the gate by itself. - Exact-head checkout and a clean checkout after execution are required in every compatibility lane. From 5e23de1387f0a424f78678c62152a006d9370d8d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 02:16:35 +0900 Subject: [PATCH 06/17] chore(ci): reseal Foundation workflow provenance --- manifest.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/manifest.json b/manifest.json index 8661ee0d2..881e344b4 100644 --- a/manifest.json +++ b/manifest.json @@ -5,8 +5,8 @@ "files": [ { "path": ".github/workflows/foundation-ci.yml", - "sha256": "26692278b68d87793b56ac302677eba376654f05e0737c3a961a343c56fcf0ec", - "bytes": 9345, + "sha256": "6db2c6204bc0f7852408dd95a2c21c0a2329df6edf764ae0f28fa29a0605314e", + "bytes": 9368, "lines": 210 }, { @@ -263,7 +263,7 @@ }, { "path": "docs/adr/0007-governed-job-analysis-evidence.md", - "sha256": "953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52", + "sha256": "953c6d2b9864a78b461b576092ec3f198f0b76709eaa7fd0ed0182f95182c52", "bytes": 5653, "lines": 57 }, From d7944583aa19c5927df1a1bf222910811cd86f7e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 02:18:10 +0900 Subject: [PATCH 07/17] fix(ci): correct Foundation manifest entry --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 881e344b4..6ace9926d 100644 --- a/manifest.json +++ b/manifest.json @@ -263,7 +263,7 @@ }, { "path": "docs/adr/0007-governed-job-analysis-evidence.md", - "sha256": "953c6d2b9864a78b461b576092ec3f198f0b76709eaa7fd0ed0182f95182c52", + "sha256": "953c6d2b9864a78b461b576092ec3f198f0b76709eaaaf7d0ed0182f95182c52", "bytes": 5653, "lines": 57 }, From 8ed91fa3df7f97e0df8253560811443bd5ab6460 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 03:09:26 +0900 Subject: [PATCH 08/17] test(ci): fail closed on incomplete owned package layouts --- .../test_foundation_ci_dependency_hygiene.sh | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/tests/test_foundation_ci_dependency_hygiene.sh b/tests/test_foundation_ci_dependency_hygiene.sh index afb364b30..36460cc1b 100644 --- a/tests/test_foundation_ci_dependency_hygiene.sh +++ b/tests/test_foundation_ci_dependency_hygiene.sh @@ -16,6 +16,51 @@ expected_service_pythonpaths=( "services/people-api/src:packages/hris-kernel/src:packages/keyverse-adapter/src" ) +validate_owned_package_layout() { + local root="$1" + local pyproject + local package_dir + local discovered=0 + + for pyproject in "${root}"/packages/*/pyproject.toml; do + [[ -f "${pyproject}" ]] || continue + discovered=$((discovered + 1)) + package_dir="${pyproject%/pyproject.toml}" + if [[ ! -d "${package_dir}/src" || ! -d "${package_dir}/tests" ]]; then + printf 'Owned Python package must provide both src and tests directories: %s\n' "${package_dir}" >&2 + return 1 + fi + done + + if [[ "${discovered}" -eq 0 ]]; then + printf 'Foundation CI package discovery found no owned Python packages.\n' >&2 + return 1 + fi +} + +validate_owned_package_layout "${repository_root}" + +layout_fixture_root="$(mktemp -d)" +trap 'rm -rf "${layout_fixture_root}"' EXIT +for missing_directory in src tests; do + fixture_package="${layout_fixture_root}/packages/missing-${missing_directory}" + mkdir -p "${fixture_package}/src" "${fixture_package}/tests" + rm -rf "${fixture_package}/${missing_directory}" + cat >"${fixture_package}/pyproject.toml" <<'EOF' +[project] +name = "orgmetra-foundation-layout-fixture" +version = "0.0.0" +requires-python = ">=3.12" +EOF + if validate_owned_package_layout "${layout_fixture_root}" >/dev/null 2>&1; then + printf 'Foundation package discovery must fail closed when an owned package omits %s.\n' "${missing_directory}" >&2 + exit 1 + fi + rm -rf "${fixture_package}" +done +rm -rf "${layout_fixture_root}" +trap - EXIT + if ! grep -Fq -- "${expected_install}" "${workflow_path}"; then printf 'Foundation CI must install only the hash-locked primary test toolchain.\n' >&2 exit 1 From f529086c2803bc6684060c265a39f3f791b216db Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 03:09:47 +0900 Subject: [PATCH 09/17] docs(ci): trace fail-closed package layout discovery --- .../traceability/foundation-python-compatibility.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/traceability/foundation-python-compatibility.md b/docs/traceability/foundation-python-compatibility.md index d21930c08..9feddd282 100644 --- a/docs/traceability/foundation-python-compatibility.md +++ b/docs/traceability/foundation-python-compatibility.md @@ -18,6 +18,12 @@ without replacing the compatibility evidence would silently weaken the declared A package-local workflow is not restored. The compatibility capability belongs to the existing `.github/workflows/foundation-ci.yml` owner. +A follow-up exact-tree review found a separate discovery fail-open edge: both Foundation package loops +intentionally skip directory entries that are not complete Python packages. Without an independent +repository-quality invariant, an owned `packages/*/pyproject.toml` could therefore become invisible to +package execution simply by losing `src/` or `tests/`. Canonical Foundation now treats that layout as a +repository contract violation before package execution rather than accepting a silent skip. + ## Decision Foundation keeps its CPython 3.14 repository-quality lane and adds CPython 3.12 and 3.13 compatibility @@ -33,6 +39,11 @@ metadata fails the compatibility job instead of being reclassified as an unsuppo selected package is compiled and its own pytest configuration is executed from its source tree. Package pytest contracts retain their existing exact statement and branch coverage gates. +The repository-quality hygiene contract enumerates every `packages/*/pyproject.toml` and requires both +`src/` and `tests/` to exist. Its self-regression constructs incomplete package fixtures and proves that +missing either directory fails closed. This keeps non-Python directories outside discovery while preventing +an owned Python package from escaping Foundation acceptance by becoming structurally incomplete. + The primary CPython 3.14 toolchain remains bound by `.github/requirements/foundation-test.txt`. CPython 3.12/3.13 use `.github/requirements/foundation-compatibility-test.txt`, installed with `--require-hashes --no-deps --only-binary=:all:`. The compatibility lock reuses the reviewed versions from @@ -43,6 +54,8 @@ the primary toolchain and binds the reviewed coverage wheels for both compatibil - `.github/workflows/foundation-ci.yml` remains the repository quality owner. - Every Foundation job uses `ubuntu-24.04`; `ubuntu-latest` is rejected by executable hygiene checks. - Compatibility discovery is package-neutral and contains no Interview Plan or Selection Monitoring switch. +- Every discovered owned Python package must have both `src/` and `tests/`; incomplete package layout is a + Foundation failure, not an accepted discovery skip. - Invalid or missing `project.requires-python` metadata fails closed; only a valid constraint that excludes the actual executed interpreter patch may skip one package. - Patch-sensitive PEP 440 constraints are evaluated against the real interpreter release, never a fabricated From 3864f4aabdd41bb5c1c5edc4410c2d3da6fb943e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 04:03:56 +0900 Subject: [PATCH 10/17] fix(ci): preserve one-job Foundation admission --- .github/workflows/foundation-ci.yml | 98 ++++++++++++++++++++--------- 1 file changed, 67 insertions(+), 31 deletions(-) diff --git a/.github/workflows/foundation-ci.yml b/.github/workflows/foundation-ci.yml index 3b533c1bd..332a11e41 100644 --- a/.github/workflows/foundation-ci.yml +++ b/.github/workflows/foundation-ci.yml @@ -33,7 +33,7 @@ jobs: 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 + - name: Set up primary Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: "3.14" @@ -119,44 +119,77 @@ jobs: 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 - - name: Prove validation is read-only - run: | - git diff --exit-code - test -z "$(git status --porcelain)" - - python-compatibility: - name: Python ${{ matrix.python-version }} declared package compatibility - runs-on: ubuntu-24.04 - timeout-minutes: 30 - strategy: - fail-fast: false - matrix: - python-version: ["3.12", "3.13"] - steps: - - name: Checkout exact candidate - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Set up Python 3.12 compatibility runtime + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: - ref: ${{ github.event.pull_request.head.sha || github.sha }} - persist-credentials: false - - name: Prove exact candidate checkout + python-version: "3.12" + check-latest: false + - name: Install reviewed Python 3.12 compatibility toolchain + run: | + python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-compatibility-test.txt + python -m pip check + - name: Execute every package that declares Python 3.12 supported 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 declared Python minor + ORGMETRA_PYTHON_MINOR: "3.12" + run: | + set -euo pipefail + executed=0 + for pyproject in packages/*/pyproject.toml; do + package_dir="${pyproject%/pyproject.toml}" + [[ -d "$package_dir/src" && -d "$package_dir/tests" ]] || continue + compatibility_decision="$( + python - "$pyproject" <<'PY' + import sys + import tomllib + from pathlib import Path + from packaging.specifiers import InvalidSpecifier, SpecifierSet + from packaging.version import Version + + pyproject = Path(sys.argv[1]) + project = tomllib.loads(pyproject.read_text(encoding="utf-8")).get("project", {}) + requires_python = project.get("requires-python") + if not isinstance(requires_python, str) or not requires_python.strip(): + raise SystemExit(f"{pyproject}: project.requires-python is required") + runtime = Version(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}") + try: + supported = runtime in SpecifierSet(requires_python) + except InvalidSpecifier as exc: + raise SystemExit( + f"{pyproject}: invalid project.requires-python: {requires_python!r}" + ) from exc + print("supported" if supported else "unsupported") + PY + )" + if [[ "$compatibility_decision" == "unsupported" ]]; then + continue + fi + if [[ "$compatibility_decision" != "supported" ]]; then + printf 'Unexpected compatibility decision for %s: %s\n' "$pyproject" "$compatibility_decision" >&2 + exit 1 + fi + package_name="$(basename "$package_dir")" + python -m compileall -q "$package_dir/src" "$package_dir/tests" + PYTHONPATH="$package_dir/src" \ + COVERAGE_FILE="/tmp/orgmetra-${package_name}-${ORGMETRA_PYTHON_MINOR}.coverage" \ + python -m pytest -c "$pyproject" "$package_dir/tests" + executed=$((executed + 1)) + done + if [[ "$executed" -eq 0 ]]; then + printf 'No owned package declared Python %s support; compatibility evidence would be vacuous.\n' "$ORGMETRA_PYTHON_MINOR" >&2 + exit 1 + fi + - name: Set up Python 3.13 compatibility runtime uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: - python-version: ${{ matrix.python-version }} + python-version: "3.13" check-latest: false - - name: Install reviewed compatibility toolchain + - name: Install reviewed Python 3.13 compatibility toolchain run: | python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-compatibility-test.txt python -m pip check - - name: Execute every package that declares this Python minor supported + - name: Execute every package that declares Python 3.13 supported env: - ORGMETRA_PYTHON_MINOR: ${{ matrix.python-version }} + ORGMETRA_PYTHON_MINOR: "3.13" run: | set -euo pipefail executed=0 @@ -204,7 +237,10 @@ jobs: printf 'No owned package declared Python %s support; compatibility evidence would be vacuous.\n' "$ORGMETRA_PYTHON_MINOR" >&2 exit 1 fi - - name: Require clean checkout + - name: Print exact manifest repair data + if: failure() + run: python tests/validate_repository.py --print-manifest + - name: Prove validation is read-only run: | git diff --exit-code test -z "$(git status --porcelain)" From 99cbff45c65e332b3cefe8de416ac1bb14805c2a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 04:04:27 +0900 Subject: [PATCH 11/17] test(ci): keep compatibility inside one Foundation job --- .../test_foundation_ci_dependency_hygiene.sh | 45 ++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/tests/test_foundation_ci_dependency_hygiene.sh b/tests/test_foundation_ci_dependency_hygiene.sh index 36460cc1b..bd6185129 100644 --- a/tests/test_foundation_ci_dependency_hygiene.sh +++ b/tests/test_foundation_ci_dependency_hygiene.sh @@ -9,7 +9,6 @@ compatibility_requirements_path="${repository_root}/.github/requirements/foundat expected_install="python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-test.txt" expected_compatibility_install="python -m pip install --require-hashes --no-deps --only-binary=:all: -r .github/requirements/foundation-compatibility-test.txt" expected_default_pr_target=$' pull_request:\n branches:\n - develop\n' -expected_compatibility_matrix=' python-version: ["3.12", "3.13"]' expected_package_discovery='for pyproject in packages/*/pyproject.toml; do' expected_service_pythonpaths=( "services/job-analysis-api/src:packages/hris-kernel/src:packages/keyverse-adapter/src" @@ -66,8 +65,8 @@ if ! grep -Fq -- "${expected_install}" "${workflow_path}"; then exit 1 fi -if ! grep -Fq -- "${expected_compatibility_install}" "${workflow_path}"; then - printf 'Foundation CI must install the hash-locked compatibility toolchain.\n' >&2 +if [[ "$(grep -Fc -- "${expected_compatibility_install}" "${workflow_path}")" -ne 2 ]]; then + printf 'Foundation CI must install the hash-locked compatibility toolchain once for each declared compatibility runtime.\n' >&2 exit 1 fi @@ -81,18 +80,29 @@ if grep -Fq -- 'runs-on: ubuntu-latest' "${workflow_path}"; then exit 1 fi -if [[ "$(grep -Fc -- 'runs-on: ubuntu-24.04' "${workflow_path}")" -ne 2 ]]; then - printf 'Foundation CI must pin both repository-quality and compatibility jobs to ubuntu-24.04.\n' >&2 +if [[ "$(grep -Fc -- 'runs-on: ubuntu-24.04' "${workflow_path}")" -ne 1 ]]; then + printf 'Foundation CI must preserve one repository-owned job on ubuntu-24.04.\n' >&2 exit 1 fi -if ! grep -Fq -- "${expected_compatibility_matrix}" "${workflow_path}"; then - printf 'Foundation CI must execute declared package compatibility on Python 3.12 and 3.13.\n' >&2 +if grep -Fq -- 'matrix:' "${workflow_path}" || grep -Fq -- 'python-compatibility:' "${workflow_path}"; then + printf 'Foundation compatibility must not recreate matrix-driven or second-job admission pressure.\n' >&2 exit 1 fi -if [[ "$(grep -Fc -- "${expected_package_discovery}" "${workflow_path}")" -ne 2 ]]; then - printf 'Foundation CI must use package-neutral discovery in both primary and compatibility lanes.\n' >&2 +for python_minor in 3.12 3.13; do + if [[ "$(grep -Fc -- "python-version: \"${python_minor}\"" "${workflow_path}")" -ne 1 ]]; then + printf 'Foundation CI must set up Python %s exactly once for sequential compatibility evidence.\n' "${python_minor}" >&2 + exit 1 + fi + if [[ "$(grep -Fc -- "ORGMETRA_PYTHON_MINOR: \"${python_minor}\"" "${workflow_path}")" -ne 1 ]]; then + printf 'Foundation CI must bind compatibility execution to Python %s.\n' "${python_minor}" >&2 + exit 1 + fi +done + +if [[ "$(grep -Fc -- "${expected_package_discovery}" "${workflow_path}")" -ne 3 ]]; then + printf 'Foundation CI must use package-neutral discovery in primary, Python 3.12, and Python 3.13 execution.\n' >&2 exit 1 fi @@ -106,16 +116,16 @@ if grep -Fq -- 'if ! python - "$pyproject"' "${workflow_path}"; then exit 1 fi -if ! grep -Fq -- 'compatibility_decision="$(' "${workflow_path}" || - ! grep -Fq -- 'from packaging.specifiers import InvalidSpecifier, SpecifierSet' "${workflow_path}" || - ! grep -Fq -- 'Unexpected compatibility decision for %s: %s' "${workflow_path}"; then - printf 'Foundation compatibility selection must fail closed on invalid requires-python metadata.\n' >&2 +if [[ "$(grep -Fc -- 'compatibility_decision="$(' "${workflow_path}")" -ne 2 ]] || + [[ "$(grep -Fc -- 'from packaging.specifiers import InvalidSpecifier, SpecifierSet' "${workflow_path}")" -ne 2 ]] || + [[ "$(grep -Fc -- 'Unexpected compatibility decision for %s: %s' "${workflow_path}")" -ne 2 ]]; then + printf 'Foundation compatibility selection must fail closed in both sequential compatibility executions.\n' >&2 exit 1 fi expected_exact_runtime='runtime = Version(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")' -if ! grep -Fq -- "${expected_exact_runtime}" "${workflow_path}"; then - printf 'Foundation compatibility selection must evaluate requires-python against the exact executed interpreter patch.\n' >&2 +if [[ "$(grep -Fc -- "${expected_exact_runtime}" "${workflow_path}")" -ne 2 ]]; then + printf 'Foundation compatibility selection must evaluate both runtimes against the exact executed interpreter patch.\n' >&2 exit 1 fi @@ -124,6 +134,11 @@ if grep -Fq -- 'runtime = Version(f"{sys.version_info.major}.{sys.version_info.m exit 1 fi +if [[ "$(grep -Fc -- 'No owned package declared Python %s support; compatibility evidence would be vacuous.' "${workflow_path}")" -ne 2 ]]; then + printf 'Foundation compatibility must fail non-vacuously for both sequential runtimes.\n' >&2 + exit 1 +fi + for expected_pythonpath in "${expected_service_pythonpaths[@]}"; do if ! grep -Fq -- "PYTHONPATH=${expected_pythonpath} COVERAGE_FILE=" "${workflow_path}"; then printf 'Foundation CI must preserve reviewed service source-tree execution: %s\n' "${expected_pythonpath}" >&2 From 23369a8c83dc373088fadbf9dd64f39793df0d42 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 04:04:49 +0900 Subject: [PATCH 12/17] docs(ci): trace single-job compatibility repair --- .../foundation-python-compatibility.md | 105 +++++++++--------- 1 file changed, 54 insertions(+), 51 deletions(-) diff --git a/docs/traceability/foundation-python-compatibility.md b/docs/traceability/foundation-python-compatibility.md index 9feddd282..d6391f341 100644 --- a/docs/traceability/foundation-python-compatibility.md +++ b/docs/traceability/foundation-python-compatibility.md @@ -10,73 +10,76 @@ ## Finding Protected Foundation CI executes repository-owned Python quality on CPython 3.14, while several merged -packages declare `requires-python = ">=3.12"`. The Structured Interview Plan work in #40 also declares -Python 3.12 support and carried real Python 3.12/3.13 compatibility jobs in its historical package-local -workflow. Protected #161 correctly retired package-local quality workflows, but adopting that deletion -without replacing the compatibility evidence would silently weaken the declared runtime contract. +packages declare `requires-python = ">=3.12"`. Structured Interview Plan #40 also carried real CPython +3.12/3.13 execution in its historical package-local workflow. Protected #161 correctly retired package-local +quality workflows, but adopting that deletion without replacement evidence would weaken the declared runtime +contract. + +Three follow-up reviews found separate fail-open defects in the first compatibility implementation. Metadata +parser failures could be reclassified as unsupported-package skips; PEP 440 was evaluated against a fabricated +`major.minor.0` rather than the executed interpreter patch; and an owned `packages/*/pyproject.toml` could +escape package acceptance if either `src/` or `tests/` disappeared. Those paths now fail closed. + +Exact-head Foundation run `34050838082` exposed a fourth defect in the implementation shape. Python 3.12 and +3.13 were introduced as a second matrix job, but protected repository policy intentionally constrains +Foundation to one job to avoid recreating the previous matrix-driven Actions admission pressure. The two +compatibility jobs themselves passed, while the canonical runner/queue contract failed before repository +validation. Compatibility evidence is therefore kept, but it executes sequentially inside the existing +`quality` job rather than widening the job graph. + +A package-local workflow is not restored. The capability remains owned by +`.github/workflows/foundation-ci.yml`. -A package-local workflow is not restored. The compatibility capability belongs to the existing -`.github/workflows/foundation-ci.yml` owner. +## Decision -A follow-up exact-tree review found a separate discovery fail-open edge: both Foundation package loops -intentionally skip directory entries that are not complete Python packages. Without an independent -repository-quality invariant, an owned `packages/*/pyproject.toml` could therefore become invisible to -package execution simply by losing `src/` or `tests/`. Canonical Foundation now treats that layout as a -repository contract violation before package execution rather than accepting a silent skip. +Foundation keeps one `quality` job on pinned `ubuntu-24.04`. That job runs the primary CPython 3.14 package, +service, and PostgreSQL contracts, then switches to CPython 3.12 and CPython 3.13 in sequence with +`actions/setup-python`. Each compatibility runtime installs the separately reviewed hash-locked compatibility +toolchain and executes every package whose `project.requires-python` includes the actual interpreter patch. +No compatibility matrix or second Foundation job is permitted. -## Decision +Primary and compatibility package execution discover `packages/*/pyproject.toml` rather than naming packages +in workflow logic. For each compatibility runtime, Foundation reads `project.requires-python` with `tomllib` +and `packaging.specifiers.SpecifierSet`, evaluates it against +`sys.version_info.major.minor.micro`, and permits a skip only when a syntactically valid constraint excludes +that exact executed release. Missing, blank, non-string, malformed TOML, invalid specifiers, or parser failures +terminate the compatibility execution. Every selected package is compiled and runs its own pytest +configuration, preserving its exact statement and branch coverage gate. + +The repository-quality hygiene contract independently enumerates every `packages/*/pyproject.toml` and +requires both `src/` and `tests/`. Its self-regression constructs missing-`src` and missing-`tests` fixtures and +requires both to fail closed. Non-Python directories without a `pyproject.toml` remain outside this contract. -Foundation keeps its CPython 3.14 repository-quality lane and adds CPython 3.12 and 3.13 compatibility -lanes on the same pinned `ubuntu-24.04` runner image. Both primary and compatibility package execution -discover `packages/*/pyproject.toml` rather than naming packages in the workflow. - -For each compatibility runtime, Foundation reads `project.requires-python` with `tomllib` and -`packaging.specifiers.SpecifierSet`. The selector evaluates that specifier against the actual interpreter -release installed by `actions/setup-python`, using `sys.version_info.major`, `minor`, and `micro`; it does -not fabricate a `.0` patch. A syntactically valid constraint may skip a package only when it excludes that -exact executed interpreter release. Missing, blank, non-string, malformed TOML, or invalid specifier -metadata fails the compatibility job instead of being reclassified as an unsupported runtime. Every -selected package is compiled and its own pytest configuration is executed from its source tree. Package -pytest contracts retain their existing exact statement and branch coverage gates. - -The repository-quality hygiene contract enumerates every `packages/*/pyproject.toml` and requires both -`src/` and `tests/` to exist. Its self-regression constructs incomplete package fixtures and proves that -missing either directory fails closed. This keeps non-Python directories outside discovery while preventing -an owned Python package from escaping Foundation acceptance by becoming structurally incomplete. - -The primary CPython 3.14 toolchain remains bound by `.github/requirements/foundation-test.txt`. -CPython 3.12/3.13 use `.github/requirements/foundation-compatibility-test.txt`, installed with -`--require-hashes --no-deps --only-binary=:all:`. The compatibility lock reuses the reviewed versions from -the primary toolchain and binds the reviewed coverage wheels for both compatibility minors. +The primary CPython 3.14 toolchain remains bound by `.github/requirements/foundation-test.txt`. CPython +3.12/3.13 use `.github/requirements/foundation-compatibility-test.txt`, installed with +`--require-hashes --no-deps --only-binary=:all:` and reviewed wheel hashes for both compatibility runtimes. ## Invariants -- `.github/workflows/foundation-ci.yml` remains the repository quality owner. -- Every Foundation job uses `ubuntu-24.04`; `ubuntu-latest` is rejected by executable hygiene checks. +- `.github/workflows/foundation-ci.yml` remains the only repository quality owner. +- Foundation expands to exactly one repository-owned job; compatibility must not add a matrix or second job. +- The Foundation job uses `ubuntu-24.04`; `ubuntu-latest` remains rejected by executable regression. +- CPython 3.12 and 3.13 compatibility executes sequentially after the primary CPython 3.14 quality contracts. - Compatibility discovery is package-neutral and contains no Interview Plan or Selection Monitoring switch. -- Every discovered owned Python package must have both `src/` and `tests/`; incomplete package layout is a - Foundation failure, not an accepted discovery skip. -- Invalid or missing `project.requires-python` metadata fails closed; only a valid constraint that excludes - the actual executed interpreter patch may skip one package. -- Patch-sensitive PEP 440 constraints are evaluated against the real interpreter release, never a fabricated - `major.minor.0` surrogate. -- A compatibility lane fails if no owned package actually declares that runtime supported; static parsing - cannot satisfy the gate by itself. -- Exact-head checkout and a clean checkout after execution are required in every compatibility lane. +- Every discovered owned Python package has both `src/` and `tests/`; incomplete layout is a Foundation + failure rather than an accepted skip. +- Invalid or missing `project.requires-python` metadata fails closed; only a valid constraint excluding the + actual executed interpreter patch may skip a package. +- Patch-sensitive PEP 440 constraints are evaluated against the executed release, never a fabricated `.0`. +- Each compatibility runtime fails if no owned package actually declares that runtime supported. - Repository-local packages are not installed into the checkout as an implicit dependency workaround. - Package-local quality workflows retired by protected #161 remain retired. ## Scope boundary This change proves declared compatibility for Python packages under `packages/`. The two HTTP services -currently declare Python 3.11 support but are still exercised by Foundation only on the primary Python -runtime. No Python 3.11 service-compatibility claim is made by this change; that is a separate service -runtime contract rather than evidence for #258 or #40. +currently declare Python 3.11 support but remain a separate #260 service-runtime contract. No Python 3.11 +service-compatibility claim is made by #258 or #40. ## Adoption After this capability is integrated on protected `develop`, #40 can discard `.github/workflows/interview-plan-quality.yml`, retain its `requires-python = ">=3.12"` declaration and -package tests, and receive Python 3.12/3.13/3.14 evidence through Foundation without adding a package name -to shared workflow logic. #42 should likewise adopt the protected generic package execution rather than -copying its mutable shared-dispatcher implementation. +package tests, and receive Python 3.12/3.13/3.14 evidence through Foundation without adding a package name to +shared workflow logic. #42 should likewise adopt the protected generic package execution rather than copying +its mutable shared-dispatcher implementation. From 79e8757515673144b68687517360cf493e93ccb8 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 04:07:50 +0900 Subject: [PATCH 13/17] fix(ci): reseal single-job Foundation workflow --- manifest.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/manifest.json b/manifest.json index 6ace9926d..7d111320f 100644 --- a/manifest.json +++ b/manifest.json @@ -5,9 +5,9 @@ "files": [ { "path": ".github/workflows/foundation-ci.yml", - "sha256": "6db2c6204bc0f7852408dd95a2c21c0a2329df6edf764ae0f28fa29a0605314e", - "bytes": 9368, - "lines": 210 + "sha256": "ff5a9ae9a311ad7e2a491f753ecc3fe91c1533e469c7551371ed5c76fc831538", + "bytes": 11381, + "lines": 246 }, { "path": ".gitignore", @@ -472,4 +472,4 @@ "lines": 637 } ] -} +} \ No newline at end of file From 01eee532159e9f88f230b1a0a19424c5e1986a81 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 05:13:40 +0900 Subject: [PATCH 14/17] fix(ci): bind compatibility toolchain provenance --- .github/workflows/foundation-ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/foundation-ci.yml b/.github/workflows/foundation-ci.yml index 332a11e41..a2ef7aba6 100644 --- a/.github/workflows/foundation-ci.yml +++ b/.github/workflows/foundation-ci.yml @@ -119,6 +119,11 @@ jobs: docker rm --force "$container_name" >/dev/null trap - EXIT done + - name: Prove compatibility toolchain provenance + run: | + expected_sha256=cebb36181e8ac995a36d73a02a45094a204ff5adb3cbcdc0c9eccff309ac6aab + actual_sha256="$(sha256sum .github/requirements/foundation-compatibility-test.txt | awk '{print $1}')" + test "$actual_sha256" = "$expected_sha256" - name: Set up Python 3.12 compatibility runtime uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: From 581e1a3f741f47a5aa5553aa0e78a786c193688d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 05:15:02 +0900 Subject: [PATCH 15/17] fix(ci): reseal compatibility toolchain provenance --- manifest.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/manifest.json b/manifest.json index 7d111320f..bb0ac6f09 100644 --- a/manifest.json +++ b/manifest.json @@ -5,9 +5,9 @@ "files": [ { "path": ".github/workflows/foundation-ci.yml", - "sha256": "ff5a9ae9a311ad7e2a491f753ecc3fe91c1533e469c7551371ed5c76fc831538", - "bytes": 11381, - "lines": 246 + "sha256": "27fd3f2a69181e6a31b49ab2a3d394bfc8dca2b8ef5e9ce39324273f7962773d", + "bytes": 11708, + "lines": 251 }, { "path": ".gitignore", @@ -83,7 +83,7 @@ }, { "path": "database/migrations/0005_outbox_delivery_finalization.sql", - "sha256": "b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961", + "sha256": "b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5ef9e8a92abba5c3cf182", "bytes": 6125, "lines": 170 }, From dd89898a0af60a48aad41869d4bfd07b2613f8c4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 05:16:45 +0900 Subject: [PATCH 16/17] fix(ci): restore exact migration provenance --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index bb0ac6f09..558d4d1c7 100644 --- a/manifest.json +++ b/manifest.json @@ -83,7 +83,7 @@ }, { "path": "database/migrations/0005_outbox_delivery_finalization.sql", - "sha256": "b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5ef9e8a92abba5c3cf182", + "sha256": "b7e8790595b288f752d6ef5cc6cbfe4e1b6712248f5b7a3a25fa60016b6a4961", "bytes": 6125, "lines": 170 }, From f1f152b0838e11cba1cf583706eb0983d56af373 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 7 Sep 2026 05:17:43 +0900 Subject: [PATCH 17/17] docs(ci): trace compatibility provenance binding --- .../foundation-python-compatibility.md | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/traceability/foundation-python-compatibility.md b/docs/traceability/foundation-python-compatibility.md index d6391f341..e801189d9 100644 --- a/docs/traceability/foundation-python-compatibility.md +++ b/docs/traceability/foundation-python-compatibility.md @@ -27,16 +27,30 @@ compatibility jobs themselves passed, while the canonical runner/queue contract validation. Compatibility evidence is therefore kept, but it executes sequentially inside the existing `quality` job rather than widening the job graph. +Exact head `79e8757515673144b68687517360cf493e93ccb8` then produced a complete Foundation GREEN in run +`34053906336`: the one `Repository quality` job passed exact checkout, runner-image proof, Foundation validation, +dependency hygiene, primary package/service/PostgreSQL contracts, Python 3.12 compatibility, Python 3.13 +compatibility, and clean-checkout proof. + +A fifth review found a provenance gap despite that GREEN. The compatibility requirement file was hash-locked at +the package line level, but the file itself was not part of the canonical Foundation manifest inventory. A +reviewed dependency set could therefore change without changing the manifest unless another tracked artifact +bound it. The active successor now makes that binding explicit: the manifest-sealed Foundation workflow verifies +SHA-256 `cebb36181e8ac995a36d73a02a45094a204ff5adb3cbcdc0c9eccff309ac6aab` for +`.github/requirements/foundation-compatibility-test.txt` before either compatibility runtime can install it. +The workflow itself is resealed in `manifest.json`, so the dependency input is transitively integrity-bound +without adding a second quality owner or mutable external source. + A package-local workflow is not restored. The capability remains owned by `.github/workflows/foundation-ci.yml`. ## Decision Foundation keeps one `quality` job on pinned `ubuntu-24.04`. That job runs the primary CPython 3.14 package, -service, and PostgreSQL contracts, then switches to CPython 3.12 and CPython 3.13 in sequence with -`actions/setup-python`. Each compatibility runtime installs the separately reviewed hash-locked compatibility -toolchain and executes every package whose `project.requires-python` includes the actual interpreter patch. -No compatibility matrix or second Foundation job is permitted. +service, and PostgreSQL contracts, proves the reviewed compatibility-toolchain file digest, then switches to +CPython 3.12 and CPython 3.13 in sequence with `actions/setup-python`. Each compatibility runtime installs the +same reviewed hash-locked compatibility toolchain and executes every package whose `project.requires-python` +includes the actual interpreter patch. No compatibility matrix or second Foundation job is permitted. Primary and compatibility package execution discover `packages/*/pyproject.toml` rather than naming packages in workflow logic. For each compatibility runtime, Foundation reads `project.requires-python` with `tomllib` @@ -52,7 +66,9 @@ requires both to fail closed. Non-Python directories without a `pyproject.toml` The primary CPython 3.14 toolchain remains bound by `.github/requirements/foundation-test.txt`. CPython 3.12/3.13 use `.github/requirements/foundation-compatibility-test.txt`, installed with -`--require-hashes --no-deps --only-binary=:all:` and reviewed wheel hashes for both compatibility runtimes. +`--require-hashes --no-deps --only-binary=:all:` and reviewed wheel hashes for both compatibility runtimes. The +compatibility file's complete bytes are additionally pinned by the manifest-sealed Foundation workflow before +installation. ## Invariants @@ -60,6 +76,7 @@ The primary CPython 3.14 toolchain remains bound by `.github/requirements/founda - Foundation expands to exactly one repository-owned job; compatibility must not add a matrix or second job. - The Foundation job uses `ubuntu-24.04`; `ubuntu-latest` remains rejected by executable regression. - CPython 3.12 and 3.13 compatibility executes sequentially after the primary CPython 3.14 quality contracts. +- The compatibility requirement file must match the reviewed SHA-256 before either compatibility install. - Compatibility discovery is package-neutral and contains no Interview Plan or Selection Monitoring switch. - Every discovered owned Python package has both `src/` and `tests/`; incomplete layout is a Foundation failure rather than an accepted skip.