"""The agent's self-report: a derived version, and a build id kept apart from it. The agent's version used to be a literal in `app.py` that an author was asked to bump on every change. Nobody did, so the September image printed the same `2026-07-17.1` as the July one — the one surface meant to answer *"did my pull work?"* gave the same answer either way. These pin the two properties that make the replacement worth having: the displayed string degrades honestly when a build carries no stamp, and the value the page COMPARES is not the value it SHOWS (rule 149). `build_info` is stdlib-only on purpose, so the suite can import it — `app` is unimportable here (torch, transformers, ultralytics are not in the CI image, which is why build.yml lints the agent and then only `compileall`s it). """ from __future__ import annotations from pathlib import Path import pytest from agent.fc_agent import build_info APP = Path(__file__).resolve().parents[1] / "agent" / "fc_agent" / "app.py" def _stamp(monkeypatch, *, version="", channel="", revision=""): monkeypatch.setattr(build_info, "FC_VERSION", version) monkeypatch.setattr(build_info, "FC_CHANNEL", channel) monkeypatch.setattr(build_info, "FC_REVISION", revision) # --- what a person reads ----------------------------------------------------- def test_an_unstamped_build_says_unknown_rather_than_nothing(monkeypatch): """A blank in the meta line reads as "no version", which is a different and false claim from "this build does not carry one". Same posture the web image's build_info takes, for the same reason.""" _stamp(monkeypatch) assert build_info.display_version() == "unknown" def test_the_channel_rides_beside_the_version_not_inside_it(monkeypatch): """Rule 149. The channel is a sibling field; a `-dev` folded into the name is issue #2993's exact failure. Rendering it in parentheses is display, not encoding — `FC_VERSION` itself never carries it, which the next test is what actually holds.""" _stamp(monkeypatch, version="2026.09.24.1052", channel="dev") assert build_info.display_version() == "2026.09.24.1052 (dev)" def test_a_version_with_no_channel_is_the_bare_version(monkeypatch): _stamp(monkeypatch, version="2026.09.24.1052") assert build_info.display_version() == "2026.09.24.1052" # --- what the page decides on ------------------------------------------------ def test_the_build_id_prefers_the_revision(monkeypatch): """Two builds of the same commit ARE the same agent and must not prompt a reload; two different commits always differ here, even when they land in the same minute and derive one version name. The revision is the only one of the three that is true of the content rather than of the clock.""" _stamp(monkeypatch, version="2026.09.24.1052", revision="a3071a754907") assert build_info.build_id() == "a3071a754907" def test_the_build_id_falls_back_to_the_version_then_to_a_constant(monkeypatch): _stamp(monkeypatch, version="2026.09.24.1052") assert build_info.build_id() == "2026.09.24.1052" _stamp(monkeypatch) # A constant, deliberately — see build_info.build_id. A per-process nonce # would make every ordinary container RESTART claim a new version had # arrived, a false positive on the surface the banner exists to keep # trustworthy. assert build_info.build_id() == "local" def test_the_displayed_string_is_never_the_compared_one(monkeypatch): """The property both of the above serve, stated once on its own. Folding these together is how the version acquires a second job and then cannot be changed without breaking the reload banner.""" _stamp(monkeypatch, version="2026.09.24.1052", channel="dev", revision="a3071a754907") assert build_info.display_version() != build_info.build_id() # --- the page wires them to the right places --------------------------------- # # Read as SOURCE, not imported: `app` pulls the agent's GPU stack. Asserting on # what is PRESENT rather than on what is absent, deliberately — a guard that # greps for the absence of a pattern trips over the comment explaining why the # pattern is gone (lesson #4365), and app.py's new comment names the old # literal it replaced. @pytest.mark.parametrize( "marker, why", [ ( 'id=build>__VERSION__', "the meta line must show the human-readable version", ), ( 'const PAGE_BUILD="__BUILD_ID__"', "the staleness check must compare the build id, not the version", ), ], ) def test_the_control_page_shows_one_value_and_compares_the_other(marker, why): assert marker in APP.read_text(), why