degenbot.build_info =================== .. py:module:: degenbot.build_info .. autoapi-nested-parse:: Build identity for the Rust extension — the stale-`.so` detector. Every compile of `degenbot_rs` runs `rust/crates/shells/degenbot-python/build.rs`, which computes a fingerprint (content hash) of the crate's sources and embeds `` — the counter advancing only when the fingerprint changes — into both the compiled library and the repo receipt file (`.build-number`). This module reads that identity back out of the *installed* `degenbot._ffi` and compares it against the receipt, so a stale cached artifact (the maturin/uv failure mode documented in AGENTS.md "Rebuilding the Rust `.so` after edits") is detected instead of silently shipped. Comparing fingerprints (not just numbers) means a no-change recompile (`cargo test`, `clippy`, feature variants) never false-positives, while any artifact actually built from different sources carries a different fingerprint. Usage: # one-line check (exit 0 fresh / 1 stale) uv run --no-sync python -m degenbot.build_info # or: just verify-build-fresh # from Python from degenbot.build_info import verify_build_fresh verify_build_fresh() # raises BuildStaleError on a stale extension Package Contents ---------------- .. py:function:: installed_build_number() -> int Return the build counter baked into the installed `degenbot._ffi`. 0 means `build.rs` did not run (the tagging is broken) — callers should treat 0 as "unknown", never as "old-but-plausible". :returns: The monotonic build counter; advances only when the crate's source content changes (see `build.rs`). .. py:function:: installed_fingerprint() -> str | None Return the source fingerprint baked into the installed extension. None when the running extension predates fingerprint tagging (or the `_ffi` surface lacks it — itself a sign of a stale artifact under an old build system). :returns: The 16-hex-char fingerprint string, or None when unavailable. .. py:class:: Receipt The repo-side `` receipt from `.build-number`. .. py:attribute:: count :type: int .. py:attribute:: fingerprint :type: str | None .. py:function:: read_receipt() -> Receipt | None Read the latest repo receipt. Only an editable/checkout install has the receipt next to the Rust sources; published wheels and a fresh clone without a first build get None, and every freshness check here is a no-op there. :returns: The `Receipt`, or None when unavailable. .. py:exception:: BuildStaleError Bases: :py:obj:`RuntimeError` The installed Rust extension predates the latest build of the crate. .. py:function:: build_is_fresh() -> bool Report whether the installed extension matches the repo receipt. Returns True whenever there is no ground truth to compare against (no receipt file, non-checkout install): absence of evidence is not staleness. With a fingerprint on both sides, identity is compared; the count only breaks ties for legacy/pre-fingerprint states. :returns: True if the installed extension is no older than the receipt. .. py:function:: verify_build_fresh() -> None Fail loudly if the installed `degenbot._ffi` is stale. :raises BuildStaleError: the installed extension predates the latest build. .. py:function:: main() -> int Run the `python -m degenbot.build_info` CLI. :returns: 0 when the extension is fresh (or no receipt exists), 1 when stale.