mod miner¶
- module miner¶
Ring-corpus miner helpers for the reproduction grind.
A mechanical miner that turns a merged upstream PR into a
bumpreproduction fixture pair has to reject two real shapes found while hand-mining ~10 merged easybuilders/easybuild-easyconfigs bumps: batch “toolchain refresh” PRs that mix a toolchain-generation definition with application recipes in one diff, and non-linear version history where the PR’s target version is not actually the newest at that toolchain generation (a backfill, not a clean next-version bump). Both checks operate on data the miner already has once it has parsed a candidate file and listed the merge-base tree, so neither needs new I/O.Functions
- fn compare_reproduction(emitted: &str, target: &str) -> ReproComparison¶
Score
emittedagainsttargetand keep the raw diff for display.
- fn is_backfill(candidate_version: &str, existing_versions: &[String]) -> bool¶
True when
candidate_versionis not the highest version already present inexisting_versionsfor the same package and toolchain generation, at the PR’s merge-base commit.A miner mining “PR bumps package X to version Y” candidates has to distinguish a clean next-version bump (Y is newer than anything already in the tree at that generation) from a backfill (an older release added alongside a newer one that already merged separately). Scoring a backfill as a bump-reproduction target compares the wrong two files. Version ordering uses
cmp_version, not a string sort, so"4.2.1"correctly outranks"3.31.11"(a plain string compare would rank them the other way around, since ‘4’ > ‘3’ only holds for the leading character and a string sort does not parse dotted version segments numerically).
- fn is_toolchain_meta_recipe(recipe: &ResolvedEasyconfig) -> bool¶
True when
recipedefines a toolchain generation itself (for examplegompi-2026.1.eb,easyblock = 'Toolchain',moduleclass = 'toolchain') rather than an application built with one.Toolchain-definition recipes are not
bumptargets: bumping an application recipe assumes a toolchain generation to move it to already exists, and a toolchain-definition recipe is that generation, not a consumer of it. A miner that does not filter these out will try to “reproduce” a recipe that never had a previous-generation counterpart to bump from in the first place.Checks
easyblockfirst since it is the more direct signal (the literal easyblock class EasyBuild uses to build a toolchain definition);moduleclassis a secondary check for recipes where the parser did not resolve aneasyblockvalue.
- fn normalize_for_scoring(text: &str) -> String¶
Strip from
texteverything that cannot change what EasyBuild builds: comments, trailing whitespace, and runs of blank lines.Two easyconfigs with the same normalization build the same thing, so this is the function that draws the
ReproScore::Semanticboundary, and the reason scoring runs on it rather than on raw text: a raw diff reports a deleted commented-out line and a lost blank line as loudly as a dropped patch, which flattens the very distinction the ladder exists to make.What it removes:
comment-only lines, dropped whole rather than left as blanks, so a deleted commented-out block does not resurface as whitespace noise;
the
# ...tail of a code line, with the code before it kept;trailing whitespace on any line not ending inside a string literal;
runs of blank lines, collapsed to one, and blank lines at either end.
What it keeps: everything inside a string literal, verbatim. A triple-quoted
descriptioncarries its own blank lines, indentation and#characters into the built module, so normalizing them away would call two different module descriptions equivalent.
- fn score_reproduction(emitted: &str, target: &str) -> ReproScore¶
Score
emittedagainst the real mergedtarget.EXACTis raw equality, so it still means what a reader assumes it means; normalization only decidesSEMANTICagainstMATERIAL.
Enums
- enum DiffTag¶
Which side of the comparison a diff line came from.
- Removed¶
Present in the real merged target, absent from the emitted file.
- Added¶
Present in the emitted file, absent from the target.
- enum ReproScore¶
Where a reproduction attempt landed on the scoreboard ladder.
The two ladder rungs missing here,
ERRORandexcluded, are not outcomes of comparing two files:ERRORmeans no file was produced to compare, andexcludedmeans the file was never a scoreable bump (a toolchain meta-recipe, a backfill, a package with no prior recipe). Both are decided before this comparison runs, and both are recorded with their reason rather than dropped.- Exact¶
Byte-identical to the merged file.
- Semantic¶
Differs only in ways that cannot change the build: comments, trailing whitespace, blank-line runs.
- Material¶
A real difference in what would be built.
Implementations
- impl ReproScore¶
Functions
- fn as_str(self) -> &'static str¶
The scoreboard spelling, for a
| File | Score | Note |row.
Traits implemented
- impl fmt::Display for ReproScore¶
Structs and Unions
- struct DiffLine¶
One differing line of the raw (un-normalized) diff.
- text: String¶
The line, exactly as it appears in that file.
- struct ReproComparison¶
A scored reproduction: the ladder rung, plus the raw diff behind it.
- score: ReproScore¶
The ladder rung, decided on normalized text.
- raw_diff: Vec<DiffLine>¶
Every line that differs between the raw files, in file order.
Deliberately raw: a
SEMANTICverdict is only auditable if the reader can see the comment and whitespace differences the score forgave and judge that call for themselves.
Implementations
- impl ReproComparison¶
Functions
- fn render_raw_diff(&self) -> String¶
The raw diff as text, one
-/+line per difference.-lines are the real merged target,+lines are what the bump emitted.