diff --git a/Cargo.lock b/Cargo.lock index cce311a..b970439 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -747,9 +747,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.190" +version = "0.2.191" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce5d3ddc6d3fa000eb1536d85e147bfe31aacaba692ed6a876f95cb7c855be78" +checksum = "65cd87c9a6d60536580b316ad985726104730a5151c99845f2490428ef91240a" [[package]] name = "libm" diff --git a/README.md b/README.md index 7ae9eea..361129c 100644 --- a/README.md +++ b/README.md @@ -368,15 +368,15 @@ for the algorithms, validity boundaries, and supporting references. - ✅ Error-bounded f64 dot, affine-difference, and determinant filtering plus optional exact signs (`dot_with_errbound`, `dot_difference_with_errbound`, `det_errbound`, `det_sign_exact`) -- ✅ Overflow- and underflow-safe Euclidean vector norms (`norm`) -- ✅ Outward-rounded interval expressions and division-free determinant signs - through D=7, with explicit inconclusive evidence - ✅ Exact determinant values and linear solves via optional arbitrary-precision arithmetic (`det_exact`, `solve_exact`, strict/rounded f64 conversions) - ✅ Explicit algorithms (LU, solve, determinant) - ✅ Inline, stack-backed storage for core types; optional arbitrary-precision exact values allocate as required - ✅ No runtime dependencies by default (optional features may add deps) +- ✅ Outward-rounded interval expressions and division-free determinant signs + through D=7, with explicit inconclusive evidence +- ✅ Overflow- and underflow-safe Euclidean vector norms (`norm`) - ✅ `unsafe` forbidden See [CHANGELOG.md](https://github.com/acgetchell/la-stack/blob/main/CHANGELOG.md) diff --git a/justfile b/justfile index e35ae21..2accb5b 100644 --- a/justfile +++ b/justfile @@ -38,8 +38,9 @@ _ensure-shfmt: _ensure-uv uv run --locked shfmt --version >/dev/null # uv enforces its exact declaration before running the locked CLI. +# Send prerequisite diagnostics to stderr so generated stdout stays clean. _ensure-uv: - uv run --locked --no-sync --no-python-downloads research-repo-tools deps check-uv + uv run --locked --no-sync --no-python-downloads research-repo-tools deps check-uv >&2 _ensure-yamllint: _ensure-uv uv run --locked yamllint --version >/dev/null @@ -468,7 +469,7 @@ release-package: # Approve the benchmark-equipped draft as the authenticated maintainer. release-publish tag: (_release-notes-check tag) - uv run --locked --no-sync research-repo-tools release publish {{ quote(tag) }} + uv run --locked --no-sync research-repo-tools release publish {{ quote(tag) }} --approve # Verify the published GitHub release, required assets, and exact crates.io version. release-verify tag: diff --git a/pyproject.toml b/pyproject.toml index 0f0f7e3..fa60068 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -119,7 +119,7 @@ cargo-nextest = "0.9.148" clippy-sarif = "0.8.0" dprint = "0.63.0" git-cliff = "2.14.2" -rumdl = "0.2.79" +rumdl = "0.3.0" sarif-fmt = "0.8.0" taplo-cli = "0.10.0" typos-cli = "1.51.1" diff --git a/scripts/tests/test_release_publishing.py b/scripts/tests/test_release_publishing.py index e7d8a13..26836ac 100644 --- a/scripts/tests/test_release_publishing.py +++ b/scripts/tests/test_release_publishing.py @@ -163,6 +163,45 @@ def test_real_notes_recipe_checks_generated_body_and_title(tmp_path: Path, misma assert (result.returncode == 0) == (mismatch == "none"), result.stderr +def test_release_notes_stdout_excludes_setup_diagnostics() -> None: + # Include the dependency commands that polluted the generated notes. + script = dry_run(REPO_ROOT, "release-notes", [TAG]).stderr + runner = ( + "uv() {\n" + ' if [[ "$*" == "run --locked --no-sync --no-python-downloads research-repo-tools deps check-uv" ]]; then\n' + " printf '%s\\n' 'fixture setup diagnostic'\n" + ' elif [[ "$*" == "sync --locked --group dev" ]]; then\n' + " return 0\n" + " else\n" + ' [[ "$1 $2 $3 $4 $5" == "run --locked --group dev research-repo-tools" ]] || return 90\n' + " shift 5\n" + f' {shlex.quote(sys.executable)} -m research_repo_tools --root {shlex.quote(str(REPO_ROOT))} "$@"\n' + " fi\n" + "}\n" + ) + result = run_command("bash", ["--noprofile", "--norc", "-euc", runner + script], cwd=REPO_ROOT, check=False) + assert result.returncode == 0, result.stderr + assert result.stdout == changelog.notes(POLICY, TAG)[0] + assert "fixture setup diagnostic" in result.stderr + + +def test_publish_recipe_passes_explicit_approval(monkeypatch: pytest.MonkeyPatch) -> None: + requested: list[str] = [] + + def publish(settings: config.Config, tag: str) -> None: + assert settings.root == REPO_ROOT + requested.append(tag) + + # Exercise the installed argument parser and dispatch, replacing only the + # irreversible publication boundary with an in-memory request recorder. + monkeypatch.setattr(release_publishing, "publish_reviewed_release", publish) + # The publication command follows the separately tested notes precheck. + command = shlex.split(dry_run(REPO_ROOT, "release-publish", [TAG]).stderr.splitlines()[-1]) + assert command[:7] == ["uv", "run", "--locked", "--no-sync", "research-repo-tools", "release", "publish"] + assert main(["--root", str(REPO_ROOT), *command[5:]]) == 0 + assert requested == [TAG] + + def test_workflow_requires_approval_revalidation_and_absence_before_oidc() -> None: workflow = yaml.safe_load(WORKFLOW.read_bytes()) # PyYAML's YAML 1.1 parser reads the Actions `on` key as True.