Skip to content

The Build AI example's run fingerprint excludes max_retries, so two runs with different coverage share one output directory #422

Description

@kstonekuan

#411 fixed this in src/hflow/build_ai_vlm_checks.py yesterday: max_retries changes which items produce answers, so it belongs in the version identity. The Build AI evaluation example has the same gap in its own run fingerprint, and it was not touched.

max_retries is recorded but sits outside the contract that gets hashed:

examples/build_ai_evaluation/evaluate.py:509   result_contract = {
                                                   ... "temperature", "max_tokens", ...
examples/build_ai_evaluation/evaluate.py:524   }
examples/build_ai_evaluation/evaluate.py:528   "fingerprint": hflow.fingerprint_contract(result_contract),
examples/build_ai_evaluation/evaluate.py:532   "max_retries": configuration.max_retries,   <- outside result_contract

It reaches the real request at :359, so it is live rather than decorative.

Why it matters here specifically

The fingerprint is not just a label. It gates output-directory reuse:

examples/build_ai_evaluation/evaluate.py:564
        if existing_metadata.fingerprint != current_metadata.fingerprint:
            raise ValueError(
                f"{metadata_path} describes a different experiment; choose another --output"
            )

So a run with max_retries=0 and a run with max_retries=5 are currently judged the same experiment and allowed to append to one output directory. Under retries a transient 500 becomes a parsed prediction; without them it becomes a failed row. The two runs have systematically different coverage, and the guard that exists to stop incompatible experiments mixing does not see the difference.

The documentation states the current behaviour accurately, which is how it stayed invisible:

docs/how-to/run-build-ai-evaluation.md:315
    the endpoint, model, prompt contents, schema mode, temperature, token limit,
    selected rows, sources, and tasks

What to do

Move max_retries into result_contract, and add it to that documented list.

Do not move worker_count. It is excluded for a good reason and the distinction is the interesting part of this issue: parallelism changes how fast the rows are evaluated, not which rows produce answers. Two runs differing only in worker count are genuinely the same experiment. api_key_environment_variable stays out for the same kind of reason: it names where a credential is read from, not what the model does.

Pattern to copy

#411, which made exactly this argument and this change one layer in. Its tests are the shape to follow: one asserting two configurations differing only in max_retries produce different fingerprints, and one asserting a configuration identical in every covered field keeps its fingerprint.

Definition of done

  1. Two configurations differing only in max_retries produce different fingerprints, pinned by a test.
  2. A configuration identical in every covered field keeps the fingerprint it has, so unchanged methodology is not invalidated. Worth a recorded value rather than comparing one config to itself; see the golden pins added to tests/test_build_ai_vlm_checks.py in fix(build-ai): cover completeness knobs in the check version contract #411 for why that distinction matters.
  3. worker_count still does not participate, with a comment saying why.
  4. docs/how-to/run-build-ai-evaluation.md:315 lists the field.
  5. Existing run directories will stop matching, which is correct. Say so in the PR.

Validation

This lives in a workspace example, so it has its own project:

uv run --locked --project examples/build_ai_evaluation ruff check examples/build_ai_evaluation
uv run --locked --project examples/build_ai_evaluation ruff format --check examples/build_ai_evaluation
uv run --locked --project examples/build_ai_evaluation ty check --project examples/build_ai_evaluation --extra-search-path . examples/build_ai_evaluation
uv run --locked --project examples/build_ai_evaluation pytest -q examples/build_ai_evaluation/tests

Then the root gate from CONTRIBUTING.md.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomershelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions