Skip to content

Commit 8fb3225

Browse files
clay-goodclaude
andcommitted
fix(rules): CHOICE-008 detect passive 'jury trial is hereby waived' & long-parenthetical jury waivers (v1.2.0)
v1.1.0 matched only the active form with the object within 40 chars of the verb, and required "waive" to sit BEFORE "jury trial". It missed two common forms: the passive "the right to a jury trial is hereby waived", and the boilerplate "waives, to the fullest extent permitted by law, any right … to a trial by jury" whose long parenthetical pushed the object past the 40-char window. Widen the active window to a sentence-bounded 80 chars ([^.] never crosses a period) and add a passive branch, tempered so a negated "jury trial is NOT waived" cannot match. Probe: 5 fire cases (2 baseline + passive x2 + long-parenthetical), 4 silent cases (do-not-waive, nothing-herein-waives, retains-right, passive-not-waived). Finding-delta over the contracts corpus and all golden tiers: zero fired-flips, zero finding-count changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 1281fa2 commit 8fb3225

367 files changed

Lines changed: 427 additions & 395 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { describe, expect, it } from "vitest";
2+
import { rule as CHOICE_008 } from "./CHOICE-008.js";
3+
import { buildContext } from "../../_test-fixtures.js";
4+
5+
const fires = (t: string) => CHOICE_008.check(buildContext(["Disputes", t])) !== null;
6+
7+
describe("CHOICE-008 — jury-trial waiver recognizes passive & long-parenthetical forms (v1.2.0)", () => {
8+
it.each([
9+
"Each party waives any right to trial by jury.",
10+
"The parties waive all rights to a jury trial.",
11+
"The right to a jury trial is hereby waived by each party.",
12+
"Any and all rights to a trial by jury are hereby waived.",
13+
"Each party knowingly and voluntarily waives, to the fullest extent permitted by law, any right it may have to a trial by jury.",
14+
])("fires on a jury-trial waiver: %s", (t) => {
15+
expect(fires(t)).toBe(true);
16+
});
17+
18+
it.each([
19+
"The parties do not waive any right to a jury trial.",
20+
"Nothing herein waives the right to a jury trial.",
21+
"Each party retains its right to a jury trial.",
22+
"The right to a jury trial is not waived by either party.",
23+
])("stays silent on a preserved / negated jury-trial right: %s", (t) => {
24+
expect(fires(t)).toBe(false);
25+
});
26+
});

