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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,11 @@
- Added sentinel delegation tests, Rust edge-case tests, seeded true-trait
recovery tests, score-equation checks, and APA 7th CAT doctoring.

#### Automatic backend preserves Rust numerical ownership

- Changed `backend="auto"` so a missing compiled Rust core fails closed instead of silently selecting the independent NumPy reference implementation.
- Kept explicit `backend="numpy"` as an explicit reference/parity choice while preserving automatic Rust resolution and Rust CPU/GPU device fallback semantics.

#### Current support-policy version line

- Aligned the public security and support policies with the released `0.7.x` pre-1.0 package line instead of the obsolete `0.1.x` policy.
Expand Down Expand Up @@ -312,6 +317,11 @@

### Fixed

#### Serving bundle export requires Rust core

- `export_serving_bundle` fails closed when the compiled Rust core is unavailable
instead of shipping incomplete bundles with null `eapsum_tables`.

#### Fail early for unimplemented estimator identities

- Restricted the public `FitConfig.estimator` vocabulary to the implemented `jmle` and `mmle` fitting paths, so unsupported `em` and `bayes` requests fail during configuration validation instead of entering a fitting path that later raises `NotImplementedError`.
Expand All @@ -331,6 +341,10 @@

- Validate automated-test-assembly content-label shape and string element types before item-information evaluation, rejecting arbitrary object labels without invoking caller-controlled `__str__`/`__repr__` callbacks while preserving accepted Python/NumPy string labels and existing assembly numerics.

#### Bound PR queue Git metadata lookup

- PR queue governance now bounds the `git rev-parse HEAD` subprocess and fails closed with a stable timeout error instead of allowing a hung local Git child to stall the evidence pipeline.

#### Diagnostics-report focus and contrast preservation

- Revealed the visually hidden diagnostics-report skip link for every actual `:focus` state while retaining the explicit `:focus-visible` treatment and strong outline.
Expand All @@ -343,6 +357,10 @@

- Stopped reflecting caller-controlled invalid response values in `person_fit_np()` validation errors while preserving the failing matrix coordinate and the complete-data 0/1 response contract.

#### Bounded mixed item-model validation

- Bounded `item_models` iterable consumption to at most one look-ahead entry beyond the calibrated item count, rejected arbitrary non-string model controls before caller `__str__`/`__repr__` hooks can execute, and removed rejected model content from public validation errors while preserving accepted aliases and Rust-owned calibration numerics.

#### Model-comparison control validation hardening

- Reject hostile semantic/numeric control objects before caller-defined `__str__`, `__repr__`, or `__float__` callbacks can execute, while preserving accepted relation identities, built-in/NumPy scalar semantics, and Rust-owned model-comparison arithmetic.
Expand Down
5 changes: 5 additions & 0 deletions docs/changelog.d/707-pr-queue-git-metadata-timeout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Bound PR queue Git metadata lookup

## Fixed

- PR queue governance now bounds the `git rev-parse HEAD` subprocess and fails closed with a stable timeout error instead of allowing a hung local Git child to stall the evidence pipeline.
6 changes: 5 additions & 1 deletion scripts/build_pr_queue_governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
_GH_TRANSIENT_STATUS_RE = re.compile(r"\bHTTP (?:502|503|504)\b", re.IGNORECASE)
_GH_JSON_MAX_ATTEMPTS = 3
_GH_JSON_RETRY_SLEEP_SECONDS = 0.5
GIT_METADATA_TIMEOUT_SECONDS = 5


def _parse_datetime(value: str) -> datetime:
Expand Down Expand Up @@ -122,15 +123,18 @@ def _resolve_path(value: str | Path, *, base: Path) -> Path:


def _source_commit(repo_root: Path) -> str:
"""Return the checked-out commit SHA, or ``unknown`` when unavailable."""
"""Return the checked-out commit SHA, failing closed on a hung Git child."""
try:
completed = subprocess.run(
["git", "rev-parse", "HEAD"],
cwd=repo_root,
capture_output=True,
text=True,
check=True,
timeout=GIT_METADATA_TIMEOUT_SECONDS,
)
except subprocess.TimeoutExpired as exc:
raise RuntimeError("source commit lookup timed out") from exc
except Exception:
return "unknown"
return completed.stdout.strip() or "unknown"
Expand Down
40 changes: 40 additions & 0 deletions tests/test_pr_queue_governance_git_timeout.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
"""Fail-first reliability contracts for PR queue governance Git metadata reads."""

from __future__ import annotations

import importlib.util
import subprocess
from pathlib import Path

import pytest


def _load_governance():
"""Load the PR queue governance script as a module for boundary tests."""
script = Path(__file__).resolve().parents[1] / "scripts" / "build_pr_queue_governance.py"
spec = importlib.util.spec_from_file_location("build_pr_queue_governance", script)
assert spec is not None
module = importlib.util.module_from_spec(spec)
assert spec.loader is not None
spec.loader.exec_module(module)
return module


def test_source_commit_bounds_git_metadata_lookup(monkeypatch, tmp_path: Path) -> None:
"""A hung ``git rev-parse`` must fail closed under a package-owned deadline."""
module = _load_governance()
observed_timeouts: list[object] = []

def timeout_run(*args, **kwargs):
observed_timeouts.append(kwargs.get("timeout"))
raise subprocess.TimeoutExpired(
cmd=args[0] if args else kwargs.get("args", ["git", "rev-parse", "HEAD"]),
timeout=kwargs.get("timeout"),
)

monkeypatch.setattr(module.subprocess, "run", timeout_run)

with pytest.raises(RuntimeError, match="source commit lookup timed out"):
module._source_commit(tmp_path)

assert observed_timeouts == [module.GIT_METADATA_TIMEOUT_SECONDS]
Loading