Skip to content

A generated file is checked against its generator, and two had stopped matching (#1034) - #1124

Merged
Rafael-SOWNet merged 1 commit into
masterfrom
a-generated-file-matches-its-generator
Aug 31, 2026
Merged

A generated file is checked against its generator, and two had stopped matching (#1034)#1124
Rafael-SOWNet merged 1 commit into
masterfrom
a-generated-file-matches-its-generator

Conversation

@Rafael-SOWNet

Copy link
Copy Markdown
Collaborator

Closes #1034.

The issue was right, and it had happened again

Nothing rebuilt the checked-in generated files and compared, so a template could stop matching its output and the build stayed green. EquationSystemFunctionPattern.txt was the first case, repaired by #1029. There was a second one live on master:

TupleToIntervalTest.txt still named MathS.Matrices.Interval, which does not exist. Regenerating TupleToIntervalTest.cs produced eighteen CS0117 errors — measured, not inferred:

TupleToIntervalTest.cs(20,28): error CS0117: 'MathS.Matrices' does not contain a definition for 'Interval'

The generator had drifted twice more: it wrote namespace UnitTest.Extensions where the test project uses AngouriMath.Tests.Extensions, and it had lost the [Trait("Area", …)] every test class here carries so dotnet test --filter can select by area. All three are repaired, and the regenerated file builds and passes its 18 tests.

Two T4 templates produced files that failed the build

The issue proposed excluding the copyright header when diffing, since no template emitted it. That understates it: IDE0073 is an error in this repository, so regenerating either CompilationExtensions.tt or Compile.Linq.Definition.tt produced a file that would not compile.

CompilationExtensions.cs(1,1): error IDE0073: A source file is missing a required header.

So they emit it now instead. That is better than an exclusion on two counts: it fixes a real break rather than agreeing to ignore it, and it means the gate has no exclusions at all — nothing that could quietly grow to hide a real difference, which is the issue's own acceptance criterion 3. MathAllMethods.tt already emitted the header and already reproduced exactly, so this makes the other two match the one that worked. BOM included: that file has none either, and no .editorconfig rule asks for one.

The gate

Sources/Utils/regenerate_all.sh regenerates everything in place, and GeneratedFilesUpToDate.yml runs it and fails on any difference, printing the diff rather than "files differ".

Three details that are deliberate:

  • The template list is read out of AngouriMath.csproj, not written in the script. A list written twice is a list that drifts, and this one would drift in the direction of covering less.
  • Paths resolve from the script's own location, not the working directory — four harnesses in the sibling workspace had a bug where a report wrote where nobody was reading, and it hid staleness for months.
  • t4 is looked up, not assumed. dotnet tool install -g dotnet-t4 installs a binary called t4, so dotnet t4 fails with "You misspelled a built-in dotnet command" — a message that reads as the caller's typo rather than a missing tool.

ANTLR keeps its own job, GrammarUpToDate.yml, because it needs a Java runtime where this needs a dotnet tool — so neither goes red for the other's reason. (That job already exists and already covers the parser, so the issue's fifth row is done.)

Acceptance criteria

  1. Fails when a template is edited without regenerating — demonstrated by pushing exactly that, on demo/generated-files-gate-goes-red, which edits TupleToIntervalTest.txt and nothing else. Locally the same edit gives exit=1 and names Sources/Tests/UnitTests/Convenience/TupleToIntervalTest.cs.
  2. The failure names the file and shows the diff — the step runs git --no-pager diff after the ::error:: lines.
  3. No header exclusion, because there is nothing to exclude any more.
  4. One tool beyond the SDK the other jobs already install.

Failed: 0, Passed: 9098, Skipped: 14 locally on net10.0, with every generated file regenerated from scratch.

🤖 Generated with Claude Code

https://claude.ai/code/session_012sonx8iAspMiwRwokT1Ura

…d matching

Nothing rebuilt the checked-in generated files and compared, so a template could stop matching its
output and the build stayed green -- the file only being discovered to be unregenerable the next
time somebody actually tried. That had already happened once, to
`EquationSystemFunctionPattern.txt`, repaired by #1029.

It had happened twice. `TupleToIntervalTest.txt` still named `MathS.Matrices.Interval`, which does
not exist, so regenerating `TupleToIntervalTest.cs` produced eighteen CS0117 errors -- measured, not
inferred. The generator had also drifted on the namespace, writing `UnitTest.Extensions` where the
test project uses `AngouriMath.Tests.Extensions`, and had lost the `Area` trait every test class
here carries so that `dotnet test --filter` can select by area. All three are repaired.

**And two of the three T4 templates did not emit the copyright header**, which is worse than
cosmetic: IDE0073 is an error in this repository, so regenerating either of them produced a file
that failed the build outright. The issue proposed excluding the header block when diffing; emitting
it is better, because then the generated file is the committed file and there is no exclusion that
could quietly grow to hide a real difference. `MathAllMethods.tt` already emitted it and already
reproduced exactly, so this makes the other two match the one that worked -- BOM included, which
that file does not have either and which no `.editorconfig` rule asks for.

`Sources/Utils/regenerate_all.sh` regenerates everything in place. The three T4 templates are read
out of `AngouriMath.csproj` rather than listed in the script, because a list written twice is a list
that drifts, and this one would drift in the direction of covering less. It resolves paths from its
own location rather than from the working directory, and it looks `t4` up rather than assuming it is
on PATH -- `dotnet tool install -g dotnet-t4` installs a binary called `t4`, so `dotnet t4` fails
with a message that reads as a typo.

`GeneratedFilesUpToDate.yml` runs it and fails on any difference, printing the diff rather than
"files differ". Demonstrated by breaking a template without regenerating its output: the job's diff
step exits 1 and names `TupleToIntervalTest.cs`.

The ANTLR parser keeps its own job, `GrammarUpToDate.yml`, because it needs a Java runtime where
this needs a dotnet tool -- so neither goes red for the other's reason.

Part of #1034.
@Rafael-SOWNet

Copy link
Copy Markdown
Collaborator Author

Criteria 1 and 2, demonstrated on CI rather than locally

#1125 is this branch with one line of Sources/Utils/Utils/TupleToIntervalTest.txt changed and its output not regenerated — nothing else. The gate went red on exactly the step that should catch it:

✓ Regenerate every generated file
X Fail if a committed generated file is not what its generator produces

The failing run. Its output, which is criterion 2 — the file is named and the diff is shown, not "files differ":

##[error]A checked-in generated file does not match its generator.
##[error]Run Sources/Utils/regenerate_all.sh and commit the result.
 Sources/Tests/UnitTests/Convenience/TupleToIntervalTest.cs | 12 ++++++------
diff --git a/Sources/Tests/UnitTests/Convenience/TupleToIntervalTest.cs ...
-            MathS.Interval(3, 4.5),
+            MathS.Interval(4.5, 3),

And the same job on this PR passes in 1m25s, so the gate starts from a clean baseline rather than from a diff nobody can fix.

#1125 is closed and its branch will be deleted; it exists only as the evidence for this.

@Rafael-SOWNet
Rafael-SOWNet merged commit 7a68049 into master Aug 31, 2026
32 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Nothing checks that a generated file still matches its generator

1 participant