src/engine/rules/choice-and-venue/CHOICE-008.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { emit, firstUnnegatedParagraphMatch } from "../_helpers.js";
44
/** CHOICE-008 — Jury trial waiver (info). */
55
export const rule: Rule = {
66
id: "CHOICE-008",
7-
version: "1.1.0",
7+
version: "1.2.0",
88
name: "Jury trial waiver",
99
category: "choice-and-venue",
1010
default_severity: "info",
@@ -16,7 +16,13 @@ export const rule: Rule = {
1616
// American drafting writes "waive any right to a JURY TRIAL" far more often
1717
// than the formal "trial by jury"; only the latter was recognized, so the
1818
// dominant form of this waiver went unreported entirely.
19-
/\bwaive[\s\S]{0,40}(?:right\s+to\s+)?(?:a\s+)?(?:trial\s+by\s+jury|jury\s+trial)\b|\bjury\s+trial\s+waiver\b/i,
19+
//
20+
// v1.2.0 widens the active-form window from 40 to a sentence-bounded 80
21+
// ([^.] never crosses a period) so the boilerplate "waives, to the fullest
22+
// extent permitted by law, any right … to a trial by jury" reaches its
23+
// object, and adds a passive branch ("the right to a jury trial is hereby
24+
// waived") tempered so a negated "jury trial is NOT waived" cannot match.
25+
/\bwaive[^.]{0,80}(?:right\s+to\s+)?(?:a\s+)?(?:trial\s+by\s+jury|jury\s+trial)\b|\bjury\s+trial\s+waiver\b|(?:trial\s+by\s+jury|jury\s+trial)(?:(?!\bnot\b|\bnever\b|\bno\b)[^.]){0,40}\bwaived\b/i,
2026
);
2127
if (!hit) return null;
2228
return emit(ctx, rule, {

tests/fixtures/expected/bad-consulting-success-fee.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"elapsed_ms": 0,
5050
"fired": false,
5151
"rule_id": "CHOICE-008",
52-
"rule_version": "1.1.0"
52+
"rule_version": "1.2.0"
5353
},
5454
{
5555
"elapsed_ms": 0,
@@ -974,7 +974,7 @@
974974
"playbook_id": "consulting-agreement",
975975
"playbook_match_confidence": 0.9,
976976
"playbook_match_reasoning": "Selected consulting-agreement (score 0.9). Title matched: \"advisory agreement\". Distinguishing phrases: \"advisory services\", \"deliverables\", \"independent contractor\".",
977-
"result_hash": "25b24738b2ca7c0d7716be6e2af76af0f88c3ad8db33ee7a0a93920a18e8a334",
977+
"result_hash": "eb95c14e194c15d98919d8928175e34011ad8c877377c37d64f08f33edaa9145",
978978
"source_file": {
979979
"name": "bad-consulting-success-fee.docx",
980980
"sha256": "6bc505eb0c1641cda4c3466a62f0b3eead258e2dc3a385e792e79f4a717ad6a5",

tests/fixtures/expected/bad-consulting.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"elapsed_ms": 0,
5050
"fired": false,
5151
"rule_id": "CHOICE-008",
52-
"rule_version": "1.1.0"
52+
"rule_version": "1.2.0"
5353
},
5454
{
5555
"elapsed_ms": 0,
@@ -1055,7 +1055,7 @@
10551055
"playbook_id": "consulting-agreement",
10561056
"playbook_match_confidence": 0.9,
10571057
"playbook_match_reasoning": "Selected consulting-agreement (score 0.9). Title matched: \"consulting agreement\". Distinguishing phrases: \"Consultant\", \"advisory services\", \"deliverables\", \"independent contractor\", \"the Consulting Services\".",
1058-
"result_hash": "45a739b3f1df2186fbec687b8a15988bb12e4ad05233301896f0fd8ab794700e",
1058+
"result_hash": "20869b94587a65c62aec95b0b5d256e7cf5621b569d2ff0d7d45727c9bb2d361",
10591059
"source_file": {
10601060
"name": "bad-consulting.docx",
10611061
"sha256": "f66f070f4bb768dbc3f21ee6782418bca5ed64451d483dab533b345a8ddbe691",

tests/fixtures/expected/bad-contractor-leaseback.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"elapsed_ms": 0,
5050
"fired": false,
5151
"rule_id": "CHOICE-008",
52-
"rule_version": "1.1.0"
52+
"rule_version": "1.2.0"
5353
},
5454
{
5555
"elapsed_ms": 0,
@@ -882,7 +882,7 @@
882882
"playbook_id": "independent-contractor",
883883
"playbook_match_confidence": 1,
884884
"playbook_match_reasoning": "Selected independent-contractor (score 1). Title matched: \"independent contractor\", \"contractor agreement\". Distinguishing phrases: \"independent contractor\", \"Contractor shall\".",
885-
"result_hash": "cc1875e03eec0c829c1d546f23f3683b6b2a1dc542c5b457b44490ab6751c770",
885+
"result_hash": "fe8e424cdad76efb7034af019942554f6bcacb41fa2b003321b84bef05d9ab56",
886886
"source_file": {
887887
"name": "bad-contractor-leaseback.docx",
888888
"sha256": "82496f664a3abe77b7ed03c7c77b47c9ffbd8c5f883389cb761b7ba68b31f98d",

tests/fixtures/expected/bad-contractor.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"elapsed_ms": 0,
5050
"fired": false,
5151
"rule_id": "CHOICE-008",
52-
"rule_version": "1.1.0"
52+
"rule_version": "1.2.0"
5353
},
5454
{
5555
"elapsed_ms": 0,
@@ -1084,7 +1084,7 @@
10841084
"playbook_id": "independent-contractor",
10851085
"playbook_match_confidence": 1,
10861086
"playbook_match_reasoning": "Selected independent-contractor (score 1). Title matched: \"independent contractor\", \"contractor agreement\". Distinguishing phrases: \"independent contractor\", \"Contractor shall\".",
1087-
"result_hash": "50b3243c01c0d6759f803bf5c4a0a458fc714ca49331a87db4b1cb8638cf977d",
1087+
"result_hash": "970e59bbf68d3908ad73dfca97f5021fd4d400d831b99bd93f8dbcee01d668f6",
10881088
"source_file": {
10891089
"name": "bad-contractor.docx",
10901090
"sha256": "7a40a2e53d068557d47cf7690838b907085994f596a0c6e2380b8ac2607543df",

tests/fixtures/expected/bad-employment-choice-of-law.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"elapsed_ms": 0,
4949
"fired": false,
5050
"rule_id": "CHOICE-008",
51-
"rule_version": "1.1.0"
51+
"rule_version": "1.2.0"
5252
},
5353
{
5454
"elapsed_ms": 0,
@@ -928,7 +928,7 @@
928928
"playbook_id": "employment-at-will-us",
929929
"playbook_match_confidence": 0.9,
930930
"playbook_match_reasoning": "Selected employment-at-will-us (score 0.9). Title matched: \"employment agreement\". Distinguishing phrases: \"at-will\", \"exempt\", \"Employee\".",
931-
"result_hash": "7f31bece164ab776f9a3859b6c109cb83c1ce85233282d2fbdfc2e60978f990f",
931+
"result_hash": "84f0286c6334110df5ccd2cf2e018543704405458e43555ec7c05a28ea5f9531",
932932
"source_file": {
933933
"name": "bad-employment-choice-of-law.docx",
934934
"sha256": "432c209852332e09cdc68eec7a183f61c5da1fa8aafe36b92e3b8bf6fd2e6c26",

tests/fixtures/expected/bad-employment-trap.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
"finding_id": "CHOICE-008-s1.4-1317",
5252
"fired": true,
5353
"rule_id": "CHOICE-008",
54-
"rule_version": "1.1.0"
54+
"rule_version": "1.2.0"
5555
},
5656
{
5757
"elapsed_ms": 0,
@@ -1001,7 +1001,7 @@
10011001
"explanation": "Jury waivers are enforceable in most US jurisdictions but unenforceable in some contexts (e.g., California for pre-dispute employment waivers). Confirm enforceability against the governing-law jurisdiction.",
10021002
"id": "CHOICE-008-s1.4-1317",
10031003
"rule_id": "CHOICE-008",
1004-
"rule_version": "1.1.0",
1004+
"rule_version": "1.2.0",
10051005
"severity": "info",
10061006
"source_citations": [],
10071007
"title": "Jury trial waiver present"
@@ -1027,7 +1027,7 @@
10271027
"playbook_id": "employment-at-will-us",
10281028
"playbook_match_confidence": 0.9,
10291029
"playbook_match_reasoning": "Selected employment-at-will-us (score 0.9). Title matched: \"employment agreement\". Distinguishing phrases: \"at-will\", \"exempt\", \"salary\", \"Employee\".",
1030-
"result_hash": "60d01154930445278cca9fecac3b31f541e44a945a114aa20b36e13de210c86d",
1030+
"result_hash": "401df9c40bb20755bb46a594684fa5d56acaab4c60b7f66b70931aada65080e5",
10311031
"source_file": {
10321032
"name": "bad-employment-trap.docx",
10331033
"sha256": "c0ef11cc8a800daead332bf1bc265f96d72af1c51953958734b1bf18c4058b2a",

tests/fixtures/expected/bad-employment.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
"finding_id": "CHOICE-008-s1.8-1416",
5151
"fired": true,
5252
"rule_id": "CHOICE-008",
53-
"rule_version": "1.1.0"
53+
"rule_version": "1.2.0"
5454
},
5555
{
5656
"elapsed_ms": 0,
@@ -1042,7 +1042,7 @@
10421042
"explanation": "Jury waivers are enforceable in most US jurisdictions but unenforceable in some contexts (e.g., California for pre-dispute employment waivers). Confirm enforceability against the governing-law jurisdiction.",
10431043
"id": "CHOICE-008-s1.8-1416",
10441044
"rule_id": "CHOICE-008",
1045-
"rule_version": "1.1.0",
1045+
"rule_version": "1.2.0",
10461046
"severity": "info",
10471047
"source_citations": [],
10481048
"title": "Jury trial waiver present"
@@ -1232,7 +1232,7 @@
12321232
"playbook_id": "employment-at-will-us",
12331233
"playbook_match_confidence": 1,
12341234
"playbook_match_reasoning": "Selected employment-at-will-us (score 1). Title matched: \"employment agreement\". Required clauses present: \"confidentiality-obligation\". Distinguishing phrases: \"at-will\", \"exempt\", \"salary\", \"Employee\".",
1235-
"result_hash": "6aa20d379f521f1afa8f90082f56b1890b1773b8c31a27c5dfc76245ad3d6c48",
1235+
"result_hash": "8be7a448b53b38d4d23fbfc1d4520f52493999dd55b44b86f0f7eac7862afdab",
12361236
"source_file": {
12371237
"name": "bad-employment.docx",
12381238
"sha256": "44e689f2fe4e8767866844995363dda962260fd37d54469e6d0fdf443136013c",

tests/fixtures/expected/bad-lease-cam.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"elapsed_ms": 0,
5050
"fired": false,
5151
"rule_id": "CHOICE-008",
52-
"rule_version": "1.1.0"
52+
"rule_version": "1.2.0"
5353
},
5454
{
5555
"elapsed_ms": 0,
@@ -921,7 +921,7 @@
921921
"playbook_id": "lease-commercial-multitenant",
922922
"playbook_match_confidence": 0.9,
923923
"playbook_match_reasoning": "Selected lease-commercial-multitenant (score 0.9). Title matched: \"office lease\". Distinguishing phrases: \"Landlord\", \"Tenant\", \"Premises\", \"Rentable Square Feet\", \"Base Rent\", \"Operating Expenses\".",
924-
"result_hash": "2de7f8c68c55322dba3476016f333cefcf7af8a0a7074b7101f234558d546458",
924+
"result_hash": "843d4747d1a4a8d523ebb6942f03ad59390c88f5805c7c5edf9ee3b0bec3e71f",
925925
"source_file": {
926926
"name": "bad-lease-cam.docx",
927927
"sha256": "1de7804edf376ad66d1a78b0c998aa4a479a18835fa4e104e20057385337a0b6",

0 commit comments

Comments
 (0)