Current behavior
_check_version (src/hflow/build_ai_vlm_checks.py:652-685) derives the version identity stamped into every Build AI check run. The OpenAI-compatible branch includes endpoint, model, response_format, temperature, and max_tokens. It excludes max_retries — validated at :164-167, defaulted at :143, and live at :715, where it is passed into the OpenAI client and decides whether transient errors become retried requests or terminal failures. The hosted branch includes only the execution label and endpoint; it excludes request_timeout_seconds — validated at :190-195 and live at :626 as the HTTP timeout.
Controlled result
Two executions that differ only in max_retries, and two that differ only in request_timeout_seconds, run through the real _check_version:
=== OpenAI path: same version identity, different completeness ===
max_retries=0 -> build-ai-single-frame-v1-eabed1f2e257cc07
max_retries=5 -> build-ai-single-frame-v1-eabed1f2e257cc07
same version: True
=== hosted path: same version identity, different completeness ===
request_timeout_seconds=1.0 -> build-ai-single-frame-v1-ac6fa96b9b859bec
request_timeout_seconds=60.0 -> build-ai-single-frame-v1-ac6fa96b9b859bec
same version: True
Why this is observable semantics, not reliability noise
The distinction that decides this issue: sampling noise changes the value of an answer; retries and timeouts change which items produce answers at all.
Temperature, which is already in the contract, adds sampling noise to a response that exists either way. max_retries and request_timeout_seconds change the failure mode and the completeness of a corpus: with max_retries=0, one transient 500 turns into a failed check run with no result; with max_retries=5, the same request becomes a parsed prediction. A short timeout drops slow-but-valid responses that a long timeout includes. Two corpora evaluated under these different settings have systematically different result sets — different error rates, different episode coverage — and a buyer comparing them under one version identity is told they are comparable when they are not.
That is the rule stated on #365: if the effective measurement path changes observable semantics, version and cache/provenance identity must change with it. The contract's own inclusion of temperature and max_tokens already establishes that behavioral knobs are version-worthy; these two knobs meet the same standard.
What to build
Open call, not assumed:
- Add the fields to the contract:
max_retries in the OpenAI-compatible branch, request_timeout_seconds in the hosted branch. The precedent is internal (temperature, max_tokens), so this is a consistency fix rather than a design change.
- Record the behavior as evidence instead: leave the contract alone and stamp attempts/timeouts as measurements on every check run, so the difference is visible in the record without moving identity.
The first matches the contract's own logic; the second matches a "retries are infrastructure" reading. What cannot stand is the current middle: knobs that change outcomes, invisible to both the identity and the record.
Definition of done
- Every execution knob that changes which items produce results is either in the version contract or recorded per run as a measurement.
- Two configurations differing only in the newly covered fields produce different version identities, pinned by a test through the real
_check_version.
- Configurations that are identical in every covered field keep their existing version, so unchanged methodology does not silently invalidate.
- The hosted and OpenAI branches treat the rule symmetrically.
- The demo above lands as a test.
Non-goals
- Changing the
max_retries or request_timeout_seconds defaults
- Changing how temperature participates in the contract
- Restructuring
step_version_from_contract or the fingerprint machinery
Validation
uv run ruff check --fix
uv run ruff format
uv run ty check
uv run pytest -q tests/test_build_ai_vlm_checks.py
uv run pytest -q
Current behavior
_check_version(src/hflow/build_ai_vlm_checks.py:652-685) derives the version identity stamped into every Build AI check run. The OpenAI-compatible branch includes endpoint, model, response_format, temperature, and max_tokens. It excludesmax_retries— validated at :164-167, defaulted at :143, and live at :715, where it is passed into the OpenAI client and decides whether transient errors become retried requests or terminal failures. The hosted branch includes only the execution label and endpoint; it excludesrequest_timeout_seconds— validated at :190-195 and live at :626 as the HTTP timeout.Controlled result
Two executions that differ only in
max_retries, and two that differ only inrequest_timeout_seconds, run through the real_check_version:Why this is observable semantics, not reliability noise
The distinction that decides this issue: sampling noise changes the value of an answer; retries and timeouts change which items produce answers at all.
Temperature, which is already in the contract, adds sampling noise to a response that exists either way.
max_retriesandrequest_timeout_secondschange the failure mode and the completeness of a corpus: withmax_retries=0, one transient 500 turns into a failed check run with no result; withmax_retries=5, the same request becomes a parsed prediction. A short timeout drops slow-but-valid responses that a long timeout includes. Two corpora evaluated under these different settings have systematically different result sets — different error rates, different episode coverage — and a buyer comparing them under one version identity is told they are comparable when they are not.That is the rule stated on #365: if the effective measurement path changes observable semantics, version and cache/provenance identity must change with it. The contract's own inclusion of
temperatureandmax_tokensalready establishes that behavioral knobs are version-worthy; these two knobs meet the same standard.What to build
Open call, not assumed:
max_retriesin the OpenAI-compatible branch,request_timeout_secondsin the hosted branch. The precedent is internal (temperature, max_tokens), so this is a consistency fix rather than a design change.The first matches the contract's own logic; the second matches a "retries are infrastructure" reading. What cannot stand is the current middle: knobs that change outcomes, invisible to both the identity and the record.
Definition of done
_check_version.Non-goals
max_retriesorrequest_timeout_secondsdefaultsstep_version_from_contractor the fingerprint machineryValidation