RepoFileAdoptionTests' adopter census cannot see a qualified call to either repo-file reader, so TheLfReadingPins_AreExactlyTheOnesDeclaredHere — an exact-set equality — passes while an undeclared LF-reading file exists in the tree today.
The two regexes, and what they miss
Darling/Darling.Tests/RepoFileAdoptionTests.cs:
private static readonly Regex RawCall = new(
@"(?<![\w.])ReadRepoFile\s*\(", RegexOptions.Compiled);
private static readonly Regex LfCall = new(
@"(?<![\w.])ReadRepoFileLf\s*\(", RegexOptions.Compiled);
The lookbehind excludes a preceding ., which is what stops ReadRepoFileLf( being double-counted as a raw call. It also makes the qualified spelling invisible to both:
| spelling |
RawCall |
LfCall |
ReadRepoFile( |
true |
false |
RepoFile.ReadRepoFile( |
false |
false |
ReadRepoFileLf( |
false |
true |
RepoFile.ReadRepoFileLf( |
false |
false |
And the raw-adopter decision compounds it — a file is raw only when RawCall.Matches(code).Count > LfCall.Matches(code).Count. With qualified calls both counts are 0, so 0 > 0 is false and the file is neither kind of adopter. It is not miscategorised; it is absent.
The declaration census is unaffected and worth stating so the fix is scoped: that pattern uses \bReadRepoFile(?:Lf)?\s*\( with a word boundary rather than the lookbehind, so ExactlyOneFile_DeclaresTheSharedRepoFileReader still works. Only call sites are blind.
There are TWO live instances, and they break different assertions
Measured on origin/dev (01fdeae92), both surviving comment and string stripping:
| file |
form |
lines |
breaks |
RepoFileResolutionEquivalenceTests.cs |
RepoFile.ReadRepoFileLf( |
164, 184 |
the LF exact-set equality |
PostgresCancelOriginTests.cs (added by #3127) |
RepoFile.ReadRepoFile( |
304, 342 |
the adopter floor |
They are not the same defect twice. The LF caller makes TheLfReadingPins_AreExactlyTheOnesDeclaredHere pass with an undeclared LF adopter in the tree. The raw caller does not enter any declared set, but it does not count toward adopters.Length >= 30 either — so the floor is measured against an undercount that is now growing, since #3127 added to it yesterday.
The LF instance passes for the wrong reason
Darling/Darling.Tests/RepoFileResolutionEquivalenceTests.cs makes two qualified LF calls that survive comment and string stripping:
164: var text = lf ? RepoFile.ReadRepoFileLf(segments) : RepoFile.ReadRepoFile(segments);
184: Assert.Throws<FileNotFoundException>(() => RepoFile.ReadRepoFileLf(missing));
It is not in s_lfReaders (eight entries, and this is not one), and the set equality passes anyway.
Its exclusion is substantively correct — it is the equivalence test for the reader, parameterised over both forms, and it normalises line endings itself at line 171 (onDisk.Replace("\r\n", "\n", ...)) rather than relying on LF anchors. So the right file is excluded for the wrong reason: the census cannot see it, not that it isn't LF-anchored.
Why that matters rather than being a curiosity
A future pin using the qualified LF form with multi-line anchors would be invisible to the set equality, so the assertion would pass while that pin sat undeclared — which is precisely the drift this class exists to catch. The guard would report the tree adopted correctly while it hadn't.
That is the class's own subject turned on itself. Its summary enumerates its known blind spots and does not mention this one.
Secondary, no live risk: the adopters.Length >= 30 floor is measured against the same undercount. It reads 38 today, so the floor is satisfied with margin, but the figure it is satisfied by is smaller than the truth.
Suggested direction
- Count qualified and unqualified separately rather than excluding
. from the match. The lookbehind exists to stop the Lf spelling being double-counted as raw — a real problem, since the name is a prefix — but that is a disambiguation need, and it is being solved by making a whole legal form unmatchable. Match (?:RepoFile\.)?ReadRepoFileLf\s*\( and (?:RepoFile\.)?ReadRepoFile\s*\( and keep the existing count comparison to separate them.
- Then re-check the declared set, because
RepoFileResolutionEquivalenceTests.cs will become visible and must be either declared or excluded on its actual grounds — that it normalises line endings itself. If it is excluded, the exclusion needs to be expressible in the assertion rather than accidental.
- Add the qualified form to the summary's blind-spot list if any part of it survives.
Acceptance criteria, both arms:
- a file making only
RepoFile.ReadRepoFileLf( calls is seen by the census, and the set equality reds if it is undeclared;
- the existing eight declared readers still satisfy the equality, and no currently-passing adopter becomes miscategorised.
The second arm matters: a fix that simply drops the lookbehind reintroduces the double-count the lookbehind was added to prevent, which would classify every LF reader as also a raw one.
Related
RepoFileAdoptionTests' adopter census cannot see a qualified call to either repo-file reader, soTheLfReadingPins_AreExactlyTheOnesDeclaredHere— an exact-set equality — passes while an undeclared LF-reading file exists in the tree today.The two regexes, and what they miss
Darling/Darling.Tests/RepoFileAdoptionTests.cs:The lookbehind excludes a preceding
., which is what stopsReadRepoFileLf(being double-counted as a raw call. It also makes the qualified spelling invisible to both:RawCallLfCallReadRepoFile(RepoFile.ReadRepoFile(ReadRepoFileLf(RepoFile.ReadRepoFileLf(And the raw-adopter decision compounds it — a file is raw only when
RawCall.Matches(code).Count > LfCall.Matches(code).Count. With qualified calls both counts are0, so0 > 0is false and the file is neither kind of adopter. It is not miscategorised; it is absent.The declaration census is unaffected and worth stating so the fix is scoped: that pattern uses
\bReadRepoFile(?:Lf)?\s*\(with a word boundary rather than the lookbehind, soExactlyOneFile_DeclaresTheSharedRepoFileReaderstill works. Only call sites are blind.There are TWO live instances, and they break different assertions
Measured on
origin/dev(01fdeae92), both surviving comment and string stripping:RepoFileResolutionEquivalenceTests.csRepoFile.ReadRepoFileLf(PostgresCancelOriginTests.cs(added by #3127)RepoFile.ReadRepoFile(They are not the same defect twice. The LF caller makes
TheLfReadingPins_AreExactlyTheOnesDeclaredHerepass with an undeclared LF adopter in the tree. The raw caller does not enter any declared set, but it does not count towardadopters.Length >= 30either — so the floor is measured against an undercount that is now growing, since #3127 added to it yesterday.The LF instance passes for the wrong reason
Darling/Darling.Tests/RepoFileResolutionEquivalenceTests.csmakes two qualified LF calls that survive comment and string stripping:It is not in
s_lfReaders(eight entries, and this is not one), and the set equality passes anyway.Its exclusion is substantively correct — it is the equivalence test for the reader, parameterised over both forms, and it normalises line endings itself at line 171 (
onDisk.Replace("\r\n", "\n", ...)) rather than relying on LF anchors. So the right file is excluded for the wrong reason: the census cannot see it, not that it isn't LF-anchored.Why that matters rather than being a curiosity
A future pin using the qualified LF form with multi-line anchors would be invisible to the set equality, so the assertion would pass while that pin sat undeclared — which is precisely the drift this class exists to catch. The guard would report the tree adopted correctly while it hadn't.
That is the class's own subject turned on itself. Its summary enumerates its known blind spots and does not mention this one.
Secondary, no live risk: the
adopters.Length >= 30floor is measured against the same undercount. It reads 38 today, so the floor is satisfied with margin, but the figure it is satisfied by is smaller than the truth.Suggested direction
.from the match. The lookbehind exists to stop theLfspelling being double-counted as raw — a real problem, since the name is a prefix — but that is a disambiguation need, and it is being solved by making a whole legal form unmatchable. Match(?:RepoFile\.)?ReadRepoFileLf\s*\(and(?:RepoFile\.)?ReadRepoFile\s*\(and keep the existing count comparison to separate them.RepoFileResolutionEquivalenceTests.cswill become visible and must be either declared or excluded on its actual grounds — that it normalises line endings itself. If it is excluded, the exclusion needs to be expressible in the assertion rather than accidental.Acceptance criteria, both arms:
RepoFile.ReadRepoFileLf(calls is seen by the census, and the set equality reds if it is undeclared;The second arm matters: a fix that simply drops the lookbehind reintroduces the double-count the lookbehind was added to prevent, which would classify every LF reader as also a raw one.
Related
DarlingPathFilterGateTestsuses the unqualified form viausing static, so it is counted and declared, and every pre-flight that came backTruedid so legitimately.