Skip to content

Commit 3c6e927

Browse files
committed
fix(rules): finish the v3 sweep and record the guards that misfired
MSA-011 is the last confirmed instance: a clause that explicitly DECLINES to allocate IP ownership names background and foreground IP — the very terms the rule looks for — so leaving ownership deliberately unresolved scored clean. Ownership then falls to default law, which for commissioned work usually leaves it with the supplier: the outcome the customer is paying to avoid. MSA-002 is REJECTED, not fixed. Its candidate denial was "Customer is not entitled to control the defense" — but that is ordinary drafting, since the indemnitor normally controls the defense. A guard there would accuse a standard indemnity clause. The narrowing MSA-011 needed makes the same point: my first frame included "does not ASSIGN ownership", which is exactly what a well-drafted MSA says — each party keeps its own background IP. Only verbs that decline to RESOLVE the question count. Both the denial and that decoy are now in the harness. docs/express-denial-sweep.md now covers v3 as well as v4, and gains a table of the six guards written during this sweep that accused compliant drafting and had to be narrowed — the § 2870 statutory carve-out, the combined bond-or- surety waiver, landlord-side insurance, a claims carve-out, legal-hold retention, and this one. The common thread is that the compliant clause very often CONTAINS a negation, so a frame keyed on "not <verb>" alone will find it. That table is the most useful thing in the document for anyone writing the next guard. 23 rules fixed across v3 and v4. 340 goldens re-baselined, result_hash only.
1 parent e4dd90b commit 3c6e927

343 files changed

Lines changed: 429 additions & 350 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.

docs/express-denial-sweep.md

Lines changed: 51 additions & 8 deletions

src/engine/rules/v3/msa-addenda-nda-express-denial.test.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,23 @@ const CASES: [Rule[], string, string, boolean, string][] = [
3434
true,
3535
"Supplier does not indemnify Customer for any third-party IP infringement claim.",
3636
],
37+
[
38+
MSA_DEEP_RULES,
39+
"MSA-011",
40+
CLEAN_MSA,
41+
true,
42+
"This Agreement does not allocate ownership of background IP or foreground IP created hereunder; ownership remains unresolved.",
43+
],
44+
[
45+
// A well-drafted MSA says the agreement "does not assign ownership of
46+
// background IP" — each party keeps its own. Only a refusal to RESOLVE
47+
// ownership is a denial, so this decoy must stay silent.
48+
MSA_DEEP_RULES,
49+
"",
50+
CLEAN_MSA,
51+
false,
52+
"Each party retains its background IP and grants a licence; this Agreement does not assign ownership of background IP to the other party.",
53+
],
3754
[
3855
MSA_DEEP_RULES,
3956
"MSA-016",
@@ -135,7 +152,10 @@ const denied = (rules: Rule[], text: string): string[] =>
135152
rules
136153
.filter((r) => {
137154
const f = r.check(buildContext(["Agreement", text]));
138-
return f !== null && /disclaim|denied/i.test(f.title);
155+
// "declined" joins the vocabulary with MSA-011. None of the
156+
// missing-clause titles in these packs use these words, so the filter
157+
// still proves it was `denied_if` that matched.
158+
return f !== null && /disclaim|denied|declined/i.test(f.title);
139159
})
140160
.map((r) => r.id);
141161

src/engine/rules/v3/msa-deep/rules.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ export const MSA_DEEP_RULES: Rule[] = [
411411
// ────────────────────────────────────────────────────────────────
412412
presence({
413413
id: "MSA-011",
414-
version: "1.1.0",
414+
version: "1.2.0",
415415
name: "Background / foreground IP allocation",
416416
description:
417417
"MSA must allocate ownership of background IP (pre-existing) and foreground IP (created during the engagement).",
@@ -433,6 +433,22 @@ export const MSA_DEEP_RULES: Rule[] = [
433433
/(background\s+(?:IP|intellectual\s+property)|pre[- ]existing\s+(?:IP|intellectual\s+property))/i,
434434
/(foreground\s+(?:IP|intellectual\s+property)|(?:developed|created|made|conceived)\s+(?:hereunder|under\s+this\s+Agreement))/i,
435435
],
436+
// Express-denial guard: a clause that explicitly DECLINES to allocate IP
437+
// names background and foreground IP, the very terms the rule looks for,
438+
// so it satisfied the presence check. Leaving ownership unresolved on
439+
// purpose is the failure this rule exists to surface.
440+
denied_if: [
441+
// NOT "assign": "this Agreement does not assign ownership of background
442+
// IP to the other party" is exactly what a well-drafted MSA says — each
443+
// party keeps its own background IP. Only verbs that decline to RESOLVE
444+
// the question count as a denial.
445+
/\b(?:does|do|shall|will)\s+not\s+(?:allocate|determine|address|resolve)\b[^.]{0,60}?\bownership/i,
446+
/\bownership\b[^.]{0,40}?\b(?:remains|is)\s+(?:unresolved|undetermined|unallocated)/i,
447+
/\bno\s+allocation\s+of\s+(?:ip|intellectual\s+property)\s+ownership/i,
448+
],
449+
denied_title: "IP ownership allocation expressly declined",
450+
denied_description:
451+
"The agreement states that it does not allocate ownership of background or foreground IP. Ownership then falls to default law, which for commissioned work usually leaves it with the supplier — the outcome the customer is paying to avoid, and worse than silence because it is deliberate.",
436452
default_severity: "warning",
437453
}),
438454
language({

tests/golden/v3/expected/ai-addendum-minimal-pass.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/golden/v3/expected/ai-addendum-missing-ai-definitions-fail.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/golden/v3/expected/ai-addendum-missing-fine-tuning-deletion-fail.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/golden/v3/expected/ai-addendum-missing-hallucination-and-human-review-fail.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/golden/v3/expected/ai-addendum-missing-output-ownership-fail.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/golden/v3/expected/ai-addendum-missing-subprocessor-disclosure-fail.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

tests/golden/v3/expected/ai-addendum-missing-transparency-disclosures-fail.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)