Skip to content

Commit 360a872

Browse files
committed
Update codes sanity checker
The check job now runs 7 mins after the codes refresh instead of 3hrs later. Moved the never-required-fields check out of TylerCodesParser and put it directly in CodesSanityChecker, and moved the knownCodeLookups list in there too. Stopped comparing against the interview's default code, since that's just a backup value and not what we actually expect the search to return - a single match is now treated as fine, nothing gets logged. Ambiguous matches now log a warning instead of an error.
1 parent 102bb91 commit 360a872

7 files changed

Lines changed: 61 additions & 111 deletions

File tree

proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/setup/tyler/TylerModuleSetup.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -243,18 +243,21 @@ public void preSetup() {
243243
scheduler.scheduleJob(
244244
buildJob("job-immediate-" + jurisdiction.getName()), immediateTrigger);
245245

246-
// Runs after the refresh job's immediate trigger above, so there's
247-
// something in the codes db for it to check by the time it fires.
248-
Trigger immediateCheckTrigger =
246+
// Runs a few minutes after the refresh job, in its own group, so it checks
247+
// against that day's freshly-updated codes without racing the refresh itself
248+
String checkTriggerName = "check-trigger-" + jurisdiction.getName();
249+
LocalTime checkTime = codesDbUpdateTime.plusMinutes(7);
250+
Trigger checkTrigger =
249251
TriggerBuilder.newTrigger()
250-
.withIdentity(
251-
"check-trigger-immediate-" + jurisdiction.getName(), "codes-check-group")
252+
.withIdentity(checkTriggerName, "codes-check-group")
252253
.startNow()
253-
.withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(40))
254+
.withSchedule(
255+
CronScheduleBuilder.dailyAtHourAndMinute(
256+
checkTime.getHour(), checkTime.getMinute() + r.nextInt(4)))
254257
.build();
255-
log.info("Scheduling immediate codes sanity check job.");
256-
scheduler.scheduleJob(
257-
buildCheckJob("check-job-immediate-" + jurisdiction.getName()), immediateCheckTrigger);
258+
259+
log.info("Scheduling daily codes sanity check job around {}", checkTime);
260+
scheduler.scheduleJob(buildCheckJob("check-job-" + jurisdiction.getName()), checkTrigger);
258261
}
259262
} catch (SchedulerException se) {
260263
log.error("Scheduler Exception: ", se);

proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/CodesSanityChecker.java

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,32 @@ public class CodesSanityChecker {
1414

1515
private static final Logger log = LoggerFactory.getLogger(CodesSanityChecker.class);
1616

17+
private static final List<String> neverRequiredFields =
18+
List.of("PartyNameSuffix", "PartyMiddleName");
19+
20+
// Seed list, pulled from docassemble-MotionToStayEviction's efiling.yml. Add more as they come
21+
// up.
22+
private static final List<MaintainedCodeCheck> knownCodeLookups =
23+
List.of(
24+
new MaintainedCodeCheck(
25+
"massachusetts",
26+
"appeals:acsj",
27+
MaintainedCodeCheck.CodeTable.CASE_CATEGORY,
28+
List.of("Appeals Court Single Justice - Civil", "Civil"),
29+
"https://github.com/SuffolkLITLab/docassemble-MotionToStayEviction/blob/"
30+
+ "213bd40790525bb45fbc5b012c5649325c7e0bae/docassemble/MotionToStayEviction/"
31+
+ "data/questions/efiling.yml#L33-L34",
32+
null),
33+
new MaintainedCodeCheck(
34+
"massachusetts",
35+
"appeals:acsj",
36+
MaintainedCodeCheck.CodeTable.CASE_TYPE,
37+
List.of("MAC Rule 6.0"),
38+
"https://github.com/SuffolkLITLab/docassemble-MotionToStayEviction/blob/"
39+
+ "213bd40790525bb45fbc5b012c5649325c7e0bae/docassemble/MotionToStayEviction/"
40+
+ "data/questions/efiling.yml#L36-L38",
41+
"8151"));
42+
1743
private final CodeDatabase cd;
1844
private final String jurisdiction;
1945

@@ -32,17 +58,20 @@ private void checkNeverRequiredFieldsForAllCourts() {
3258
if (courtCode.equals("1")) {
3359
continue;
3460
}
35-
Optional<CourtLocationInfo> court = cd.getFullLocationInfo(courtCode);
36-
if (court.isEmpty()) {
37-
continue;
61+
DataFields fields = cd.getDataFields(courtCode);
62+
for (String fieldCode : neverRequiredFields) {
63+
if (fields.getFieldRow(fieldCode).isrequired) {
64+
log.error(
65+
"Court {}: {} is marked required in datafieldconfig, which shouldn't happen",
66+
courtCode,
67+
fieldCode);
68+
}
3869
}
39-
TylerCodesParser parser = new TylerCodesParser(cd, null, court.get(), false);
40-
parser.checkNeverRequiredFields();
4170
}
4271
}
4372

4473
private void checkKnownCodeLookups() {
45-
for (MaintainedCodeCheck check : KnownCodeLookups.ALL) {
74+
for (MaintainedCodeCheck check : knownCodeLookups) {
4675
if (!check.jurisdiction().equals(jurisdiction)) {
4776
continue;
4877
}
@@ -79,36 +108,23 @@ private List<NameAndCode> fetchOptions(MaintainedCodeCheck check) {
79108
private void report(MaintainedCodeCheck check, CodeSearchMatcher.MatchResult result) {
80109
switch (result.type()) {
81110
case OK -> {
82-
String actualCode = result.matches().get(0).getCode();
83-
if (!actualCode.equals(check.expectedDefaultCode())) {
84-
log.error(
85-
"Court {} {}: filters {} now resolve to {}, but the interview at {} expects {}",
86-
check.courtCode(),
87-
check.table(),
88-
check.filters(),
89-
actualCode,
90-
check.sourceInterviewUrl(),
91-
check.expectedDefaultCode());
92-
}
111+
// A single match means the interview's search still resolves cleanly(nothing to report)
93112
}
94113
case NO_MATCH ->
95114
log.error(
96-
"Court {} {}: filters {} matched nothing, but the interview at {} expects {}",
115+
"Court {} {}: filters {} matched nothing. See {}",
97116
check.courtCode(),
98117
check.table(),
99118
check.filters(),
100-
check.sourceInterviewUrl(),
101-
check.expectedDefaultCode());
119+
check.sourceInterviewUrl());
102120
case AMBIGUOUS ->
103-
log.error(
104-
"Court {} {}: filters {} matched more than one code ({}), but the interview at {}"
105-
+ " expects {}",
121+
log.warn(
122+
"Court {} {}: filters {} matched more than one code ({}). See {}",
106123
check.courtCode(),
107124
check.table(),
108125
check.filters(),
109126
result.matches(),
110-
check.sourceInterviewUrl(),
111-
check.expectedDefaultCode());
127+
check.sourceInterviewUrl());
112128
}
113129
}
114130
}

proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/KnownCodeLookups.java

Lines changed: 0 additions & 32 deletions
This file was deleted.

proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/MaintainedCodeCheck.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,13 @@
22

33
import java.util.List;
44

5-
// One entry in the hand-maintained list of interview code lookups.
6-
// Each entry mirrors a _filters/_default pair from a real interview's efiling.yml.
5+
// One entry in the hand-maintained list of interview code lookups. Each entry
6+
// mirrors a _filters list from a real interview's efiling.yml
77
public record MaintainedCodeCheck(
88
String jurisdiction,
99
String courtCode,
1010
CodeTable table,
1111
List<String> filters,
12-
String expectedDefaultCode,
1312
String sourceInterviewUrl,
1413
String caseCategoryCode) {
1514

proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodesParser.java

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -186,28 +186,15 @@ public Result<FilingCode, CodeError> vetFilingType(
186186
});
187187
}
188188

189-
private static final List<String> neverRequiredFields =
190-
List.of("PartyNameSuffix", "PartyMiddleName");
191-
192-
public List<String> checkNeverRequiredFields() {
193-
List<String> offendingFields = new ArrayList<>();
194-
for (String fieldCode : neverRequiredFields) {
195-
DataFieldRow row = allDataFields.getFieldRow(fieldCode);
196-
if (row.isrequired) {
197-
log.error(
198-
"DEV WARNING: Court {}: {} shouldn't ever be required, but this court has it set that way",
199-
this.court.code,
200-
fieldCode);
201-
offendingFields.add(fieldCode);
202-
}
203-
}
204-
return offendingFields;
205-
}
206-
207189
public Result<String, CodeError> vetSuffix(Optional<String> maybeSuffix) {
208190
DataFieldRow suffixRow = allDataFields.getFieldRow("PartyNameSuffix");
209191
if (suffixRow.isvisible) {
210192
List<NameAndCode> suffixes = cd.getNameSuffixes(this.court.code);
193+
if ((maybeSuffix.isEmpty() || maybeSuffix.get().isBlank()) && suffixRow.isrequired) {
194+
log.error(
195+
"DEV WARNING: Court {}: WHY would you ever require a suffix? There aren't empty suffix codes at all.",
196+
this.court.code);
197+
}
211198
String suffix = maybeSuffix.orElse("");
212199
Optional<NameAndCode> suffixMatch =
213200
suffixes.stream().filter(s -> s.getName().equalsIgnoreCase(suffix)).findFirst();

proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/ecf4/tyler/TylerCodesParserTest.java

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -470,29 +470,6 @@ public void testFilingComponents() {
470470
assertThat(resAgain).containsErr(new NoMatchingCode("333", List.of()));
471471
}
472472

473-
@Test
474-
public void testCheckNeverRequiredFieldsNoneRequired() {
475-
when(dataFields.getFieldRow("PartyNameSuffix"))
476-
.thenReturn(
477-
new DataFieldRow("1", "Suffix", true, false, "", "", "", "", "", "", false, "01"));
478-
when(dataFields.getFieldRow("PartyMiddleName"))
479-
.thenReturn(
480-
new DataFieldRow("2", "Middle Name", true, false, "", "", "", "", "", "", false, "01"));
481-
assertThat(((TylerCodesParser) parser).checkNeverRequiredFields()).isEmpty();
482-
}
483-
484-
@Test
485-
public void testCheckNeverRequiredFieldsSuffixRequired() {
486-
when(dataFields.getFieldRow("PartyNameSuffix"))
487-
.thenReturn(
488-
new DataFieldRow("1", "Suffix", true, true, "", "", "", "", "", "", false, "01"));
489-
when(dataFields.getFieldRow("PartyMiddleName"))
490-
.thenReturn(
491-
new DataFieldRow("2", "Middle Name", true, false, "", "", "", "", "", "", false, "01"));
492-
assertThat(((TylerCodesParser) parser).checkNeverRequiredFields())
493-
.containsExactly("PartyNameSuffix");
494-
}
495-
496473
DocumentTypeTableRow docType =
497474
new DocumentTypeTableRow("4444", null, filingCode.code, "false", null, null, null);
498475

proxyserver/src/test/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/CodesSanityCheckerTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private void loadFromXmls() throws Exception {
6363
}
6464
}
6565

66-
// Illinois/adams doesn't have any KnownCodeLookups entries seeded (those are
66+
// Illinois/adams doesn't have any code lookups entries seeded (those are
6767
// all MA's so far), so this mainly proves the whole pipeline runs
6868
// cleanly against a real Postgres schema without throwing.
6969
@Test

0 commit comments

Comments
 (0)