Structured build diagnostics - #1012
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #1012 +/- ##
==========================================
- Coverage 71.72% 70.89% -0.84%
==========================================
Files 370 377 +7
Lines 20287 20776 +489
Branches 2686 2711 +25
==========================================
+ Hits 14551 14729 +178
- Misses 4670 4975 +305
- Partials 1066 1072 +6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
ddaspit
left a comment
There was a problem hiding this comment.
@ddaspit reviewed 31 files and all commit messages, and made 19 comments.
Reviewable status: all files reviewed, 19 unresolved discussions (waiting on Enkidu93).
a discussion (no related file):
Are you planning on adding unit tests? And yes, we will want to add a page for the diagnostics to the wiki page. It would probably be good to have a link to the wiki page in the Swagger docs.
src/Serval/src/Serval.Translation/Dtos/ExecutionDataDto.cs line 14 at r1 (raw file):
[Obsolete] public IReadOnlyList<string> Warnings { get; init; } = []; public IReadOnlyList<DiagnosticDto> Diagnostics { get; init; } = [];
This should be optional.
src/Machine/src/Serval.Machine.Shared/Services/EchoPreprocessBuildJob.cs line 59 at r1 (raw file):
sourceLanguageTag, targetLanguageTag, true,
Make the parameter name explicit.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 475 at r1 (raw file):
.Select(b => new Diagnostic { Code = "MODEL-004",
I think this is supposed to be MODEL-003.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 479 at r1 (raw file):
Severity = Models.DiagnosticSeverity.Warn, Message = $"The average pretranslation model confidence {b.averageConfidence} in book {b.bookId} is unusually low for the base model {ModelName}",
This confidence should be formatted.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 488 at r1 (raw file):
}); if (badBookConfidences.Any())
This deferred LINQ query is getting run multiple times.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 492 at r1 (raw file):
Build? currentBuild = await _builds.GetAsync(b => b.Id == buildId, cancellationToken); await _builds.UpdateAsync(
Can we perform this update and the next in a single Mongo call?
src/Machine/src/Serval.Machine.Shared/Services/EchoWordAlignmentPreprocessBuildJob.cs line 119 at r1 (raw file):
sourceLanguageTag, targetLanguageTag, true,
Make the parameter name explicit.
src/Serval/src/Serval.Translation/Dtos/DiagnosticDto.cs line 3 at r1 (raw file):
namespace Serval.Translation.Dtos; public record DiagnosticDto
We should call this TranslationDiagnosticDto, so the name doesn't collide with the word alignment diagnostic in Serval.Client. ExecutionDataDto should really be renamed too, but that would be a breaking change at this point.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 203 at r1 (raw file):
} protected virtual IReadOnlyList<BuildDiagnostic> GetDiagnostics(
We have a MaxWarnings. We should probably have a MaxDiagnostics.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 225 at r1 (raw file):
string versificationName, IReadOnlyList<UsfmVersificationDiagnosticContract> usfmDiagnostics ) in ParallelCorpusService.AnalyzeUsfmVersification(parallelCorpora)
I don't love that we are running AnalyzeUsfmVersification twice for a build. Could we do this once and pass it to GetWarnings and GetDiagnostics or derive the warnings from the diagnostics?
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 243 at r1 (raw file):
Serval.Shared.Contracts.UsfmVersificationDiagnosticType.InvalidChapter => new BuildDiagnostic { Code = "USFM-001",
This is probably overkill, but I would feel a bit less anxious if the number part of the code was 4 digits.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 406 at r1 (raw file):
} if (projectVersifications.Count > 1)
I don't think this is correct. It is checking the number of projects, not the number of versifications.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 415 at r1 (raw file):
Severity = BuildDiagnosticSeverity.Info, Message = $"There are multiple versifications represented among Paratext projects selected for training or inferencing: {string.Join(", ", projectVersifications)}.",
Are you intending to print out the dictionary entries?
src/Serval/src/Serval.WordAlignment/Dtos/WordAlignmentExecutionDataDto.cs line 14 at r1 (raw file):
[Obsolete] public IReadOnlyList<string> Warnings { get; init; } = []; public IReadOnlyList<DiagnosticDto> Diagnostics { get; init; } = [];
This should be optional.
src/Machine/src/Serval.Machine.Shared/Services/NmtPreprocessBuildJob.cs line 27 at r1 (raw file):
private readonly ILanguageTagService _languageTagService = languageTagService; private const string ModelName = "NLLB"; private const string MinimumTrainCount = "600"; //TODO move to options?
This should be an int and probably be an option.
src/Machine/src/Serval.Machine.Shared/Services/NmtPreprocessBuildJob.cs line 234 at r1 (raw file):
Data = new Dictionary<string, object> { { "resolvedCode", sourceLanguageTag },
Is this supposed to be resolvedCode instead of sourceLanguageTag?
src/Machine/src/Serval.Machine.Shared/Services/NmtPreprocessBuildJob.cs line 253 at r1 (raw file):
Data = new Dictionary<string, object> { { "resolvedCode", targetLanguageTag },
Is this supposed to be resolvedCode instead of targetLanguageTag?
src/Serval/src/Serval.WordAlignment/Dtos/DiagnosticDto.cs line 3 at r1 (raw file):
namespace Serval.WordAlignment.Dtos; public record DiagnosticDto
This should be called WordAlignmentDiagnosticDto.
Enkidu93
left a comment
There was a problem hiding this comment.
@Enkidu93 made 19 comments.
Reviewable status: all files reviewed, 19 unresolved discussions (waiting on ddaspit).
a discussion (no related file):
Previously, ddaspit (Damien Daspit) wrote…
Are you planning on adding unit tests? And yes, we will want to add a page for the diagnostics to the wiki page. It would probably be good to have a link to the wiki page in the Swagger docs.
Yep, I don't know if you saw the high-level comment I left when I opened the PR. Those are among the TODOs. (I know sometimes Reviewable seems to bury those top-level initial comments which is frustrating.) I wasn't sure exactly how we want to handle the wiki: I figured once the code and document have both been reviewed, I'll basically copy the doc into the wiki and link it in the StartBuild Swagger docs since there isn't a way, I don't think, to make the wiki update part of this PR per se. I will work on tests though - although I expect those will be a little hairy.
src/Machine/src/Serval.Machine.Shared/Services/EchoPreprocessBuildJob.cs line 59 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
Make the parameter name explicit.
Done
src/Machine/src/Serval.Machine.Shared/Services/EchoWordAlignmentPreprocessBuildJob.cs line 119 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
Make the parameter name explicit.
Done.
src/Machine/src/Serval.Machine.Shared/Services/NmtPreprocessBuildJob.cs line 27 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
This should be an
intand probably be an option.
OK, I made it an int. In general, how do we want to handle these options? I don't like having the model name in two classes for example. I suppose we could have some kind of diagnostics factory that has these options configured. It could have a method like CreateDiagnostic(string code, Dictionary<string, object> data) and we could validate all the data parameters there. Then we could also more easily test the factory with unit tests and then just confirm that the factory method is being called correctly with a mock in the build job classes. I think it also would make it easier to add new diagnostics. The only tricky part would be that this service would need to be called from both PlatformService (or at least that's the natural place) and the build job classes and potentially other places in the future. I'm not sure where a class like this would live. What do you think?
src/Machine/src/Serval.Machine.Shared/Services/NmtPreprocessBuildJob.cs line 234 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
Is this supposed to be
resolvedCodeinstead ofsourceLanguageTag?
Yes, good catch. Something unit tests will catch hopefully 🤪.
src/Machine/src/Serval.Machine.Shared/Services/NmtPreprocessBuildJob.cs line 253 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
Is this supposed to be
resolvedCodeinstead oftargetLanguageTag?
Yes, done.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 203 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
We have a
MaxWarnings. We should probably have aMaxDiagnostics.
OK, as long as it's a pretty high value, I think that's fine. I figure we'll want to sort by severity before limiting. The only thing that's a little weird is adding a diagnostic that means there were too many diagnostics 🤔 - I'm not sure I like that. What do you think? Maybe it's fine.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 225 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
I don't love that we are running
AnalyzeUsfmVersificationtwice for a build. Could we do this once and pass it toGetWarningsandGetDiagnosticsor derive the warnings from the diagnostics?
We could. The only reason I did it this way was so that the warnings and diagnostics were completely separate. That way we could strip out the warnings easily when the time comes without affecting the diagnostics and adding the diagnostics wouldn't affect the warnings. But I could just make the warnings a list of all the diagnostic messages.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 243 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
This is probably overkill, but I would feel a bit less anxious if the number part of the code was 4 digits.
OK 😆, I can do that.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 406 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
I don't think this is correct. It is checking the number of projects, not the number of versifications.
Yes, sorry, I switched to a map since Nathaniel asked but didn't update this properly. Done.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 415 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
Are you intending to print out the dictionary entries?
I think we probably ought to. What do you think? I can format them another way explicitly if you prefer.
src/Serval/src/Serval.Translation/Dtos/DiagnosticDto.cs line 3 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
We should call this
TranslationDiagnosticDto, so the name doesn't collide with the word alignment diagnostic inServal.Client.ExecutionDataDtoshould really be renamed too, but that would be a breaking change at this point.
Done. Yeah, I noticed that :/.
src/Serval/src/Serval.Translation/Dtos/ExecutionDataDto.cs line 14 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
This should be optional.
Done.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 475 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
I think this is supposed to be
MODEL-003.
Yes, done.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 479 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
This confidence should be formatted.
Done.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 488 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
This deferred LINQ query is getting run multiple times.
Done. Good catch. Just ToList()'d it. Do we have a preference for the new spread syntax where we can just use ToList()? I totally understand using it for concatenation, but I feel like it's a little less readable than, e.g., ToList() it situations like these.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 492 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
Can we perform this update and the next in a single Mongo call?
Yep, done.
src/Serval/src/Serval.WordAlignment/Dtos/DiagnosticDto.cs line 3 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
This should be called
WordAlignmentDiagnosticDto.
Done.
src/Serval/src/Serval.WordAlignment/Dtos/WordAlignmentExecutionDataDto.cs line 14 at r1 (raw file):
Previously, ddaspit (Damien Daspit) wrote…
This should be optional.
Done.
ddaspit
left a comment
There was a problem hiding this comment.
@ddaspit partially reviewed 15 files and all commit messages, made 7 comments, and resolved 15 discussions.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on Enkidu93).
a discussion (no related file):
Previously, Enkidu93 (Eli C. Lowry) wrote…
Yep, I don't know if you saw the high-level comment I left when I opened the PR. Those are among the TODOs. (I know sometimes Reviewable seems to bury those top-level initial comments which is frustrating.) I wasn't sure exactly how we want to handle the wiki: I figured once the code and document have both been reviewed, I'll basically copy the doc into the wiki and link it in the
StartBuildSwagger docs since there isn't a way, I don't think, to make the wiki update part of this PR per se. I will work on tests though - although I expect those will be a little hairy.
Yes, that sounds right.
src/Machine/src/Serval.Machine.Shared/Services/NmtPreprocessBuildJob.cs line 27 at r1 (raw file):
Previously, Enkidu93 (Eli C. Lowry) wrote…
OK, I made it an int. In general, how do we want to handle these options? I don't like having the model name in two classes for example. I suppose we could have some kind of diagnostics factory that has these options configured. It could have a method like
CreateDiagnostic(string code, Dictionary<string, object> data)and we could validate all the data parameters there. Then we could also more easily test the factory with unit tests and then just confirm that the factory method is being called correctly with a mock in the build job classes. I think it also would make it easier to add new diagnostics. The only tricky part would be that this service would need to be called from bothPlatformService(or at least that's the natural place) and the build job classes and potentially other places in the future. I'm not sure where a class like this would live. What do you think?
When you create the diagnostic factory in Serval, make sure that it isn't coupled to the Machine engine implementation in any way.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 203 at r1 (raw file):
Previously, Enkidu93 (Eli C. Lowry) wrote…
OK, as long as it's a pretty high value, I think that's fine. I figure we'll want to sort by severity before limiting. The only thing that's a little weird is adding a diagnostic that means there were too many diagnostics 🤔 - I'm not sure I like that. What do you think? Maybe it's fine.
I think it is fine. We need some way to communicate that we hit the max. We certainly don't want to create a huge Build that we store in the DB or pass from the API endpoint.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 225 at r1 (raw file):
Previously, Enkidu93 (Eli C. Lowry) wrote…
We could. The only reason I did it this way was so that the warnings and diagnostics were completely separate. That way we could strip out the warnings easily when the time comes without affecting the diagnostics and adding the diagnostics wouldn't affect the warnings. But I could just make the warnings a list of all the diagnostic messages.
If we generate the warnings from the diagnostics, it should be easy to strip out.
src/Machine/src/Serval.Machine.Shared/Services/PreprocessBuildJob.cs line 415 at r1 (raw file):
Previously, Enkidu93 (Eli C. Lowry) wrote…
I think we probably ought to. What do you think? I can format them another way explicitly if you prefer.
I would prefer that we explicitly formatted them even if it is basically the same as ToString generates for a dictionary entry.
src/Serval/src/Serval.Translation/Services/PlatformService.cs line 488 at r1 (raw file):
Previously, Enkidu93 (Eli C. Lowry) wrote…
Done. Good catch. Just
ToList()'d it. Do we have a preference for the new spread syntax where we can just useToList()? I totally understand using it for concatenation, but I feel like it's a little less readable than, e.g.,ToList()it situations like these.
I prefer ToList, but I also don't like fighting with the suggestions from VS Code. I'm fine with either.
src/Serval/src/Serval.WordAlignment/Dtos/WordAlignmentDiagnosticDto.cs line 3 at r2 (raw file):
namespace Serval.WordAlignment.Dtos; public record WordAlignmentDiagnosticDto
Thinking about this a bit more. I think this should be a shared DTO in Serval.Shared. The corresponding model can also be shared.
Fixes #965.
See https://docs.google.com/document/d/1719NBOAx0NRvk8WpcciTqvFPPZDRSK-oZXbrIKUgL20/edit?tab=t.0#heading=h.dsj2hidolq5 for details.
This work so far does not include:
This change is