Repository: OpenRefine/OpenRefine (java)

Issue:
Make reconciliation errors selectable by facets
<!-- Please provide a clear and concise description of your problem or unsatisfied needs. Ex. I'm always frustrated when [...] or, It would be easier if OpenRefine did [...]. This comment can be deleted, if desired, but it will be hidden in your final submission. Please make sure that your new text is outside the enclosing angle brackets. -->

Consider a reconciliation process where some cells could not reconcile properly, resulting in errors stored in cells.
As a user, I want to:
* be notified that those errors happened, without manually scrolling through the dataset to find red text
* be able to easily select all the rows where errors happened, to either fix them manually or re-run reconciliation on this subset only

### Proposed solution

Adapt the reconciliation judgment facet to have a new category, "error", corresponding to the cells with a non-null reconciliation error.

This could be done either by changing the expression that defines the facet (such as `if(isNonBlank(cell.recon.error), "error", forNonBlank(cell.recon.judgment, v, v, if(isNonBlank(value), "(unreconciled)", "(blank)")))`),
or by introducing a new judgment value in the backend. I think the latter would be cleaner.

### Alternatives considered

Introduce another facet for that? It seems a bit overkill to me, and would take up more screen space.
<!-- If there alternative solutions that you have considered or think should be considered, please list them here -->

### Current screenshot

