RUBRIC SUB-CRITERIA
⚡ Help me build
{[
{label:"Identifies strongest authority per argument",weight:1.5,score:0.82},
{label:"Anticipates and rebuts counterarguments",weight:1.0,score:0.65},
{label:"Logical chain from facts to conclusion",weight:1.0,score:0.80},
{label:"Clear, accessible language",weight:0.5,score:0.85},
].map((sc,i)=>(
{sc.label}
weight {sc.weight}
=0.7?c.green:c.amber}} />
=0.7?c.green:c.amber,fontFamily:mono,fontSize:10,minWidth:32}}>{sc.score.toFixed(2)}
))}
+ Add sub-criterion
Roll up by
)}
>
);
}
return null;
}
// ─── Pass threshold (changes based on result type) ───
function PassThreshold({outcome}) {
if (outcome.resultType === "pass_fail") {
return (
Passes when the check returns true.
);
}
if (outcome.resultType === "checklist") {
return (
Passes when
pass.
);
}
if (outcome.resultType === "score") {
return (
Passes when score ≥
on the configured scale.
);
}
return null;
}
// ─── Result indicator (compact, for card header) ───
function ResultIndicator({outcome, compact}) {
if (!outcome.status || outcome.status === "pending") {
return
;
}
if (outcome.resultType === "pass_fail") {
return
;
}
if (outcome.resultType === "checklist") {
return (
{outcome.count.passed} / {outcome.count.total}
);
}
if (outcome.resultType === "score") {
const passed = outcome.score >= outcome.threshold;
return (
{outcome.score.toFixed(2)}
);
}
}
// ─── Result detail (expanded view in card body) ───
function ResultDetail({outcome}) {
if (outcome.status === "verified") {
return (
{outcome.resultType==="score" && (
score {outcome.score.toFixed(2)} / threshold {outcome.threshold.toFixed(2)}
)}
{outcome.resultType==="checklist" && (
{outcome.count.passed} of {outcome.count.total}
)}
{outcome.lastResultText || "Passed."}
);
}
// Failed — checklist case
if (outcome.status === "failed" && outcome.resultType === "checklist") {
return (
{outcome.count.passed} of {outcome.count.total}
{[
{label:"Citation #1: Tellabs, Inc. v. Makor", status:true},
{label:"Citation #2: Janus Capital Group v. First Derivative", status:true},
{label:"Citation #3: Halliburton Co. v. Erica P. John Fund", status:true},
{label:"Citation #4: Matrixx Initiatives v. Siracusano", status:true},
{label:"Citation #5: Smith v. Jones, 432 F.3d 12", status:false, note:"holding mischaracterized"},
{label:"Citation #6: Basic Inc. v. Levinson", status:true},
{label:"Citation #7: Stoneridge Investment Partners v. Scientific-Atlanta", status:true},
{label:"Citation #8: In re Acme Corp.", status:false, note:"case not found in casedb"},
].map((cp,i)=>(
{cp.status?"✓":"✕"}
{cp.label}
{cp.note && {cp.note}}
))}
);
}
// Failed — pass/fail case
if (outcome.status === "failed" && outcome.resultType === "pass_fail") {
return (
3 of 19 citations did not resolve via citation-checker after 3 lookup attempts each:
• Smith v. Jones, 432 F.3d 12 (5th Cir. 2007) — case not found
• In re Acme Corp., 215 B.R. 89 (Bankr. S.D.N.Y. 1997) — no matching case
• Doe v. Smith — citation incomplete
Feedback for next iteration: "Re-verify citation sources for §III paragraph 4; consider removing citations that cannot be verified."
);
}
// Scored
if (outcome.status === "verified" && outcome.resultType === "score") {
return (
{outcome.score.toFixed(2)}
threshold {outcome.threshold.toFixed(2)}
);
}
return null;
}
// ─── Collapsible port drawer ───
function PortsDrawer() {
const inputs = [
{label:"subject_in", role:"required · data", color:c.accent, wired:"◆ Draft Brief"},
{label:"reference_in", role:"optional · data", color:c.accent, wired:null},
{label:"evidence_in.N", role:"optional · expandable", color:c.accent, wired:"◇ Case Record"},
{label:"claims_in", role:"optional · data", color:c.accent, wired:"◈ Brief Claims"},
{label:"human_response_in", role:"optional · data", color:c.amber, wired:null, note:"active when human review used"},
];
const outputs = [
{label:"verdict_out", role:"always · data", color:c.cyan, wired:null},
{label:"passed_out", role:"signal+data", color:c.green, wired:"↺ Loop.stop_in"},
{label:"failed_out", role:"signal+data", color:c.red, wired:"↺ Loop.return_in"},
{label:"feedback_out", role:"data", color:c.purple, wired:"↺ Loop.feedback_in"},
{label:"human_review_out", role:"signal+data", color:c.amber, wired:"👤 Human Review", note:"per outcome routing"},
{label:"needs_more_info_out", role:"signal+data", color:c.cyan, wired:null, note:"when gathering exhausted"},
{label:"gathered_out", role:"data", color:c.cyan, wired:null},
{label:"signal_out", role:"always · signal", color:c.amber, wired:null},
{label:"error_out", role:"signal+data", color:c.red, wired:null},
];
return (
INPUTS
{inputs.map((p,i)=>
)}
OUTPUTS
{outputs.map((p,i)=>
)}
);
}
function PortRow({port}) {
return (
{port.label}
{port.role}
{port.wired ? (
→ {port.wired}
) : (
{port.note || "unwired"}
)}
);
}
// ═══════════════════════════════════════════════════════════════
// EXTRACTOR (same naming/layout principles applied)
// ═══════════════════════════════════════════════════════════════
function ExtractorView() {
const [portsOpen, setPortsOpen] = useState(false);
const [expandedType, setExpandedType] = useState("ct1");
return (
◈
Claim Extractor
step.claim_extractor · Brief Claims
50 claims extracted
cache hit
Preset…
▶ Run
✕
{/* LEFT SIDEBAR */}
{/* MAIN — claim types */}
{/* Summary banner */}
Last Run — 50 claims extracted (cached)
$0.00 (cached) · was $0.12 fresh · 8:34 AM
{[
{name:"CaseCitation",count:19,color:c.accent},
{name:"FactualAssertion",count:18,color:c.green},
{name:"LegalProposition",count:7,color:c.purple},
{name:"OpposingArgument",count:4,color:c.amber},
{name:"ProceduralFact",count:2,color:c.cyan},
].map((t,i)=>(
{t.name.toUpperCase()}
{t.count}
))}
{/* Claim types header */}
Claim Types
What to extract. Each type defines its instruction, fields, and how it's used downstream.
+ Add Claim Type
{CLAIM_TYPES.map(t => (
setExpandedType(expandedType===t.id?null:t.id)} />
))}
{/* Port drawer */}
setPortsOpen(!portsOpen)} style={{padding:"8px 22px",display:"flex",alignItems:"center",gap:8,cursor:"pointer",fontSize:10,fontFamily:sans,color:c.textSec,fontWeight:600,letterSpacing:0.5,textTransform:"uppercase"}}>
{portsOpen?"▾":"▸"}
Ports
1 input · 4 outputs
{portsOpen && (
)}
);
}
const CLAIM_TYPES = [
{id:"ct1", name:"CaseCitation", desc:"Citations to legal cases — full citation, case name, holding as characterized.", count:19, evaluable:true, authority:true, consumedBy:["Citations resolve to real cases","Cited holdings characterized accurately"]},
{id:"ct2", name:"FactualAssertion", desc:"Factual claims about the matter — dates, amounts, events, parties.", count:18, evaluable:true, authority:false, consumedBy:["No factual claims unsupported"]},
{id:"ct3", name:"LegalProposition", desc:"Statements of legal rules or principles.", count:7, evaluable:true, authority:false, consumedBy:[]},
{id:"ct4", name:"OpposingArgument", desc:"References to opposing counsel's arguments.", count:4, evaluable:true, authority:false, consumedBy:[]},
{id:"ct5", name:"ProceduralFact", desc:"Statements about case procedural posture.", count:2, evaluable:false, authority:false, consumedBy:[]},
];
function ClaimTypeCard({type, expanded, onToggle}) {
return (
{expanded?"▾":"▸"}
{type.name}
{type.evaluable ?
EVALUABLE :
NOT EVALUABLE}
{type.authority &&
NEEDS SPECIALIST}
{type.consumedBy.length>0 &&
USED BY {type.consumedBy.length}}
{!expanded && (
{type.desc}
)}
0?c.text:c.textTer,fontFamily:mono}}>{type.count}
{expanded && (
What this extracts
Name
Description
Extraction instruction (what the extractor reads)
This is operative. The extractor reads it directly to find claims of this type.
Fields to extract
{[
{name:"case_name", type:"text", req:true},
{name:"citation", type:"text", req:true},
{name:"court", type:"enum", req:false},
{name:"year", type:"number", req:false},
{name:"holding_quoted", type:"text", req:false},
].map((f,i)=>(
{f.name}
{f.type}
{f.req?"required":"optional"}
))}
+ Add field
{type.authority && (
<>
Preferred specialist for verification
Downstream Evaluators that check claims of this type will use this specialist by default.
>
)}
Source spans
{type.consumedBy.length>0 && (
<>
Used by these outcomes
{type.consumedBy.map((o,i)=>(
↗ {o}
))}
>
)}
)}
);
}