ADR-010: Fixture oracle and atomicity¶
Status¶
Accepted; amended by ADR-012 (F-1), ADR-013 (F-5, F-6) and ADR-014 (F-4, F-5), ADR-050 and ADR-053 (F-2).
Decision¶
The fixture ground truth is written by hand before the code it grades, never recorded from it.
F-1 — Import atomicity: a file is migrated completely or not at all¶
If any finding in a file is withheld, every otherwise-auto one is withheld too, with bail
file_not_fully_migrated and a caused_by naming the bails that fired
(ADR-012), and the file is left exactly as it was.
google.genai has none of the legacy top-level names, so a renamed import beside one
surviving legacy call imports cleanly and raises AttributeError on first use.
F-2 — The manifest gains the new pin as soon as anything migrates, and loses the old one only when nothing needs it¶
manifest_dependency is two edits on one legacy declaration, graded repository-wide. Adding
google-genai is auto once any in-scope file migrates, because a partial migration needs
both distributions. Removing the legacy pin waits, with both pins kept and the files named,
while a file imports the legacy SDK (repo_not_fully_migrated) or imports an undeclared
distribution only the legacy SDK installed (transitive_dependency_in_use), because
un-pinning would break the install. A file matching the byte prefilter that the user's
exclude or a narrowed include removed is named and does not block; one the default
include leaves out blocks. A pack whose new SDK is its legacy distribution has one pin for both
APIs, which moves in the run that migrates every file or not at all
(ADR-053 D6).
F-3 — count_tokens may drop the sampling config, and must not drop the rest¶
The constructor's sampling parameters are dropped from count_tokens with the warning
count_tokens_config_dropped: a token count does not depend on sampling.
system_instruction= is counted, so it refuses the group as
count_tokens_config_carries_semantics; a constructor's tools= refuses it earlier, whatever
the call, as afc_semantics_differ.
F-4 — The closed vocabularies live in the repository¶
Finding.kind, Finding.confidence_reason, the fixture verdict, and the bail and warning
codes are written out in docs/SCAN_VOCABULARY.md and held equal to
models/vocabulary.py, because three fixture defects were members invented where no list could be read.
The attested member is manifest_dependency, not manifest_declaration, and not_a_usage
is a verdict: a prose mention is neither an edit nor a review item.
F-5 — needs_review never emits a hunk, so .after.py needs a label¶
A withheld finding (needs_review, unsupported) names a bail and emits no hunk; any other
names none (ADR-014 D6 exempts model_proposed). Every ground-truth file declares
after_file_is: fix_apply_output (each .after.py is byte-for-byte what fix --apply
writes; ADR-013 D3), human_answer_key (what a person would write, beyond the tool) or
none, so no harness infers whether a hunk is due.
F-6 — configure → Client stays automatic and carries a warning¶
The rewrite is auto, but Client(...) validates the key at construction where configure
did not, so a module-level client whose credential keyword is not set to a non-empty string
literal carries client_constructed_eagerly (ADR-013 D5). Refusing every non-literal key would make
the one rule every repository needs manual.
F-7 — C-22's positional arguments are mapped by index, not bailed¶
Positional constructor arguments are mapped against the legacy order (model_name,
safety_settings, generation_config, tools, tool_config, system_instruction) of 0.8.6, with the
warning positional_args_mapped_by_index; with the order known, a bail would gain nothing.
F-8 — C-18's await is preserved, not inserted, and the branch is automatic¶
The legacy generate_content_async and the new generate_content_stream are coroutine
functions, so runnable legacy code reads
async for x in await model.generate_content_async(p, stream=True); the rewrite keeps the
await, is auto and warns async_stream_await_preserved. Without the await the loop
already raises TypeError, and bails async_stream_await_missing.
Consequences¶
- A partial migration whose tests pass is
partialin BENCHMARK.md, neververified_success. - COVERAGE.md records what the fixtures do not cover.
- The encoding fixtures are
-text -diff;tests/unit/test_fixture_encoding.pyfails on drift.