Currently, cells with reconciliation errors have status "none":
![image](https://github.com/OpenRefine/OpenRefine/assets/309908/6601f4a7-02f2-4b58-a299-141ea0824fa4)

After this change, it would look like this instead:
![image](https://github.com/OpenRefine/OpenRefine/assets/309908/41e98b1a-d774-4a67-aaf9-b5f778bf4af1)

Pull request:
The reconciliation errors are now selectable by facets
Fixes #6232 

Changes proposed in this pull request:
- The reconciliation errors can now be selected through facets 
- A test is also added in the StandardReconConfigTests file that checks that the judgment has been set to error in case of an error.



Patch:
diff --git a/.github/workflows/snapshot_release.yml b/.github/workflows/snapshot_release.yml
index 4cd3ce040..9683bf2ab 100644
--- a/.github/workflows/snapshot_release.yml
+++ b/.github/workflows/snapshot_release.yml
@@ -63,7 +63,7 @@ jobs:
           node-version: '16'
 
       - name: Restore Tests dependency cache
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/cache
@@ -245,7 +245,7 @@ jobs:
 
     - name: Package and upload to OSSRH
       run: |
-        mvn -B package deploy -DskipTests=true -DrepositoryId=ossrh -Dapple.notarization.username=$APPLE_USERNAME -Dapple.notarization.password=$APPLE_PASSWORD -Dapple.notarization.team.id=$APPLE_TEAM_ID
+        mvn -B deploy -DskipTests=true -DrepositoryId=ossrh -Dapple.notarization.username=$APPLE_USERNAME -Dapple.notarization.password=$APPLE_PASSWORD -Dapple.notarization.team.id=$APPLE_TEAM_ID
       env:
         OSSRH_USER: ${{ secrets.OSSRH_USER }}
         OSSRH_PASS: ${{ secrets.OSSRH_PASS }}
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 3a812db33..31264c060 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -24,12 +24,12 @@ When browsing our documentation, feel free to use the edit button to suggest imp
 ##  Contributing code 
 
 You can contribute code in various ways:
-- Fix bugs or implement new features. Follow [our guide towards your first code contribution](https://openrefine.org/docs/technical-reference/contributing#your-first-code-pull-request).
+- Fix bugs or implement new features. Follow [our guide towards your first code contribution](https://openrefine.org/docs/technical-reference/code-contributions)
 - Develop an OpenRefine extension
 - Develop a reconciliation service
 
 All developers including new distributions and plugin developers are invited to leverage the following OpenRefine project management areas to avoid splitting the community in different communication channels.
-- the [official documentation](https://openrefine.org/docs/technical-reference/technical-reference-index) for shared documentation between both user docs and [technical reference](https://docs.openrefine.org/technical-reference/technical-reference-index)
+- the [official documentation](https://openrefine.org/docs/) for shared documentation between both user docs and [technical reference](https://docs.openrefine.org/technical-reference/contributing)
 - the [developer forum](https://forum.openrefine.org/c/dev/8) for technical questions, new feature development and anything code related. We invite you to share you idea there first. Someone may be able to point out to existing development saving you hours of research and development. 
 - [OpenRefine github issue tracker](https://github.com/OpenRefine/OpenRefine/issues) for requesting new features and bug reports.
 - [Gitter Chat](https://gitter.im/OpenRefine/OpenRefine)
diff --git a/GOVERNANCE.md b/GOVERNANCE.md
index bf0a74484..7feb82b87 100644
--- a/GOVERNANCE.md
+++ b/GOVERNANCE.md
@@ -90,15 +90,16 @@ Advisory Committee members:
 * Can be part of the Admin team for the project on GitHub
 
 #### Conflict of Interest
-In the event of any conflict of interest (a Committee Member, their family member, or someone with whom the Committee Member has a close academic or employment relationship is involved in a decision), the Committee Member must immediately notify other Committee Members. The Committee Member will be asked to recuse themselves from ongoing conversations, and decision process regarding the Transaction.  
+In the event of any conflict of interest (a Committee Member, their family member, or someone with whom the Committee Member has a close academic or employment relationship is involved in a decision), the Committee Member must immediately notify other Committee Members. The Committee Members will be asked to recuse themselves from ongoing conversations and decision processes regarding the Transaction.  
 
 #### Current list of Advisory Committee members
 * Jan Ainali
 * Antonin Delpeuch
-* [Open Position]
+* Julie Faure-Lacroix
+* Esther Jackson
 
 ### Project Manager
-OpenRefine's Project Manager (paid position) works closely with OpenRefine’s advisory and steering committees, and with its communities of users and contributors.
+OpenRefine's Project Manager (paid position) works closely with OpenRefine’s advisory and steering committees and with its communities of users and contributors.
 
 The Project Manager:
 * Helps to improve OpenRefine's governance and community diversity
diff --git a/extensions/database/pom.xml b/extensions/database/pom.xml
index 5826dd92c..66ccf7d4f 100644
--- a/extensions/database/pom.xml
+++ b/extensions/database/pom.xml
@@ -105,7 +105,7 @@
     <dependency>
       <groupId>org.xerial</groupId>
       <artifactId>sqlite-jdbc</artifactId>
-      <version>3.45.0.0</version>
+      <version>3.45.1.0</version>
     </dependency>
     <dependency>
       <groupId>com.fasterxml.jackson.core</groupId>
diff --git a/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java b/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java
index 277feb032..7d11e18f7 100644
--- a/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java
+++ b/extensions/database/src/com/google/refine/extension/database/DatabaseConfiguration.java
@@ -67,6 +67,13 @@ public class DatabaseConfiguration {
     }
 
     public void setDatabaseHost(String databaseServer) {
+        // forbid setting settings inside the host parameter:
+        // https://dev.mysql.com/doc/connector-j/en/connector-j-reference-jdbc-url-format.html
+        if (databaseServer == null ||
+                databaseServer.contains("(") ||
+                databaseServer.contains("=")) {
+            throw new IllegalArgumentException("Invalid host supplied");
+        }
         this.databaseHost = databaseServer;
     }
 
diff --git a/extensions/wikibase/module/langs/translation-nl.json b/extensions/wikibase/module/langs/translation-nl.json
index 3191073f6..cc8840267 100644
--- a/extensions/wikibase/module/langs/translation-nl.json
+++ b/extensions/wikibase/module/langs/translation-nl.json
@@ -129,5 +129,9 @@
     "wikibase-account/password-remember-me-title": "Je wachtwoord wordt niet opgeslagen. Vink dit vakje niet aan als je op een publieke computer werkt.",
     "wikibase-account/owner-only-consumer-remember-me-title": "Je inloggegevens worden onversleuteld opgeslagen in cookies. Vink dit vakje niet aan als je op een publieke computer werkt.",
     "perform-wikibase-edits/review-your-edits": "Je gaat zo dadelijk $1 bewerkingen uploaden naar <a href=\"$2\" target=\"_blank\">$3</a>. Kijk deze grondig na. Grote batch-bewerkingen moeten eerst via een <a href=\"https://www.wikidata.org/wiki/Wikidata:Requests_for_permissions/Bot\" target=\"_blank\">bot-review</a> gecheckt worden.",
-    "wikibase-account/consumer-token-label": "Consumententoken"
+    "wikibase-account/consumer-token-label": "Consumententoken",
+    "wikibase-management/discover-manifests": "Ontdek Wikibase-instanties…",
+    "wikibase-management/cancel": "Annuleren",
+    "wikibase-management/ok": "OKÉ",
+    "wikibase-addition/version-error": "Manifest versie $1 wordt niet ondersteund. OpenRefine ondersteund alleen manifest versies 1.x en 2.x."
 }
diff --git a/main/src/com/google/refine/commands/recon/ReconClearOneCellCommand.java b/main/src/com/google/refine/commands/recon/ReconClearOneCellCommand.java
index 8508e8468..eabf19441 100644
--- a/main/src/com/google/refine/commands/recon/ReconClearOneCellCommand.java
+++ b/main/src/com/google/refine/commands/recon/ReconClearOneCellCommand.java
@@ -155,6 +155,7 @@ public class ReconClearOneCellCommand extends Command {
             } else {
                 int newChange = 0;
                 int matchChange = 0;
+                int errorChange = 0;
 
                 if (oldJudgment == Judgment.New) {
                     newChange--;
@@ -162,11 +163,14 @@ public class ReconClearOneCellCommand extends Command {
                 if (oldJudgment == Judgment.Matched) {
                     matchChange--;
                 }
+                if (oldJudgment == Judgment.Error)
+                    errorChange--;
 
                 stats = new ReconStats(
                         stats.nonBlanks + 1,
                         stats.newTopics + newChange,
-                        stats.matchedTopics + matchChange);
+                        stats.matchedTopics + matchChange,
+                        stats.errorTopics + errorChange);
             }
 
             String description = "Clear recon data for single cell on row " + (rowIndex + 1) +
diff --git a/main/src/com/google/refine/commands/recon/ReconJudgeOneCellCommand.java b/main/src/com/google/refine/commands/recon/ReconJudgeOneCellCommand.java
index 8b83a6691..c093e6cb0 100644
--- a/main/src/com/google/refine/commands/recon/ReconJudgeOneCellCommand.java
+++ b/main/src/com/google/refine/commands/recon/ReconJudgeOneCellCommand.java
@@ -190,10 +190,18 @@ public class ReconJudgeOneCellCommand extends Command {
             newCell.recon.judgmentBatchSize = 1;
 
             if (judgment == Judgment.None) {
-                newCell.recon.judgment = Recon.Judgment.None;
+                if (cell.recon.error == null) {
+                    newCell.recon.judgment = Recon.Judgment.None;
+                } else {
+                    newCell.recon.judgment = Recon.Judgment.Error;
+                }
                 newCell.recon.match = null;
-
                 description = "Discard recon judgment for " + cellDescription;
+
+            } else if (judgment == Judgment.Error) {
+
+                throw new IllegalArgumentException("Cannot manually set judgment to 'error'");
+
             } else if (judgment == Judgment.New) {
                 newCell.recon.judgment = Recon.Judgment.New;
                 newCell.recon.match = null;
@@ -222,6 +230,7 @@ public class ReconJudgeOneCellCommand extends Command {
             } else {
                 int newChange = 0;
                 int matchChange = 0;
+                int errorsChange = 0;
 
                 if (oldJudgment == Judgment.New) {
                     newChange--;
@@ -229,17 +238,24 @@ public class ReconJudgeOneCellCommand extends Command {
                 if (oldJudgment == Judgment.Matched) {
                     matchChange--;
                 }
+                if (oldJudgment == Judgment.Error) {
+                    errorsChange--;
+                }
                 if (newCell.recon.judgment == Judgment.New) {
                     newChange++;
                 }
                 if (newCell.recon.judgment == Judgment.Matched) {
                     matchChange++;
                 }
+                if (newCell.recon.judgment == Judgment.Error) {
+                    errorsChange++;
+                }
 
                 stats = new ReconStats(
                         stats.nonBlanks,
                         stats.newTopics + newChange,
-                        stats.matchedTopics + matchChange);
+                        stats.matchedTopics + matchChange,
+                        stats.errorTopics + errorsChange);
             }
 
             Change change = new ReconChange(
diff --git a/main/src/com/google/refine/model/Recon.java b/main/src/com/google/refine/model/Recon.java
index b1a531d23..5d9304b8e 100644
--- a/main/src/com/google/refine/model/Recon.java
+++ b/main/src/com/google/refine/model/Recon.java
@@ -69,7 +69,8 @@ public class Recon implements HasFields {
         @JsonProperty("none")
         None, @JsonProperty("matched")
         Matched, @JsonProperty("new")
-        New
+        New, @JsonProperty("error")
+        Error
     }
 
     @Deprecated
@@ -78,6 +79,8 @@ public class Recon implements HasFields {
             return "matched";
         } else if (judgment == Judgment.New) {
             return "new";
+        } else if (judgment == Judgment.Error) {
+            return "errors";
         } else {
             return "none";
         }
@@ -89,6 +92,8 @@ public class Recon implements HasFields {
             return Judgment.Matched;
         } else if ("new".equals(s)) {
             return Judgment.New;
+        } else if ("errors".equals(s)) {
+            return Judgment.Error;
         } else {
             return Judgment.None;
         }
@@ -198,6 +203,7 @@ public class Recon implements HasFields {
 
         r.match = match;
         r.matchRank = matchRank;
+        r.error = error;
     }
 
     public void addCandidate(ReconCandidate candidate) {
diff --git a/main/src/com/google/refine/model/ReconStats.java b/main/src/com/google/refine/model/ReconStats.java
index 11325e789..ce55c9434 100644
--- a/main/src/com/google/refine/model/ReconStats.java
+++ b/main/src/com/google/refine/model/ReconStats.java
@@ -51,21 +51,26 @@ public class ReconStats {
     final public int newTopics;
     @JsonProperty("matchedTopics")
     final public int matchedTopics;
+    @JsonProperty("errorTopics")
+    final public int errorTopics;
 
     @JsonCreator
     public ReconStats(
             @JsonProperty("nonBlanks") int nonBlanks,
             @JsonProperty("newTopics") int newTopics,
-            @JsonProperty("matchedTopics") int matchedTopics) {
+            @JsonProperty("matchedTopics") int matchedTopics,
+            @JsonProperty("errorTopics") int errorTopics) {
         this.nonBlanks = nonBlanks;
         this.newTopics = newTopics;
         this.matchedTopics = matchedTopics;
+        this.errorTopics = errorTopics;
     }
 
     static public ReconStats create(Project project, int cellIndex) {
         int nonBlanks = 0;
         int newTopics = 0;
         int matchedTopics = 0;
+        int errorTopics = 0;
 
         for (Row row : project.rows) {
             Cell cell = row.getCell(cellIndex);
@@ -77,12 +82,14 @@ public class ReconStats {
                         newTopics++;
                     } else if (cell.recon.judgment == Judgment.Matched) {
                         matchedTopics++;
+                    } else if (cell.recon.judgment == Judgment.Error) {
+                        errorTopics++;
                     }
                 }
             }
         }
 
-        return new ReconStats(nonBlanks, newTopics, matchedTopics);
+        return new ReconStats(nonBlanks, newTopics, matchedTopics, errorTopics);
     }
 
     public void save(Writer writer) {
diff --git a/main/src/com/google/refine/model/recon/StandardReconConfig.java b/main/src/com/google/refine/model/recon/StandardReconConfig.java
index 8101facf0..80d0b45cc 100644
--- a/main/src/com/google/refine/model/recon/StandardReconConfig.java
+++ b/main/src/com/google/refine/model/recon/StandardReconConfig.java
@@ -464,12 +464,14 @@ public class StandardReconConfig extends ReconConfig {
         } catch (IOException e) {
             Recon recon = new Recon(historyEntryID, identifierSpace, schemaSpace);
             recon.error = e.getMessage();
+            recon.judgment = Judgment.Error;
             recons.add(recon);
         }
 
         if (o == null) { // utility method returns null instead of throwing
             Recon recon = new Recon(historyEntryID, identifierSpace, schemaSpace);
             recon.error = "The reconciliation service returned an invalid response";
+            recon.judgment = Judgment.Error;
             recons.add(recon);
 
         } else {
@@ -488,11 +490,13 @@ public class StandardReconConfig extends ReconConfig {
                     } else {
                         recon = new Recon(historyEntryID, identifierSpace, schemaSpace);
                         recon.error = "The service returned a JSON response without \"result\" field for query " + key;
+                        recon.judgment = Judgment.Error;
 
                     }
                 } else {
                     recon = new Recon(historyEntryID, identifierSpace, schemaSpace);
                     recon.error = "The service returned a JSON response without \"" + key + "\" field ";
+                    recon.judgment = Judgment.Error;
                 }
 
                 if (recon != null) {
@@ -506,6 +510,7 @@ public class StandardReconConfig extends ReconConfig {
         while (recons.size() < jobs.size()) {
             Recon recon = new Recon(historyEntryID, identifierSpace, schemaSpace);
             recon.error = "No. of recon objects was less than no. of jobs";
+            recon.judgment = Judgment.Error;
             recons.add(recon);
         }
 
diff --git a/main/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperation.java b/main/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperation.java
index 369404f2e..079fd98be 100644
--- a/main/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperation.java
+++ b/main/src/com/google/refine/operations/recon/ReconJudgeSimilarCellsOperation.java
@@ -222,8 +222,10 @@ public class ReconJudgeSimilarCellsOperation extends EngineDependentMassCellOper
                                     recon.judgment = Recon.Judgment.New;
                                     recon.match = null;
                                 } else if (_judgment == Judgment.None) {
-                                    recon.judgment = Recon.Judgment.None;
+                                    recon.judgment = recon.error == null ? Recon.Judgment.None : Recon.Judgment.Error;
                                     recon.match = null;
+                                } else if (_judgment == Judgment.Error) {
+                                    throw new IllegalArgumentException("Cannot manually set judgment to 'error'");
                                 }
 
                                 _dupReconMap.put(cell.recon.id, recon);
diff --git a/packaging/pom.xml b/packaging/pom.xml
index b21c43a56..073ee37f7 100644
--- a/packaging/pom.xml
+++ b/packaging/pom.xml
@@ -26,7 +26,7 @@
     <mac.dmg.path>${project.build.directory}/${project.build.finalName}-mac-${project.version}.dmg</mac.dmg.path>
     <mac.signing.identity>Code for Science and Society, Inc.</mac.signing.identity>
     <!-- Apple Notarization settings -->
-    <apple.notarization.timeout>10m</apple.notarization.timeout>
+    <apple.notarization.timeout>15m</apple.notarization.timeout>
 
     <windows.jre.path>${project.build.directory}/windows_jre</windows.jre.path>
     <windows.jre.url>https://api.adoptium.net/v3/binary/latest/${embedded.jre.version}/ga/windows/x64/jre/hotspot/normal/eclipse?project=jdk</windows.jre.url>
diff --git a/pom.xml b/pom.xml
index 4098e5c8d..3d0d5ca85 100644
--- a/pom.xml
+++ b/pom.xml
@@ -75,7 +75,7 @@
     <jackson.version>2.16.1</jackson.version>
     <servlet-api.version>4.0.1</servlet-api.version>
     <butterfly.version>1.2.5</butterfly.version>
-    <slf4j.version>2.0.11</slf4j.version>
+    <slf4j.version>2.0.12</slf4j.version>
     <log4j.version>2.22.1</log4j.version>
     <jetty.version>10.0.16</jetty.version>
     <okhttp.version>4.12.0</okhttp.version>
@@ -88,7 +88,7 @@
     <commons-validator.version>1.8.0</commons-validator.version>
     <org-jvnet-localizer.version>1.31</org-jvnet-localizer.version>
     <!-- v1.15 of commons-codec is needed for Jena 3.14+ - copied from org.apache.jena:jena:pom -->
-    <commons-codec.version>1.16.0</commons-codec.version>
+    <commons-codec.version>1.16.1</commons-codec.version>
     <commons-compress.version>1.25.0</commons-compress.version>
     <velocity.version>2.3</velocity.version>
     <marc4j.version>2.9.5</marc4j.version>


Test patch:
diff --git a/.github/workflows/pull_request_e2e.yml b/.github/workflows/pull_request_e2e.yml
index 391b52c9b..48ab36bef 100644
--- a/.github/workflows/pull_request_e2e.yml
+++ b/.github/workflows/pull_request_e2e.yml
@@ -61,7 +61,7 @@ jobs:
           node-version: '16'
 
       - name: Restore Tests dependency cache
-        uses: actions/cache@v3
+        uses: actions/cache@v4
         with:
           path: |
             ~/cache
diff --git a/extensions/database/tests/src/com/google/refine/extension/database/DatabaseConfigurationTest.java b/extensions/database/tests/src/com/google/refine/extension/database/DatabaseConfigurationTest.java
index ef101c896..b45f19b58 100644
--- a/extensions/database/tests/src/com/google/refine/extension/database/DatabaseConfigurationTest.java
+++ b/extensions/database/tests/src/com/google/refine/extension/database/DatabaseConfigurationTest.java
@@ -2,6 +2,7 @@
 package com.google.refine.extension.database;
 
 import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertThrows;
 
 import org.testng.annotations.Test;
 
@@ -19,4 +20,13 @@ public class DatabaseConfigurationTest {
         // the database name is escaped, preventing the exploit
         assertEquals(url, "jdbc:mysql://my.host/test%3FallowLoadLocalInfile=true%23");
     }
+
+    @Test
+    public void testSetMaliciousHost() {
+        DatabaseConfiguration config = new DatabaseConfiguration();
+        config.setDatabaseType("mysql");
+
+        assertThrows(IllegalArgumentException.class,
+                () -> config.setDatabaseHost("127.0.0.1:3306,(allowLoadLocalInfile=true,allowUrlInLocalInfile=true),127.0.0.1"));
+    }
 }
diff --git a/main/tests/cypress/package.json b/main/tests/cypress/package.json
index 0ab6dd681..c5eb1ace6 100644
--- a/main/tests/cypress/package.json
+++ b/main/tests/cypress/package.json
@@ -24,6 +24,6 @@
         "eslint-config-google": "^0.14.0",
         "eslint-config-prettier": "^9.1.0",
         "eslint-plugin-cypress": "^2.15.1",
-        "prettier": "3.2.4"
+        "prettier": "3.2.5"
     }
 }
diff --git a/main/tests/cypress/yarn.lock b/main/tests/cypress/yarn.lock
index 7a601b5e3..07e07f4cb 100644
--- a/main/tests/cypress/yarn.lock
+++ b/main/tests/cypress/yarn.lock
@@ -1308,10 +1308,10 @@ prelude-ls@^1.2.1:
   resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz"
   integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
 
-prettier@3.2.4:
-  version "3.2.4"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.4.tgz#4723cadeac2ce7c9227de758e5ff9b14e075f283"
-  integrity sha512-FWu1oLHKCrtpO1ypU6J0SbK2d9Ckwysq6bHj/uaCP26DxrPpppCLQRGVuqAxSTvhF00AcvDRyYrLNW7ocBhFFQ==
+prettier@3.2.5:
+  version "3.2.5"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
+  integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
 
 pretty-bytes@^5.6.0:
   version "5.6.0"
diff --git a/main/tests/server/src/com/google/refine/model/ColumnTests.java b/main/tests/server/src/com/google/refine/model/ColumnTests.java
index 7aa7c2523..f367dd415 100644
--- a/main/tests/server/src/com/google/refine/model/ColumnTests.java
+++ b/main/tests/server/src/com/google/refine/model/ColumnTests.java
@@ -76,7 +76,8 @@ public class ColumnTests {
                 + "\"reconStats\":{"
                 + "    \"nonBlanks\":299,"
                 + "    \"newTopics\":0,"
-                + "    \"matchedTopics\":222"
+                + "    \"matchedTopics\":222,"
+                + "    \"errorTopics\":0"
                 + "}}";
         TestUtils.isSerializedTo(Column.load(json), json);
     }
diff --git a/main/tests/server/src/com/google/refine/model/ReconStatsTests.java b/main/tests/server/src/com/google/refine/model/ReconStatsTests.java
index aa394f297..2e2f50189 100644
--- a/main/tests/server/src/com/google/refine/model/ReconStatsTests.java
+++ b/main/tests/server/src/com/google/refine/model/ReconStatsTests.java
@@ -35,7 +35,7 @@ public class ReconStatsTests {
 
     @Test
     public void serializeReconStats() {
-        ReconStats rs = new ReconStats(3, 1, 2);
-        TestUtils.isSerializedTo(rs, "{\"nonBlanks\":3,\"newTopics\":1,\"matchedTopics\":2}");
+        ReconStats rs = new ReconStats(3, 1, 2, 0);
+        TestUtils.isSerializedTo(rs, "{\"nonBlanks\":3,\"newTopics\":1,\"matchedTopics\":2,\"errorTopics\":0}");
     }
 }
diff --git a/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java b/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java
index 967a4a52b..78158431c 100644
--- a/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java
+++ b/main/tests/server/src/com/google/refine/model/recon/StandardReconConfigTests.java
@@ -298,6 +298,7 @@ public class StandardReconConfigTests extends RefineTest {
             Cell cell = row.cells.get(1);
             assertNotNull(cell.value);
             assertNotNull(cell.recon.error);
+            assertEquals(cell.recon.judgment, Recon.Judgment.Error);
             // the recon object has error attribute
         }
     }