diff --git a/workbench-ui/src/app/trace/ConstructionEvidencePanel.tsx b/workbench-ui/src/app/trace/ConstructionEvidencePanel.tsx
index db0c854e..de970e95 100644
--- a/workbench-ui/src/app/trace/ConstructionEvidencePanel.tsx
+++ b/workbench-ui/src/app/trace/ConstructionEvidencePanel.tsx
@@ -1,4 +1,4 @@
-import { useMemo } from "react";
+import { useMemo, type ReactNode } from "react";
import type { ConstructionEvidence } from "../../types/constructionEvidence";
import { MetadataTable } from "../../design/components/MetadataTable/MetadataTable";
import { StableJsonViewer } from "../../design/components/StableJsonViewer";
@@ -19,6 +19,27 @@ export interface ConstructionEvidencePanelProps {
errorMessage: (error: unknown) => string;
}
+function renderValue(val: string | ReactNode) {
+ if (typeof val === "string" && val.includes("(invariant met: versor_error < 1e-6)")) {
+ const parts = val.split("(invariant met: versor_error < 1e-6)");
+ return (
+
+ {parts.map((part, index) => (
+
+ {part}
+ {index < parts.length - 1 && (
+
+ invariant met: versor_error < 1e-6
+
+ )}
+
+ ))}
+
+ );
+ }
+ return val;
+}
+
function rowValue(value: string) {
return value;
}
@@ -41,7 +62,7 @@ function DetailSection({ section }: { section: ConstructionEvidenceDetailSection
({
key: row.key,
- value: row.value,
+ value: renderValue(row.value),
mono: true,
}))}
/>
@@ -119,7 +140,7 @@ export function ConstructionEvidencePanel({
({
key: row.key,
- value: row.value,
+ value: renderValue(row.value),
}))}
/>
) : null}
@@ -138,7 +159,7 @@ export function ConstructionEvidencePanel({
({
key: row.key,
- value: row.value,
+ value: renderValue(row.value),
mono: true,
}))}
/>
diff --git a/workbench-ui/src/app/trace/constructionEvidencePanelModel.ts b/workbench-ui/src/app/trace/constructionEvidencePanelModel.ts
index c13c2bb6..ab4b9c00 100644
--- a/workbench-ui/src/app/trace/constructionEvidencePanelModel.ts
+++ b/workbench-ui/src/app/trace/constructionEvidencePanelModel.ts
@@ -17,6 +17,8 @@ export interface ConstructionEvidenceSummaryRow {
value: string;
}
+import { AssessmentBindingView } from "../../types/constructionEvidence";
+
export interface ConstructionEvidenceDetailItem {
title: string;
rows: ConstructionEvidenceSummaryRow[];
@@ -209,6 +211,12 @@ function detailSections(evidence: ConstructionEvidence): ConstructionEvidenceDet
{ key: "unresolved_hazards", value: noneIfEmpty(assessment.unresolved_hazards) },
{ key: "explanation", value: assessment.explanation || "none" },
{ key: "evidence_spans", value: spanList(evidence.problem_text, assessment.evidence_spans) },
+ {
+ key: "bindings",
+ value: assessment.bindings && assessment.bindings.length > 0
+ ? assessment.bindings.map(b => `${b.role}=${b.target_id}${b.versor_error !== undefined && b.versor_error < 1e-6 ? " (invariant met: versor_error < 1e-6)" : (b.versor_error !== undefined ? ` (versor_error: ${b.versor_error})` : "")}`).join("; ")
+ : "none"
+ },
],
})),
},
diff --git a/workbench-ui/src/types/constructionEvidence.ts b/workbench-ui/src/types/constructionEvidence.ts
index 7e4a0c84..9fcf5e0d 100644
--- a/workbench-ui/src/types/constructionEvidence.ts
+++ b/workbench-ui/src/types/constructionEvidence.ts
@@ -36,6 +36,7 @@ export interface MentionBindingView {
source_mention_id: string;
target_mention_id: string;
evidence_spans: SourceSpanView[];
+ bindings?: AssessmentBindingView[];
}
export interface BoundRelationRoleView {
@@ -50,6 +51,12 @@ export interface BoundRelationView {
evidence_spans: SourceSpanView[];
}
+export interface AssessmentBindingView {
+ role: string;
+ target_id: string;
+ versor_error?: number;
+}
+
export interface ContractAssessmentView {
candidate_organ: string;
family_id: string | null;
diff --git a/workbench-ui/update.cjs b/workbench-ui/update.cjs
new file mode 100644
index 00000000..6cbdfb2a
--- /dev/null
+++ b/workbench-ui/update.cjs
@@ -0,0 +1,12 @@
+const fs = require('fs');
+const file = 'src/types/constructionEvidence.ts';
+let content = fs.readFileSync(file, 'utf8');
+content = content.replace(
+ 'export interface ContractAssessmentView {',
+ 'export interface AssessmentBindingView {\n role: string;\n target_id: string;\n versor_error?: number;\n}\n\nexport interface ContractAssessmentView {'
+);
+content = content.replace(
+ 'evidence_spans: SourceSpanView[];\n}',
+ 'evidence_spans: SourceSpanView[];\n bindings?: AssessmentBindingView[];\n}'
+);
+fs.writeFileSync(file, content, 'utf8');
diff --git a/workbench-ui/update.js b/workbench-ui/update.js
new file mode 100644
index 00000000..6cbdfb2a
--- /dev/null
+++ b/workbench-ui/update.js
@@ -0,0 +1,12 @@
+const fs = require('fs');
+const file = 'src/types/constructionEvidence.ts';
+let content = fs.readFileSync(file, 'utf8');
+content = content.replace(
+ 'export interface ContractAssessmentView {',
+ 'export interface AssessmentBindingView {\n role: string;\n target_id: string;\n versor_error?: number;\n}\n\nexport interface ContractAssessmentView {'
+);
+content = content.replace(
+ 'evidence_spans: SourceSpanView[];\n}',
+ 'evidence_spans: SourceSpanView[];\n bindings?: AssessmentBindingView[];\n}'
+);
+fs.writeFileSync(file, content, 'utf8');